!6811 support sendable array buffer

Merge pull request !6811 from lijiamin/fix
This commit is contained in:
openharmony_ci 2024-04-08 15:46:46 +00:00 committed by Gitee
commit 37929da422
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
27 changed files with 1785 additions and 41 deletions

View File

@ -573,6 +573,7 @@ ecma_source = [
"ecmascript/builtins/builtins_ark_tools.cpp",
"ecmascript/builtins/builtins_array.cpp",
"ecmascript/builtins/builtins_shared_array.cpp",
"ecmascript/builtins/builtins_sendable_arraybuffer.cpp",
"ecmascript/builtins/builtins_arraybuffer.cpp",
"ecmascript/builtins/builtins_async_from_sync_iterator.cpp",
"ecmascript/builtins/builtins_async_function.cpp",
@ -844,6 +845,7 @@ ecma_source = [
"ecmascript/shared_objects/js_shared_map_iterator.cpp",
"ecmascript/shared_objects/js_shared_set.cpp",
"ecmascript/shared_objects/js_shared_set_iterator.cpp",
"ecmascript/shared_objects/js_sendable_arraybuffer.cpp",
"ecmascript/stackmap/ark_stackmap_builder.cpp",
"ecmascript/stackmap/ark_stackmap_parser.cpp",
"ecmascript/stackmap/litecg/litecg_stackmap_type.cpp",

View File

@ -20,6 +20,7 @@
#include "ecmascript/base/error_type.h"
#include "ecmascript/base/typed_array_helper-inl.h"
#include "ecmascript/builtins/builtins_arraybuffer.h"
#include "ecmascript/builtins/builtins_sendable_arraybuffer.h"
#include "ecmascript/ecma_macros.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
@ -35,6 +36,7 @@
#include "ecmascript/object_factory.h"
#include "ecmascript/property_detector-inl.h"
#include "ecmascript/shared_objects/js_shared_typed_array.h"
#include "ecmascript/shared_objects/js_sendable_arraybuffer.h"
namespace panda::ecmascript::base {
using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
@ -122,13 +124,13 @@ JSTaggedValue TypedArrayHelper::SharedTypedArrayConstructor(EcmaRuntimeCallInfo
if (firstArg->IsTypedArray() || firstArg->IsSharedTypedArray()) {
return TypedArrayHelper::CreateFromTypedArray(argv, obj, arrayType);
}
if (firstArg->IsArrayBuffer() || firstArg->IsSharedArrayBuffer()) {
return TypedArrayHelper::CreateFromArrayBuffer(argv, obj, arrayType);
if (firstArg->IsArrayBuffer() || firstArg->IsSharedArrayBuffer() || firstArg->IsSendableArrayBuffer()) {
return TypedArrayHelper::CreateFromSendableArrayBuffer(argv, obj, arrayType);
}
if (firstArg->IsStableJSArray(thread)) {
return TypedArrayHelper::FastCopyElementFromArray(argv, obj, arrayType);
}
return TypedArrayHelper::CreateFromOrdinaryObject(argv, obj, arrayType);
return TypedArrayHelper::CreateFromSendableOrdinaryObject(argv, obj, arrayType);
}
JSTaggedValue TypedArrayHelper::FastCopyElementFromArray(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
@ -248,6 +250,100 @@ JSTaggedValue TypedArrayHelper::CreateFromOrdinaryObject(EcmaRuntimeCallInfo *ar
return obj.GetTaggedValue();
}
// es11 22.2.4.4 TypedArray ( object )
JSTaggedValue TypedArrayHelper::CreateFromSendableOrdinaryObject(EcmaRuntimeCallInfo *argv,
const JSHandle<JSObject> &obj,
const DataViewType arrayType)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
EcmaVM *ecmaVm = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv();
JSHandle<JSTaggedValue> objectArg = BuiltinsBase::GetCallArg(argv, 0);
JSHandle<JSObject> object(objectArg);
// 5. Let usingIterator be ? GetMethod(object, @@iterator).
JSHandle<JSTaggedValue> iteratorSymbol = env->GetIteratorSymbol();
JSHandle<JSTaggedValue> usingIterator =
JSObject::GetMethod(thread, JSHandle<JSTaggedValue>::Cast(object), iteratorSymbol);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 6. If usingIterator is not undefined, then
if (!usingIterator->IsUndefined()) {
CVector<JSHandle<JSTaggedValue>> vec;
// a. Let values be ? IterableToList(object, usingIterator).
// b. Let len be the number of elements in values.
// c. Perform ? AllocateTypedArrayBuffer(O, len).
JSHandle<JSTaggedValue> iterator = JSIterator::GetIterator(thread, objectArg, usingIterator);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> next(thread, JSTaggedValue::True());
while (!next->IsFalse()) {
next = JSIterator::IteratorStep(thread, iterator);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (!next->IsFalse()) {
JSHandle<JSTaggedValue> nextValue = JSIterator::IteratorValue(thread, next);
vec.push_back(nextValue);
}
}
uint32_t len = static_cast<uint32_t>(vec.size());
TypedArrayHelper::AllocateSharedTypedArrayBuffer(thread, obj, len, arrayType);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// d. Let k be 0.
// e. Repeat, while k < len
// i. Let Pk be ! ToString(k).
// ii. Let kValue be the first element of values and remove that element from values.
// iii. Perform ? Set(O, Pk, kValue, true).
// iv. Set k to k + 1.
JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
uint32_t k = 0;
while (k < len) {
tKey.Update(JSTaggedValue(k));
JSHandle<JSTaggedValue> kKey(JSTaggedValue::ToString(thread, tKey));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> kValue = vec[k];
JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), kKey, kValue, true);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
k++;
}
// f. Assert: values is now an empty List.
// g. Return O.
return obj.GetTaggedValue();
}
// 7. NOTE: object is not an Iterable so assume it is already an array-like object.
// 8. Let arrayLike be object.
// 9. Let len be ? LengthOfArrayLike(arrayLike).
JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
JSTaggedNumber lenTemp =
JSTaggedValue::ToLength(thread, JSTaggedValue::GetProperty(thread, objectArg, lengthKey).GetValue());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint64_t rawLen = lenTemp.GetNumber();
// 10. Perform ? AllocateTypedArrayBuffer(O, len).
TypedArrayHelper::AllocateSharedTypedArrayBuffer(thread, obj, rawLen, arrayType);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 11. Let k be 0.
// 12. Repeat, while k < len
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(arrayLike, Pk).
// c. Perform ? Set(O, Pk, kValue, true).
// d. Set k to k + 1.
JSMutableHandle<JSTaggedValue> tKey(thread, JSTaggedValue::Undefined());
uint32_t len = static_cast<uint32_t>(rawLen);
uint32_t k = 0;
while (k < len) {
tKey.Update(JSTaggedValue(k));
JSHandle<JSTaggedValue> kKey(JSTaggedValue::ToString(thread, tKey));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> kValue = JSTaggedValue::GetProperty(thread, objectArg, kKey).GetValue();
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSTaggedValue::SetProperty(thread, JSHandle<JSTaggedValue>::Cast(obj), kKey, kValue, true);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
k++;
}
// 13. Return O.
return obj.GetTaggedValue();
}
// es11 22.2.4.3 TypedArray ( typedArray )
JSTaggedValue TypedArrayHelper::CreateFromTypedArray(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
const DataViewType arrayType)
@ -423,6 +519,78 @@ JSTaggedValue TypedArrayHelper::CreateFromArrayBuffer(EcmaRuntimeCallInfo *argv,
return obj.GetTaggedValue();
}
// es11 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
JSTaggedValue TypedArrayHelper::CreateFromSendableArrayBuffer(EcmaRuntimeCallInfo *argv,
const JSHandle<JSObject> &obj,
const DataViewType arrayType)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
// 5. Let elementSize be the Element Size value specified in Table 61 for constructorName.
// 6. Let offset be ? ToIndex(byteOffset).
uint32_t elementSize = TypedArrayHelper::GetSizeFromType(arrayType);
JSHandle<JSTaggedValue> byteOffset = BuiltinsBase::GetCallArg(argv, 1);
JSTaggedNumber index = JSTaggedValue::ToIndex(thread, byteOffset);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
auto offset = static_cast<uint32_t>(index.GetNumber());
// 7. If offset modulo elementSize ≠ 0, throw a RangeError exception.
if (offset % elementSize != 0) {
THROW_RANGE_ERROR_AND_RETURN(thread, "The offset cannot be an integral multiple of elementSize.",
JSTaggedValue::Exception());
}
// 8. If length is not undefined, then
// a. Let newLength be ? ToIndex(length).
JSHandle<JSTaggedValue> length = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
uint64_t newLength = 0;
if (!length->IsUndefined()) {
index = JSTaggedValue::ToIndex(thread, length);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
newLength = static_cast<uint64_t>(index.GetNumber());
}
// 9. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
JSHandle<JSTaggedValue> buffer = BuiltinsBase::GetCallArg(argv, 0);
if (builtins::BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The srcData is detached buffer.", JSTaggedValue::Exception());
}
// 10. Let bufferByteLength be buffer.[[ArrayBufferByteLength]].
uint32_t bufferByteLength = JSHandle<JSSendableArrayBuffer>(buffer)->GetArrayBufferByteLength();
// 11. If length is undefined, then
// a. If bufferByteLength modulo elementSize ≠ 0, throw a RangeError exception.
// b. Let newByteLength be bufferByteLength - offset.
// c. If newByteLength < 0, throw a RangeError exception.
uint64_t newByteLength = 0;
if (length->IsUndefined()) {
if (bufferByteLength % elementSize != 0) {
THROW_RANGE_ERROR_AND_RETURN(thread, "The bufferByteLength cannot be an integral multiple of elementSize.",
JSTaggedValue::Exception());
}
if (bufferByteLength < offset) {
THROW_RANGE_ERROR_AND_RETURN(thread, "The newByteLength is less than 0.", JSTaggedValue::Exception());
}
newByteLength = bufferByteLength - offset;
} else {
// 12. Else,
// a. Let newByteLength be newLength × elementSize.
// b. If offset + newByteLength > bufferByteLength, throw a RangeError exception.
newByteLength = newLength * elementSize;
if (offset + newByteLength > bufferByteLength) {
THROW_RANGE_ERROR_AND_RETURN(thread, "The newByteLength is out of range.", JSTaggedValue::Exception());
}
}
// 13. Set O.[[ViewedArrayBuffer]] to buffer.
// 14. Set O.[[ByteLength]] to newByteLength.
// 15. Set O.[[ByteOffset]] to offset.
// 16. Set O.[[ArrayLength]] to newByteLength / elementSize.
JSSharedTypedArray *jsTypedArray = JSSharedTypedArray::Cast(*obj);
jsTypedArray->SetViewedArrayBufferOrByteArray(thread, buffer);
jsTypedArray->SetByteLength(newByteLength);
jsTypedArray->SetByteOffset(offset);
jsTypedArray->SetArrayLength(newByteLength / elementSize);
// 17. Return O.
return obj.GetTaggedValue();
}
// es11 22.2.4.2.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto )
JSHandle<JSObject> TypedArrayHelper::AllocateTypedArray(JSThread *thread,
const JSHandle<JSTaggedValue> &constructorName,
@ -621,7 +789,7 @@ JSHandle<JSObject> TypedArrayHelper::AllocateSharedTypedArrayBuffer(JSThread *th
if (byteLength > JSTypedArray::MAX_ONHEAP_LENGTH) {
JSHandle<JSTaggedValue> constructor = thread->GetEcmaVM()->GetGlobalEnv()->GetArrayBufferFunction();
data = JSHandle<JSTaggedValue>(thread,
BuiltinsArrayBuffer::AllocateArrayBuffer(thread, constructor, byteLength));
builtins::BuiltinsSendableArrayBuffer::AllocateSendableArrayBuffer(thread, constructor, byteLength));
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle<JSObject>(thread, JSTaggedValue::Exception()));
ASSERT_PRINT(!JSHandle<TaggedObject>(obj)->GetClass()->IsOnHeapFromBitField(), "must be not on heap");
} else {

View File

@ -95,10 +95,15 @@ public:
private:
static JSTaggedValue CreateFromOrdinaryObject(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
const DataViewType arrayType);
static JSTaggedValue CreateFromSendableOrdinaryObject(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
const DataViewType arrayType);
static JSTaggedValue CreateFromTypedArray(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
const DataViewType arrayType);
static JSTaggedValue CreateFromArrayBuffer(EcmaRuntimeCallInfo *argv, const JSHandle<JSObject> &obj,
const DataViewType arrayType);
static JSTaggedValue CreateFromSendableArrayBuffer(EcmaRuntimeCallInfo *argv,
const JSHandle<JSObject> &obj,
const DataViewType arrayType);
static JSHandle<JSObject> AllocateTypedArrayBuffer(JSThread *thread, const JSHandle<JSObject> &obj,
uint64_t length, const DataViewType arrayType);
static JSHandle<JSObject> AllocateSharedTypedArrayBuffer(JSThread *thread, const JSHandle<JSObject> &obj,

View File

@ -3837,6 +3837,11 @@ void Builtins::RegisterSendableContainers(const JSHandle<GlobalEnv> &env) const
PropertyDescriptor desc(thread_, env->GetSharedArrayFunction(), true, false, true);
JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc);
}
{
JSHandle<JSTaggedValue> nameString(factory_->NewFromUtf8("SendableArrayBuffer"));
PropertyDescriptor desc(thread_, env->GetSBuiltininArrayBufferFunction(), true, false, true);
JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc);
}
#define REGISTER_BUILTIN_SHARED_TYPED_ARRAY(Type, ctorName, TYPE, bytesPerElement) \
{ \
JSHandle<JSTaggedValue> nameString(factory_->NewFromUtf8(#ctorName)); \

View File

@ -363,6 +363,8 @@ private:
const JSHandle<JSFunction> &sFuncPrototype) const;
void InitializeSFunction(const JSHandle<GlobalEnv> &env,
const JSHandle<JSFunction> &sFuncPrototype) const;
void InitializeSArrayBuffer(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &objFuncClass,
const JSHandle<JSFunction> &sFuncPrototype) const;
void InitializeSSet(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &sObjPrototype,
const JSHandle<JSFunction> &sFuncPrototype) const;
void InitializeSMap(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &sObjPrototype,
@ -394,6 +396,8 @@ private:
JSHandle<JSHClass> CreateSTypedArrayPrototypeHClass(const JSHandle<JSObject> &sObjPrototype) const;
JSHandle<JSHClass> CreateSTypedArrayFunctionHClass(const JSHandle<JSFunction> &sFuncPrototype) const;
JSHandle<JSHClass> CreateSSpecificTypedArrayFuncHClass(const JSHandle<JSFunction> &sFuncPrototype) const;
JSHandle<JSHClass> CreateSArrayBufferPrototypeHClass(const JSHandle<JSObject> &sObjPrototype) const;
JSHandle<JSHClass> CreateSArrayBufferFunctionHClass(const JSHandle<JSFunction> &sFuncPrototype) const;
void InitializeSCtor(const JSHandle<JSHClass> &protoHClass, const JSHandle<JSFunction> &ctor,
std::string_view name, int length) const;

View File

@ -0,0 +1,956 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/builtins/builtins_sendable_arraybuffer.h"
#include <typeinfo>
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/base/number_helper.h"
#include "ecmascript/builtins/builtins_bigint.h"
#include "ecmascript/ecma_macros.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/js_arraybuffer.h"
#include "ecmascript/js_object-inl.h"
#include "ecmascript/js_tagged_number.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/shared_objects/js_sendable_arraybuffer.h"
#include "ecmascript/base/typed_array_helper-inl.h"
#include "ecmascript/base/typed_array_helper.h"
#include "securec.h"
#include "cstdio"
#include "cstring"
namespace panda::ecmascript::builtins {
using TypedArrayHelper = base::TypedArrayHelper;
// 24.1.2.1 ArrayBuffer(length)
JSTaggedValue BuiltinsSendableArrayBuffer::ArrayBufferConstructor(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, SendableArrayBuffer, Constructor);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
// 1. If NewTarget is undefined, throw a TypeError exception.
if (newTarget->IsUndefined()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "newtarget is undefined", JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> lengthHandle = GetCallArg(argv, 0);
JSTaggedNumber lenNum = JSTaggedValue::ToIndex(thread, lengthHandle);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint64_t length = lenNum.GetNumber();
return AllocateSendableArrayBuffer(thread, newTarget, length);
}
// 24.1.3.1 ArrayBuffer.isView(arg)
JSTaggedValue BuiltinsSendableArrayBuffer::IsView(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, SendableArrayBuffer, IsView);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> arg = GetCallArg(argv, 0);
// 1. If Type(arg) is not Object, return false.
if (!arg->IsECMAObject()) {
return BuiltinsSendableArrayBuffer::GetTaggedBoolean(false);
}
// 2. If arg has a [[ViewedArrayBuffer]] internal slot, return true.
if (arg->IsDataView() || arg->IsTypedArray()) {
return BuiltinsSendableArrayBuffer::GetTaggedBoolean(true);
}
// 3. Return false.
return BuiltinsSendableArrayBuffer::GetTaggedBoolean(false);
}
// 24.1.3.3 get ArrayBuffer [ @@species ]
JSTaggedValue BuiltinsSendableArrayBuffer::Species(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(argv->GetThread(), SendableArrayBuffer, Species);
return GetThis(argv).GetTaggedValue();
}
// 24.1.4.1 get ArrayBuffer.prototype.byteLength
JSTaggedValue BuiltinsSendableArrayBuffer::GetByteLength(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, SendableArrayBuffer, GetByteLength);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
// 1. Let O be the this value.
JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
// 2. If Type(O) is not Object, throw a TypeError exception.
if (!thisHandle->IsECMAObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not an object", JSTaggedValue::Exception());
}
// 3. If O does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
if (!thisHandle->IsSendableArrayBuffer()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "don't have internal slot", JSTaggedValue::Exception());
}
// 4. If IsDetachedBuffer(O) is true, throw a TypeError exception.
if (IsDetachedBuffer(thisHandle.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "IsDetachedBuffer", JSTaggedValue::Exception());
}
JSHandle<JSSendableArrayBuffer> arrBuf(thisHandle);
// 5. Let length be the value of Os [[ArrayBufferByteLength]] internal slot.
uint32_t length = arrBuf->GetArrayBufferByteLength();
// 6. Return length.
return JSTaggedValue(length);
}
// 24.1.4.3 ArrayBuffer.prototype.slice(start, end)
JSTaggedValue BuiltinsSendableArrayBuffer::Slice(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, SendableArrayBuffer, Slice);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
// 1. Let O be the this value.
JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
// 2. If Type(O) is not Object, throw a TypeError exception.
if (!thisHandle->IsHeapObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not an object", JSTaggedValue::Exception());
}
JSHandle<JSArrayBuffer> arrBuf(thisHandle);
// 3. If O does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
if (!thisHandle->IsSendableArrayBuffer()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "don't have internal slot", JSTaggedValue::Exception());
}
// 4. If IsDetachedBuffer(O) is true, throw a TypeError exception.
if (IsDetachedBuffer(thisHandle.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "this value IsDetachedBuffer", JSTaggedValue::Exception());
}
// 5. Let len be the value of Os [[ArrayBufferByteLength]] internal slot.
int32_t len = static_cast<int32_t>(arrBuf->GetArrayBufferByteLength());
JSHandle<JSTaggedValue> startHandle = GetCallArg(argv, 0);
// 6. Let relativeStart be ToInteger(start).
JSTaggedNumber relativeStart = JSTaggedValue::ToInteger(thread, startHandle);
// 7. ReturnIfAbrupt(relativeStart).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
int32_t start = base::NumberHelper::DoubleInRangeInt32(relativeStart.GetNumber());
int32_t end = 0;
int32_t first = 0;
int32_t last = 0;
// 8. If relativeStart < 0, let first be max((len + relativeStart),0); else let first be min(relativeStart, len).
if (start < 0) {
first = std::max((len + start), 0);
} else {
first = std::min(start, len);
}
// 9. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
JSHandle<JSTaggedValue> endHandle = GetCallArg(argv, 1);
if (endHandle->IsUndefined()) {
end = len;
} else {
JSTaggedNumber relativeEnd = JSTaggedValue::ToInteger(thread, endHandle);
// 10. ReturnIfAbrupt(relativeEnd).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
end = base::NumberHelper::DoubleInRangeInt32(relativeEnd.GetNumber());
}
// 11. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
if (end < 0) {
last = std::max((len + end), 0);
} else {
last = std::min(end, len);
}
// 12. Let newLen be max(final-first,0).
uint32_t newLen = std::max((last - first), 0);
// 13. Let ctor be SpeciesConstructor(O, %ArrayBuffer%).
JSHandle<JSTaggedValue> defaultConstructor = env->GetSBuiltininArrayBufferFunction();
JSHandle<JSObject> objHandle(thisHandle);
JSHandle<JSTaggedValue> constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor);
// 14. ReturnIfAbrupt(ctor).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 15. Let new be Construct(ctor, «newLen»).
JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, constructor, undefined, undefined, 1);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(JSTaggedValue(newLen));
JSTaggedValue taggedNewArrBuf = JSFunction::Construct(info);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> newArrBuf(thread, taggedNewArrBuf);
// 16. ReturnIfAbrupt(new).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 17. If new does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
if (!newArrBuf->IsSendableArrayBuffer()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "don't have bufferdata internal slot", JSTaggedValue::Exception());
}
// 18. If IsDetachedBuffer(new) is true, throw a TypeError exception.
if (IsDetachedBuffer(newArrBuf.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "new arrayBuffer IsDetachedBuffer", JSTaggedValue::Exception());
}
// 19. If SameValue(new, O) is true, throw a TypeError exception.
if (JSTaggedValue::SameValue(newArrBuf.GetTaggedValue(), thisHandle.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "value of new arraybuffer and this is same", JSTaggedValue::Exception());
}
JSHandle<JSSendableArrayBuffer> newJsArrBuf(newArrBuf);
// 20. If the value of news [[ArrayBufferByteLength]] internal slot < newLen, throw a TypeError exception.
uint32_t newArrBufLen = newJsArrBuf->GetArrayBufferByteLength();
if (newArrBufLen < newLen) {
THROW_TYPE_ERROR_AND_RETURN(thread, "new array buffer length smaller than newlen", JSTaggedValue::Exception());
}
// 21. NOTE: Side-effects of the above steps may have detached O.
// 22. If IsDetachedBuffer(O) is true, throw a TypeError exception.
if (IsDetachedBuffer(thisHandle.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "this value IsDetachedBuffer", JSTaggedValue::Exception());
}
if (newLen > 0) {
// 23. Let fromBuf be the value of Os [[ArrayBufferData]] internal slot.
void *fromBuf = GetDataPointFromBuffer(arrBuf.GetTaggedValue());
// 24. Let toBuf be the value of news [[ArrayBufferData]] internal slot.
void *toBuf = GetDataPointFromBuffer(newJsArrBuf.GetTaggedValue());
// 25. Perform CopyDataBlockBytes(toBuf, fromBuf, first, newLen).
JSArrayBuffer::CopyDataPointBytes(toBuf, fromBuf, first, newLen);
}
// Return new.
return newArrBuf.GetTaggedValue();
}
// 24.1.1.1 AllocateArrayBuffer(constructor, byteLength)
JSTaggedValue BuiltinsSendableArrayBuffer::AllocateSendableArrayBuffer(
JSThread *thread, const JSHandle<JSTaggedValue> &newTarget, uint64_t byteLength)
{
BUILTINS_API_TRACE(thread, SendableArrayBuffer, AllocateSendableArrayBuffer);
/**
* 1. Let obj be OrdinaryCreateFromConstructor(constructor, "%ArrayBufferPrototype%",
* «[[ArrayBufferData]], [[ArrayBufferByteLength]]» ).
* */
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> arrBufFunc = env->GetSBuiltininArrayBufferFunction();
JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(arrBufFunc), newTarget);
ASSERT(obj.GetTaggedValue().IsInSharedHeap());
// 2. ReturnIfAbrupt
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 4. Let block be CreateByteDataBlock(byteLength).
if (byteLength > INT_MAX) {
THROW_RANGE_ERROR_AND_RETURN(thread, "Out of range", JSTaggedValue::Exception());
}
uint64_t totalNativeSize = static_cast<uint64_t>(thread->GetNativeAreaAllocator()->GetArrayBufferNativeSize());
if (UNLIKELY(totalNativeSize > MAX_NATIVE_SIZE_LIMIT)) {
THROW_RANGE_ERROR_AND_RETURN(thread, NATIVE_SIZE_OUT_OF_LIMIT_MESSAGE, JSTaggedValue::Exception());
}
uint32_t arrayByteLength = static_cast<uint32_t>(byteLength);
JSHandle<JSSendableArrayBuffer> arrayBuffer(obj);
// 6. Set objs [[ArrayBufferData]] internal slot to block.
factory->NewJSSendableArrayBufferData(arrayBuffer, arrayByteLength);
// 7. Set objs [[ArrayBufferByteLength]] internal slot to byteLength.
arrayBuffer->SetArrayBufferByteLength(arrayByteLength);
// 8. Return obj.
return arrayBuffer.GetTaggedValue();
}
// 24.1.1.2 IsDetachedBuffer()
bool BuiltinsSendableArrayBuffer::IsDetachedBuffer(JSTaggedValue arrayBuffer)
{
if (arrayBuffer.IsByteArray()) {
return false;
}
// 1. Assert: Type(arrayBuffer) is Object and it has an [[ArrayBufferData]] internal slot.
ASSERT(arrayBuffer.IsSendableArrayBuffer());
JSSendableArrayBuffer *buffer = JSSendableArrayBuffer::Cast(arrayBuffer.GetTaggedObject());
JSTaggedValue dataSlot = buffer->GetArrayBufferData();
// 2. If arrayBuffers [[ArrayBufferData]] internal slot is null, return true.
// 3. Return false.
return dataSlot.IsNull();
}
// 24.1.1.4
JSTaggedValue BuiltinsSendableArrayBuffer::CloneArrayBuffer(JSThread *thread,
const JSHandle<JSTaggedValue> &srcBuffer,
uint32_t srcByteOffset,
JSHandle<JSTaggedValue> constructor)
{
BUILTINS_API_TRACE(thread, SendableArrayBuffer, CloneArrayBuffer);
// 1. Assert: Type(srcBuffer) is Object and it has an [[ArrayBufferData]] internal slot.
ASSERT(srcBuffer->IsSendableArrayBuffer() || srcBuffer->IsSharedArrayBuffer() || srcBuffer->IsByteArray());
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
// 2. If cloneConstructor is not present
if (constructor->IsUndefined()) {
// a. Let cloneConstructor be SpeciesConstructor(srcBuffer, %ArrayBuffer%).
JSHandle<JSTaggedValue> defaultConstructor = env->GetSBuiltininArrayBufferFunction();
JSHandle<JSObject> objHandle(srcBuffer);
constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor);
// b. ReturnIfAbrupt(cloneConstructor).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// c. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
if (IsDetachedBuffer(srcBuffer.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", JSTaggedValue::Exception());
} else {
ASSERT(constructor->IsConstructor());
}
}
// 4. Let srcLength be the value of srcBuffers [[ArrayBufferByteLength]] internal slot.
JSHandle<JSArrayBuffer> arrBuf(srcBuffer);
uint32_t srcLen = arrBuf->GetArrayBufferByteLength();
// 5. Assert: srcByteOffset ≤ srcLength.
ASSERT(srcByteOffset <= srcLen);
// 6. Let cloneLength be srcLength srcByteOffset.
int32_t cloneLen = static_cast<int32_t>(srcLen - srcByteOffset);
// 8. Let targetBuffer be AllocateArrayBuffer(cloneConstructor, cloneLength).
JSTaggedValue taggedBuf = AllocateSendableArrayBuffer(thread, constructor, cloneLen);
// 9. ReturnIfAbrupt(targetBuffer).
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 10. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
if (IsDetachedBuffer(srcBuffer.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", JSTaggedValue::Exception());
}
// 11. Let targetBlock be the value of targetBuffers [[ArrayBufferData]] internal slot.
JSHandle<JSArrayBuffer> newArrBuf(thread, taggedBuf);
// Perform CopyDataBlockBytes(targetBlock, 0, srcBlock, srcByteOffset, cloneLength).
// 7. Let srcBlock be the value of srcBuffers [[ArrayBufferData]] internal slot.
void *fromBuf = GetDataPointFromBuffer(arrBuf.GetTaggedValue());
void *toBuf = GetDataPointFromBuffer(taggedBuf);
if (cloneLen > 0) {
JSArrayBuffer::CopyDataPointBytes(toBuf, fromBuf, srcByteOffset, cloneLen);
}
return taggedBuf;
}
// 24.1.1.5
// NOLINTNEXTLINE(readability-function-size)
JSTaggedValue BuiltinsSendableArrayBuffer::GetValueFromBuffer(
JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex, DataViewType type, bool littleEndian)
{
void *pointer = GetDataPointFromBuffer(arrBuf);
uint8_t *block = reinterpret_cast<uint8_t *>(pointer);
return GetValueFromBuffer(thread, byteIndex, block, type, littleEndian);
}
JSTaggedValue BuiltinsSendableArrayBuffer::GetValueFromBuffer(JSThread *thread, uint32_t byteIndex, uint8_t *block,
DataViewType type, bool littleEndian)
{
switch (type) {
case DataViewType::UINT8:
case DataViewType::UINT8_CLAMPED: {
uint8_t res = block[byteIndex]; // NOLINT
return GetTaggedInt(res);
}
case DataViewType::INT8: {
uint8_t res = block[byteIndex]; // NOLINT
auto int8Res = static_cast<int8_t>(res);
return GetTaggedInt(int8Res);
}
case DataViewType::UINT16:
return GetValueFromBufferForInteger<uint16_t, NumberSize::UINT16>(block, byteIndex, littleEndian);
case DataViewType::INT16:
return GetValueFromBufferForInteger<int16_t, NumberSize::INT16>(block, byteIndex, littleEndian);
case DataViewType::UINT32:
return GetValueFromBufferForInteger<uint32_t, NumberSize::UINT32>(block, byteIndex, littleEndian);
case DataViewType::INT32:
return GetValueFromBufferForInteger<int32_t, NumberSize::INT32>(block, byteIndex, littleEndian);
case DataViewType::FLOAT32:
return GetValueFromBufferForFloat<float, UnionType32, NumberSize::FLOAT32>(block, byteIndex, littleEndian);
case DataViewType::FLOAT64:
return GetValueFromBufferForFloat<double, UnionType64, NumberSize::FLOAT64>(block, byteIndex, littleEndian);
case DataViewType::BIGINT64:
return GetValueFromBufferForBigInt<int64_t, NumberSize::BIGINT64>(thread, block, byteIndex, littleEndian);
case DataViewType::BIGUINT64:
return GetValueFromBufferForBigInt<uint64_t, NumberSize::BIGUINT64>(thread, block, byteIndex, littleEndian);
default:
break;
}
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
// 24.1.1.6
JSTaggedValue BuiltinsSendableArrayBuffer::SetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex,
DataViewType type, const JSHandle<JSTaggedValue> &value,
bool littleEndian)
{
if (UNLIKELY(IsBigIntElementType(type))) {
JSHandle<JSTaggedValue> arrBufHandle(thread, arrBuf);
switch (type) {
case DataViewType::BIGINT64:
SetValueInBufferForBigInt<int64_t>(thread, value, arrBufHandle, byteIndex, littleEndian);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
break;
case DataViewType::BIGUINT64:
SetValueInBufferForBigInt<uint64_t>(thread, value, arrBufHandle, byteIndex, littleEndian);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
return JSTaggedValue::Undefined();
}
void *pointer = GetDataPointFromBuffer(arrBuf);
uint8_t *block = reinterpret_cast<uint8_t *>(pointer);
JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, value.GetTaggedValue());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
double val = numberValue.GetNumber();
return SetValueInBuffer(thread, byteIndex, block, type, val, littleEndian);
}
// es12 25.1.2.7 IsBigIntElementType ( type )
bool BuiltinsSendableArrayBuffer::IsBigIntElementType(DataViewType type)
{
if (type == DataViewType::BIGINT64 || type == DataViewType::BIGUINT64) {
return true;
}
return false;
}
// es12 25.1.2.6 IsUnclampedIntegerElementType ( type )
bool BuiltinsSendableArrayBuffer::IsUnclampedIntegerElementType(DataViewType type)
{
switch (type) {
case DataViewType::INT8:
case DataViewType::INT16:
case DataViewType::INT32:
case DataViewType::UINT8:
case DataViewType::UINT16:
case DataViewType::UINT32:
return true;
default:
return false;
}
}
template<typename T>
void BuiltinsSendableArrayBuffer::SetTypeData(uint8_t *block, T value, uint32_t index)
{
uint32_t sizeCount = sizeof(T);
uint8_t *res = reinterpret_cast<uint8_t *>(&value);
for (uint32_t i = 0; i < sizeCount; i++) {
*(block + index + i) = *(res + i); // NOLINT
}
}
template<typename T>
void BuiltinsSendableArrayBuffer::FastSetTypeData(uint8_t *byteBeginOffset, uint8_t *byteEndOffset, T value)
{
uint32_t sizeCount = sizeof(T);
if (sizeCount == 1) {
memset_s(byteBeginOffset, byteEndOffset-byteBeginOffset, value, byteEndOffset-byteBeginOffset);
} else {
uint8_t *resAddr = reinterpret_cast<uint8_t *>(&value);
for (uint8_t *addr = byteBeginOffset; addr < byteEndOffset; addr += sizeCount) {
for (uint32_t i = 0; i < sizeCount; ++i) {
*(addr + i) = *(resAddr + i);
}
}
}
}
template <typename T>
T BuiltinsSendableArrayBuffer::LittleEndianToBigEndian(T liValue)
{
uint8_t sizeCount = sizeof(T);
T biValue;
switch (sizeCount) {
case NumberSize::UINT16:
biValue = ((liValue & 0x00FF) << BITS_EIGHT) // NOLINT
| ((liValue & 0xFF00) >> BITS_EIGHT); // NOLINT
break;
case NumberSize::UINT32:
biValue = ((liValue & 0x000000FF) << BITS_TWENTY_FOUR) // NOLINT
| ((liValue & 0x0000FF00) << BITS_EIGHT) // NOLINT
| ((liValue & 0x00FF0000) >> BITS_EIGHT) // NOLINT
| ((liValue & 0xFF000000) >> BITS_TWENTY_FOUR); // NOLINT
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
break;
}
return biValue;
}
template <typename T>
T BuiltinsSendableArrayBuffer::LittleEndianToBigEndian64Bit(T liValue)
{
return ((liValue & 0x00000000000000FF) << BITS_FIFTY_SIX) // NOLINT
| ((liValue & 0x000000000000FF00) << BITS_FORTY) // NOLINT
| ((liValue & 0x0000000000FF0000) << BITS_TWENTY_FOUR) // NOLINT
| ((liValue & 0x00000000FF000000) << BITS_EIGHT) // NOLINT
| ((liValue & 0x000000FF00000000) >> BITS_EIGHT) // NOLINT
| ((liValue & 0x0000FF0000000000) >> BITS_TWENTY_FOUR) // NOLINT
| ((liValue & 0x00FF000000000000) >> BITS_FORTY) // NOLINT
| ((liValue & 0xFF00000000000000) >> BITS_FIFTY_SIX); // NOLINT
}
template<typename T, BuiltinsSendableArrayBuffer::NumberSize size>
JSTaggedValue BuiltinsSendableArrayBuffer::GetValueFromBufferForInteger(
uint8_t *block, uint32_t byteIndex, bool littleEndian)
{
ASSERT_PRINT(std::is_integral_v<T>, "T must be integral");
ASSERT_PRINT(sizeof(T) == size, "Invalid number size");
ASSERT_PRINT(sizeof(T) >= sizeof(uint16_t), "T must have a size more than uint8");
ASSERT(size >= NumberSize::UINT16 || size <= NumberSize::FLOAT64);
T res = *reinterpret_cast<T *>(block + byteIndex);
if (!littleEndian) {
res = LittleEndianToBigEndian(res);
}
// uint32_t maybe overflow with TaggedInt
// NOLINTNEXTLINE(readability-braces-around-statements,bugprone-suspicious-semicolon)
if constexpr (std::is_same_v<T, uint32_t>) {
// NOLINTNEXTLINE(clang-diagnostic-sign-compare)
if (res > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
return GetTaggedDouble(static_cast<double>(res));
}
}
return GetTaggedInt(res);
}
template<typename T, typename UnionType, BuiltinsSendableArrayBuffer::NumberSize size>
JSTaggedValue BuiltinsSendableArrayBuffer::GetValueFromBufferForFloat(
uint8_t *block, uint32_t byteIndex, bool littleEndian)
{
ASSERT_PRINT((std::is_same_v<T, float> || std::is_same_v<T, double>), "T must be correct type");
ASSERT_PRINT(sizeof(T) == size, "Invalid number size");
UnionType unionValue = {0};
// NOLINTNEXTLINE(readability-braces-around-statements)
if constexpr (std::is_same_v<T, float>) {
unionValue.uValue = *reinterpret_cast<uint32_t *>(block + byteIndex);
uint32_t res = LittleEndianToBigEndian(unionValue.uValue);
return CommonConvert<T, uint32_t>(unionValue.value, res, littleEndian);
} else if constexpr (std::is_same_v<T, double>) { // NOLINTNEXTLINE(readability-braces-around-statements)
unionValue.uValue = *reinterpret_cast<uint64_t *>(block + byteIndex);
uint64_t res = LittleEndianToBigEndian64Bit(unionValue.uValue);
return CommonConvert<T, uint64_t>(unionValue.value, res, littleEndian);
}
return GetTaggedDouble(unionValue.value);
}
template<typename T1, typename T2>
JSTaggedValue BuiltinsSendableArrayBuffer::CommonConvert(T1 &value, T2 &res, bool littleEndian)
{
if (std::isnan(value) && !JSTaggedValue::IsImpureNaN(value)) {
return GetTaggedDouble(value);
}
if (!littleEndian) {
T1 d = base::bit_cast<T1>(res);
if (JSTaggedValue::IsImpureNaN(d)) {
return GetTaggedDouble(base::NAN_VALUE);
}
return GetTaggedDouble(d);
} else {
if (JSTaggedValue::IsImpureNaN(value)) {
return GetTaggedDouble(base::NAN_VALUE);
}
}
return GetTaggedDouble(value);
}
template<typename T, BuiltinsSendableArrayBuffer::NumberSize size>
JSTaggedValue BuiltinsSendableArrayBuffer::GetValueFromBufferForBigInt(JSThread *thread, uint8_t *block,
uint32_t byteIndex, bool littleEndian)
{
ASSERT_PRINT((std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t>), "T must be uint64_t/int64_t");
auto pTmp = *reinterpret_cast<uint64_t *>(block + byteIndex);
if (!littleEndian) {
pTmp = LittleEndianToBigEndian64Bit(pTmp);
}
if constexpr (std::is_same_v<T, uint64_t>) {
return BigInt::Uint64ToBigInt(thread, pTmp).GetTaggedValue();
}
return BigInt::Int64ToBigInt(thread, pTmp).GetTaggedValue();
}
template<typename T>
void BuiltinsSendableArrayBuffer::SetValueInBufferForByte(double val, uint8_t *block, uint32_t byteIndex)
{
ASSERT_PRINT((std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t>), "T must be int8/uint8");
T res;
if (std::isnan(val) || std::isinf(val)) {
res = 0;
SetTypeData(block, res, byteIndex);
return;
}
auto int64Val = static_cast<int64_t>(val);
auto *resArr = reinterpret_cast<T *>(&int64Val);
res = *resArr;
SetTypeData(block, res, byteIndex);
}
void BuiltinsSendableArrayBuffer::SetValueInBufferForUint8Clamped(double val, uint8_t *block, uint32_t byteIndex)
{
uint8_t res;
if (std::isnan(val) || val <= 0) {
res = 0;
} else if (val > UINT8_MAX) {
res = UINT8_MAX;
} else {
// same as ToUint8Clamp
res = std::lrint(val);
}
SetTypeData(block, res, byteIndex);
}
template<typename T>
void BuiltinsSendableArrayBuffer::SetValueInBufferForInteger(
double val, uint8_t *block, uint32_t byteIndex, bool littleEndian)
{
ASSERT_PRINT(std::is_integral_v<T>, "T must be integral");
ASSERT_PRINT(sizeof(T) >= sizeof(uint16_t), "T must have a size more than uint8");
T res;
if (std::isnan(val) || std::isinf(val)) {
res = 0;
SetTypeData(block, res, byteIndex);
return;
}
auto int64Val = static_cast<int64_t>(val);
// NOLINTNEXTLINE(readability-braces-around-statements)
if constexpr (std::is_same_v<T, uint16_t>) {
auto *pTmp = reinterpret_cast<int16_t *>(&int64Val);
int16_t tmp = *pTmp;
res = static_cast<T>(tmp);
} else { // NOLINTNEXTLINE(readability-braces-around-statements)
auto *pTmp = reinterpret_cast<T *>(&int64Val);
res = *pTmp;
}
if (!littleEndian) {
res = LittleEndianToBigEndian<T>(res);
}
SetTypeData(block, res, byteIndex);
}
template<typename T>
void BuiltinsSendableArrayBuffer::SetValueInBufferForFloat(
double val, uint8_t *block, uint32_t byteIndex, bool littleEndian)
{
ASSERT_PRINT((std::is_same_v<T, float> || std::is_same_v<T, double>), "T must be float type");
auto data = static_cast<T>(val);
if (std::isnan(val)) {
SetTypeData(block, data, byteIndex);
return;
}
if (!littleEndian) {
if constexpr (std::is_same_v<T, float>) {
uint32_t res = base::bit_cast<uint32_t>(data);
data = base::bit_cast<T>(LittleEndianToBigEndian(res));
} else if constexpr (std::is_same_v<T, double>) {
uint64_t res = base::bit_cast<uint64_t>(data);
data = base::bit_cast<T>(LittleEndianToBigEndian64Bit(res));
}
}
SetTypeData(block, data, byteIndex);
}
template<typename T>
void BuiltinsSendableArrayBuffer::SetValueInBufferForBigInt(JSThread *thread,
const JSHandle<JSTaggedValue> &val,
JSHandle<JSTaggedValue> &arrBuf,
uint32_t byteIndex, bool littleEndian)
{
ASSERT_PRINT((std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>), "T must be int64_t/uint64_t");
T value = 0;
bool lossless = true;
if constexpr(std::is_same_v<T, uint64_t>) {
BigInt::BigIntToUint64(thread, val, reinterpret_cast<uint64_t *>(&value), &lossless);
} else {
BigInt::BigIntToInt64(thread, val, reinterpret_cast<int64_t *>(&value), &lossless);
}
RETURN_IF_ABRUPT_COMPLETION(thread);
if (!littleEndian) {
value = LittleEndianToBigEndian64Bit<T>(value);
}
void *pointer = GetDataPointFromBuffer(arrBuf.GetTaggedValue());
uint8_t *block = reinterpret_cast<uint8_t *>(pointer);
SetTypeData(block, value, byteIndex);
}
template<typename T>
void BuiltinsSendableArrayBuffer::SetValueInBufferForBigInt(JSThread *thread,
double val, uint8_t *block,
uint32_t byteIndex, bool littleEndian)
{
ASSERT_PRINT((std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>), "T must be int64_t/uint64_t");
T value = 0;
bool lossless = true;
JSHandle<JSTaggedValue> valHandle(thread, GetTaggedDouble(val));
if constexpr(std::is_same_v<T, uint64_t>) {
BigInt::BigIntToUint64(thread, valHandle, reinterpret_cast<uint64_t *>(&value), &lossless);
} else {
BigInt::BigIntToInt64(thread, valHandle, reinterpret_cast<int64_t *>(&value), &lossless);
}
RETURN_IF_ABRUPT_COMPLETION(thread);
if (!littleEndian) {
value = LittleEndianToBigEndian64Bit<T>(value);
}
SetTypeData(block, value, byteIndex);
}
JSTaggedValue BuiltinsSendableArrayBuffer::FastSetValueInBuffer(
JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex, DataViewType type, double val, bool littleEndian)
{
void *pointer = GetDataPointFromBuffer(arrBuf);
uint8_t *block = reinterpret_cast<uint8_t *>(pointer);
return SetValueInBuffer(thread, byteIndex, block, type, val, littleEndian);
}
JSTaggedValue BuiltinsSendableArrayBuffer::SetValueInBuffer(JSThread* thread, uint32_t byteIndex, uint8_t *block,
DataViewType type, double val, bool littleEndian)
{
switch (type) {
case DataViewType::UINT8:
SetValueInBufferForByte<uint8_t>(val, block, byteIndex);
break;
case DataViewType::UINT8_CLAMPED:
SetValueInBufferForUint8Clamped(val, block, byteIndex);
break;
case DataViewType::INT8:
SetValueInBufferForByte<int8_t>(val, block, byteIndex);
break;
case DataViewType::UINT16:
SetValueInBufferForInteger<uint16_t>(val, block, byteIndex, littleEndian);
break;
case DataViewType::INT16:
SetValueInBufferForInteger<int16_t>(val, block, byteIndex, littleEndian);
break;
case DataViewType::UINT32:
SetValueInBufferForInteger<uint32_t>(val, block, byteIndex, littleEndian);
break;
case DataViewType::INT32:
SetValueInBufferForInteger<int32_t>(val, block, byteIndex, littleEndian);
break;
case DataViewType::FLOAT32:
SetValueInBufferForFloat<float>(val, block, byteIndex, littleEndian);
break;
case DataViewType::FLOAT64:
SetValueInBufferForFloat<double>(val, block, byteIndex, littleEndian);
break;
case DataViewType::BIGINT64:
SetValueInBufferForBigInt<int64_t>(thread, val, block, byteIndex, littleEndian);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
break;
case DataViewType::BIGUINT64:
SetValueInBufferForBigInt<uint64_t>(thread, val, block, byteIndex, littleEndian);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
return JSTaggedValue::Undefined();
}
void *BuiltinsSendableArrayBuffer::GetDataPointFromBuffer(JSTaggedValue arrBuf, uint32_t byteOffset)
{
if (arrBuf.IsByteArray()) {
return reinterpret_cast<void *>(ToUintPtr(ByteArray::Cast(arrBuf.GetTaggedObject())->GetData()) + byteOffset);
}
JSSendableArrayBuffer *arrayBuffer = JSSendableArrayBuffer::Cast(arrBuf.GetTaggedObject());
if (arrayBuffer->GetArrayBufferByteLength() == 0) {
return nullptr;
}
JSTaggedValue data = arrayBuffer->GetArrayBufferData();
return reinterpret_cast<void *>(ToUintPtr(JSNativePointer::Cast(data.GetTaggedObject())
->GetExternalPointer()) + byteOffset);
}
JSTaggedValue BuiltinsSendableArrayBuffer::TypedArrayToList(JSThread *thread, JSHandle<JSTypedArray>& items)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> bufferHandle(thread, items->GetViewedArrayBufferOrByteArray());
uint32_t arrayLen = items->GetArrayLength();
JSHandle<JSObject> newArrayHandle(thread, JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<TaggedArray> oldElements(thread, newArrayHandle->GetElements());
JSHandle<TaggedArray> elements = (oldElements->GetLength() < arrayLen) ?
factory->ExtendArray(oldElements, arrayLen) : oldElements;
newArrayHandle->SetElements(thread, elements);
uint32_t offset = items->GetByteOffset();
uint32_t elementSize = TypedArrayHelper::GetElementSize(items);
DataViewType elementType = TypedArrayHelper::GetType(items);
uint32_t index = 0;
while (index < arrayLen) {
uint32_t byteIndex = index * elementSize + offset;
JSHandle<JSTaggedValue> result(thread, GetValueFromBuffer(thread, bufferHandle.GetTaggedValue(),
byteIndex, elementType, true));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
ElementAccessor::Set(thread, newArrayHandle, index, result, true);
index++;
}
JSHandle<JSArray>(newArrayHandle)->SetArrayLength(thread, arrayLen);
return newArrayHandle.GetTaggedValue();
}
template<typename T>
void BuiltinsSendableArrayBuffer::FastSetValueInBufferForByte(uint8_t *byteBeginOffset,
uint8_t *byteEndOffset,
double val)
{
ASSERT_PRINT(sizeof(T) == 1, "sizeof(T) must be one");
ASSERT_PRINT((std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t>), "T must be int8/uint8");
T res;
if (std::isnan(val) || std::isinf(val)) {
res = 0;
} else {
auto int64Val = static_cast<int64_t>(val);
auto *resArr = reinterpret_cast<T *>(&int64Val);
res = *resArr;
}
FastSetTypeData(byteBeginOffset, byteEndOffset, res);
}
void BuiltinsSendableArrayBuffer::FastSetValueInBufferForUint8Clamped(uint8_t *byteBeginOffset,
uint8_t *byteEndOffset,
double val)
{
uint8_t res;
if (std::isnan(val) || val <= 0) {
res = 0;
} else {
val = val >= UINT8_MAX ? UINT8_MAX : val;
constexpr double HALF = 0.5;
val = val == HALF ? 0 : std::round(val);
res = static_cast<uint64_t>(val);
}
FastSetTypeData(byteBeginOffset, byteEndOffset, res);
}
template<typename T>
void BuiltinsSendableArrayBuffer::FastSetValueInBufferForInteger(uint8_t *byteBeginOffset,
uint8_t *byteEndOffset,
double val, bool littleEndian)
{
ASSERT_PRINT(std::is_integral_v<T>, "T must be integral");
ASSERT_PRINT(sizeof(T) >= sizeof(uint16_t), "T must have a size more than uint8");
T res;
if (std::isnan(val) || std::isinf(val)) {
res = 0;
} else {
auto int64Val = static_cast<int64_t>(val);
// NOLINTNEXTLINE(readability-braces-around-statements)
if constexpr (std::is_same_v<T, uint16_t>) {
auto *pTmp = reinterpret_cast<int16_t *>(&int64Val);
int16_t tmp = *pTmp;
res = static_cast<T>(tmp);
} else { // NOLINTNEXTLINE(readability-braces-around-statements)
auto *pTmp = reinterpret_cast<T *>(&int64Val);
res = *pTmp;
}
if (!littleEndian) {
res = LittleEndianToBigEndian<T>(res);
}
}
FastSetTypeData(byteBeginOffset, byteEndOffset, res);
}
template<typename T>
void BuiltinsSendableArrayBuffer::FastSetValueInBufferForFloat(uint8_t *byteBeginOffset,
uint8_t *byteEndOffset,
double val, bool littleEndian)
{
ASSERT_PRINT((std::is_same_v<T, float> || std::is_same_v<T, double>), "T must be float type");
auto data = static_cast<T>(val);
if (!std::isnan(val)) {
if (!littleEndian) {
if constexpr (std::is_same_v<T, float>) {
uint32_t res = base::bit_cast<uint32_t>(data);
data = base::bit_cast<T>(LittleEndianToBigEndian(res));
} else if constexpr (std::is_same_v<T, double>) {
uint64_t res = base::bit_cast<uint64_t>(data);
data = base::bit_cast<T>(LittleEndianToBigEndian64Bit(res));
}
}
}
FastSetTypeData(byteBeginOffset, byteEndOffset, data);
}
template<typename T>
void BuiltinsSendableArrayBuffer::FastSetValueInBufferForBigInt(JSThread *thread,
uint8_t *byteBeginOffset,
uint8_t *byteEndOffset,
double val, bool littleEndian)
{
ASSERT_PRINT((std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>), "T must be int64_t/uint64_t");
T value = 0;
bool lossless = true;
JSHandle<JSTaggedValue> valHandle(thread, GetTaggedDouble(val));
if constexpr(std::is_same_v<T, uint64_t>) {
BigInt::BigIntToUint64(thread, valHandle, reinterpret_cast<uint64_t *>(&value), &lossless);
} else {
BigInt::BigIntToInt64(thread, valHandle, reinterpret_cast<int64_t *>(&value), &lossless);
}
RETURN_IF_ABRUPT_COMPLETION(thread);
if (!littleEndian) {
value = LittleEndianToBigEndian64Bit<T>(value);
}
FastSetTypeData(byteBeginOffset, byteEndOffset, value);
}
JSTaggedValue BuiltinsSendableArrayBuffer::TryFastSetValueInBuffer([[maybe_unused]] JSThread *thread,
JSTaggedValue arrBuf,
uint32_t byteBeginOffset, uint32_t byteEndOffset,
DataViewType type, double val, bool littleEndian)
{
uint8_t *beginPointer = reinterpret_cast<uint8_t *>(GetDataPointFromBuffer(arrBuf, byteBeginOffset));
uint8_t *endPointer = reinterpret_cast<uint8_t *>(GetDataPointFromBuffer(arrBuf, byteEndOffset));
switch (type) {
case DataViewType::UINT8:
FastSetValueInBufferForByte<uint8_t>(beginPointer, endPointer, val);
break;
case DataViewType::UINT8_CLAMPED:
FastSetValueInBufferForUint8Clamped(beginPointer, endPointer, val);
break;
case DataViewType::INT8:
FastSetValueInBufferForByte<int8_t>(beginPointer, endPointer, val);
break;
case DataViewType::UINT16:
FastSetValueInBufferForInteger<uint16_t>(beginPointer, endPointer, val, littleEndian);
break;
case DataViewType::INT16:
FastSetValueInBufferForInteger<int16_t>(beginPointer, endPointer, val, littleEndian);
break;
case DataViewType::UINT32:
FastSetValueInBufferForInteger<uint32_t>(beginPointer, endPointer, val, littleEndian);
break;
case DataViewType::INT32:
FastSetValueInBufferForInteger<int32_t>(beginPointer, endPointer, val, littleEndian);
break;
case DataViewType::FLOAT32:
FastSetValueInBufferForFloat<float>(beginPointer, endPointer, val, littleEndian);
break;
case DataViewType::FLOAT64:
FastSetValueInBufferForFloat<double>(beginPointer, endPointer, val, littleEndian);
break;
case DataViewType::BIGINT64:
FastSetValueInBufferForBigInt<int64_t>(thread, beginPointer, endPointer, val, littleEndian);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
break;
case DataViewType::BIGUINT64:
FastSetValueInBufferForBigInt<uint64_t>(thread, beginPointer, endPointer, val, littleEndian);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
return JSTaggedValue::Undefined();
}
} // namespace panda::ecmascript::builtins

View File

@ -0,0 +1,197 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_BUILTINS_BUILTINS_SENDABLE_ARRAYBUFFER_H
#define ECMASCRIPT_BUILTINS_BUILTINS_SENDABLE_ARRAYBUFFER_H
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/base/number_helper.h"
#include "ecmascript/js_dataview.h"
#include "ecmascript/js_typed_array.h"
// List of functions in ArrayBuffer, excluding the '@@' properties.
// V(name, func, length, stubIndex)
// where BuiltinsArrayBuffer::func refers to the native implementation of ArrayBuffer[name].
// kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available.
#define BUILTIN_ARRAY_BUFFER_FUNCTIONS(V) \
/* ArrayBuffer.isView ( arg ) */ \
V("isView", IsView, 1, ArrayBufferIsView)
namespace panda::ecmascript::builtins {
using DataViewType = ecmascript::DataViewType;
using BuiltinFunctionEntry = base::BuiltinFunctionEntry;
class BuiltinsSendableArrayBuffer : public base::BuiltinsBase {
public:
enum NumberSize : uint8_t {
UINT16 = 2, INT16 = 2, UINT32 = 4, INT32 = 4, FLOAT32 = 4, FLOAT64 = 8, BIGINT64 = 8, BIGUINT64 = 8
};
// 24.1.2.1 ArrayBuffer(length)
static JSTaggedValue ArrayBufferConstructor(EcmaRuntimeCallInfo *argv);
// 24.1.3.1 ArrayBuffer.isView(arg)
static JSTaggedValue IsView(EcmaRuntimeCallInfo *argv);
// 24.1.3.3 get ArrayBuffer[@@species]
static JSTaggedValue Species(EcmaRuntimeCallInfo *argv);
// 24.1.4.1 get ArrayBuffer.prototype.byteLength
static JSTaggedValue GetByteLength(EcmaRuntimeCallInfo *argv);
// 24.1.4.3 ArrayBuffer.prototype.slice()
static JSTaggedValue Slice(EcmaRuntimeCallInfo *argv);
// 24.1.1.2 IsDetachedBuffer(arrayBuffer)
static bool IsDetachedBuffer(JSTaggedValue arrayBuffer);
// 24.1.1.5 GetValueFromBuffer ( arrayBuffer, byteIndex, type, isLittleEndian )
static JSTaggedValue GetValueFromBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex,
DataViewType type, bool littleEndian);
// 24.1.1.6 SetValueInBuffer ( arrayBuffer, byteIndex, type, value, isLittleEndian )
static JSTaggedValue SetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex,
DataViewType type, const JSHandle<JSTaggedValue> &value, bool littleEndian);
// 24.1.1.4 CloneArrayBuffer( srcBuffer, srcByteOffset [, cloneConstructor] )
static JSTaggedValue CloneArrayBuffer(JSThread *thread, const JSHandle<JSTaggedValue> &srcBuffer,
uint32_t srcByteOffset, JSHandle<JSTaggedValue> constructor);
// 24.1.1.1 AllocateArrayBuffer(constructor, byteLength)
static JSTaggedValue AllocateSendableArrayBuffer(
JSThread *thread, const JSHandle<JSTaggedValue> &newTarget, uint64_t byteLength);
// es12 25.1.2.6 IsUnclampedIntegerElementType ( type )
static bool IsUnclampedIntegerElementType(DataViewType type);
// es12 25.1.2.7 IsBigIntElementType ( type )
static bool IsBigIntElementType(DataViewType type);
// Excluding the '@@' internal properties
static Span<const base::BuiltinFunctionEntry> GetArrayBufferFunctions()
{
return Span<const base::BuiltinFunctionEntry>(ARRAY_BUFFER_FUNCTIONS);
}
static JSTaggedValue FastSetValueInBuffer(JSThread* thread, JSTaggedValue arrBuf, uint32_t byteIndex,
DataViewType type, double val, bool littleEndian);
static JSTaggedValue TryFastSetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteBeginOffset,
uint32_t byteEndOffset, DataViewType type,
double val, bool littleEndian);
template<typename T>
static void FastSetValueInBufferForByte(uint8_t *byteBeginOffset, uint8_t *byteEndOffset,
double val);
static void FastSetValueInBufferForUint8Clamped(uint8_t *byteBeginOffset, uint8_t *byteEndOffset,
double val);
template<typename T>
static void FastSetValueInBufferForInteger(uint8_t *byteBeginOffset, uint8_t *byteEndOffset,
double val, bool littleEndian);
template<typename T>
static void FastSetValueInBufferForFloat(uint8_t *byteBeginOffset, uint8_t *byteEndOffset,
double val, bool littleEndian);
template<typename T>
static void FastSetValueInBufferForBigInt(JSThread *thread, uint8_t *byteBeginOffset, uint8_t *byteEndOffset,
double val, bool littleEndian);
static JSTaggedValue SetValueInBuffer(JSThread *thread, uint32_t byteIndex, uint8_t *block,
DataViewType type, double val, bool littleEndian);
static JSTaggedValue GetValueFromBuffer(JSThread *thread, uint32_t byteIndex, uint8_t *block,
DataViewType type, bool littleEndian);
static void *GetDataPointFromBuffer(JSTaggedValue arrBuf, uint32_t byteOffset = 0);
static size_t GetNumPrototypeInlinedProperties()
{
// 3 : 3 more inline properties in Set.prototype
// (1) Set.prototype.slice
// (2) Set.prototype [ @@toStringTag ]
// (3) get Set.prototype.size
return 3;
}
static Span<const std::pair<std::string_view, bool>> GetPrototypeProperties()
{
return Span<const std::pair<std::string_view, bool>>(ARRAYBUFFER_PROTOTYPE_PROPERTIES);
}
static Span<const std::pair<std::string_view, bool>> GetFunctionProperties()
{
return Span<const std::pair<std::string_view, bool>>(ARRAYBUFFER_FUNCTION_PROPERTIES);
}
private:
#define BUILTIN_ARRAY_BUFFER_ENTRY(name, func, length, id) \
BuiltinFunctionEntry::Create(name, BuiltinsSendableArrayBuffer::func, length, kungfu::BuiltinsStubCSigns::id),
static constexpr std::array ARRAY_BUFFER_FUNCTIONS = {BUILTIN_ARRAY_BUFFER_FUNCTIONS(BUILTIN_ARRAY_BUFFER_ENTRY)};
#undef BUILTIN_ARRAY_BUFFER_ENTRY
#define ARRAYBUFFER_PROPERTIES_PAIR(name, func, length, id) \
std::pair<std::string_view, bool>(name, false),
static constexpr std::array ARRAYBUFFER_PROTOTYPE_PROPERTIES = {
std::pair<std::string_view, bool>("slice", false),
std::pair<std::string_view, bool>("byteLength", true),
std::pair<std::string_view, bool>("[Symbol.toStringTag]", false),
};
static constexpr std::array ARRAYBUFFER_FUNCTION_PROPERTIES = {
std::pair<std::string_view, bool>("length", false),
std::pair<std::string_view, bool>("name", false),
std::pair<std::string_view, bool>("prototype", false),
BUILTIN_ARRAY_BUFFER_FUNCTIONS(ARRAYBUFFER_PROPERTIES_PAIR)
std::pair<std::string_view, bool>("[Symbol.species]", true),
};
#undef SET_PROPERTIES_PAIR
template <typename T>
static T LittleEndianToBigEndian(T liValue);
template<typename T>
static T LittleEndianToBigEndian64Bit(T liValue);
template<typename T>
static void SetTypeData(uint8_t *block, T value, uint32_t index);
template<typename T>
static void FastSetTypeData(uint8_t *byteBeginOffset, uint8_t *byteEndOffset, T value);
template<typename T, NumberSize size>
static JSTaggedValue GetValueFromBufferForInteger(uint8_t *block, uint32_t byteIndex, bool littleEndian);
template<typename T, typename UnionType, NumberSize size>
static JSTaggedValue GetValueFromBufferForFloat(uint8_t *block, uint32_t byteIndex, bool littleEndian);
template<typename T1, typename T2>
static JSTaggedValue CommonConvert(T1 &value, T2 &res, bool littleEndian);
template<typename T, NumberSize size>
static JSTaggedValue GetValueFromBufferForBigInt(JSThread *thread, uint8_t *block,
uint32_t byteIndex, bool littleEndian);
template<typename T>
static void SetValueInBufferForByte(double val, uint8_t *block, uint32_t byteIndex);
static void SetValueInBufferForUint8Clamped(double val, uint8_t *block, uint32_t byteIndex);
template<typename T>
static void SetValueInBufferForInteger(double val, uint8_t *block, uint32_t byteIndex, bool littleEndian);
template<typename T>
static void SetValueInBufferForFloat(double val, uint8_t *block, uint32_t byteIndex, bool littleEndian);
template<typename T>
static void SetValueInBufferForBigInt(JSThread *thread, const JSHandle<JSTaggedValue> &val,
JSHandle<JSTaggedValue> &arrBuf, uint32_t byteIndex, bool littleEndian);
template<typename T>
static void SetValueInBufferForBigInt(JSThread *thread, double val,
uint8_t *block, uint32_t byteIndex, bool littleEndian);
static JSTaggedValue TypedArrayToList(JSThread *thread, JSHandle<JSTypedArray>& items);
static constexpr uint64_t MAX_NATIVE_SIZE_LIMIT = 4_GB;
static constexpr char const *NATIVE_SIZE_OUT_OF_LIMIT_MESSAGE = "total array buffer size out of limit(4_GB)";
friend class BuiltinsArray;
friend class BuiltinsSharedArray;
};
} // namespace panda::ecmascript::builtins
#endif // ECMASCRIPT_BUILTINS_BUILTINS_SENDABLE_ARRAYBUFFER_H

