diff --git a/BUILD.gn b/BUILD.gn index e5872bad28..740189c87f 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -327,6 +327,7 @@ ecma_source = [ "ecmascript/builtins/builtins_reflect.cpp", "ecmascript/builtins/builtins_regexp.cpp", "ecmascript/builtins/builtins_set.cpp", + "ecmascript/builtins/builtins_sharedarraybuffer.cpp", "ecmascript/builtins/builtins_string.cpp", "ecmascript/builtins/builtins_string_iterator.cpp", "ecmascript/builtins/builtins_symbol.cpp", @@ -458,6 +459,7 @@ ecma_source = [ "ecmascript/regexp/regexp_parser.cpp", "ecmascript/regexp/regexp_parser_cache.cpp", "ecmascript/runtime_api.cpp", + "ecmascript/sharedMemoryManaged/sharedmemorymanager.cpp", "ecmascript/tagged_dictionary.cpp", "ecmascript/tagged_tree.cpp", "ecmascript/template_string.cpp", diff --git a/ecmascript/base/typed_array_helper.cpp b/ecmascript/base/typed_array_helper.cpp index c52acf8651..a76c453f06 100644 --- a/ecmascript/base/typed_array_helper.cpp +++ b/ecmascript/base/typed_array_helper.cpp @@ -72,7 +72,7 @@ JSTaggedValue TypedArrayHelper::TypedArrayConstructor(EcmaRuntimeCallInfo *argv, if (firstArg->IsTypedArray()) { return TypedArrayHelper::CreateFromTypedArray(argv, obj, constructorName); } - if (firstArg->IsArrayBuffer()) { + if (firstArg->IsArrayBuffer() || firstArg->IsSharedArrayBuffer()) { return TypedArrayHelper::CreateFromArrayBuffer(argv, obj, constructorName); } return TypedArrayHelper::CreateFromOrdinaryObject(argv, obj); diff --git a/ecmascript/builtins.cpp b/ecmascript/builtins.cpp index a24488ca90..c553c50a8a 100644 --- a/ecmascript/builtins.cpp +++ b/ecmascript/builtins.cpp @@ -59,6 +59,7 @@ #include "ecmascript/builtins/builtins_regexp.h" #include "ecmascript/builtins/builtins_relative_time_format.h" #include "ecmascript/builtins/builtins_set.h" +#include "ecmascript/builtins/builtins_sharedarraybuffer.h" #include "ecmascript/builtins/builtins_string.h" #include "ecmascript/builtins/builtins_string_iterator.h" #include "ecmascript/builtins/builtins_symbol.h" @@ -151,6 +152,7 @@ using PluralRules = builtins::BuiltinsPluralRules; using DisplayNames = builtins::BuiltinsDisplayNames; using ContainersPrivate = containers::ContainersPrivate; +using SharedArrayBuffer = builtins::BuiltinsSharedArrayBuffer; bool GetAbsolutePath(const std::string &relativePath, std::string &absPath) { @@ -300,6 +302,7 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread) InitializeString(env, primRefObjDynclass); InitializeArrayBuffer(env, objFuncDynclass); InitializeDataView(env, objFuncDynclass); + InitializeSharedArrayBuffer(env, objFuncDynclass); JSHandle argumentsDynclass = factory_->CreateJSArguments(); env->SetArgumentsClass(thread_, argumentsDynclass); @@ -2225,6 +2228,51 @@ void Builtins::InitializeReflect(const JSHandle &env, env->SetReflectFunction(thread_, reflectObject.GetTaggedValue()); } +void Builtins::InitializeSharedArrayBuffer(const JSHandle &env, + const JSHandle &objFuncDynclass) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + // SharedArrayBuffer.prototype + JSHandle sharedArrayBufferFuncPrototype = factory_->NewJSObject(objFuncDynclass); + JSHandle sharedArrayBufferFuncPrototypeValue(sharedArrayBufferFuncPrototype); + + // SharedArrayBuffer.prototype_or_dynclass + JSHandle sharedArrayBufferFuncInstanceDynclass = + factory_->NewEcmaDynClass( + JSArrayBuffer::SIZE, JSType::JS_SHARED_ARRAY_BUFFER, sharedArrayBufferFuncPrototypeValue); + + // SharedArrayBuffer = new Function() + JSHandle SharedArrayBufferFunction(NewBuiltinConstructor(env, sharedArrayBufferFuncPrototype, + SharedArrayBuffer::SharedArrayBufferConstructor, "SharedArrayBuffer", FunctionLength::ONE)); + + JSHandle(SharedArrayBufferFunction) + ->SetFunctionPrototype(thread_, sharedArrayBufferFuncInstanceDynclass.GetTaggedValue()); + + // SharedArrayBuffer prototype method + SetFunction(env, sharedArrayBufferFuncPrototype, "slice", SharedArrayBuffer::Slice, FunctionLength::TWO); + + // SharedArrayBuffer method + SetFunction(env, SharedArrayBufferFunction, + "IsSharedArrayBuffer", SharedArrayBuffer::IsSharedArrayBuffer, FunctionLength::ONE); + + // 25.2.3.2 get SharedArrayBuffer [ @@species ] + JSHandle speciesSymbol = env->GetSpeciesSymbol(); + JSHandle speciesGetter = + CreateGetter(env, SharedArrayBuffer::Species, "[Symbol.species]", FunctionLength::ZERO); + SetGetter(JSHandle(SharedArrayBufferFunction), speciesSymbol, speciesGetter); + + // 25.2.4.1 get SharedArrayBuffer.prototype.byteLength + JSHandle lengthGetter = + CreateGetter(env, SharedArrayBuffer::GetByteLength, "byteLength", FunctionLength::ZERO); + JSHandle lengthKey(factory_->NewFromCanBeCompressString("byteLength")); + SetGetter(sharedArrayBufferFuncPrototype, lengthKey, lengthGetter); + + // 25.2.4.4 SharedArrayBuffer.prototype [ @@toStringTag ] + SetStringTagSymbol(env, sharedArrayBufferFuncPrototype, "SharedArrayBuffer"); + + env->SetSharedArrayBufferFunction(thread_, SharedArrayBufferFunction.GetTaggedValue()); +} + void Builtins::InitializePromise(const JSHandle &env, const JSHandle &promiseFuncDynclass) { [[maybe_unused]] EcmaHandleScope scope(thread_); diff --git a/ecmascript/builtins.h b/ecmascript/builtins.h index cdd18852c1..42cb8d6fe2 100644 --- a/ecmascript/builtins.h +++ b/ecmascript/builtins.h @@ -158,6 +158,8 @@ private: void InitializeArrayBuffer(const JSHandle &env, const JSHandle &objFuncDynclass) const; + void InitializeSharedArrayBuffer(const JSHandle &env, const JSHandle &objFuncDynclass) const; + void InitializeDataView(const JSHandle &env, const JSHandle &objFuncDynclass) const; void InitializeProxy(const JSHandle &env); diff --git a/ecmascript/builtins/builtins_dataview.cpp b/ecmascript/builtins/builtins_dataview.cpp index a6f221cd1d..b193e8a74a 100644 --- a/ecmascript/builtins/builtins_dataview.cpp +++ b/ecmascript/builtins/builtins_dataview.cpp @@ -43,7 +43,7 @@ JSTaggedValue BuiltinsDataView::DataViewConstructor(EcmaRuntimeCallInfo *argv) THROW_TYPE_ERROR_AND_RETURN(thread, "buffer is not Object", JSTaggedValue::Exception()); } // 3. If buffer does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception. - if (!bufferHandle->IsArrayBuffer()) { + if (!bufferHandle->IsArrayBuffer() && !bufferHandle->IsSharedArrayBuffer()) { THROW_TYPE_ERROR_AND_RETURN(thread, "buffer is not ArrayBuffer", JSTaggedValue::Exception()); } JSHandle offsetHandle = GetCallArg(argv, 1); diff --git a/ecmascript/builtins/builtins_sharedarraybuffer.cpp b/ecmascript/builtins/builtins_sharedarraybuffer.cpp new file mode 100644 index 0000000000..80eeac2609 --- /dev/null +++ b/ecmascript/builtins/builtins_sharedarraybuffer.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (c) 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_sharedarraybuffer.h" + +#include "ecmascript/ecma_macros.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/global_env.h" +#include "ecmascript/internal_call_params.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 "securec.h" + +namespace panda::ecmascript::builtins { +// 25.2.2.1 SharedArrayBuffer ( [ length ] ) +JSTaggedValue BuiltinsSharedArrayBuffer::SharedArrayBufferConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArrayBuffer, Constructor); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle 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 lengthHandle = GetCallArg(argv, 0); + // 2. Let byteLength be ? ToIndex(length). + JSTaggedNumber lenNum = JSTaggedValue::ToIndex(thread, lengthHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + double byteLength = lenNum.GetNumber(); + // 3. Return ? AllocateSharedArrayBuffer(NewTarget, byteLength). + return AllocateSharedArrayBuffer(thread, newTarget, byteLength); +} + +// 25.2.1.2 IsSharedArrayBuffer ( obj ) +JSTaggedValue BuiltinsSharedArrayBuffer::IsSharedArrayBuffer(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(thread, SharedArrayBuffer, IsSharedArrayBuffer); + [[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread()); + JSHandle arg = GetCallArg(argv, 0); + // 1. If Type(arg) is not Object,and it not has an [[ArrayBufferData]] internal slot return false. + if (!arg->IsECMAObject()) { + return BuiltinsSharedArrayBuffer::GetTaggedBoolean(false); + } + if (!arg->IsSharedArrayBuffer()) { + return BuiltinsSharedArrayBuffer::GetTaggedBoolean(false); + } + // 2. Let bufferData be obj.[[ArrayBufferData]]. + JSHandle buffer(arg); + JSTaggedValue bufferdata = buffer->GetArrayBufferData(); + // 3. If bufferData is null, return false. + if (bufferdata == JSTaggedValue::Null()) { + return BuiltinsSharedArrayBuffer::GetTaggedBoolean(false); + } + // 4. If this ArrayBuffer is not shared, return false. + if (buffer->GetShared() == false) { + return BuiltinsSharedArrayBuffer::GetTaggedBoolean(false); + } + return BuiltinsSharedArrayBuffer::GetTaggedBoolean(true); +} + +bool BuiltinsSharedArrayBuffer::IsShared(JSTaggedValue arrayBuffer) +{ + if (!arrayBuffer.IsSharedArrayBuffer()) { + return false; + } + JSArrayBuffer *buffer = JSArrayBuffer::Cast(arrayBuffer.GetTaggedObject()); + JSTaggedValue dataSlot = buffer->GetArrayBufferData(); + // 2. If arrayBuffer’s [[ArrayBufferData]] internal slot is null, return false. + if (dataSlot.IsNull()) { + return false; + } + // 3. If this ArrayBuffer is not shared, return false. + return buffer->GetShared(); +} + +// 25.2.1.1 AllocateSharedArrayBuffer ( constructor, byteLength ) +JSTaggedValue BuiltinsSharedArrayBuffer::AllocateSharedArrayBuffer( + JSThread *thread, const JSHandle &newTarget, double byteLength) +{ + BUILTINS_API_TRACE(thread, SharedArrayBuffer, AllocateSharedArrayBuffer); + /** + * 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%SharedArrayBuffer.prototype%", + * «[[ArrayBufferData]], [[ArrayBufferByteLength]] »). + * */ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + JSHandle shaArrBufFunc = env->GetSharedArrayBufferFunction(); + JSHandle obj = factory->NewJSObjectByConstructor(JSHandle(shaArrBufFunc), newTarget); + // 2. ReturnIfAbrupt + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 3. Assert: byteLength is a positive integer. + ASSERT(JSTaggedValue(byteLength).IsInteger()); + ASSERT(byteLength >= 0); + // 4. Let block be CreateSharedByteDataBlock(byteLength). + if (byteLength > INT_MAX) { + THROW_RANGE_ERROR_AND_RETURN(thread, "Out of range", JSTaggedValue::Exception()); + } + JSHandle sharedArrayBuffer(obj); + // 6. Set obj’s [[ArrayBufferData]] internal slot to block. + factory->NewJSSharedArrayBufferData(sharedArrayBuffer, byteLength); + // 7. Set obj’s [[ArrayBufferByteLength]] internal slot to byteLength. + sharedArrayBuffer->SetArrayBufferByteLength(static_cast(byteLength)); + // 8. Return obj. + return sharedArrayBuffer.GetTaggedValue(); +} + +// 25.2.3.2 get SharedArrayBuffer [ @@species ] +JSTaggedValue BuiltinsSharedArrayBuffer::Species(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArrayBuffer, Species); + // 1. Return the this value. + return GetThis(argv).GetTaggedValue(); +} + +// 25.2.4.1 get SharedArrayBuffer.prototype.byteLength +JSTaggedValue BuiltinsSharedArrayBuffer::GetByteLength(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArrayBuffer, GetByteLength); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle 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->IsSharedArrayBuffer()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "don't have internal slot", JSTaggedValue::Exception()); + } + JSHandle shaArrBuf(thisHandle); + // 5. Let length be the value of O’s [[SharedArrayBufferByteLength]] internal slot. + uint32_t length = shaArrBuf->GetArrayBufferByteLength(); + // 6. Return length. + return JSTaggedValue(length); +} + +// 25.2.4.3 SharedArrayBuffer.prototype.slice ( start, end ) +JSTaggedValue BuiltinsSharedArrayBuffer::Slice(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArrayBuffer, Slice); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + // 1. Let O be the this value. + JSHandle 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()); + } + JSHandle shaArrBuf(thisHandle); + // 3. If O does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception. + if (!thisHandle->IsSharedArrayBuffer()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "don't have internal slot", JSTaggedValue::Exception()); + } + // 4. If IsSharedArrayBuffer(O) is false, throw a TypeError exception. + if (!IsShared(thisHandle.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "this value not IsSharedArrayBuffer", JSTaggedValue::Exception()); + } + // 5. Let len be the value of O’s [[ArrayBufferByteLength]] internal slot. + int32_t len = shaArrBuf->GetArrayBufferByteLength(); + JSHandle 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; + int32_t first; + int32_t last; + // 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 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). + last = end < 0 ? std::max((len + end), 0) : 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, %SharedArrayBuffer%). + JSHandle defaultConstructor = env->GetSharedArrayBufferFunction(); + JSHandle objHandle(thisHandle); + JSHandle constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor); + // 14. ReturnIfAbrupt(ctor). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 15. Let new be Construct(ctor, «newLen»). + JSHandle undefined = globalConst->GetHandledUndefined(); + InternalCallParams *arguments = thread->GetInternalCallParams(); + arguments->MakeArgv(JSTaggedValue(newLen)); + JSTaggedValue taggedNewArrBuf = JSFunction::Construct(thread, constructor, 1, arguments->GetArgv(), undefined); + JSHandle 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->IsSharedArrayBuffer()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "don't have bufferdata internal slot", JSTaggedValue::Exception()); + } + // 18. If IsSharedArrayBuffer(new) is false, throw a TypeError exception. + if (!IsShared(newArrBuf.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "new arrayBuffer not IsSharedArrayBuffer", 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 newJsShaArrBuf(newArrBuf); + // 20. If the value of new’s [[ArrayBufferByteLength]] internal slot < newLen, throw a TypeError exception. + uint32_t newArrBufLen = newJsShaArrBuf->GetArrayBufferByteLength(); + if (newArrBufLen < newLen) { + THROW_TYPE_ERROR_AND_RETURN(thread, "new array buffer length smaller than newlen", JSTaggedValue::Exception()); + } + if (newLen > 0) { + // 23. Let fromBuf be the value of O’s [[ArrayBufferData]] internal slot. + JSTaggedValue from = shaArrBuf->GetArrayBufferData(); + // 24. Let toBuf be the value of new’s [[ArrayBufferData]] internal slot. + JSTaggedValue to = newJsShaArrBuf->GetArrayBufferData(); + // 25. Perform CopyDataBlockBytes(toBuf, fromBuf, first, newLen). + JSArrayBuffer::CopyDataBlockBytes(to, from, first, newLen); + } + // Return new. + return newArrBuf.GetTaggedValue(); +} +} // namespace panda::ecmascript::builtins \ No newline at end of file diff --git a/ecmascript/builtins/builtins_sharedarraybuffer.h b/ecmascript/builtins/builtins_sharedarraybuffer.h new file mode 100644 index 0000000000..2d883b573f --- /dev/null +++ b/ecmascript/builtins/builtins_sharedarraybuffer.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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_SHAREDARRAYBUFFER_H +#define ECMASCRIPT_BUILTINS_BUILTINS_SHAREDARRAYBUFFER_H + +#include "ecmascript/base/builtins_base.h" +#include "ecmascript/base/number_helper.h" +#include "ecmascript/js_dataview.h" + +namespace panda::ecmascript::builtins { +class BuiltinsSharedArrayBuffer : public base::BuiltinsBase { +public: + // 25.2.2.1 SharedArrayBuffer ( [ length ] ) + static JSTaggedValue SharedArrayBufferConstructor(EcmaRuntimeCallInfo *argv); + // 25.2.1.2 IsSharedArrayBuffer ( obj ) + static JSTaggedValue IsSharedArrayBuffer(EcmaRuntimeCallInfo *argv); + // 24.2.3.2 get SharedArrayBuffer [ @@species ] + static JSTaggedValue Species(EcmaRuntimeCallInfo *argv); + // 25.2.4.1 get SharedArrayBuffer.prototype.byteLength + static JSTaggedValue GetByteLength(EcmaRuntimeCallInfo *argv); + // 25.2.4.3 SharedArrayBuffer.prototype.slice ( start, end ) + static JSTaggedValue Slice(EcmaRuntimeCallInfo *argv); + + static bool IsShared(JSTaggedValue arrayBuffer); +private: + // 25.2.1.1 AllocateSharedArrayBuffer ( constructor, byteLength ) + static JSTaggedValue AllocateSharedArrayBuffer(JSThread *thread, const JSHandle &newTarget, + double byteLength); +}; +} // namespace panda::ecmascript::builtins + +#endif // ECMASCRIPT_BUILTINS_BUILTINS_SHAREDARRAYBUFFER_H \ No newline at end of file diff --git a/ecmascript/dfx/hprof/heap_snapshot.cpp b/ecmascript/dfx/hprof/heap_snapshot.cpp index d8b7c8e7ba..3135cc5654 100644 --- a/ecmascript/dfx/hprof/heap_snapshot.cpp +++ b/ecmascript/dfx/hprof/heap_snapshot.cpp @@ -262,6 +262,8 @@ CString *HeapSnapShot::GenerateNodeName(TaggedObject *entry) return GetString("StringIterator"); case JSType::JS_ARRAY_BUFFER: return GetString("ArrayBuffer"); + case JSType::JS_SHARED_ARRAY_BUFFER: + return GetString("SharedArrayBuffer"); case JSType::JS_PROXY_REVOC_FUNCTION: return GetString("ProxyRevocFunction"); case JSType::PROMISE_REACTIONS: diff --git a/ecmascript/dump.cpp b/ecmascript/dump.cpp index 4a4dd64461..2d4835a4fa 100644 --- a/ecmascript/dump.cpp +++ b/ecmascript/dump.cpp @@ -197,6 +197,8 @@ CString JSHClass::DumpJSType(JSType type) return "StringIterator"; case JSType::JS_ARRAY_BUFFER: return "ArrayBuffer"; + case JSType::JS_SHARED_ARRAY_BUFFER: + return "SharedArrayBuffer"; case JSType::JS_PROXY_REVOC_FUNCTION: return "ProxyRevocFunction"; case JSType::PROMISE_REACTIONS: @@ -524,6 +526,9 @@ static void DumpObject(TaggedObject *obj, std::ostream &os) case JSType::JS_ARRAY_BUFFER: JSArrayBuffer::Cast(obj)->Dump(os); break; + case JSType::JS_SHARED_ARRAY_BUFFER: + JSArrayBuffer::Cast(obj)->Dump(os); + break; case JSType::PROMISE_REACTIONS: PromiseReaction::Cast(obj)->Dump(os); break; @@ -1579,6 +1584,8 @@ void GlobalEnv::Dump(std::ostream &os) const GetInt16ArrayFunction().GetTaggedValue().Dump(os); os << " - ArrayBufferFunction: "; GetArrayBufferFunction().GetTaggedValue().Dump(os); + os << " - SharedArrayBufferFunction: "; + GetSharedArrayBufferFunction().GetTaggedValue().Dump(os); os << " - SymbolFunction: "; GetSymbolFunction().GetTaggedValue().Dump(os); os << " - RangeErrorFunction: "; @@ -2793,6 +2800,9 @@ static void DumpObject(TaggedObject *obj, case JSType::JS_ARRAY_BUFFER: JSArrayBuffer::Cast(obj)->DumpForSnapshot(vec); return; + case JSType::JS_SHARED_ARRAY_BUFFER: + JSArrayBuffer::Cast(obj)->DumpForSnapshot(vec); + return; case JSType::JS_PROXY_REVOC_FUNCTION: JSProxyRevocFunction::Cast(obj)->DumpForSnapshot(vec); return; @@ -3407,6 +3417,8 @@ void GlobalEnv::DumpForSnapshot(std::vector> & vec.push_back(std::make_pair(CString("Float32ArrayFunction"), GetFloat32ArrayFunction().GetTaggedValue())); vec.push_back(std::make_pair(CString("Float64ArrayFunction"), GetFloat64ArrayFunction().GetTaggedValue())); vec.push_back(std::make_pair(CString("ArrayBufferFunction"), GetArrayBufferFunction().GetTaggedValue())); + vec.push_back( + std::make_pair(CString("SharedArrayBufferFunction"), GetSharedArrayBufferFunction().GetTaggedValue())); vec.push_back(std::make_pair(CString("SymbolFunction"), GetSymbolFunction().GetTaggedValue())); vec.push_back(std::make_pair(CString("RangeErrorFunction"), GetRangeErrorFunction().GetTaggedValue())); vec.push_back(std::make_pair(CString("ReferenceErrorFunction"), GetReferenceErrorFunction().GetTaggedValue())); diff --git a/ecmascript/global_env.h b/ecmascript/global_env.h index bfae562f7e..e6af2bb609 100644 --- a/ecmascript/global_env.h +++ b/ecmascript/global_env.h @@ -54,6 +54,7 @@ class JSThread; V(JSTaggedValue, BigInt64ArrayFunction, BIGINT64_ARRAY_FUNCTION_INDEX) \ V(JSTaggedValue, BigUint64ArrayFunction, BIGUINT64_ARRAY_FUNCTION_INDEX) \ V(JSTaggedValue, ArrayBufferFunction, ARRAY_BUFFER_FUNCTION_INDEX) \ + V(JSTaggedValue, SharedArrayBufferFunction, SHAREDARRAY_BUFFER_FUNCTION_INDEX) \ V(JSTaggedValue, ArrayProtoValuesFunction, ARRAY_PROTO_VALUES_FUNCTION_INDEX) \ V(JSTaggedValue, DataViewFunction, DATA_VIEW_FUNCTION_INDEX) \ V(JSTaggedValue, SymbolFunction, SYMBOL_FUNCTION_INDEX) \ diff --git a/ecmascript/js_hclass.h b/ecmascript/js_hclass.h index 161a4c01e2..3c9787cb16 100644 --- a/ecmascript/js_hclass.h +++ b/ecmascript/js_hclass.h @@ -114,6 +114,7 @@ class ProtoChangeDetails; JS_DISPLAYNAMES, /* ///////////////////////////////////////////////////////////////////////////////-PADDING */ \ \ JS_ARRAY_BUFFER, /* ///////////////////////////////////////////////////////////////////////////////-PADDING */ \ + JS_SHARED_ARRAY_BUFFER, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_PROMISE, /* ///////////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_DATA_VIEW, /* /////////////////////////////////////////////////////////////////////////////////////// */ \ JS_ARGUMENTS, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \ @@ -733,6 +734,11 @@ public: return GetObjectType() == JSType::JS_ARRAY_BUFFER; } + inline bool IsSharedArrayBuffer() const + { + return GetObjectType() == JSType::JS_SHARED_ARRAY_BUFFER; + } + inline bool IsDataView() const { return GetObjectType() == JSType::JS_DATA_VIEW; diff --git a/ecmascript/js_serializer.cpp b/ecmascript/js_serializer.cpp index 2f4673e8a3..d6acd4e54c 100644 --- a/ecmascript/js_serializer.cpp +++ b/ecmascript/js_serializer.cpp @@ -27,6 +27,7 @@ #include "ecmascript/js_set.h" #include "ecmascript/js_typed_array.h" #include "ecmascript/linked_hash_table-inl.h" +#include "ecmascript/sharedMemoryManaged/sharedmemorymanager.h" #include "libpandabase/mem/mem.h" #include "securec.h" @@ -292,6 +293,7 @@ bool JSSerializer::WriteTaggedObject(const JSHandle &value) case JSType::JS_BIGUINT64_ARRAY: return WriteJSTypedArray(value, SerializationUID::JS_BIGUINT64_ARRAY); case JSType::JS_ARRAY_BUFFER: + case JSType::JS_SHARED_ARRAY_BUFFER: return WriteJSArrayBuffer(value); case JSType::STRING: return WriteEcmaString(value); @@ -602,8 +604,15 @@ bool JSSerializer::WriteJSArrayBuffer(const JSHandle &value) return false; } - if (!WriteType(SerializationUID::JS_ARRAY_BUFFER)) { - return false; + bool shared = arrayBuffer->GetShared(); + if (shared) { + if (!WriteType(SerializationUID::JS_SHARED_ARRAY_BUFFER)) { + return false; + } + } else { + if (!WriteType(SerializationUID::JS_ARRAY_BUFFER)) { + return false; + } } // Write Accessors(ArrayBufferByteLength) @@ -614,7 +623,6 @@ bool JSSerializer::WriteJSArrayBuffer(const JSHandle &value) } // write Accessor shared which indicate the C memory is shared - bool shared = arrayBuffer->GetShared(); if (!WriteBoolean(shared)) { bufferSize_ = oldSize; return false; @@ -623,6 +631,7 @@ bool JSSerializer::WriteJSArrayBuffer(const JSHandle &value) if (shared) { JSHandle np(thread_, arrayBuffer->GetArrayBufferData()); void *buffer = np->GetExternalPointer(); + JSSharedMemoryManager::GetInstance()->CreateOrLoad(&buffer, arrayLength); uint64_t bufferAddr = (uint64_t)buffer; if (!WriteRawData(&bufferAddr, sizeof(uint64_t))) { bufferSize_ = oldSize; @@ -895,6 +904,7 @@ JSHandle JSDeserializer::DeserializeJSTaggedValue() return ReadJSTypedArray(SerializationUID::JS_BIGUINT64_ARRAY); case SerializationUID::NATIVE_FUNCTION_POINTER: return ReadNativeFunctionPointer(); + case SerializationUID::JS_SHARED_ARRAY_BUFFER: case SerializationUID::JS_ARRAY_BUFFER: return ReadJSArrayBuffer(); case SerializationUID::TAGGED_OBJECT_REFERNCE: @@ -1243,7 +1253,7 @@ JSHandle JSDeserializer::ReadJSArrayBuffer() if (shared) { uint64_t *bufferAddr = reinterpret_cast(GetBuffer(sizeof(uint64_t))); void* bufferData = ToVoidPtr(*bufferAddr); - JSHandle arrayBuffer = factory_->NewJSArrayBuffer(bufferData, arrayLength, nullptr, nullptr); + JSHandle arrayBuffer = factory_->NewJSSharedArrayBuffer(bufferData, arrayLength); arrayBufferTag = JSHandle::Cast(arrayBuffer); referenceMap_.insert(std::pair(objectId_++, arrayBufferTag)); } else { diff --git a/ecmascript/js_serializer.h b/ecmascript/js_serializer.h index 7b92e4920a..65566ed94d 100644 --- a/ecmascript/js_serializer.h +++ b/ecmascript/js_serializer.h @@ -54,6 +54,7 @@ enum class SerializationUID : uint8_t { JS_MAP, JS_ARRAY, JS_ARRAY_BUFFER, + JS_SHARED_ARRAY_BUFFER, // TypedArray begin JS_UINT8_ARRAY, JS_UINT8_CLAMPED_ARRAY, diff --git a/ecmascript/js_tagged_value-inl.h b/ecmascript/js_tagged_value-inl.h index 1654c5ff54..acad083d29 100644 --- a/ecmascript/js_tagged_value-inl.h +++ b/ecmascript/js_tagged_value-inl.h @@ -980,6 +980,11 @@ inline bool JSTaggedValue::IsArrayBuffer() const return IsHeapObject() && GetTaggedObject()->GetClass()->IsArrayBuffer(); } +inline bool JSTaggedValue::IsSharedArrayBuffer() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsSharedArrayBuffer(); +} + inline bool JSTaggedValue::IsDataView() const { return IsHeapObject() && GetTaggedObject()->GetClass()->IsDataView(); diff --git a/ecmascript/js_tagged_value.h b/ecmascript/js_tagged_value.h index 15142105df..cc2bcf2107 100644 --- a/ecmascript/js_tagged_value.h +++ b/ecmascript/js_tagged_value.h @@ -293,6 +293,7 @@ public: bool IsForinIterator() const; bool IsStringIterator() const; bool IsArrayBuffer() const; + bool IsSharedArrayBuffer() const; bool IsJSSetIterator() const; bool IsJSMapIterator() const; diff --git a/ecmascript/mem/object_xray-inl.h b/ecmascript/mem/object_xray-inl.h index 054bd16742..30a87456d6 100644 --- a/ecmascript/mem/object_xray-inl.h +++ b/ecmascript/mem/object_xray-inl.h @@ -168,6 +168,9 @@ void ObjectXRay::VisitObjectBody(TaggedObject *object, JSHClass *klass, const Ec case JSType::JS_ARRAY_BUFFER: JSArrayBuffer::Cast(object)->VisitRangeSlot(visitor); break; + case JSType::JS_SHARED_ARRAY_BUFFER: + JSArrayBuffer::Cast(object)->VisitRangeSlot(visitor); + break; case JSType::JS_PROMISE: JSPromise::Cast(object)->VisitRangeSlot(visitor); break; diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 4ec325599b..22e894b14f 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -84,6 +84,7 @@ #include "ecmascript/module/js_module_namespace.h" #include "ecmascript/module/js_module_source_text.h" #include "ecmascript/record.h" +#include "ecmascript/sharedMemoryManaged/sharedmemorymanager.h" #include "ecmascript/symbol_table-inl.h" #include "ecmascript/tagged_tree-inl.h" #include "ecmascript/template_map.h" @@ -172,7 +173,23 @@ void ObjectFactory::NewJSArrayBufferData(const JSHandle &array, i } JSHandle pointer = NewJSNativePointer(newData, NativeAreaAllocator::FreeBufferFunc, vm_->GetNativeAreaAllocator()); - array->SetArrayBufferData(thread_, pointer.GetTaggedValue()); + array->SetArrayBufferData(thread_, pointer); +} + +void ObjectFactory::NewJSSharedArrayBufferData(const JSHandle &array, int32_t length) +{ + if (length == 0) { + return; + } + void *newData = nullptr; + JSSharedMemoryManager::GetInstance()->CreateOrLoad(&newData, length); + if (memset_s(newData, length, 0, length) != EOK) { + LOG_ECMA(FATAL) << "memset_s failed"; + UNREACHABLE(); + } + JSHandle pointer = NewJSNativePointer(newData, JSSharedMemoryManager::RemoveSharedMemory, + JSSharedMemoryManager::GetInstance()); + array->SetArrayBufferData(thread_, pointer); } JSHandle ObjectFactory::NewJSArrayBuffer(int32_t length) @@ -234,6 +251,39 @@ JSHandle ObjectFactory::NewJSDataView(JSHandle buffer return arrayBuffer; } +JSHandle ObjectFactory::NewJSSharedArrayBuffer(int32_t length) +{ + JSHandle env = vm_->GetGlobalEnv(); + + JSHandle constructor(env->GetSharedArrayBufferFunction()); + JSHandle newTarget(constructor); + JSHandle sharedArrayBuffer(NewJSObjectByConstructor(constructor, newTarget)); + sharedArrayBuffer->SetArrayBufferByteLength(length); + if (length > 0) { + NewJSSharedArrayBufferData(sharedArrayBuffer, length); + sharedArrayBuffer->SetShared(true); + } + return sharedArrayBuffer; +} + +JSHandle ObjectFactory::NewJSSharedArrayBuffer(void *buffer, int32_t length) +{ + JSHandle env = vm_->GetGlobalEnv(); + + JSHandle constructor(env->GetSharedArrayBufferFunction()); + JSHandle newTarget(constructor); + JSHandle sharedArrayBuffer(NewJSObjectByConstructor(constructor, newTarget)); + length = buffer == nullptr ? 0 : length; + sharedArrayBuffer->SetArrayBufferByteLength(length); + if (length > 0) { + JSHandle pointer = NewJSNativePointer(buffer, JSSharedMemoryManager::RemoveSharedMemory, + JSSharedMemoryManager::GetInstance()); + sharedArrayBuffer->SetArrayBufferData(thread_, pointer); + sharedArrayBuffer->SetShared(true); + } + return sharedArrayBuffer; +} + void ObjectFactory::NewJSRegExpByteCodeData(const JSHandle ®exp, void *buffer, size_t size) { if (buffer == nullptr) { @@ -782,6 +832,11 @@ JSHandle ObjectFactory::NewJSObjectByConstructor(const JSHandleSetArrayBufferByteLength(0); JSArrayBuffer::Cast(*obj)->ClearBitField(); break; + case JSType::JS_SHARED_ARRAY_BUFFER: + JSArrayBuffer::Cast(*obj)->SetArrayBufferData(thread_, JSTaggedValue::Undefined()); + JSArrayBuffer::Cast(*obj)->SetArrayBufferByteLength(0); + JSArrayBuffer::Cast(*obj)->SetShared(true); + break; case JSType::JS_PROMISE: JSPromise::Cast(*obj)->SetPromiseState(PromiseState::PENDING); JSPromise::Cast(*obj)->SetPromiseResult(thread_, JSTaggedValue::Undefined()); diff --git a/ecmascript/object_factory.h b/ecmascript/object_factory.h index 70eb700e46..247a7f3269 100644 --- a/ecmascript/object_factory.h +++ b/ecmascript/object_factory.h @@ -325,6 +325,12 @@ public: JSHandle NewJSDataView(JSHandle buffer, uint32_t offset, uint32_t length); + void NewJSSharedArrayBufferData(const JSHandle &array, int32_t length); + + JSHandle NewJSSharedArrayBuffer(int32_t length); + + JSHandle NewJSSharedArrayBuffer(void *buffer, int32_t length); + void NewJSRegExpByteCodeData(const JSHandle ®exp, void *buffer, size_t size); template diff --git a/ecmascript/runtime_call_id.h b/ecmascript/runtime_call_id.h index 31d60bf552..82e7d32fb2 100644 --- a/ecmascript/runtime_call_id.h +++ b/ecmascript/runtime_call_id.h @@ -270,6 +270,12 @@ namespace panda::ecmascript { V(ArrayBuffer, SetValueInBuffer) \ V(ArrayBuffer, CloneArrayBuffer) \ V(ArrayBuffer, AllocateArrayBuffer) \ + V(SharedArrayBuffer, Constructor) \ + V(SharedArrayBuffer, Slice) \ + V(SharedArrayBuffer, AllocateSharedArrayBuffer) \ + V(SharedArrayBuffer, IsSharedArrayBuffer) \ + V(SharedArrayBuffer, Species) \ + V(SharedArrayBuffer, GetByteLength) \ V(AsyncFunction, Constructor) \ V(Boolean, Constructor) \ V(Boolean, ThisBooleanValue) \ diff --git a/ecmascript/sharedMemoryManaged/sharedmemorymanager.cpp b/ecmascript/sharedMemoryManaged/sharedmemorymanager.cpp new file mode 100644 index 0000000000..1956bd082a --- /dev/null +++ b/ecmascript/sharedMemoryManaged/sharedmemorymanager.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 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/sharedMemoryManaged/sharedmemorymanager.h" + +namespace panda::ecmascript { +static constexpr size_t MALLOC_SIZE_LIMIT = 2147483648; // Max internal memory used by the VM declared in options + +JSSharedMemoryManager::~JSSharedMemoryManager() +{ + os::memory::LockHolder lock(jsSharedMemoryLock_); + auto iter = loadedJSSharedMemory_.begin(); + while (iter != loadedJSSharedMemory_.end()) { + const void *pointer = ToVoidPtr(iter->first); + FreeBuffer(const_cast(pointer)); + iter = loadedJSSharedMemory_.erase(iter); + } +} + +void JSSharedMemoryManager::CreateOrLoad(void **pointer, size_t size) +{ + if (*pointer != nullptr) { + if (loadedJSSharedMemory_.find((uint64_t)*pointer) != loadedJSSharedMemory_.end()) { + IncreaseRefSharedMemory(*pointer); + } + return; + } + *pointer = AllocateBuffer(size); + InsertSharedMemory(*pointer); +} + +void JSSharedMemoryManager::InsertSharedMemory(const void *pointer) +{ + os::memory::LockHolder lock(jsSharedMemoryLock_); + if (loadedJSSharedMemory_.find((uint64_t)pointer) == loadedJSSharedMemory_.end()) { + loadedJSSharedMemory_[(uint64_t)pointer] = 1; + } +} + +void JSSharedMemoryManager::IncreaseRefSharedMemory(const void *pointer) +{ + os::memory::LockHolder lock(jsSharedMemoryLock_); + if (loadedJSSharedMemory_.find((uint64_t)pointer) != loadedJSSharedMemory_.end()) { + loadedJSSharedMemory_[(uint64_t)pointer]++; + } +} + +void JSSharedMemoryManager::DecreaseRefSharedMemory(const void *pointer) +{ + os::memory::LockHolder lock(jsSharedMemoryLock_); + auto iter = loadedJSSharedMemory_.find((uint64_t)pointer); + if (iter != loadedJSSharedMemory_.end()) { + if (iter->second > 1) { + iter->second--; + return; + } + loadedJSSharedMemory_.erase(iter); + FreeBuffer(const_cast(pointer)); + } +} + +void *JSSharedMemoryManager::AllocateBuffer(size_t size) +{ + if (size == 0) { + LOG_ECMA_MEM(FATAL) << "size must have a size bigger than 0"; + UNREACHABLE(); + } + if (size >= MALLOC_SIZE_LIMIT) { + LOG_ECMA_MEM(FATAL) << "size must be less than the maximum"; + UNREACHABLE(); + } + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) + void *ptr = malloc(size); + if (ptr == nullptr) { + LOG_ECMA_MEM(FATAL) << "malloc failed"; + UNREACHABLE(); + } +#if ECMASCRIPT_ENABLE_ZAP_MEM + if (memset_s(ptr, size, INVALID_VALUE, size) != EOK) { + LOG_ECMA_MEM(FATAL) << "memset failed"; + UNREACHABLE(); + } +#endif + return ptr; +} + +void JSSharedMemoryManager::FreeBuffer(void *mem) +{ + if (mem == nullptr) { + return; + } + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) + free(mem); +} + +void JSSharedMemoryManager::RemoveSharedMemory(void *pointer, void *data) +{ + if (pointer == nullptr || data == nullptr) { + return; + } + // dec ref in menorymanager + JSSharedMemoryManager *jsSharedMemoryManager = static_cast(data); + jsSharedMemoryManager->DecreaseRefSharedMemory(pointer); +} +} // namespace panda::ecmascript diff --git a/ecmascript/sharedMemoryManaged/sharedmemorymanager.h b/ecmascript/sharedMemoryManaged/sharedmemorymanager.h new file mode 100644 index 0000000000..dda1b7706a --- /dev/null +++ b/ecmascript/sharedMemoryManaged/sharedmemorymanager.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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_SHARED_MEMORY_MANAGER_MANAGER_H +#define ECMASCRIPT_SHARED_MEMORY_MANAGER_MANAGER_H + +#include "ecmascript/tooling/js_pt_extractor.h" +#include "libpandabase/utils/logger.h" +#include "os/mutex.h" + +namespace panda { +class EcmaVm; +namespace ecmascript { +class JSSharedMemoryManager { +public: + PUBLIC_API ~JSSharedMemoryManager(); + + static JSSharedMemoryManager *GetInstance() + { + static JSSharedMemoryManager jsSharedMemoryManager; + return &jsSharedMemoryManager; + } + void CreateOrLoad(void **pointer, size_t size); + static void RemoveSharedMemory(void *pointer, void *data); +private: + JSSharedMemoryManager() = default; + + void InsertSharedMemory(const void *pointer); + void IncreaseRefSharedMemory(const void *pointer); + void DecreaseRefSharedMemory(const void *pointer); + void FreeBuffer(void *mem); + void *AllocateBuffer(size_t size); + os::memory::RecursiveMutex jsSharedMemoryLock_; + CMap loadedJSSharedMemory_; +}; +} // namespace ecmascript +} // namespace panda +#endif // ECMASCRIPT_SHARED_MEMORY_MANAGER_MANAGER_H diff --git a/ecmascript/tests/dump_test.cpp b/ecmascript/tests/dump_test.cpp index 458496fb17..dcdb3f0df3 100644 --- a/ecmascript/tests/dump_test.cpp +++ b/ecmascript/tests/dump_test.cpp @@ -460,6 +460,7 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump) NEW_OBJECT_AND_DUMP(JSDisplayNames, JS_DISPLAYNAMES) break; } + case JSType::JS_SHARED_ARRAY_BUFFER: case JSType::JS_ARRAY_BUFFER: { CHECK_DUMP_FIELDS(JSObject::SIZE, JSArrayBuffer::SIZE, 2) NEW_OBJECT_AND_DUMP(JSArrayBuffer, JS_ARRAY_BUFFER) diff --git a/ecmascript/tests/js_serializer_test.cpp b/ecmascript/tests/js_serializer_test.cpp index 5ef7fd0904..36409b6a8b 100644 --- a/ecmascript/tests/js_serializer_test.cpp +++ b/ecmascript/tests/js_serializer_test.cpp @@ -423,6 +423,38 @@ public: Destroy(); } + void JSSharedArrayBufferTest(std::pair data, + const JSHandle &originArrayBuffer, int32_t byteLength, const char *msg) + { + Init(); + JSDeserializer deserializer(thread, data.first, data.second); + JSHandle res = deserializer.DeserializeJSTaggedValue(); + EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSArrayBuffer fail"; + EXPECT_TRUE(res->IsSharedArrayBuffer()) << "[NotJSArrayBuffer] Deserialize JSArrayBuffer fail"; + JSHandle resJSArrayBuffer = JSHandle::Cast(res); + int32_t resByteLength = resJSArrayBuffer->GetArrayBufferByteLength(); + EXPECT_TRUE(resByteLength == byteLength) << "Not Same ByteLength"; + JSHandle bufferData(thread, originArrayBuffer->GetArrayBufferData()); + auto np = JSHandle::Cast(bufferData); + void *buffer = np->GetExternalPointer(); + ASSERT_NE(buffer, nullptr); + JSHandle resBufferData(thread, resJSArrayBuffer->GetArrayBufferData()); + JSHandle resNp = JSHandle::Cast(resBufferData); + void *resBuffer = resNp->GetExternalPointer(); + ASSERT_NE(resBuffer, nullptr); + EXPECT_TRUE((uint64_t)buffer == (uint64_t)resBuffer) << "Not Same pointer!"; + for (int32_t i = 0; i < resByteLength; i++) { + EXPECT_TRUE(static_cast(resBuffer)[i] == static_cast(buffer)[i]) << "Not Same Buffer"; + } + + if (msg != nullptr) { + if (memcpy_s(resBuffer, byteLength, msg, byteLength) != EOK) { + EXPECT_TRUE(false) << " memcpy error!"; + } + } + Destroy(); + } + void JSRegexpTest(std::pair data) { Init(); @@ -997,25 +1029,24 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBufferShared2) { std::string msg = "hello world"; int msgBufferLen = msg.length() + 1; - char* msgBuffer = new char[msgBufferLen] { 0 }; - if (memcpy_s(msgBuffer, msgBufferLen, msg.c_str(), msgBufferLen) != EOK) { - delete[] msgBuffer; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle jsArrayBuffer = factory->NewJSSharedArrayBuffer(msgBufferLen); + JSHandle BufferData(thread, jsArrayBuffer->GetArrayBufferData()); + JSHandle resNp = JSHandle::Cast(BufferData); + void *Buffer = resNp->GetExternalPointer(); + if (memcpy_s(Buffer, msgBufferLen, msg.c_str(), msgBufferLen) != EOK) { EXPECT_TRUE(false) << " memcpy error"; } - - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle jsArrayBuffer = factory->NewJSArrayBuffer(msgBuffer, msgBufferLen, nullptr, nullptr, true); - JSSerializer *serializer = new JSSerializer(thread); bool success = serializer->SerializeJSTaggedValue(JSHandle::Cast(jsArrayBuffer)); EXPECT_TRUE(success) << "Serialize JSArrayBuffer fail"; std::pair data = serializer->ReleaseBuffer(); JSDeserializerTest jsDeserializerTest; std::string changeStr = "world hello"; - std::thread t1(&JSDeserializerTest::JSArrayBufferTest, + std::thread t1(&JSDeserializerTest::JSSharedArrayBufferTest, jsDeserializerTest, data, jsArrayBuffer, 12, changeStr.c_str()); t1.join(); - EXPECT_TRUE(strcmp(msgBuffer, "world hello") == 0) << "Serialize JSArrayBuffer fail"; + EXPECT_TRUE(strcmp((char *)Buffer, "world hello") == 0) << "Serialize JSArrayBuffer fail"; delete serializer; };