mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-27 20:20:52 +00:00
!6811 support sendable array buffer
Merge pull request !6811 from lijiamin/fix
This commit is contained in:
commit
37929da422
2
BUILD.gn
2
BUILD.gn
@ -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",
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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)); \
|
||||
|
@ -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;
|
||||
|
956
ecmascript/builtins/builtins_sendable_arraybuffer.cpp
Normal file
956
ecmascript/builtins/builtins_sendable_arraybuffer.cpp
Normal 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 O’s [[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 O’s [[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 new’s [[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 O’s [[ArrayBufferData]] internal slot.
|
||||
void *fromBuf = GetDataPointFromBuffer(arrBuf.GetTaggedValue());
|
||||
// 24. Let toBuf be the value of new’s [[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 obj’s [[ArrayBufferData]] internal slot to block.
|
||||
factory->NewJSSendableArrayBufferData(arrayBuffer, arrayByteLength);
|
||||
// 7. Set obj’s [[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 arrayBuffer’s [[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 srcBuffer’s [[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 targetBuffer’s [[ArrayBufferData]] internal slot.
|
||||
JSHandle<JSArrayBuffer> newArrBuf(thread, taggedBuf);
|
||||
// Perform CopyDataBlockBytes(targetBlock, 0, srcBlock, srcByteOffset, cloneLength).
|
||||
// 7. Let srcBlock be the value of srcBuffer’s [[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
|
197
ecmascript/builtins/builtins_sendable_arraybuffer.h
Normal file
197
ecmascript/builtins/builtins_sendable_arraybuffer.h
Normal 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
|
@ -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());
|
||||
|
@ -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 O’s [[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 O’s [[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 O’s [[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 O’s [[ViewedArrayBuffer]] internal slot.
|
||||
JSTaggedValue buffer = JSHandle<JSTypedArray>::Cast(thisHandle)->GetViewedArrayBufferOrByteArray();
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -555,6 +555,7 @@ public:
|
||||
bool IsStringIterator() const;
|
||||
bool IsArrayBuffer() const;
|
||||
bool IsSharedArrayBuffer() const;
|
||||
bool IsSendableArrayBuffer() const;
|
||||
|
||||
bool IsJSSetIterator() const;
|
||||
bool IsJSSharedSetIterator() const;
|
||||
|
@ -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 O’s [[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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) \
|
||||
|
82
ecmascript/shared_objects/js_sendable_arraybuffer.cpp
Normal file
82
ecmascript/shared_objects/js_sendable_arraybuffer.cpp
Normal 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
|
58
ecmascript/shared_objects/js_sendable_arraybuffer.h
Normal file
58
ecmascript/shared_objects/js_sendable_arraybuffer.h
Normal 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
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user