View File

@ -1795,6 +1795,8 @@ JSTaggedValue BuiltinsSharedArray::ToString(EcmaRuntimeCallInfo *argv)
thread, thisHandle.GetTaggedValue().GetTaggedObject());
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return ToStringImpl(argv, thread, thisHandle);
} else if (thisHandle->IsTypedArray()) {
return ToStringImpl(argv, thread, thisHandle);
} else {
auto error = ContainerError::BindError(thread, "The toString method cannot be bound.");
THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());

View File

@ -386,11 +386,6 @@ JSTaggedValue BuiltinsSharedTypedArray::GetBuffer(EcmaRuntimeCallInfo *argv)
if (!thisHandle->IsECMAObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
}
// 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
if (!thisHandle->IsSharedTypedArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[ViewedArrayBuffer]] internal slot.",
JSTaggedValue::Exception());
}
// 4. Let buffer be the value of Os [[ViewedArrayBuffer]] internal slot.
JSHandle<JSTypedArray> typedArray = JSHandle<JSTypedArray>::Cast(thisHandle);
JSTaggedValue buffer = JSTypedArray::GetOffHeapBuffer(thread, typedArray);
@ -411,11 +406,6 @@ JSTaggedValue BuiltinsSharedTypedArray::GetByteLength(EcmaRuntimeCallInfo *argv)
if (!thisHandle->IsECMAObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
}
// 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
if (!thisHandle->IsSharedTypedArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[ViewedArrayBuffer]] internal slot.",
JSTaggedValue::Exception());
}
// 4. Let buffer be the value of Os [[ViewedArrayBuffer]] internal slot.
JSHandle<JSTypedArray> typeArrayObj = JSHandle<JSTypedArray>::Cast(thisHandle);
JSTaggedValue buffer = typeArrayObj->GetViewedArrayBufferOrByteArray();
@ -441,11 +431,6 @@ JSTaggedValue BuiltinsSharedTypedArray::GetByteOffset(EcmaRuntimeCallInfo *argv)
if (!thisHandle->IsECMAObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
}
// 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
if (!thisHandle->IsSharedTypedArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[ViewedArrayBuffer]] internal slot.",
JSTaggedValue::Exception());
}
// 4. Let buffer be the value of Os [[ViewedArrayBuffer]] internal slot.
JSHandle<JSTypedArray> typeArrayObj = JSHandle<JSTypedArray>::Cast(thisHandle);
JSTaggedValue buffer = typeArrayObj->GetViewedArrayBufferOrByteArray();
@ -763,7 +748,7 @@ JSTaggedValue BuiltinsSharedTypedArray::Join(EcmaRuntimeCallInfo *argv)
JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
if (!thisHandle->IsSharedTypedArray()) {
if (!thisHandle->IsSharedTypedArray() && !thisHandle->IsTypedArray()) {
THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
}
@ -882,11 +867,6 @@ JSTaggedValue BuiltinsSharedTypedArray::GetLength(EcmaRuntimeCallInfo *argv)
if (!thisHandle->IsECMAObject()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception());
}
// 3. If O does not have a [[TypedArrayName]] internal slot, throw a TypeError exception.
if (!thisHandle->IsSharedTypedArray()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[TypedArrayName]] internal slot.",
JSTaggedValue::Exception());
}
// 4. Assert: O has [[ViewedArrayBuffer]] and [[ArrayLength]] internal slots.
// 5. Let buffer be the value of Os [[ViewedArrayBuffer]] internal slot.
JSTaggedValue buffer = JSHandle<JSTypedArray>::Cast(thisHandle)->GetViewedArrayBufferOrByteArray();

View File

@ -18,12 +18,14 @@
#include "ecmascript/builtins/builtins_function.h"
#include "ecmascript/builtins/builtins_object.h"
#include "ecmascript/builtins/builtins_symbol.h"
#include "ecmascript/builtins/builtins_sendable_arraybuffer.h"
#include "ecmascript/builtins/builtins_shared_function.h"
#include "ecmascript/builtins/builtins_shared_object.h"
#include "ecmascript/builtins/builtins_shared_map.h"
#include "ecmascript/builtins/builtins_shared_set.h"
#include "ecmascript/builtins/builtins_shared_typedarray.h"
#include "ecmascript/shared_objects/js_shared_array.h"
#include "ecmascript/shared_objects/js_sendable_arraybuffer.h"
#include "ecmascript/shared_objects/js_shared_map.h"
#include "ecmascript/shared_objects/js_shared_object.h"
#include "ecmascript/shared_objects/js_shared_set.h"
@ -42,6 +44,7 @@ using BuiltinsSharedSet = builtins::BuiltinsSharedSet;
using BuiltinsSharedMap = builtins::BuiltinsSharedMap;
using BuiltinsSharedArray = builtins::BuiltinsSharedArray;
using BuiltinsSharedTypedArray = builtins::BuiltinsSharedTypedArray;
using BuiltinsSendableArrayBuffer = builtins::BuiltinsSendableArrayBuffer;
void Builtins::InitializeSObjectAndSFunction(const JSHandle<GlobalEnv> &env) const
{
@ -69,6 +72,7 @@ void Builtins::InitializeSObjectAndSFunction(const JSHandle<GlobalEnv> &env) con
InitializeSMap(env, sObjPrototype, sFuncPrototype);
InitializeSharedArray(env, sObjPrototype, sFuncPrototype);
InitializeSTypedArray(env, sObjPrototype, sFuncPrototype);
InitializeSArrayBuffer(env, sObjPrototype, sFuncPrototype);
env->SetSObjectFunctionPrototype(thread_, sObjPrototype);
}
@ -117,6 +121,69 @@ void Builtins::InitializeSObject(const JSHandle<GlobalEnv> &env, const JSHandle<
SetSAccessor(sObjPrototype, fieldIndex, protoGetter, protoSetter);
}
void Builtins::InitializeSArrayBuffer(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &sObjPrototype,
const JSHandle<JSFunction> &sFuncPrototype) const
{
[[maybe_unused]] EcmaHandleScope scope(thread_);
const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
// SendableArrayBuffer.prototype
JSHandle<JSHClass> arrayBufferPrototypeHClass = CreateSArrayBufferPrototypeHClass(sObjPrototype);
JSHandle<JSObject> arrayBufferPrototype =
factory_->NewSharedOldSpaceJSObjectWithInit(arrayBufferPrototypeHClass);
JSHandle<JSTaggedValue> arrayBufferPrototypeValue(arrayBufferPrototype);
// SendableArrayBuffer.prototype_or_hclass
auto emptySLayout = globalConst->GetHandledEmptySLayoutInfo();
JSHandle<JSHClass> arrayBufferIHClass = factory_->NewSEcmaHClass(
JSSendableArrayBuffer::SIZE, 0, JSType::JS_SENDABLE_ARRAY_BUFFER, arrayBufferPrototypeValue, emptySLayout);
// SendableArrayBuffer = new Function()
JSHandle<JSHClass> arrayBufferFuncHClass = CreateSArrayBufferFunctionHClass(sFuncPrototype);
JSHandle<JSFunction> arrayBufferFunction =
factory_->NewSFunctionByHClass(reinterpret_cast<void *>(BuiltinsSendableArrayBuffer::ArrayBufferConstructor),
arrayBufferFuncHClass, FunctionKind::BUILTIN_CONSTRUCTOR);
InitializeSCtor(arrayBufferIHClass, arrayBufferFunction, "SendableArrayBuffer", FunctionLength::ONE);
JSHandle<JSObject> globalObject(thread_, env->GetGlobalObject());
JSHandle<JSTaggedValue> nameString(factory_->NewFromUtf8("SendableArrayBuffer"));
PropertyDescriptor desc(thread_, JSHandle<JSTaggedValue>::Cast(arrayBufferFunction), true, false, true);
JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc);
RETURN_IF_ABRUPT_COMPLETION(thread_);
// SendableArrayBuffer prototype method
uint32_t fieldIndex = 0;
SetSFunction(env, arrayBufferPrototype, "slice",
BuiltinsSendableArrayBuffer::Slice, fieldIndex++, FunctionLength::TWO);
// 24.1.4.1 get SendableArrayBuffer.prototype.byteLength
JSHandle<JSTaggedValue> lengthGetter =
CreateSGetterSetter(env, BuiltinsSendableArrayBuffer::GetByteLength, "byteLength", FunctionLength::ZERO);
SetSAccessor(
JSHandle<JSObject>(arrayBufferPrototype), fieldIndex++, lengthGetter, globalConst->GetHandledUndefined());
// 24.1.4.4 SendableArrayBuffer.prototype[@@toStringTag]
JSHandle<JSTaggedValue> strTag(factory_->NewFromUtf8("SendableArrayBuffer"));
arrayBufferPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, strTag.GetTaggedValue());
// 24.1.3.3 get SendableArrayBuffer[@@species]
fieldIndex = JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX + 1;
JSHandle<JSTaggedValue> speciesGetter =
CreateSGetterSetter(env, BuiltinsSendableArrayBuffer::Species, "[Symbol.species]", FunctionLength::ZERO);
SetSAccessor(
JSHandle<JSObject>(arrayBufferFunction), fieldIndex++, speciesGetter, globalConst->GetHandledUndefined());
// SendableArrayBuffer method
for (const base::BuiltinFunctionEntry& entry: BuiltinsSendableArrayBuffer::GetArrayBufferFunctions()) {
SetSFunction(env, JSHandle<JSObject>(arrayBufferFunction), entry.GetName(), entry.GetEntrypoint(), fieldIndex++,
entry.GetLength(), entry.GetBuiltinStubId());
}
env->SetSendableArrayBufferPrototype(thread_, arrayBufferPrototype);
env->SetSBuiltininArrayBufferFunction(thread_, arrayBufferFunction);
}
void Builtins::InitializeSSet(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &sObjPrototype,
const JSHandle<JSFunction> &sFuncPrototype) const
{
@ -368,6 +435,35 @@ JSHandle<JSHClass> Builtins::CreateSFunctionHClass(const JSHandle<JSFunction> &s
return sobjPrototypeHClass;
}
JSHandle<JSHClass> Builtins::CreateSArrayBufferFunctionHClass(const JSHandle<JSFunction> &sFuncPrototype) const
{
uint32_t index = 0;
auto env = vm_->GetGlobalEnv();
PropertyAttributes attributes = PropertyAttributes::Default(false, false, false);
attributes.SetIsInlinedProps(true);
attributes.SetRepresentation(Representation::TAGGED);
auto properties = BuiltinsSendableArrayBuffer::GetFunctionProperties();
uint32_t length = properties.size();
JSHandle<JSTaggedValue> keyString;
JSHandle<LayoutInfo> layout = factory_->CreateSLayoutInfo(length);
for (const auto &[key, isAccessor] : properties) {
attributes.SetOffset(index);
attributes.SetIsAccessor(isAccessor);
if (key == "[Symbol.species]") {
keyString = env->GetSpeciesSymbol();
} else {
keyString = JSHandle<JSTaggedValue>(factory_->NewFromUtf8(key));
}
layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes);
}
JSHandle<JSHClass> sobjPrototypeHClass =
factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION,
JSHandle<JSTaggedValue>(sFuncPrototype), JSHandle<JSTaggedValue>(layout));
sobjPrototypeHClass->SetConstructor(true);
sobjPrototypeHClass->SetCallable(true);
return sobjPrototypeHClass;
}
JSHandle<JSHClass> Builtins::CreateSSetFunctionHClass(const JSHandle<JSFunction> &sFuncPrototype) const
{
uint32_t index = 0;
@ -454,6 +550,35 @@ JSHandle<JSHClass> Builtins::CreateSFunctionPrototypeHClass(const JSHandle<JSTag
return sobjPrototypeHClass;
}
JSHandle<JSHClass> Builtins::CreateSArrayBufferPrototypeHClass(const JSHandle<JSObject> &sObjPrototype) const
{
uint32_t index = 0;
auto env = vm_->GetGlobalEnv();
PropertyAttributes attributes = PropertyAttributes::Default(false, false, false);
attributes.SetIsInlinedProps(true);
attributes.SetRepresentation(Representation::TAGGED);
auto properties = BuiltinsSendableArrayBuffer::GetPrototypeProperties();
uint32_t length = properties.size();
ASSERT(length == BuiltinsSendableArrayBuffer::GetNumPrototypeInlinedProperties());
JSHandle<LayoutInfo> layout = factory_->CreateSLayoutInfo(length);
JSHandle<JSTaggedValue> keyString;
for (const auto &[key, isAccessor] : properties) {
attributes.SetOffset(index);
attributes.SetIsAccessor(isAccessor);
if (key == "[Symbol.toStringTag]") {
keyString = env->GetToStringTagSymbol();
} else {
keyString = JSHandle<JSTaggedValue>(factory_->NewFromUtf8(key));
}
layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes);
}
JSHandle<JSHClass> sArrayBufferPrototypeHClass =
factory_->NewSEcmaHClass(JSSharedObject::SIZE, length, JSType::JS_SHARED_OBJECT,
JSHandle<JSTaggedValue>(sObjPrototype),
JSHandle<JSTaggedValue>(layout));
return sArrayBufferPrototypeHClass;
}
JSHandle<JSHClass> Builtins::CreateSSetPrototypeHClass(const JSHandle<JSObject> &sObjPrototype) const
{
uint32_t index = 0;

View File

@ -382,6 +382,8 @@ CString *HeapSnapshot::GenerateNodeName(TaggedObject *entry)
return GetString("StringIterator");
case JSType::JS_ARRAY_BUFFER:
return GetString("ArrayBuffer");
case JSType::JS_SENDABLE_ARRAY_BUFFER:
return GetString("SendableArrayBuffer");
case JSType::JS_SHARED_ARRAY_BUFFER:
return GetString("SharedArrayBuffer");
case JSType::JS_PROXY_REVOC_FUNCTION:

View File

@ -110,6 +110,7 @@
#include "ecmascript/require/js_cjs_require.h"
#include "ecmascript/require/js_cjs_exports.h"
#include "ecmascript/shared_objects/js_shared_array.h"
#include "ecmascript/shared_objects/js_sendable_arraybuffer.h"
#include "ecmascript/shared_objects/js_shared_array_iterator.h"
#include "ecmascript/shared_objects/js_shared_map.h"
#include "ecmascript/shared_objects/js_shared_map_iterator.h"
@ -314,6 +315,8 @@ CString JSHClass::DumpJSType(JSType type)
return "RegExpIterator";
case JSType::JS_ARRAY_BUFFER:
return "ArrayBuffer";
case JSType::JS_SENDABLE_ARRAY_BUFFER:
return "SendableArrayBuffer";
case JSType::JS_SHARED_ARRAY_BUFFER:
return "SharedArrayBuffer";
case JSType::JS_PROXY_REVOC_FUNCTION:
@ -915,6 +918,9 @@ static void DumpObject(TaggedObject *obj, std::ostream &os)
case JSType::JS_ARRAY_BUFFER:
JSArrayBuffer::Cast(obj)->Dump(os);
break;
case JSType::JS_SENDABLE_ARRAY_BUFFER:
JSSendableArrayBuffer::Cast(obj)->Dump(os);
break;
case JSType::JS_SHARED_ARRAY_BUFFER:
JSArrayBuffer::Cast(obj)->Dump(os);
break;
@ -2914,6 +2920,14 @@ void JSArrayBuffer::Dump(std::ostream &os) const
os << " - Shared: " << GetShared();
}
void JSSendableArrayBuffer::Dump(std::ostream &os) const
{
os << " - byte-length: " << GetArrayBufferByteLength();
os << " - buffer-data: ";
GetArrayBufferData().Dump(os);
os << " - Shared: " << GetShared();
}
void PromiseReaction::Dump(std::ostream &os) const
{
os << " - promise-capability: ";
@ -4399,6 +4413,9 @@ static void DumpObject(TaggedObject *obj, std::vector<Reference> &vec, bool isVm
case JSType::JS_SHARED_ARRAY_BUFFER:
JSArrayBuffer::Cast(obj)->DumpForSnapshot(vec);
return;
case JSType::JS_SENDABLE_ARRAY_BUFFER:
JSSendableArrayBuffer::Cast(obj)->DumpForSnapshot(vec);
return;
case JSType::JS_PROXY_REVOC_FUNCTION:
JSProxyRevocFunction::Cast(obj)->DumpForSnapshot(vec);
return;
@ -5682,6 +5699,14 @@ void JSArrayBuffer::DumpForSnapshot(std::vector<Reference> &vec) const
JSObject::DumpForSnapshot(vec);
}
void JSSendableArrayBuffer::DumpForSnapshot(std::vector<Reference> &vec) const
{
vec.emplace_back(CString("buffer-data"), GetArrayBufferData());
vec.emplace_back(CString("byte-length"), JSTaggedValue(GetArrayBufferByteLength()));
vec.emplace_back(CString("shared"), JSTaggedValue(GetShared()));
JSObject::DumpForSnapshot(vec);
}
void PromiseReaction::DumpForSnapshot(std::vector<Reference> &vec) const
{
vec.emplace_back(CString("promise-capability"), GetPromiseCapability());

View File

@ -36,9 +36,9 @@ public:
GLOBAL_ENV_FIELDS(GLOBAL_ENV_SLOT)
static constexpr uint8_t FIRST_DETECTOR_SYMBOL_INDEX = static_cast<uint8_t>(Field::REPLACE_SYMBOL_INDEX);
static constexpr uint8_t LAST_DETECTOR_SYMBOL_INDEX = static_cast<uint8_t>(Field::SPECIES_SYMBOL_INDEX);
static constexpr uint8_t FINAL_INDEX = static_cast<uint8_t>(GlobalEnvField::FINAL_INDEX);
static constexpr uint16_t FINAL_INDEX = static_cast<uint16_t>(GlobalEnvField::FINAL_INDEX);
static constexpr uint8_t RESERVED_LENGTH = 1; // divide the gc area
static constexpr uint8_t JSTHREAD_INDEX = FINAL_INDEX; // not need gc
static constexpr uint16_t JSTHREAD_INDEX = FINAL_INDEX; // not need gc
#undef GLOBAL_ENV_SLOT
JSTaggedValue GetGlobalObject() const

View File

@ -226,6 +226,7 @@
V(JSTaggedValue, SObjectFunctionPrototype, SHARED_OBJECT_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, SFunctionFunction, SHARED_FUNCTION_FUNCTION_INDEX) \
V(JSTaggedValue, SFunctionPrototype, SHARED_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, SBuiltininArrayBufferFunction, SENDABLE_BUILTIN_ARRAY_BUFFER_FUNCTION_INDEX) \
V(JSTaggedValue, SBuiltininSetFunction, SHARED_BUILTIN_SET_FUNCTION_INDEX) \
V(JSTaggedValue, SBuiltininMapFunction, SHARED_BUILTIN_MAP_FUNCTION_INDEX) \
V(JSTaggedValue, SConstructorClass, SHARED_CONSTRUCTOR_CLASS_INDEX) \
@ -248,6 +249,7 @@
V(JSTaggedValue, UnscopablesSymbol, UNSCOPABLES_SYMBOL_INDEX) \
V(JSTaggedValue, NativeBindingSymbol, NATIVE_BINDING_SYMBOL_INDEX) \
V(JSTaggedValue, HasInstanceSymbol, HASINSTANCE_SYMBOL_INDEX) \
V(JSTaggedValue, SendableArrayBufferPrototype, SENDABLE_ARRAY_BUFFER_PROTOTYPE_INDEX) \
V(JSTaggedValue, SharedArrayFunction, SHARED_ARRAY_FUNCTION_INDEX) \
V(JSTaggedValue, SharedArrayPrototype, SHARED_ARRAY_PROTOTYPE_INDEX) \
V(JSTaggedValue, SharedMapPrototype, SHARED_MAP_PROTOTYPE_INDEX) \
@ -284,7 +286,7 @@
namespace panda::ecmascript {
#define GLOBAL_ENV_FIELD_ENUM_ITEM(Type, Name, INDEX) INDEX,
enum class GlobalEnvField: uint8_t {
enum class GlobalEnvField: uint16_t {
GLOBAL_ENV_FIELDS(GLOBAL_ENV_FIELD_ENUM_ITEM)
FINAL_INDEX
};

View File

@ -198,6 +198,7 @@ void JSHClass::Initialize(const JSThread *thread, uint32_t size, JSType type,
case JSType::JS_SHARED_FLOAT64_ARRAY:
case JSType::JS_SHARED_BIGINT64_ARRAY:
case JSType::JS_SHARED_BIGUINT64_ARRAY:
case JSType::JS_SENDABLE_ARRAY_BUFFER:
case JSType::BIGINT:
case JSType::LINE_STRING:
case JSType::CONSTANT_STRING:

View File

@ -165,6 +165,7 @@ struct Reference;
\
JS_ARRAY_BUFFER, /* ///////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_SHARED_ARRAY_BUFFER, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_SENDABLE_ARRAY_BUFFER, /* //////////////////////////////////////////////////////////////////////-PADDING */ \
JS_PROMISE, /* ///////////////////////////////////////////////////////////////////////////////-PADDING */ \
JS_DATA_VIEW, /* /////////////////////////////////////////////////////////////////////////////////////// */ \
JS_ARGUMENTS, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \
@ -1281,6 +1282,11 @@ public:
return GetObjectType() == JSType::JS_SHARED_ARRAY_BUFFER;
}
inline bool IsSendableArrayBuffer() const
{
return GetObjectType() == JSType::JS_SENDABLE_ARRAY_BUFFER;
}
inline bool IsDataView() const
{
return GetObjectType() == JSType::JS_DATA_VIEW;

View File

@ -329,6 +329,7 @@ bool JSSerializer::WriteTaggedObject(const JSHandle<JSTaggedValue> &value)
return WriteJSTypedArray(value, SerializationUID::JS_BIGUINT64_ARRAY);
case JSType::JS_ARRAY_BUFFER:
case JSType::JS_SHARED_ARRAY_BUFFER:
case JSType::JS_SENDABLE_ARRAY_BUFFER:
return WriteJSArrayBuffer(value);
case JSType::LINE_STRING:
case JSType::CONSTANT_STRING:

View File

@ -1422,6 +1422,11 @@ inline bool JSTaggedValue::IsSharedArrayBuffer() const
return IsHeapObject() && GetTaggedObject()->GetClass()->IsSharedArrayBuffer();
}
inline bool JSTaggedValue::IsSendableArrayBuffer() const
{
return IsHeapObject() && GetTaggedObject()->GetClass()->IsSendableArrayBuffer();
}
inline bool JSTaggedValue::IsDataView() const
{
return IsHeapObject() && GetTaggedObject()->GetClass()->IsDataView();

View File

@ -555,6 +555,7 @@ public:
bool IsStringIterator() const;
bool IsArrayBuffer() const;
bool IsSharedArrayBuffer() const;
bool IsSendableArrayBuffer() const;
bool IsJSSetIterator() const;
bool IsJSSharedSetIterator() const;

View File

@ -18,10 +18,12 @@
#include "ecmascript/accessor_data.h"
#include "ecmascript/base/typed_array_helper-inl.h"
#include "ecmascript/builtins/builtins_arraybuffer.h"
#include "ecmascript/builtins/builtins_sendable_arraybuffer.h"
namespace panda::ecmascript {
using TypedArrayHelper = base::TypedArrayHelper;
using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
using BuiltinsSendableArrayBuffer = builtins::BuiltinsSendableArrayBuffer;
JSHandle<JSTaggedValue> JSTypedArray::ToPropKey(JSThread *thread, const JSHandle<JSTaggedValue> &key)
{
@ -91,7 +93,10 @@ bool JSTypedArray::HasProperty(JSThread *thread, const JSHandle<JSTaggedValue> &
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
if (!numericIndex.IsUndefined()) {
JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray();
if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
}
if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
}
if (!numericIndex.IsInteger()) {
@ -385,7 +390,11 @@ OperationResult JSTypedArray::IntegerIndexedElementGet(JSThread *thread, const J
JSHandle<JSTypedArray> typedarrayObj(typedarray);
JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray();
// 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer",
OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
}
if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer",
OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
}
@ -424,7 +433,12 @@ OperationResult JSTypedArray::IntegerIndexedElementGet(JSThread *thread, const J
// 13. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
// 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
JSTaggedValue result;
if (buffer.IsSendableArrayBuffer()) {
result = BuiltinsSendableArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
} else {
result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
}
return OperationResult(thread, result, PropertyMetaData(true));
}
@ -435,7 +449,10 @@ bool JSTypedArray::IsValidIntegerIndex(const JSHandle<JSTaggedValue> &typedArray
// 2. If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, return false.
JSHandle<JSTypedArray> typedarrayObj(typedArray);
JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray();
if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
return false;
}
if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
return false;
}
// 3. If ! IsIntegralNumber(index) is false, return false.
@ -505,7 +522,12 @@ bool JSTypedArray::FastCopyElementToArray(JSThread *thread, const JSHandle<JSTag
JSHandle<JSTaggedValue> bufferHandle = JSHandle<JSTaggedValue>(thread,
typedarrayObj->GetViewedArrayBufferOrByteArray());
// 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
if (BuiltinsArrayBuffer::IsDetachedBuffer(bufferHandle.GetTaggedValue())) {
if (!bufferHandle.GetTaggedValue().IsSendableArrayBuffer() &&
BuiltinsArrayBuffer::IsDetachedBuffer(bufferHandle.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
}
if (bufferHandle.GetTaggedValue().IsSendableArrayBuffer() &&
BuiltinsSendableArrayBuffer::IsDetachedBuffer(bufferHandle.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", false);
}
@ -523,8 +545,14 @@ bool JSTypedArray::FastCopyElementToArray(JSThread *thread, const JSHandle<JSTag
// 12. Let indexedPosition = (index × elementSize) + offset.
uint32_t byteIndex = index * elementSize + offset;
// 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, bufferHandle.GetTaggedValue(),
byteIndex, elementType, true);
JSTaggedValue result;
if (bufferHandle.GetTaggedValue().IsSendableArrayBuffer()) {
result = BuiltinsSendableArrayBuffer::GetValueFromBuffer(thread, bufferHandle.GetTaggedValue(),
byteIndex, elementType, true);
} else {
result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, bufferHandle.GetTaggedValue(),
byteIndex, elementType, true);
}
array->Set(thread, index, result);
}
return true;
@ -542,7 +570,10 @@ OperationResult JSTypedArray::FastElementGet(JSThread *thread, const JSHandle<JS
JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray();
// 10.4.5.15 TypedArrayGetElement ( O, index )
// 1. If IsValidIntegerIndex(O, index) is false, return undefined.
if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
}
if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
return OperationResult(thread, JSTaggedValue::Undefined(), PropertyMetaData(true));
}
@ -561,7 +592,12 @@ OperationResult JSTypedArray::FastElementGet(JSThread *thread, const JSHandle<JS
// 13. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
// 14. Return GetValueFromBuffer(buffer, indexedPosition, elementType).
JSTaggedValue result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
JSTaggedValue result;
if (buffer.IsSendableArrayBuffer()) {
result = BuiltinsSendableArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
} else {
result = BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
}
return OperationResult(thread, result, PropertyMetaData(true));
}
@ -602,7 +638,12 @@ bool JSTypedArray::IntegerIndexedElementSet(JSThread *thread, const JSHandle<JST
// 10. Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
DataViewType elementType = TypedArrayHelper::GetType(typedarrayObj);
// 11. Perform SetValueInBuffer(buffer, indexedPosition, elementType, numValue).
BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer, byteIndex, elementType, numValueHandle, true);
if (buffer.IsSendableArrayBuffer()) {
BuiltinsSendableArrayBuffer::SetValueInBuffer(
thread, buffer, byteIndex, elementType, numValueHandle, true);
} else {
BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer, byteIndex, elementType, numValueHandle, true);
}
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
}
return true;
@ -652,7 +693,10 @@ JSTaggedValue JSTypedArray::FastGetPropertyByIndex(JSThread *thread, const JSTag
// Let buffer be the value of Os [[ViewedArrayBuffer]] internal slot.
JSTypedArray *typedarrayObj = JSTypedArray::Cast(typedarray.GetTaggedObject());
JSTaggedValue buffer = typedarrayObj->GetViewedArrayBufferOrByteArray();
if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
if (!buffer.IsSendableArrayBuffer() && BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) {
return JSTaggedValue::Undefined();
}
if (buffer.IsSendableArrayBuffer() && BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer)) {
return JSTaggedValue::Undefined();
}
@ -672,6 +716,9 @@ JSTaggedValue JSTypedArray::FastGetPropertyByIndex(JSThread *thread, const JSTag
// Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
DataViewType elementType = TypedArrayHelper::GetType(jsType);
// Return GetValueFromBuffer(buffer, indexedPosition, elementType).
if (buffer.IsSendableArrayBuffer()) {
return BuiltinsSendableArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
}
return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, byteIndex, elementType, true);
}
@ -709,6 +756,10 @@ JSTaggedValue JSTypedArray::FastSetPropertyByIndex(JSThread *thread, const JSTag
// Let elementType be the String value of the Element Type value in Table 49 for arrayTypeName.
DataViewType elementType = TypedArrayHelper::GetType(jsType);
// Perform SetValueInBuffer(buffer, indexedPosition, elementType, numValue).
if (buffer.IsSendableArrayBuffer()) {
return BuiltinsSendableArrayBuffer::FastSetValueInBuffer(thread,
buffer, byteIndex, elementType, numValue.GetNumber(), true);
}
return BuiltinsArrayBuffer::FastSetValueInBuffer(thread,
buffer, byteIndex, elementType, numValue.GetNumber(), true);
}
@ -770,8 +821,13 @@ bool JSTypedArray::FastTypedArrayFill(JSThread *thread, const JSHandle<JSTaggedV
uint64_t byteBeginOffset = start * elementSize + offset;
uint64_t byteEndOffset = std::min(end, arrLen) * elementSize + offset;
if (byteBeginOffset <= byteEndOffset) {
BuiltinsArrayBuffer::TryFastSetValueInBuffer(thread, buffer,
byteBeginOffset, byteEndOffset, elementType, numValue.GetNumber(), true);
if (buffer.IsSendableArrayBuffer()) {
BuiltinsSendableArrayBuffer::TryFastSetValueInBuffer(thread, buffer,
byteBeginOffset, byteEndOffset, elementType, numValue.GetNumber(), true);
} else {
BuiltinsArrayBuffer::TryFastSetValueInBuffer(thread, buffer,
byteBeginOffset, byteEndOffset, elementType, numValue.GetNumber(), true);
}
}
return true;
}

View File

@ -107,6 +107,7 @@
#include "ecmascript/module/js_module_source_text.h"
#include "ecmascript/module/js_shared_module.h"
#include "ecmascript/shared_objects/js_shared_array.h"
#include "ecmascript/shared_objects/js_sendable_arraybuffer.h"
#include "ecmascript/shared_objects/js_shared_array_iterator.h"
#include "ecmascript/shared_objects/js_shared_map.h"
#include "ecmascript/shared_objects/js_shared_map_iterator.h"
@ -322,6 +323,9 @@ public:
case JSType::JS_ARRAY_BUFFER:
JSArrayBuffer::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_SENDABLE_ARRAY_BUFFER:
JSSendableArrayBuffer::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_SHARED_ARRAY_BUFFER:
JSArrayBuffer::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;

View File

@ -125,6 +125,7 @@
#include "ecmascript/require/js_cjs_require.h"
#include "ecmascript/shared_mm/shared_mm.h"
#include "ecmascript/shared_objects/js_shared_array.h"
#include "ecmascript/shared_objects/js_sendable_arraybuffer.h"
#include "ecmascript/shared_objects/js_shared_array_iterator.h"
#include "ecmascript/shared_objects/js_shared_map.h"
#include "ecmascript/shared_objects/js_shared_map_iterator.h"
@ -279,6 +280,41 @@ void ObjectFactory::NewJSArrayBufferData(const JSHandle<JSArrayBuffer> &array, i
vm_->GetNativeAreaAllocator()->IncreaseNativeSizeStats(length, NativeFlag::ARRAY_BUFFER);
}
void ObjectFactory::NewJSSendableArrayBufferData(const JSHandle<JSSendableArrayBuffer> &array, int32_t length)
{
if (length == 0) {
return;
}
JSTaggedValue data = array->GetArrayBufferData();
size_t size = static_cast<size_t>(length) * sizeof(uint8_t);
NativeAreaAllocator *nativeAreaAllocator = sHeap_->GetNativeAreaAllocator();
if (!data.IsUndefined()) {
auto *pointer = JSNativePointer::Cast(data.GetTaggedObject());
auto newData = nativeAreaAllocator->AllocateBuffer(size);
if (memset_s(newData, length, 0, length) != EOK) {
LOG_FULL(FATAL) << "memset_s failed";
UNREACHABLE();
}
pointer->ResetExternalPointer(newData);
nativeAreaAllocator->ModifyNativeSizeStats(pointer->GetBindingSize(), size,
NativeFlag::ARRAY_BUFFER);
return;
}
auto newData = nativeAreaAllocator->AllocateBuffer(size);
if (memset_s(newData, length, 0, length) != EOK) {
LOG_FULL(FATAL) << "memset_s failed";
UNREACHABLE();
}
JSHandle<JSNativePointer> pointer = NewSJSNativePointer(newData, NativeAreaAllocator::FreeBufferFunc,
nativeAreaAllocator, false, size,
NativeFlag::ARRAY_BUFFER);
array->SetArrayBufferData(thread_, pointer);
array->SetWithNativeAreaAllocator(true);
nativeAreaAllocator->IncreaseNativeSizeStats(length, NativeFlag::ARRAY_BUFFER);
}
void ObjectFactory::NewJSSharedArrayBufferData(const JSHandle<JSArrayBuffer> &array, int32_t length)
{
if (length == 0) {
@ -1324,6 +1360,10 @@ void ObjectFactory::InitializeJSObject(const JSHandle<JSObject> &obj, const JSHa
JSArrayBuffer::Cast(*obj)->SetArrayBufferByteLength(0);
JSArrayBuffer::Cast(*obj)->SetShared(true);
break;
case JSType::JS_SENDABLE_ARRAY_BUFFER:
JSSendableArrayBuffer::Cast(*obj)->SetArrayBufferData(thread_, JSTaggedValue::Undefined());
JSSendableArrayBuffer::Cast(*obj)->SetArrayBufferByteLength(0);
break;
case JSType::JS_PROMISE:
JSPromise::Cast(*obj)->SetPromiseState(PromiseState::PENDING);
JSPromise::Cast(*obj)->SetPromiseResult(thread_, JSTaggedValue::Undefined());

View File

@ -74,6 +74,7 @@ class JSGeneratorObject;
class CompletionRecord;
class GeneratorContext;
class JSArrayBuffer;
class JSSendableArrayBuffer;
class JSDataView;
class JSPromise;
class JSPromiseReactionsFunction;
@ -497,6 +498,7 @@ public:
bool canShareHClass);
void NewJSArrayBufferData(const JSHandle<JSArrayBuffer> &array, int32_t length);
void NewJSSendableArrayBufferData(const JSHandle<JSSendableArrayBuffer> &array, int32_t length);
JSHandle<JSArrayBuffer> NewJSArrayBuffer(int32_t length);

View File

@ -345,6 +345,15 @@ namespace panda::ecmascript {
V(SharedArrayBuffer, IsView) \
V(SharedArrayBuffer, Species) \
V(SharedArrayBuffer, GetByteLength) \
V(SendableArrayBuffer, Constructor) \
V(SendableArrayBuffer, Slice) \
V(SendableArrayBuffer, Species) \
V(SendableArrayBuffer, GetByteLength) \
V(SendableArrayBuffer, GetValueFromBuffer) \
V(SendableArrayBuffer, SetValueInBuffer) \
V(SendableArrayBuffer, CloneArrayBuffer) \
V(SendableArrayBuffer, AllocateSendableArrayBuffer) \
V(SendableArrayBuffer, IsView) \
V(AsyncFromSyncIterator, Next) \
V(AsyncFromSyncIterator, Throw) \
V(AsyncFromSyncIterator, Return) \

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/shared_objects/js_sendable_arraybuffer.h"
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/ecma_macros.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/mem/barriers-inl.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/platform/os.h"
#include "ecmascript/tagged_array.h"
#include "securec.h"
namespace panda::ecmascript {
void JSSendableArrayBuffer::CopyDataBlockBytes(
JSTaggedValue toBlock, JSTaggedValue fromBlock, int32_t fromIndex, int32_t count)
{
void *fromBuf = JSNativePointer::Cast(fromBlock.GetTaggedObject())->GetExternalPointer();
void *toBuf = JSNativePointer::Cast(toBlock.GetTaggedObject())->GetExternalPointer();
CopyDataPointBytes(toBuf, fromBuf, fromIndex, count);
}
void JSSendableArrayBuffer::CopyDataPointBytes(void *toBuf, void *fromBuf, int32_t fromIndex, int32_t count)
{
auto *from = static_cast<uint8_t *>(fromBuf);
auto *to = static_cast<uint8_t *>(toBuf);
if (memcpy_s(to, count, from + fromIndex, count) != EOK) { // NOLINT
LOG_FULL(FATAL) << "memcpy_s failed";
UNREACHABLE();
}
}
void JSSendableArrayBuffer::Attach(JSThread *thread, uint32_t arrayBufferByteLength,
JSTaggedValue arrayBufferData, bool transferWithNativeAreaAllocator)
{
ASSERT(arrayBufferData.IsJSNativePointer());
// only in transition, should the JSSendableArrayBuffer with NativeAreaAllocator increase mem usage
if (transferWithNativeAreaAllocator) {
LOG_FULL(DEBUG) << "attaching for transfer";
JSHandle<JSNativePointer> np(thread, arrayBufferData.GetTaggedObject());
NativeAreaAllocator *allocator = thread->GetEcmaVM()->GetNativeAreaAllocator();
allocator->IncreaseNativeMemoryUsage(MallocUsableSize(np->GetExternalPointer()));
np->SetData(allocator);
}
SetArrayBufferByteLength(arrayBufferByteLength);
SetArrayBufferData(thread, arrayBufferData);
}
void JSSendableArrayBuffer::Detach(JSThread *thread, bool transferWithNativeAreaAllocator)
{
JSTaggedValue arrayBufferData = GetArrayBufferData();
// already detached.
if (arrayBufferData.IsNull()) {
return;
}
// only in transition, should the JSSendableArrayBuffer with NativeAreaAllocator decrease mem usage
if (transferWithNativeAreaAllocator) {
LOG_FULL(DEBUG) << "detaching for transfer";
JSHandle<JSNativePointer> np(thread, arrayBufferData.GetTaggedObject());
NativeAreaAllocator *allocator = thread->GetEcmaVM()->GetNativeAreaAllocator();
allocator->DecreaseNativeMemoryUsage(MallocUsableSize(np->GetExternalPointer()));
np->SetData(nullptr);
}
SetArrayBufferData(thread, JSTaggedValue::Null());
SetArrayBufferByteLength(0);
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_JS_SENDABLE_ARRAYBUFFER_H
#define ECMASCRIPT_JS_SENDABLE_ARRAYBUFFER_H
#include "ecmascript/js_object.h"
namespace panda::ecmascript {
class JSSendableArrayBuffer final : public JSObject {
public:
CAST_NO_CHECK(JSSendableArrayBuffer);
// 6.2.6.2
static void CopyDataBlockBytes(JSTaggedValue toBlock, JSTaggedValue fromBlock, int32_t fromIndex, int32_t count);
static void CopyDataPointBytes(void *toBuf, void *fromBuf, int32_t fromIndex, int32_t count);
void Attach(JSThread *thread, uint32_t arrayBufferByteLength, JSTaggedValue arrayBufferData,
bool transferWithNativeAreaAllocator = false);
void Detach(JSThread *thread, bool transferWithNativeAreaAllocator = false);
bool IsDetach()
{
JSTaggedValue arrayBufferData = GetArrayBufferData();
return arrayBufferData.IsNull();
}
static constexpr size_t DATA_OFFSET = JSObject::SIZE;
ACCESSORS(ArrayBufferData, DATA_OFFSET, BYTE_LENGTH_OFFSET)
ACCESSORS_PRIMITIVE_FIELD(ArrayBufferByteLength, uint32_t, BYTE_LENGTH_OFFSET, BIT_FIELD_OFFSET)
ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET)
DEFINE_ALIGN_SIZE(LAST_OFFSET);
// define BitField
static constexpr size_t SHARED_BITS = 1;
static constexpr size_t WITH_NATIVE_AREA_ALLOCATOR_BITS = 1;
FIRST_BIT_FIELD(BitField, Shared, bool, SHARED_BITS)
NEXT_BIT_FIELD(BitField, WithNativeAreaAllocator, bool, WITH_NATIVE_AREA_ALLOCATOR_BITS, Shared)
DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, DATA_OFFSET, BYTE_LENGTH_OFFSET)
DECL_DUMP()
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_JS_SENDABLE_ARRAYBUFFER_H

View File

@ -113,6 +113,7 @@
#include "ecmascript/module/js_module_source_text.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/shared_objects/js_shared_array.h"
#include "ecmascript/shared_objects/js_sendable_arraybuffer.h"
#include "ecmascript/shared_objects/js_shared_array_iterator.h"
#include "ecmascript/shared_objects/js_shared_map.h"
#include "ecmascript/shared_objects/js_shared_map_iterator.h"
@ -829,6 +830,11 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump)
NEW_OBJECT_AND_DUMP(JSArrayBuffer, JS_ARRAY_BUFFER);
break;
}
case JSType::JS_SENDABLE_ARRAY_BUFFER: {
CHECK_DUMP_FIELDS(JSObject::SIZE, JSSendableArrayBuffer::SIZE, 2U);
NEW_OBJECT_AND_DUMP(JSSendableArrayBuffer, JS_SENDABLE_ARRAY_BUFFER);
break;
}
case JSType::JS_PROMISE: {
CHECK_DUMP_FIELDS(JSObject::SIZE, JSPromise::SIZE, 4U);
NEW_OBJECT_AND_DUMP(JSPromise, JS_PROMISE);