diff --git a/static_core/plugins/ets/runtime/CMakeLists.txt b/static_core/plugins/ets/runtime/CMakeLists.txt index be56e23fe07544866f4a09584c0c70b1ec3ec670..cb085368de26ee1ccf0fb6cec9184d7855eb8e71 100644 --- a/static_core/plugins/ets/runtime/CMakeLists.txt +++ b/static_core/plugins/ets/runtime/CMakeLists.txt @@ -99,6 +99,7 @@ set(ETS_RUNTIME_SOURCES ${ETS_EXT_SOURCES}/unhandled_manager/unhandled_object_manager.cpp ${ETS_EXT_SOURCES}/mem/ets_gc_stat.cpp ${ETS_EXT_SOURCES}/mem/ets_reference_processor.cpp + ${ETS_EXT_SOURCES}/mem/native_allocator.cpp ${ETS_EXT_SOURCES}/ani/ani_helpers.cpp ${ETS_EXT_SOURCES}/ets_coroutine.cpp ${ETS_EXT_SOURCES}/ets_entrypoints.cpp @@ -177,10 +178,22 @@ if (PANDA_TARGET_OHOS) ${ETS_EXT_SOURCES}/platform/ohos/logger.cpp) endif() +if (PANDA_TARGET_WINDOWS) + list (APPEND ETS_RUNTIME_SOURCES + ${ETS_EXT_SOURCES}/platform/windows/os.cpp) +elseif (PANDA_TARGET_MACOS) + list (APPEND ETS_RUNTIME_SOURCES + ${ETS_EXT_SOURCES}/platform/mac/os.cpp) +else() # PANDA_TARGET_LINUX + list (APPEND ETS_RUNTIME_SOURCES + ${ETS_EXT_SOURCES}/platform/linux/os.cpp) +endif() + panda_target_sources(arkruntime_obj PRIVATE ${ETS_RUNTIME_SOURCES}) panda_target_include_directories(arkruntime_obj PUBLIC ${PANDA_BINARY_ROOT}/cross_values ${PANDA_ETS_PLUGIN_SOURCE}/runtime/ + ${PANDA_ETS_PLUGIN_SOURCE}/runtime/platform/ ${PANDA_BINARY_ROOT}/ # The line below needed only for stdlib. It must be removed after stdlib separation from runtime is implemented(#18135). ${PANDA_ETS_PLUGIN_SOURCE}/runtime/ani/ diff --git a/static_core/plugins/ets/runtime/ets_libbase_runtime.yaml b/static_core/plugins/ets/runtime/ets_libbase_runtime.yaml index 20640a94bee3518b9f4ed57bc5e7cb834b22a550..f1432ed52e365794f4c5353702f9ab77eefd49d7 100644 --- a/static_core/plugins/ets/runtime/ets_libbase_runtime.yaml +++ b/static_core/plugins/ets/runtime/ets_libbase_runtime.yaml @@ -3048,10 +3048,122 @@ intrinsics: args: [] impl: ark::ets::intrinsics::EtsEscompatBigUInt64ArrayReverse +############################################### +# escompat.TypedArrays.allocNativeArrayBuffer # +############################################### + - name: Int8ArrayAllocNativeArrayBuffer + space: ets + class_name: escompat.Int8Array + method_name: allocNativeArrayBuffer + static: true + signature: + ret: escompat.ArrayBuffer + args: [ i32 ] + impl: ark::ets::intrinsics::EtsEscompatTypedArrayAllocNativeArrayBuffer + + - name: Int16ArrayAllocNativeArrayBuffer + space: ets + class_name: escompat.Int16Array + method_name: allocNativeArrayBuffer + static: true + signature: + ret: escompat.ArrayBuffer + args: [ i32 ] + impl: ark::ets::intrinsics::EtsEscompatTypedArrayAllocNativeArrayBuffer + + - name: Int32ArrayAllocNativeArrayBuffer + space: ets + class_name: escompat.Int32Array + method_name: allocNativeArrayBuffer + static: true + signature: + ret: escompat.ArrayBuffer + args: [ i32 ] + impl: ark::ets::intrinsics::EtsEscompatTypedArrayAllocNativeArrayBuffer + + - name: BigInt64ArrayAllocNativeArrayBuffer + space: ets + class_name: escompat.BigInt64Array + method_name: allocNativeArrayBuffer + static: true + signature: + ret: escompat.ArrayBuffer + args: [ i32 ] + impl: ark::ets::intrinsics::EtsEscompatTypedArrayAllocNativeArrayBuffer + + - name: Float32ArrayAllocNativeArrayBuffer + space: ets + class_name: escompat.Float32Array + method_name: allocNativeArrayBuffer + static: true + signature: + ret: escompat.ArrayBuffer + args: [ i32 ] + impl: ark::ets::intrinsics::EtsEscompatTypedArrayAllocNativeArrayBuffer + + - name: Float64ArrayAllocNativeArrayBuffer + space: ets + class_name: escompat.Float64Array + method_name: allocNativeArrayBuffer + static: true + signature: + ret: escompat.ArrayBuffer + args: [ i32 ] + impl: ark::ets::intrinsics::EtsEscompatTypedArrayAllocNativeArrayBuffer + + - name: UInt8ArrayAllocNativeArrayBuffer + space: ets + class_name: escompat.Uint8Array + method_name: allocNativeArrayBuffer + static: true + signature: + ret: escompat.ArrayBuffer + args: [ i32 ] + impl: ark::ets::intrinsics::EtsEscompatTypedArrayAllocNativeArrayBuffer + + - name: UInt8ClampedArrayAllocNativeArrayBuffer + space: ets + class_name: escompat.Uint8ClampedArray + method_name: allocNativeArrayBuffer + static: true + signature: + ret: escompat.ArrayBuffer + args: [ i32 ] + impl: ark::ets::intrinsics::EtsEscompatTypedArrayAllocNativeArrayBuffer + + - name: UInt16ArrayAllocNativeArrayBuffer + space: ets + class_name: escompat.Uint16Array + method_name: allocNativeArrayBuffer + static: true + signature: + ret: escompat.ArrayBuffer + args: [ i32 ] + impl: ark::ets::intrinsics::EtsEscompatTypedArrayAllocNativeArrayBuffer + + - name: UInt32ArrayAllocNativeArrayBuffer + space: ets + class_name: escompat.Uint32Array + method_name: allocNativeArrayBuffer + static: true + signature: + ret: escompat.ArrayBuffer + args: [ i32 ] + impl: ark::ets::intrinsics::EtsEscompatTypedArrayAllocNativeArrayBuffer + + - name: BigUInt64ArrayAllocNativeArrayBuffer + space: ets + class_name: escompat.BigUint64Array + method_name: allocNativeArrayBuffer + static: true + signature: + ret: escompat.ArrayBuffer + args: [ i32 ] + impl: ark::ets::intrinsics::EtsEscompatTypedArrayAllocNativeArrayBuffer + ############################################ # escompat.TypedArrays.allocReversedBuffer # ############################################ - - name: Int8ArrayAllocReversedBuffer space: ets class_name: escompat.Int8Array diff --git a/static_core/plugins/ets/runtime/ets_vm.cpp b/static_core/plugins/ets/runtime/ets_vm.cpp index ab1dff4cbff7ba3a0a8bea2be9f7f9cbd0de8a52..d9b580b24f10c4c8162dc42ad8c2c5defea3007f 100644 --- a/static_core/plugins/ets/runtime/ets_vm.cpp +++ b/static_core/plugins/ets/runtime/ets_vm.cpp @@ -21,6 +21,7 @@ #include "include/mem/panda_string.h" #include "jit/profile_saver_worker.h" #include "libpandabase/macros.h" +#include "mem/native_allocator.h" #include "plugins/ets/runtime/ani/ani_vm_api.h" #include "plugins/ets/runtime/ani/verify/verify_ani_vm_api.h" #include "plugins/ets/runtime/ets_class_linker_extension.h" @@ -176,6 +177,7 @@ PandaEtsVM::PandaEtsVM(Runtime *runtime, const RuntimeOptions &options, mem::Mem auto heapManager = mm_->GetHeapManager(); auto allocator = heapManager->GetInternalAllocator(); + nativeAllocator_ = MakePandaUnique(); runtimeIface_ = allocator->New(); if (options.IsIncrementalProfilesaverEnabled()) { diff --git a/static_core/plugins/ets/runtime/ets_vm.h b/static_core/plugins/ets/runtime/ets_vm.h index ea07c83bac8375d328a26b2f941defaa2d51e7ff..f8e8bcc94543a26976b7876350ef1d6219f02dd0 100644 --- a/static_core/plugins/ets/runtime/ets_vm.h +++ b/static_core/plugins/ets/runtime/ets_vm.h @@ -30,6 +30,7 @@ #include "libpandabase/mem/mem.h" #include "libpandabase/utils/expected.h" #include "libpandabase/os/mutex.h" +#include "mem/native_allocator.h" #include "runtime/coroutines/stackful_coroutine.h" #include "runtime/include/compiler_interface.h" #include "runtime/include/external_callback_poster.h" @@ -414,6 +415,11 @@ public: return fullGCLongTimeListener_->GetFullGCLongTimeCount(); } + mem::NativeAllocator *GetNativeAllocator() const + { + return nativeAllocator_.get(); + } + PANDA_PUBLIC_API void AddRootProvider(mem::RootProvider *provider); PANDA_PUBLIC_API void RemoveRootProvider(mem::RootProvider *provider); @@ -485,6 +491,7 @@ private: RunEventLoopFunction runEventLoop_ = nullptr; WalkEventLoopFunction walkEventLoop_ = nullptr; PandaUniquePtr stdLibCache_ {nullptr}; + PandaUniquePtr nativeAllocator_ {nullptr}; size_t preForkWorkerCount_ = 0; diff --git a/static_core/plugins/ets/runtime/intrinsics/escompat_TypedArrays.cpp b/static_core/plugins/ets/runtime/intrinsics/escompat_TypedArrays.cpp index eff6a7cb6a95f400e5c3926c47e3aa9ddced2eb2..f8e9d695433457a1f0233595ce60164cceee11a9 100644 --- a/static_core/plugins/ets/runtime/intrinsics/escompat_TypedArrays.cpp +++ b/static_core/plugins/ets/runtime/intrinsics/escompat_TypedArrays.cpp @@ -20,11 +20,14 @@ #include "ets_handle.h" #include "libpandabase/utils/utf.h" #include "libpandabase/utils/utils.h" +#include "include/mem/allocator.h" + #include "plugins/ets/runtime/types/ets_typed_arrays.h" #include "plugins/ets/runtime/types/ets_typed_unsigned_arrays.h" #include "plugins/ets/runtime/intrinsics/helpers/ets_intrinsics_helpers.h" #include "intrinsics.h" #include "cross_values.h" +#include "types/ets_arraybuffer.h" #include "types/ets_object.h" #include "types/ets_primitives.h" @@ -50,10 +53,15 @@ static void *GetNativeData(T *array) ThrowEtsException(coro, panda_file_items::class_descriptors::TYPE_ERROR, "ArrayBuffer was detached"); return nullptr; } - return arrayBuffer->GetData(); } +template +static void *GetUnsafeNativeData(T *array) +{ + return reinterpret_cast(*array->GetBuffer()).GetData(); +} + template static void EtsEscompatTypedArraySet(T *thisArray, EtsInt pos, typename T::ElementType val) { @@ -74,10 +82,7 @@ static void EtsEscompatTypedArraySet(T *thisArray, EtsInt pos, typename T::Eleme ThrowEtsException(coro, panda_file_items::class_descriptors::RANGE_ERROR, "invalid index"); return; } - // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) - ObjectAccessor::SetPrimitive( - // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) - data, pos * sizeof(typename T::ElementType) + static_cast(thisArray->GetByteOffset()), val); + static_cast(data)[pos] = val; } template @@ -100,16 +105,7 @@ typename T::ElementType EtsEscompatTypedArrayGet(T *thisArray, EtsInt pos) ThrowEtsException(coro, panda_file_items::class_descriptors::RANGE_ERROR, "invalid index"); return 0; } - /** - * False-positive static-analyzer report: - * GC can happen only on ThrowException in GetNativeData. - * But such case meaning data to be nullptr and retun prevents - * us from proceeding - */ - // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) - return ObjectAccessor::GetPrimitive( - // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) - data, pos * sizeof(typename T::ElementType) + static_cast(thisArray->GetByteOffset())); + return static_cast(data)[pos]; } template @@ -1000,28 +996,20 @@ REVERSE_CALL_DECL(BigUInt64) #undef REVERSE_CALL_DECL -/// @brief Creates a new ByteArray (for ArrayBuffer) with specified size. Should be nonMovable. -static inline EtsByteArray *CreateByteArrayNonMov(EtsInt byteLen) +static inline EtsEscompatArrayBuffer *CreateArrayBufferExternalData(EtsCoroutine *coro, EtsInt byteLen, void *externalData) { - auto klass = EtsByteArray::GetComponentClass()->GetRuntimeClass(); - auto *array = - reinterpret_cast(Thread::GetCurrent()->GetVM()->GetHeapManager()->AllocateNonMovableObject( - klass, sizeof(EtsByteArray) + byteLen, DEFAULT_ALIGNMENT, ManagedThread::GetCurrent(), - mem::ObjectAllocatorBase::ObjMemInitPolicy::NO_INIT)); - array->UpdateLength(byteLen); - return array; + auto *cls = PlatformTypes(coro)->escompatArrayBuffer; + EtsEscompatArrayBuffer* buf = EtsEscompatArrayBuffer::FromEtsObject(EtsObject::Create(cls)); + buf->Initialize(byteLen, externalData); + return buf; } -/// @brief Creates a new ArrayBuffer with specified ByteArray and size. -static inline EtsEscompatArrayBuffer *CreateArrayBufferExternalData(EtsInt byteLen, EtsByteArray *externalData) +EtsEscompatArrayBuffer *EtsEscompatTypedArrayAllocNativeArrayBuffer(EtsInt byteLen) { - auto *klass = PlatformTypes(EtsCoroutine::GetCurrent())->escompatArrayBuffer->GetRuntimeClass(); - auto *buffer = - reinterpret_cast(Thread::GetCurrent()->GetVM()->GetHeapManager()->AllocateObject( - klass, sizeof(EtsEscompatArrayBuffer), DEFAULT_ALIGNMENT, ManagedThread::GetCurrent(), - mem::ObjectAllocatorBase::ObjMemInitPolicy::NO_INIT, false)); - buffer->Initialize(EtsCoroutine::GetCurrent(), byteLen, externalData); - return buffer; + auto coro = EtsCoroutine::GetCurrent(); + auto allocator = coro->GetPandaVM()->GetNativeAllocator(); + auto data = allocator->AllocateBuffer(byteLen); + return CreateArrayBufferExternalData(coro, byteLen, data); } /* @@ -1032,19 +1020,22 @@ static EtsEscompatArrayBuffer *EtsEscompatTypedArrayAllocReversedBuffer(T *thisA { using ElementType = typename T::ElementType; const EtsInt srcLength = thisArray->GetLengthInt(); - const ElementType *src = static_cast(GetNativeData(thisArray)); + const void *src = GetUnsafeNativeData(thisArray); const EtsInt lenBytes = srcLength * sizeof(ElementType); - EtsByteArray *data = CreateByteArrayNonMov(lenBytes); + auto coro = EtsCoroutine::GetCurrent(); + auto allocator = coro->GetPandaVM()->GetNativeAllocator(); + void *data = allocator->AllocateBuffer(lenBytes); if (UNLIKELY(src == nullptr || data == nullptr)) { return nullptr; } - auto *dest = data->GetData(); + ElementType *dest = static_cast(data); + const ElementType *typedSrc = static_cast(src); ASSERT(dest != nullptr); for (int i = 0; i < srcLength; i++) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic, clang-analyzer-core.NullDereference) - dest[i] = src[(srcLength - 1) - i]; + dest[i] = typedSrc[(srcLength - 1) - i]; } - return CreateArrayBufferExternalData(lenBytes, data); + return CreateArrayBufferExternalData(coro, lenBytes, data); } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) @@ -1086,21 +1077,17 @@ static EtsEscompatArrayBuffer *EtsEscompatTypedArrayAllocBufferWith(T *thisArray "offset is out of bounds"); return nullptr; } - const ElementType *src = static_cast(GetNativeData(thisArray)); const EtsInt lenBytes = srcLength * sizeof(ElementType); - EtsByteArray *data = CreateByteArrayNonMov(lenBytes); - if (UNLIKELY(src == nullptr || data == nullptr)) { - return nullptr; - } - auto *dest = data->GetData(); - ASSERT(dest != nullptr); - if (LIKELY(lenBytes > 0)) { - [[maybe_unused]] auto err = memcpy_s(dest, lenBytes, src, lenBytes); + auto coro = EtsCoroutine::GetCurrent(); + auto allocator = coro->GetPandaVM()->GetNativeAllocator(); + const void *src = GetUnsafeNativeData(thisArray); + void *data = allocator->AllocateBuffer(lenBytes); + if (LIKELY(lenBytes > 0 && src != nullptr && data != nullptr)) { + [[maybe_unused]] auto err = memcpy_s(data, lenBytes, src, lenBytes); ASSERT(err == EOK); + static_cast(data)[pos] = val; } - // NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic) - dest[pos] = val; - return CreateArrayBufferExternalData(lenBytes, data); + return CreateArrayBufferExternalData(coro, lenBytes, data); } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) @@ -1162,20 +1149,17 @@ static EtsEscompatArrayBuffer *EtsEscompatTypedArrayAllocSlicedBufferImpl(T *thi beg = NormalizeIndex(beg, srcLength); end = NormalizeIndex(end, srcLength); const EtsInt lengthInt = beg <= end ? end - beg : 0; - // NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic) - const ElementType *src = static_cast(GetNativeData(thisArray)) + beg; const EtsInt lenBytes = lengthInt * sizeof(ElementType); - EtsByteArray *data = CreateByteArrayNonMov(lenBytes); - if (UNLIKELY(src == nullptr || data == nullptr)) { - return nullptr; - } - auto *dest = data->GetData(); - ASSERT(dest != nullptr); - if (LIKELY(lenBytes > 0)) { - [[maybe_unused]] auto err = memcpy_s(dest, lenBytes, src, lenBytes); + auto coro = EtsCoroutine::GetCurrent(); + auto allocator = coro->GetPandaVM()->GetNativeAllocator(); + const void *src = GetUnsafeNativeData(thisArray); + void *data = allocator->AllocateBuffer(lenBytes); + if (LIKELY(lenBytes > 0 && data != nullptr && src != nullptr)) { + auto typedSrc = reinterpret_cast(src) + beg; + [[maybe_unused]] auto err = memcpy_s(data, lenBytes, typedSrc, lenBytes); ASSERT(err == EOK); } - return CreateArrayBufferExternalData(lenBytes, data); + return CreateArrayBufferExternalData(coro, lenBytes, data); } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) diff --git a/static_core/plugins/ets/runtime/mem/native_allocator.cpp b/static_core/plugins/ets/runtime/mem/native_allocator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..466488b592b6405ebd218c3dab1d617343e43f86 --- /dev/null +++ b/static_core/plugins/ets/runtime/mem/native_allocator.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 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 "native_allocator.h" +#include +#include + +#include "libpandabase/macros.h" +#include "mem/malloc_mem_pool-inl.h" +#include "platform/os.h" + +namespace ark::mem { +void *NativeAllocator::AllocateBuffer(size_t size) +{ + if (size == 0) { + return reinterpret_cast(static_cast(-1)); + } + + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) + void *ptr = malloc(size); + if (ptr == nullptr) { + LOG_MALLOC_MEM_POOL(FATAL) << "AllocateBuffer: malloc failed"; + UNREACHABLE(); + } + + size_t allocatedSize = ark::os::MallocUsableSize(ptr); + IncreaseNativeMemoryUsage(allocatedSize); + return ptr; +} + +void NativeAllocator::FreeBuffer(void *ptr) +{ + if (ptr == nullptr || ptr == reinterpret_cast(static_cast(-1))) { + return; + } + + size_t allocatedSize = ark::os::MallocUsableSize(ptr); + DecreaseNativeMemoryUsage(allocatedSize); + free(ptr); +} +} // namespace ark::mem \ No newline at end of file diff --git a/static_core/plugins/ets/runtime/mem/native_allocator.h b/static_core/plugins/ets/runtime/mem/native_allocator.h new file mode 100644 index 0000000000000000000000000000000000000000..4a82538cc27cd9cf3a28138984e2439d6418a523 --- /dev/null +++ b/static_core/plugins/ets/runtime/mem/native_allocator.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025 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 PANDA_PLUGINS_ETS_RUNTIME_MEM_NATIVE_ALLOCATOR_H +#define PANDA_PLUGINS_ETS_RUNTIME_MEM_NATIVE_ALLOCATOR_H + +#include +#include + +#include "macros.h" +#include "mem/malloc_mem_pool-inl.h" +#include "utils/logger.h" + +namespace ark::mem { +class NativeAllocator { +public: + NativeAllocator() = default; + virtual ~NativeAllocator() + { + if (nativeMemoryUsage_ > 0) { + LOG(ERROR, RUNTIME) << "Native memory leak: " << nativeMemoryUsage_ << " bytes"; + } + } + + void *AllocateBuffer(size_t size); + void FreeBuffer(void *mem); + + void IncreaseNativeMemoryUsage(size_t bytes) + { + size_t current = nativeMemoryUsage_.fetch_add(bytes, std::memory_order_relaxed) + bytes; + size_t max = maxNativeMemoryUsage_.load(std::memory_order_relaxed); + while (current > max && !maxNativeMemoryUsage_.compare_exchange_weak(max, current, std::memory_order_relaxed)) { + } + } + + void DecreaseNativeMemoryUsage(size_t bytes) + { + nativeMemoryUsage_.fetch_sub(bytes, std::memory_order_relaxed); + } + + size_t GetNativeMemoryUsage() const + { + return nativeMemoryUsage_.load(std::memory_order_relaxed); + } + + size_t GetMaxNativeMemoryUsage() const + { + return maxNativeMemoryUsage_.load(std::memory_order_relaxed); + } + +private: + NO_COPY_SEMANTIC(NativeAllocator); + NO_MOVE_SEMANTIC(NativeAllocator); + + std::atomic nativeMemoryUsage_ {0}; + std::atomic maxNativeMemoryUsage_ {0}; +}; + +} // namespace ark::mem + +#endif \ No newline at end of file diff --git a/static_core/plugins/ets/runtime/platform/linux/os.cpp b/static_core/plugins/ets/runtime/platform/linux/os.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c4634f03f6de5d3a1f826066bf21ecec263bee0 --- /dev/null +++ b/static_core/plugins/ets/runtime/platform/linux/os.cpp @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2025 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 "os.h" + +#include + +namespace ark::os { +size_t MallocUsableSize(void *ptr) +{ + return malloc_usable_size(ptr); +} +} // namespace ark::os \ No newline at end of file diff --git a/static_core/plugins/ets/runtime/platform/mac/os.cpp b/static_core/plugins/ets/runtime/platform/mac/os.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf507c2485ac9db71a007d74167081bdd3b7f364 --- /dev/null +++ b/static_core/plugins/ets/runtime/platform/mac/os.cpp @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2025 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 "os.h" + +#include + +namespace ark::os { +size_t MallocUsableSize(void *ptr) +{ + return malloc_size(ptr); +} +} // namespace ark::os diff --git a/static_core/plugins/ets/runtime/platform/os.h b/static_core/plugins/ets/runtime/platform/os.h new file mode 100644 index 0000000000000000000000000000000000000000..5c1f6e9915e6f9744c9cc29bdf2e74942538afe4 --- /dev/null +++ b/static_core/plugins/ets/runtime/platform/os.h @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2025 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 PANDA_ETS_RUNTIME_PLATFORMS_OS_H +#define PANDA_ETS_RUNTIME_PLATFORMS_OS_H + +#include + +namespace ark::os { +size_t MallocUsableSize(void *ptr); + +} // namespace ark::os +#endif // PANDA_ETS_RUNTIME_PLATFORMS_OS_H diff --git a/static_core/plugins/ets/runtime/platform/windows/os.cpp b/static_core/plugins/ets/runtime/platform/windows/os.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4fb5f891662b2d225848061a8042335da614eb1e --- /dev/null +++ b/static_core/plugins/ets/runtime/platform/windows/os.cpp @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2025 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 "os.h" + +#include + +namespace ark::os { +size_t MallocUsableSize(void *ptr) +{ + return _msize(ptr); +} +} // namespace ark::os diff --git a/static_core/plugins/ets/runtime/types/ets_arraybuffer-inl.h b/static_core/plugins/ets/runtime/types/ets_arraybuffer-inl.h index f53a49006cc47fab48e6bd0345b65b1b090af6e3..cb578c65fc37a08b8138c24c39db6f8cf2d07b6d 100644 --- a/static_core/plugins/ets/runtime/types/ets_arraybuffer-inl.h +++ b/static_core/plugins/ets/runtime/types/ets_arraybuffer-inl.h @@ -16,6 +16,9 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_TYPES_ETS_ARRAYBUFFER_INL_H #define PANDA_PLUGINS_ETS_RUNTIME_TYPES_ETS_ARRAYBUFFER_INL_H +#include +#include +#include "mem/mem.h" #include "runtime/include/thread_scopes.h" #include "plugins/ets/runtime/types/ets_arraybuffer.h" @@ -74,45 +77,56 @@ namespace ark::ets { template T EtsEscompatArrayBuffer::GetElement(uint32_t index, uint32_t byteOffset) { - auto *currentCoro = EtsCoroutine::GetCurrent(); - auto *obj = ObjectAccessor::GetObject(currentCoro, this, MEMBER_OFFSET(EtsEscompatArrayBuffer, managedData_)); - T val; // CC-OFF(G.EXP.09-CPP) variable is used in code gen macro - EXECUTE_METHOD_DEPENDS_ON_TYPE(val, GetVolatile, T, obj, index, byteOffset); - return val; -} + auto *obj = reinterpret_cast(static_cast(nativeData_) + + static_cast(byteOffset) + + static_cast(index * sizeof(T))); + auto* atomicPtr = reinterpret_cast *>(obj); + return atomicPtr->load(std::memory_order_relaxed); +} template void EtsEscompatArrayBuffer::SetElement(uint32_t index, uint32_t byteOffset, T element) { - auto *currentCoro = EtsCoroutine::GetCurrent(); - auto *obj = ObjectAccessor::GetObject(currentCoro, this, MEMBER_OFFSET(EtsEscompatArrayBuffer, managedData_)); - EXECUTE_VOID_METHOD_DEPENDS_ON_TYPE(SetVolatile, T, obj, index, byteOffset, element); + auto *obj = reinterpret_cast(static_cast(nativeData_) + + static_cast(byteOffset) + + static_cast(index * sizeof(T))); + auto* atomicPtr = reinterpret_cast *>(obj); + atomicPtr->store(element); } template T EtsEscompatArrayBuffer::GetVolatileElement(uint32_t index, uint32_t byteOffset) { - auto *currentCoro = EtsCoroutine::GetCurrent(); - auto *obj = ObjectAccessor::GetObject(currentCoro, this, MEMBER_OFFSET(EtsEscompatArrayBuffer, managedData_)); - T val; // CC-OFF(G.EXP.09-CPP) variable is used in code gen macro - EXECUTE_METHOD_DEPENDS_ON_TYPE(val, GetVolatile, T, obj, index, byteOffset); - return val; + auto *obj = reinterpret_cast(static_cast(nativeData_) + + static_cast(byteOffset) + + static_cast(index * sizeof(T))); + auto* atomicPtr = reinterpret_cast *>(obj); + return atomicPtr->load(); } template void EtsEscompatArrayBuffer::SetVolatileElement(uint32_t index, uint32_t byteOffset, T element) { - auto *currentCoro = EtsCoroutine::GetCurrent(); - auto *obj = ObjectAccessor::GetObject(currentCoro, this, MEMBER_OFFSET(EtsEscompatArrayBuffer, managedData_)); - EXECUTE_VOID_METHOD_DEPENDS_ON_TYPE(SetVolatile, T, obj, index, byteOffset, element); + auto *obj = reinterpret_cast(static_cast(nativeData_) + + static_cast(byteOffset) + + static_cast(index * sizeof(T))); + auto* atomicPtr = reinterpret_cast *>(obj); + atomicPtr->store(element); } template std::pair EtsEscompatArrayBuffer::CompareAndExchangeElement(uint32_t index, uint32_t byteOffset, T oldElement, T newElement, bool strong) { - auto *currentCoro = EtsCoroutine::GetCurrent(); - auto *obj = ObjectAccessor::GetObject(currentCoro, this, MEMBER_OFFSET(EtsEscompatArrayBuffer, managedData_)); + auto *obj = reinterpret_cast(static_cast(nativeData_) + + static_cast(byteOffset) + + static_cast(index * sizeof(T))); + auto* atomicPtr = reinterpret_cast *>(obj); + if (strong) { + return {atomicPtr->compare_exchange_strong(oldElement, newElement), oldElement}; + } else { + return {atomicPtr->compare_exchange_weak(oldElement, newElement), oldElement}; + } std::pair val; // CC-OFF(G.EXP.09-CPP) variable is used in code gen macro EXECUTE_METHOD_DEPENDS_ON_TYPE(val, CompareAndExchange, T, obj, index, byteOffset, oldElement, newElement, strong); return val; @@ -120,61 +134,94 @@ std::pair EtsEscompatArrayBuffer::CompareAndExchangeElement(uint32_t in template T EtsEscompatArrayBuffer::ExchangeElement(uint32_t index, uint32_t byteOffset, T element) { - auto *currentCoro = EtsCoroutine::GetCurrent(); - auto *obj = ObjectAccessor::GetObject(currentCoro, this, MEMBER_OFFSET(EtsEscompatArrayBuffer, managedData_)); - T val; // CC-OFF(G.EXP.09-CPP) variable is used in code gen macro - EXECUTE_METHOD_DEPENDS_ON_TYPE(val, Exchange, T, obj, index, byteOffset, element); - return val; + auto *obj = reinterpret_cast(static_cast(nativeData_) + + static_cast(byteOffset) + + static_cast(index * sizeof(T))); + auto* atomicPtr = reinterpret_cast *>(obj); + return atomicPtr->exchange(element); } template T EtsEscompatArrayBuffer::GetAndAdd(uint32_t index, uint32_t byteOffset, T element) { - auto *currentCoro = EtsCoroutine::GetCurrent(); - auto *obj = ObjectAccessor::GetObject(currentCoro, this, MEMBER_OFFSET(EtsEscompatArrayBuffer, managedData_)); - T val; // CC-OFF(G.EXP.09-CPP) variable is used in code gen macro - EXECUTE_METHOD_DEPENDS_ON_TYPE(val, GetAndAdd, T, obj, index, byteOffset, element); - return val; + auto *obj = reinterpret_cast(static_cast(nativeData_) + + static_cast(byteOffset) + + static_cast(index * sizeof(T))); + auto* atomicPtr = reinterpret_cast *>(obj); + if (std::is_floating_point_v) { + T oldValue = atomicPtr->load(); + T newValue; + do { + newValue = oldValue + element; + } while (!atomicPtr->compare_exchange_weak(oldValue, newValue)); + return oldValue; + } else { + return atomicPtr->fetch_add(element); + } } template T EtsEscompatArrayBuffer::GetAndSub(uint32_t index, uint32_t byteOffset, T element) { - auto *currentCoro = EtsCoroutine::GetCurrent(); - auto *obj = ObjectAccessor::GetObject(currentCoro, this, MEMBER_OFFSET(EtsEscompatArrayBuffer, managedData_)); - T val; // CC-OFF(G.EXP.09-CPP) variable is used in code gen macro - EXECUTE_METHOD_DEPENDS_ON_TYPE(val, GetAndSub, T, obj, index, byteOffset, element); - return val; + auto *obj = reinterpret_cast(static_cast(nativeData_) + + static_cast(byteOffset) + + static_cast(index * sizeof(T))); + auto* atomicPtr = reinterpret_cast *>(obj); + if (std::is_floating_point_v) { + T oldValue = atomicPtr->load(); + T newValue; + do { + newValue = oldValue - element; + } while (!atomicPtr->compare_exchange_weak(oldValue, newValue)); + return oldValue; + } else { + return atomicPtr->fetch_sub(element); + } } template T EtsEscompatArrayBuffer::GetAndBitwiseOr(uint32_t index, uint32_t byteOffset, T element) { - auto *currentCoro = EtsCoroutine::GetCurrent(); - auto *obj = ObjectAccessor::GetObject(currentCoro, this, MEMBER_OFFSET(EtsEscompatArrayBuffer, managedData_)); - T val; // CC-OFF(G.EXP.09-CPP) variable is used in code gen macro - EXECUTE_METHOD_DEPENDS_ON_TYPE(val, GetAndBitwiseOr, T, obj, index, byteOffset, element); - return val; + auto *obj = reinterpret_cast(static_cast(nativeData_) + + static_cast(byteOffset) + + static_cast(index * sizeof(T))); + auto* atomicPtr = reinterpret_cast *>(obj); + if constexpr (std::is_floating_point_v) { // NOLINT(readability-braces-around-statements) + LOG(FATAL, RUNTIME) << "Could not do bitwise or for float/double"; + UNREACHABLE(); + } else { + return atomicPtr->fetch_or(element); + } } template T EtsEscompatArrayBuffer::GetAndBitwiseAnd(uint32_t index, uint32_t byteOffset, T element) { - auto *currentCoro = EtsCoroutine::GetCurrent(); - auto *obj = ObjectAccessor::GetObject(currentCoro, this, MEMBER_OFFSET(EtsEscompatArrayBuffer, managedData_)); - T val; // CC-OFF(G.EXP.09-CPP) variable is used in code gen macro - EXECUTE_METHOD_DEPENDS_ON_TYPE(val, GetAndBitwiseAnd, T, obj, index, byteOffset, element); - return val; + auto *obj = reinterpret_cast(static_cast(nativeData_) + + static_cast(byteOffset) + + static_cast(index * sizeof(T))); + auto* atomicPtr = reinterpret_cast *>(obj); + if constexpr (std::is_floating_point_v) { // NOLINT(readability-braces-around-statements) + LOG(FATAL, RUNTIME) << "Could not do bitwise or for float/double"; + UNREACHABLE(); + } else { + return atomicPtr->fetch_and(element); + } } template T EtsEscompatArrayBuffer::GetAndBitwiseXor(uint32_t index, uint32_t byteOffset, T element) { - auto *currentCoro = EtsCoroutine::GetCurrent(); - auto *obj = ObjectAccessor::GetObject(currentCoro, this, MEMBER_OFFSET(EtsEscompatArrayBuffer, managedData_)); - T val; // CC-OFF(G.EXP.09-CPP) variable is used in code gen macro - EXECUTE_METHOD_DEPENDS_ON_TYPE(val, GetAndBitwiseXor, T, obj, index, byteOffset, element); - return val; + auto *obj = reinterpret_cast(static_cast(nativeData_) + + static_cast(byteOffset) + + static_cast(index * sizeof(T))); + auto* atomicPtr = reinterpret_cast *>(obj); + if constexpr (std::is_floating_point_v) { // NOLINT(readability-braces-around-statements) + LOG(FATAL, RUNTIME) << "Could not do bitwise or for float/double"; + UNREACHABLE(); + } else { + return atomicPtr->fetch_xor(element); + } } #undef EXECUTE_VOID_METHOD_DEPENDS_ON_TYPE diff --git a/static_core/plugins/ets/runtime/types/ets_arraybuffer.h b/static_core/plugins/ets/runtime/types/ets_arraybuffer.h index 694099feecb0d3f535bf68b4ce18cc17111d6022..ec3157bf204016a0442855986618b9c75b0138ec 100644 --- a/static_core/plugins/ets/runtime/types/ets_arraybuffer.h +++ b/static_core/plugins/ets/runtime/types/ets_arraybuffer.h @@ -18,6 +18,7 @@ #include "include/mem/allocator.h" #include "include/object_accessor.h" +#include "libpandabase/macros.h" #include "plugins/ets/runtime/types/ets_object.h" #include "plugins/ets/runtime/types/ets_array.h" #include "plugins/ets/runtime/types/ets_primitives.h" @@ -69,23 +70,47 @@ public: return reinterpret_cast(array->GetData()); } - /// Creates ArrayBuffer with managed buffer. + static void NativeBufferFinalizer(void *data, void *hint) + { + // The hint is the NativeAllocator instance + auto *nativeAllocator = static_cast(hint); + nativeAllocator->FreeBuffer(data); + } + + /// Creates ArrayBuffer with a buffer allocated by NativeAllocator. static EtsEscompatArrayBuffer *Create(EtsCoroutine *coro, size_t length, void **resultData) { ASSERT_MANAGED_CODE(); ASSERT(!coro->HasPendingException()); + auto *vm = coro->GetPandaVM(); + if (UNLIKELY(vm == nullptr)) { + *resultData = nullptr; + return nullptr; + } + auto *nativeAllocator = vm->GetNativeAllocator(); + if (UNLIKELY(nativeAllocator == nullptr)) { + *resultData = nullptr; + return nullptr; + } + + void *buffer = nativeAllocator->AllocateBuffer(length); + + // Create the ArrayBuffer object itself. [[maybe_unused]] EtsHandleScope scope(coro); auto *cls = PlatformTypes(coro)->escompatArrayBuffer; EtsHandle handle(coro, EtsEscompatArrayBuffer::FromEtsObject(EtsObject::Create(cls))); + if (UNLIKELY(handle.GetPtr() == nullptr)) { + nativeAllocator->FreeBuffer(buffer); + *resultData = nullptr; ASSERT(coro->HasPendingException()); return nullptr; } - auto *buf = AllocateNonMovableArray(length); - handle->InitializeByDefault(coro, buf); - *resultData = handle->GetData(); + handle->InitBufferByExternalData(coro, handle, buffer, NativeBufferFinalizer, nativeAllocator, length); + + *resultData = buffer; return handle.GetPtr(); } @@ -143,7 +168,8 @@ public: bool IsExternal() const { - return ObjectAccessor::GetObject(this, GetManagedDataOffset()) == nullptr; + return false; + // return ObjectAccessor::GetObject(this, GetManagedDataOffset()) == nullptr; } bool IsDetachable() const @@ -207,13 +233,10 @@ public: } /// Initializes ArrayBuffer with its own array. - void Initialize(EtsCoroutine *coro, size_t length, EtsByteArray *array) + void Initialize(size_t byteLength, void *externalNativeData) { - ASSERT(array != nullptr); - ObjectAccessor::SetObject(coro, this, GetManagedDataOffset(), array->GetCoreType()); - byteLength_ = length; - nativeData_ = - GetAddress(EtsByteArray::FromCoreType(ObjectAccessor::GetObject(coro, this, GetManagedDataOffset()))); + byteLength_ = byteLength; + nativeData_ = reinterpret_cast(externalNativeData); ASSERT(nativeData_ != 0); isResizable_ = ToEtsBoolean(false); } @@ -321,7 +344,7 @@ private: ASSERT(length <= static_cast(std::numeric_limits::max())); byteLength_ = static_cast(length); nativeData_ = reinterpret_cast(data); - ASSERT(nativeData_ != 0); + // ASSERT(nativeData_ != 0); isResizable_ = ToEtsBoolean(false); RegisterFinalizationInfo(coro, arrayBufferHandle, finalizerFunction, finalizerHint); diff --git a/static_core/plugins/ets/stdlib/escompat/TypedArrays.ets b/static_core/plugins/ets/stdlib/escompat/TypedArrays.ets index ad82424461e4effa832572647fd1f721e778fd95..3c8a9c6a11e4c88b0d6c87e4201497806bbaec95 100644 --- a/static_core/plugins/ets/stdlib/escompat/TypedArrays.ets +++ b/static_core/plugins/ets/stdlib/escompat/TypedArrays.ets @@ -104,7 +104,7 @@ export final class Int8Array implements Iterable, ArrayLike { const arr = Types.identity_cast(items as ArrayLike) this.byteLength = arr.length * Int8Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Int8Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { let temp: double = arr.$_get(i); @@ -224,7 +224,7 @@ export final class Int8Array implements Iterable, ArrayLike { let arr = Array.from((buf as ArrayLike)) this.byteLength = arr.length * Int8Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Int8Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toByte()) @@ -255,7 +255,7 @@ export final class Int8Array implements Iterable, ArrayLike { this.lengthInt = length.toInt() this.byteLength = this.lengthInt * Int8Array.BYTES_PER_ELEMENT this.byteOffset = 0 - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Int8Array.allocNativeArrayBuffer(this.byteLength) } /** @@ -719,7 +719,7 @@ export final class Int8Array implements Iterable, ArrayLike { if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = Int8Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -1326,7 +1326,7 @@ export final class Int8Array implements Iterable, ArrayLike { * @returns a new Int8Array where for each element from current Int8Array fn was applied */ public map(fn: (val: number, index: int, array: Int8Array) => number): Int8Array { - let resBuf = new ArrayBuffer(this.lengthInt * Int8Array.BYTES_PER_ELEMENT) + let resBuf = Int8Array.allocNativeArrayBuffer(this.lengthInt * Int8Array.BYTES_PER_ELEMENT) let res = new Int8Array(resBuf, 0, (resBuf.getByteLength() / Int8Array.BYTES_PER_ELEMENT).toInt()) for (let i = 0; i < this.lengthInt; ++i) { res.set(i, fn((this.getUnsafe(i)).toDouble(), i, this).toByte()) @@ -1369,7 +1369,7 @@ export final class Int8Array implements Iterable, ArrayLike { ++resLen } } - let resBuf = new ArrayBuffer(resLen * Int8Array.BYTES_PER_ELEMENT) + let resBuf = Int8Array.allocNativeArrayBuffer(resLen * Int8Array.BYTES_PER_ELEMENT) let res = new Int8Array(resBuf, 0) for (let i = 0, j = 0; i < this.lengthInt; ++i) { if (markers[i]) { @@ -1476,23 +1476,25 @@ export final class Int8Array implements Iterable, ArrayLike { return this } - private final sliceImpl(begin: int, end: int): Int8Array { + private sliceImpl(begin: int, end: int): Int8Array { return new Int8Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): Int8Array { + private toReversedImpl(): Int8Array { return new Int8Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: byte): Int8Array { + private withImpl(index: int, value: byte): Int8Array { return new Int8Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: byte): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: byte): ArrayBuffer - private final native getUnsafe(index: int): byte + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer + + private native getUnsafe(index: int): byte private setUnsafe(insertPos: int, val: byte): void { const BPE = Int8Array.BYTES_PER_ELEMENT.toInt() @@ -1601,7 +1603,7 @@ export final class Int16Array implements Iterable, ArrayLike { const arr = Types.identity_cast(items as ArrayLike) this.byteLength = arr.length * Int16Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Int16Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { let temp: double = arr.$_get(i); @@ -1725,7 +1727,7 @@ export final class Int16Array implements Iterable, ArrayLike { let arr = Array.from((buf as ArrayLike)) this.byteLength = arr.length * Int16Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Int16Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toShort()) @@ -1756,7 +1758,7 @@ export final class Int16Array implements Iterable, ArrayLike { this.lengthInt = length.toInt() this.byteLength = this.lengthInt * Int16Array.BYTES_PER_ELEMENT this.byteOffset = 0 - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Int16Array.allocNativeArrayBuffer(this.byteLength) } /** @@ -2220,7 +2222,7 @@ export final class Int16Array implements Iterable, ArrayLike { if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = Int16Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -2827,7 +2829,7 @@ export final class Int16Array implements Iterable, ArrayLike { * @returns a new Int16Array where for each element from current Int16Array fn was applied */ public map(fn: (val: number, index: int, array: Int16Array) => number): Int16Array { - let resBuf = new ArrayBuffer(this.lengthInt * Int16Array.BYTES_PER_ELEMENT) + let resBuf = Int16Array.allocNativeArrayBuffer(this.lengthInt * Int16Array.BYTES_PER_ELEMENT) let res = new Int16Array(resBuf, 0, (resBuf.getByteLength() / Int16Array.BYTES_PER_ELEMENT).toInt()) for (let i = 0; i < this.lengthInt; ++i) { res.set(i, fn((this.getUnsafe(i)).toDouble(), i, this).toShort()) @@ -2870,7 +2872,7 @@ export final class Int16Array implements Iterable, ArrayLike { ++resLen } } - let resBuf = new ArrayBuffer(resLen * Int16Array.BYTES_PER_ELEMENT) + let resBuf = Int16Array.allocNativeArrayBuffer(resLen * Int16Array.BYTES_PER_ELEMENT) let res = new Int16Array(resBuf, 0) for (let i = 0, j = 0; i < this.lengthInt; ++i) { if (markers[i]) { @@ -2977,23 +2979,25 @@ export final class Int16Array implements Iterable, ArrayLike { return this } - private final sliceImpl(begin: int, end: int): Int16Array { + private sliceImpl(begin: int, end: int): Int16Array { return new Int16Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): Int16Array { + private toReversedImpl(): Int16Array { return new Int16Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: short): Int16Array { + private withImpl(index: int, value: short): Int16Array { return new Int16Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: short): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: short): ArrayBuffer + + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer - private final native getUnsafe(index: int): short + private native getUnsafe(index: int): short private setUnsafe(insertPos: int, val: short): void { const BPE = Int16Array.BYTES_PER_ELEMENT.toInt() @@ -3115,7 +3119,7 @@ export final class Int32Array implements Iterable, ArrayLike { const arr = Types.identity_cast(items as ArrayLike) this.byteLength = arr.length * Int32Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Int32Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { let temp: double = arr.$_get(i); @@ -3239,7 +3243,7 @@ export final class Int32Array implements Iterable, ArrayLike { let arr = Array.from((buf as ArrayLike)) this.byteLength = arr.length * Int32Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Int32Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toInt()) @@ -3270,7 +3274,7 @@ export final class Int32Array implements Iterable, ArrayLike { this.lengthInt = length.toInt() this.byteLength = this.lengthInt * Int32Array.BYTES_PER_ELEMENT this.byteOffset = 0 - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Int32Array.allocNativeArrayBuffer(this.byteLength) } /** @@ -3698,7 +3702,7 @@ export final class Int32Array implements Iterable, ArrayLike { if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = Int32Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -4305,7 +4309,7 @@ export final class Int32Array implements Iterable, ArrayLike { * @returns a new Int32Array where for each element from current Int32Array fn was applied */ public map(fn: (val: number, index: int, array: Int32Array) => number): Int32Array { - let resBuf = new ArrayBuffer(this.lengthInt * Int32Array.BYTES_PER_ELEMENT) + let resBuf = Int32Array.allocNativeArrayBuffer(this.lengthInt * Int32Array.BYTES_PER_ELEMENT) let res = new Int32Array(resBuf, 0, (resBuf.getByteLength() / Int32Array.BYTES_PER_ELEMENT).toInt()) for (let i = 0; i < this.lengthInt; ++i) { res.set(i, fn((this.getUnsafe(i)).toDouble(), i, this).toInt()) @@ -4348,7 +4352,7 @@ export final class Int32Array implements Iterable, ArrayLike { ++resLen } } - let resBuf = new ArrayBuffer(resLen * Int32Array.BYTES_PER_ELEMENT) + let resBuf = Int32Array.allocNativeArrayBuffer(resLen * Int32Array.BYTES_PER_ELEMENT) let res = new Int32Array(resBuf, 0) for (let i = 0, j = 0; i < this.lengthInt; ++i) { if (markers[i]) { @@ -4455,23 +4459,25 @@ export final class Int32Array implements Iterable, ArrayLike { return this } - private final sliceImpl(begin: int, end: int): Int32Array { + private sliceImpl(begin: int, end: int): Int32Array { return new Int32Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): Int32Array { + private toReversedImpl(): Int32Array { return new Int32Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: int): Int32Array { + private withImpl(index: int, value: int): Int32Array { return new Int32Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: int): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: int): ArrayBuffer + + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer - private final native getUnsafe(index: int): int + private native getUnsafe(index: int): int private setUnsafe(insertPos: int, val: int): void { const BPE = Int32Array.BYTES_PER_ELEMENT.toInt() @@ -4593,7 +4599,7 @@ export final class BigInt64Array implements Iterable, ArrayLike const arr = Types.identity_cast(items as ArrayLike) this.byteLength = arr.length * BigInt64Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = BigInt64Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).getLong()) @@ -4711,7 +4717,7 @@ export final class BigInt64Array implements Iterable, ArrayLike let arr = Array.from((buf as ArrayLike)) this.byteLength = arr.length * BigInt64Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = BigInt64Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toLong()) @@ -4742,7 +4748,7 @@ export final class BigInt64Array implements Iterable, ArrayLike this.lengthInt = length.toInt() this.byteLength = this.lengthInt * BigInt64Array.BYTES_PER_ELEMENT this.byteOffset = 0 - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = BigInt64Array.allocNativeArrayBuffer(this.byteLength) } /** @@ -5196,7 +5202,7 @@ export final class BigInt64Array implements Iterable, ArrayLike if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = BigInt64Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -5803,7 +5809,7 @@ export final class BigInt64Array implements Iterable, ArrayLike * @returns a new BigInt64Array where for each element from current BigInt64Array fn was applied */ public map(fn: (val: BigInt, index: int, array: BigInt64Array) => BigInt): BigInt64Array { - let resBuf = new ArrayBuffer(this.lengthInt * BigInt64Array.BYTES_PER_ELEMENT) + let resBuf = BigInt64Array.allocNativeArrayBuffer(this.lengthInt * BigInt64Array.BYTES_PER_ELEMENT) let res = new BigInt64Array(resBuf, 0, (resBuf.getByteLength() / BigInt64Array.BYTES_PER_ELEMENT).toInt()) for (let i = 0; i < this.lengthInt; ++i) { res.set(i, fn(new BigInt(this.getUnsafe(i)), i, this).getLong()) @@ -5846,7 +5852,7 @@ export final class BigInt64Array implements Iterable, ArrayLike ++resLen } } - let resBuf = new ArrayBuffer(resLen * BigInt64Array.BYTES_PER_ELEMENT) + let resBuf = BigInt64Array.allocNativeArrayBuffer(resLen * BigInt64Array.BYTES_PER_ELEMENT) let res = new BigInt64Array(resBuf, 0) for (let i = 0, j = 0; i < this.lengthInt; ++i) { if (markers[i]) { @@ -5953,23 +5959,25 @@ export final class BigInt64Array implements Iterable, ArrayLike return this } - private final sliceImpl(begin: int, end: int): BigInt64Array { + private sliceImpl(begin: int, end: int): BigInt64Array { return new BigInt64Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): BigInt64Array { + private toReversedImpl(): BigInt64Array { return new BigInt64Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: long): BigInt64Array { + private withImpl(index: int, value: long): BigInt64Array { return new BigInt64Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: long): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: long): ArrayBuffer - private final native getUnsafe(index: int): long + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer + + private native getUnsafe(index: int): long private setUnsafe(insertPos: int, val: long): void { const BPE = BigInt64Array.BYTES_PER_ELEMENT.toInt() @@ -6091,7 +6099,7 @@ export final class Float32Array implements Iterable, ArrayLike { const arr = Types.identity_cast(items as ArrayLike) this.byteLength = arr.length * Float32Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Float32Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toFloat()); @@ -6209,7 +6217,7 @@ export final class Float32Array implements Iterable, ArrayLike { let arr = Array.from((buf as ArrayLike)) this.byteLength = arr.length * Float32Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Float32Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toFloat()) @@ -6240,7 +6248,7 @@ export final class Float32Array implements Iterable, ArrayLike { this.lengthInt = length.toInt() this.byteLength = this.lengthInt * Float32Array.BYTES_PER_ELEMENT this.byteOffset = 0 - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Float32Array.allocNativeArrayBuffer(this.byteLength) } /** @@ -6663,7 +6671,7 @@ export final class Float32Array implements Iterable, ArrayLike { if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = Float32Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -7287,7 +7295,7 @@ export final class Float32Array implements Iterable, ArrayLike { * @returns a new Float32Array where for each element from current Float32Array fn was applied */ public map(fn: (val: number, index: int, array: Float32Array) => number): Float32Array { - let resBuf = new ArrayBuffer(this.lengthInt * Float32Array.BYTES_PER_ELEMENT) + let resBuf = Float32Array.allocNativeArrayBuffer(this.lengthInt * Float32Array.BYTES_PER_ELEMENT) let res = new Float32Array(resBuf, 0, (resBuf.getByteLength() / Float32Array.BYTES_PER_ELEMENT).toInt()) for (let i = 0; i < this.lengthInt; ++i) { res.set(i, fn((this.getUnsafe(i)).toDouble(), i, this).toFloat()) @@ -7330,7 +7338,7 @@ export final class Float32Array implements Iterable, ArrayLike { ++resLen } } - let resBuf = new ArrayBuffer(resLen * Float32Array.BYTES_PER_ELEMENT) + let resBuf = Float32Array.allocNativeArrayBuffer(resLen * Float32Array.BYTES_PER_ELEMENT) let res = new Float32Array(resBuf, 0) for (let i = 0, j = 0; i < this.lengthInt; ++i) { if (markers[i]) { @@ -7437,23 +7445,25 @@ export final class Float32Array implements Iterable, ArrayLike { return this } - private final sliceImpl(begin: int, end: int): Float32Array { + private sliceImpl(begin: int, end: int): Float32Array { return new Float32Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): Float32Array { + private toReversedImpl(): Float32Array { return new Float32Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: float): Float32Array { + private withImpl(index: int, value: float): Float32Array { return new Float32Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: float): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: float): ArrayBuffer + + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer - private final native getUnsafe(index: int): float + private native getUnsafe(index: int): float private setUnsafe(insertPos: int, val: float): void { const BPE = Float32Array.BYTES_PER_ELEMENT.toInt() @@ -7575,7 +7585,7 @@ export final class Float64Array implements Iterable, ArrayLike { const arr = Types.identity_cast(items as ArrayLike) this.byteLength = arr.length * Float64Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Float64Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toDouble()); @@ -7693,7 +7703,7 @@ export final class Float64Array implements Iterable, ArrayLike { let arr = Array.from((buf as ArrayLike)) this.byteLength = arr.length * Float64Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Float64Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toDouble()) @@ -7724,7 +7734,7 @@ export final class Float64Array implements Iterable, ArrayLike { this.lengthInt = length.toInt() this.byteLength = this.lengthInt * Float64Array.BYTES_PER_ELEMENT this.byteOffset = 0 - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = Float64Array.allocNativeArrayBuffer(this.byteLength) } /** @@ -8070,7 +8080,7 @@ export final class Float64Array implements Iterable, ArrayLike { if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = Float64Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -8655,7 +8665,7 @@ export final class Float64Array implements Iterable, ArrayLike { * @returns a new Float64Array where for each element from current Float64Array fn was applied */ public map(fn: (val: number, index: int, array: Float64Array) => number): Float64Array { - let resBuf = new ArrayBuffer(this.lengthInt * Float64Array.BYTES_PER_ELEMENT) + let resBuf = Float64Array.allocNativeArrayBuffer(this.lengthInt * Float64Array.BYTES_PER_ELEMENT) let res = new Float64Array(resBuf, 0, (resBuf.getByteLength() / Float64Array.BYTES_PER_ELEMENT).toInt()) for (let i = 0; i < this.lengthInt; ++i) { res.set(i, fn((this.getUnsafe(i)).toDouble(), i, this).toDouble()) @@ -8698,7 +8708,7 @@ export final class Float64Array implements Iterable, ArrayLike { ++resLen } } - let resBuf = new ArrayBuffer(resLen * Float64Array.BYTES_PER_ELEMENT) + let resBuf = Float64Array.allocNativeArrayBuffer(resLen * Float64Array.BYTES_PER_ELEMENT) let res = new Float64Array(resBuf, 0) for (let i = 0, j = 0; i < this.lengthInt; ++i) { if (markers[i]) { @@ -8805,23 +8815,25 @@ export final class Float64Array implements Iterable, ArrayLike { return this } - private final sliceImpl(begin: int, end: int): Float64Array { + private sliceImpl(begin: int, end: int): Float64Array { return new Float64Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): Float64Array { + private toReversedImpl(): Float64Array { return new Float64Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: double): Float64Array { + private withImpl(index: int, value: double): Float64Array { return new Float64Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: double): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: double): ArrayBuffer + + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer - private final native getUnsafe(index: int): double + private native getUnsafe(index: int): double private setUnsafe(insertPos: int, val: double): void { const BPE = Float64Array.BYTES_PER_ELEMENT.toInt() diff --git a/static_core/plugins/ets/stdlib/escompat/TypedUArrays.ets b/static_core/plugins/ets/stdlib/escompat/TypedUArrays.ets index e797811ef82da30072b2341682c96074e5d45078..fc1fcf3a892a22c5886fb7d2a00b24f10c4402f6 100644 --- a/static_core/plugins/ets/stdlib/escompat/TypedUArrays.ets +++ b/static_core/plugins/ets/stdlib/escompat/TypedUArrays.ets @@ -113,7 +113,7 @@ export final class Uint8ClampedArray implements Iterable, ArrayLike(items as ArrayLike) this.byteLengthInt = arr.length * Uint8ClampedArray.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = Uint8ClampedArray.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafeClamp(i, Uint8ClampedArray.toUint8Clamped(arr.$_get(i))) @@ -225,7 +225,7 @@ export final class Uint8ClampedArray implements Iterable, ArrayLike((buf as ArrayLike)) this.byteLengthInt = arr.length * Uint8ClampedArray.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = Uint8ClampedArray.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, Uint8ClampedArray.clamp(arr.$_get(i).toInt())) @@ -256,7 +256,7 @@ export final class Uint8ClampedArray implements Iterable, ArrayLike, ArrayLike temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = Uint8ClampedArray.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -1311,7 +1311,7 @@ export final class Uint8ClampedArray implements Iterable, ArrayLike number): Uint8ClampedArray { - let resBuf = new ArrayBuffer(this.lengthInt * Uint8ClampedArray.BYTES_PER_ELEMENT) + let resBuf = Uint8ClampedArray.allocNativeArrayBuffer(this.lengthInt * Uint8ClampedArray.BYTES_PER_ELEMENT) let res = new Uint8ClampedArray(resBuf) for (let i = 0; i < this.lengthInt; i++) { const fnRes = fn(this.getUnsafe(i).toDouble(), i, this) @@ -1478,21 +1478,23 @@ export final class Uint8ClampedArray implements Iterable, ArrayLike 255) { @@ -1612,7 +1614,7 @@ export final class Uint8Array implements Iterable, ArrayLike { const arr = Types.identity_cast(items as ArrayLike) this.byteLengthInt = arr.length * Uint8Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = Uint8Array.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { let temp: double = arr.$_get(i); @@ -1730,7 +1732,7 @@ export final class Uint8Array implements Iterable, ArrayLike { let arr = Array.from((buf as ArrayLike)) this.byteLengthInt = arr.length * Uint8Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = Uint8Array.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toInt()) @@ -1761,7 +1763,7 @@ export final class Uint8Array implements Iterable, ArrayLike { this.lengthInt = length.toInt() this.byteLengthInt = this.lengthInt * Uint8Array.BYTES_PER_ELEMENT this.byteOffsetInt = 0 - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = Uint8Array.allocNativeArrayBuffer(this.byteLengthInt) } /** @@ -2217,7 +2219,7 @@ export final class Uint8Array implements Iterable, ArrayLike { if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = Uint8Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -2818,7 +2820,7 @@ export final class Uint8Array implements Iterable, ArrayLike { * @returns a new Uint8Array where for each element from current Uint8Array fn was applied */ public map(fn: (val: number, index: int, array: Uint8Array) => number): Uint8Array { - let resBuf = new ArrayBuffer(this.lengthInt * Uint8Array.BYTES_PER_ELEMENT) + let resBuf = Uint8Array.allocNativeArrayBuffer(this.lengthInt * Uint8Array.BYTES_PER_ELEMENT) let res = new Uint8Array(resBuf) for (let i = 0; i < this.lengthInt; i++) { const fnRes = fn(this.getUnsafe(i).toDouble(), i, this) @@ -2985,21 +2987,23 @@ export final class Uint8Array implements Iterable, ArrayLike { /** String \"Uint8Array\" */ public readonly name = "Uint8Array" - private final sliceImpl(begin: int, end: int): Uint8Array { + private sliceImpl(begin: int, end: int): Uint8Array { return new Uint8Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): Uint8Array { + private toReversedImpl(): Uint8Array { return new Uint8Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: int): Uint8Array { + private withImpl(index: int, value: int): Uint8Array { return new Uint8Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: int): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: int): ArrayBuffer + + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer private static clamp(val: int): int { return val @@ -3113,7 +3117,7 @@ export final class Uint16Array implements Iterable, ArrayLike { const arr = Types.identity_cast(items as ArrayLike) this.byteLengthInt = arr.length * Uint16Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = Uint16Array.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { let temp: double = arr.$_get(i); @@ -3235,7 +3239,7 @@ export final class Uint16Array implements Iterable, ArrayLike { let arr = Array.from((buf as ArrayLike)) this.byteLengthInt = arr.length * Uint16Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = Uint16Array.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toInt()) @@ -3266,7 +3270,7 @@ export final class Uint16Array implements Iterable, ArrayLike { this.lengthInt = length.toInt() this.byteLengthInt = this.lengthInt * Uint16Array.BYTES_PER_ELEMENT this.byteOffsetInt = 0 - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = Uint16Array.allocNativeArrayBuffer(this.byteLengthInt) } /** @@ -3708,7 +3712,7 @@ export final class Uint16Array implements Iterable, ArrayLike { if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = Uint16Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -4309,7 +4313,7 @@ export final class Uint16Array implements Iterable, ArrayLike { * @returns a new Uint16Array where for each element from current Uint16Array fn was applied */ public map(fn: (val: number, index: int, array: Uint16Array) => number): Uint16Array { - let resBuf = new ArrayBuffer(this.lengthInt * Uint16Array.BYTES_PER_ELEMENT) + let resBuf = Uint16Array.allocNativeArrayBuffer(this.lengthInt * Uint16Array.BYTES_PER_ELEMENT) let res = new Uint16Array(resBuf) for (let i = 0; i < this.lengthInt; i++) { const fnRes = fn(this.getUnsafe(i).toDouble(), i, this) @@ -4476,21 +4480,23 @@ export final class Uint16Array implements Iterable, ArrayLike { /** String \"Uint16Array\" */ public readonly name = "Uint16Array" - private final sliceImpl(begin: int, end: int): Uint16Array { + private sliceImpl(begin: int, end: int): Uint16Array { return new Uint16Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): Uint16Array { + private toReversedImpl(): Uint16Array { return new Uint16Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: int): Uint16Array { + private withImpl(index: int, value: int): Uint16Array { return new Uint16Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: int): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: int): ArrayBuffer + + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer private static clamp(val: int): int { return val @@ -4615,7 +4621,7 @@ export final class Uint32Array implements Iterable, ArrayLike { const arr = Types.identity_cast(items as ArrayLike) this.byteLengthInt = arr.length * Uint32Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = Uint32Array.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { let temp: double = arr.$_get(i); @@ -4737,7 +4743,7 @@ export final class Uint32Array implements Iterable, ArrayLike { let arr = Array.from((buf as ArrayLike)) this.byteLengthInt = arr.length * Uint32Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = Uint32Array.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toLong()) @@ -4768,7 +4774,7 @@ export final class Uint32Array implements Iterable, ArrayLike { this.lengthInt = length.toInt() this.byteLengthInt = this.lengthInt * Uint32Array.BYTES_PER_ELEMENT this.byteOffsetInt = 0 - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = Uint32Array.allocNativeArrayBuffer(this.byteLengthInt) } /** @@ -5233,7 +5239,7 @@ export final class Uint32Array implements Iterable, ArrayLike { if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = Uint32Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -5834,7 +5840,7 @@ export final class Uint32Array implements Iterable, ArrayLike { * @returns a new Uint32Array where for each element from current Uint32Array fn was applied */ public map(fn: (val: number, index: int, array: Uint32Array) => number): Uint32Array { - let resBuf = new ArrayBuffer(this.lengthInt * Uint32Array.BYTES_PER_ELEMENT) + let resBuf = Uint32Array.allocNativeArrayBuffer(this.lengthInt * Uint32Array.BYTES_PER_ELEMENT) let res = new Uint32Array(resBuf) for (let i = 0; i < this.lengthInt; i++) { const fnRes = fn(this.getUnsafe(i).toDouble(), i, this) @@ -6001,21 +6007,23 @@ export final class Uint32Array implements Iterable, ArrayLike { /** String \"Uint32Array\" */ public readonly name = "Uint32Array" - private final sliceImpl(begin: int, end: int): Uint32Array { + private sliceImpl(begin: int, end: int): Uint32Array { return new Uint32Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): Uint32Array { + private toReversedImpl(): Uint32Array { return new Uint32Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: long): Uint32Array { + private withImpl(index: int, value: long): Uint32Array { return new Uint32Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: long): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: long): ArrayBuffer + + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer private static clamp(val: long): long { return val @@ -6140,7 +6148,7 @@ export final class BigUint64Array implements Iterable, ArrayLike const arr = Types.identity_cast(items as ArrayLike) this.byteLengthInt = arr.length * BigUint64Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = BigUint64Array.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafeClamp(i, arr.$_get(i).getULong()) @@ -6256,7 +6264,7 @@ export final class BigUint64Array implements Iterable, ArrayLike let arr = Array.from((buf as ArrayLike)) this.byteLengthInt = arr.length * BigUint64Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = BigUint64Array.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).toLong()) @@ -6287,7 +6295,7 @@ export final class BigUint64Array implements Iterable, ArrayLike this.lengthInt = length.toInt() this.byteLengthInt = this.lengthInt * BigUint64Array.BYTES_PER_ELEMENT this.byteOffsetInt = 0 - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = BigUint64Array.allocNativeArrayBuffer(this.byteLengthInt) } /** @@ -6748,7 +6756,7 @@ export final class BigUint64Array implements Iterable, ArrayLike if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = BigUint64Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -7353,7 +7361,7 @@ export final class BigUint64Array implements Iterable, ArrayLike * @returns a new BigUint64Array where for each element from current BigUint64Array fn was applied */ public map(fn: (val: BigInt, index: int, array: BigUint64Array) => BigInt): BigUint64Array { - let resBuf = new ArrayBuffer(this.lengthInt * BigUint64Array.BYTES_PER_ELEMENT) + let resBuf = BigUint64Array.allocNativeArrayBuffer(this.lengthInt * BigUint64Array.BYTES_PER_ELEMENT) let res = new BigUint64Array(resBuf) for (let i = 0; i < this.lengthInt; i++) { const fnRes = fn(new BigInt(this.getUnsafe(i)), i, this) @@ -7520,21 +7528,23 @@ export final class BigUint64Array implements Iterable, ArrayLike /** String \"BigUint64Array\" */ public readonly name = "BigUint64Array" - private final sliceImpl(begin: int, end: int): BigUint64Array { + private sliceImpl(begin: int, end: int): BigUint64Array { return new BigUint64Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): BigUint64Array { + private toReversedImpl(): BigUint64Array { return new BigUint64Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: long): BigUint64Array { + private withImpl(index: int, value: long): BigUint64Array { return new BigUint64Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: long): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: long): ArrayBuffer + + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer private static clamp(val: long): long { return val diff --git a/static_core/plugins/ets/subproject_sources.gn b/static_core/plugins/ets/subproject_sources.gn index 3030854f153e27e6bd4baea2ba66cee0e46bfc90..e2464ee419d3aafc72464fa01794d7cf83417661 100644 --- a/static_core/plugins/ets/subproject_sources.gn +++ b/static_core/plugins/ets/subproject_sources.gn @@ -182,6 +182,7 @@ srcs_runtime = [ "runtime/intrinsics/helpers/json_helper.cpp", "runtime/mem/ets_gc_stat.cpp", "runtime/mem/ets_reference_processor.cpp", + "runtime/mem/native_allocator.cpp", "runtime/ani/ani_helpers.cpp", "runtime/types/ets_class.cpp", "runtime/types/ets_field.cpp", diff --git a/static_core/plugins/ets/templates/stdlib/typedArray.ets.j2 b/static_core/plugins/ets/templates/stdlib/typedArray.ets.j2 index 75d75a966cc1b026d46ce27717d141c3158920f9..c84bfc9a437e5ec86e4bdefe2c4d3fe64d8eca51 100644 --- a/static_core/plugins/ets/templates/stdlib/typedArray.ets.j2 +++ b/static_core/plugins/ets/templates/stdlib/typedArray.ets.j2 @@ -123,7 +123,7 @@ export final class {{N}}Array implements Iterable<{{subsetTypeValues}}>, ArrayLi const arr = Types.identity_cast<{{subsetTypeValues}}>(items as ArrayLike<{{subsetTypeValues}}>) this.byteLength = arr.length * {{N}}Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = {{N}}Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { {%- if N == 'BigInt64' %} @@ -256,7 +256,7 @@ export final class {{N}}Array implements Iterable<{{subsetTypeValues}}>, ArrayLi let arr = Array.from((buf as ArrayLike)) this.byteLength = arr.length * {{N}}Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = {{N}}Array.allocNativeArrayBuffer(this.byteLength) this.byteOffset = 0 for (let i: int = 0; i < this.lengthInt; ++i) { this.setUnsafe(i, arr.$_get(i).to{{T.capitalize()}}()) @@ -287,7 +287,7 @@ export final class {{N}}Array implements Iterable<{{subsetTypeValues}}>, ArrayLi this.lengthInt = length.toInt() this.byteLength = this.lengthInt * {{N}}Array.BYTES_PER_ELEMENT this.byteOffset = 0 - this.buffer = new ArrayBuffer(this.byteLength) + this.buffer = {{N}}Array.allocNativeArrayBuffer(this.byteLength) } /** @@ -898,7 +898,7 @@ export final class {{N}}Array implements Iterable<{{subsetTypeValues}}>, ArrayLi if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = {{N}}Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -1613,7 +1613,7 @@ export final class {{N}}Array implements Iterable<{{subsetTypeValues}}>, ArrayLi * @returns a new {{N}}Array where for each element from current {{N}}Array fn was applied */ public map(fn: (val: {{elType}}, index: {{idxType}}, array: {{N}}Array) => {{elType}}): {{N}}Array { - let resBuf = new ArrayBuffer(this.lengthInt * {{N}}Array.BYTES_PER_ELEMENT) + let resBuf = {{N}}Array.allocNativeArrayBuffer(this.lengthInt * {{N}}Array.BYTES_PER_ELEMENT) let res = new {{N}}Array(resBuf, 0, (resBuf.getByteLength() / {{N}}Array.BYTES_PER_ELEMENT).toInt()) for (let i = 0; i < this.lengthInt; ++i) { res.set(i, fn({{castToEl % 'this.getUnsafe(i)'}}, i{{castToIdx}}, this){{castFromEl}}) @@ -1656,7 +1656,7 @@ export final class {{N}}Array implements Iterable<{{subsetTypeValues}}>, ArrayLi ++resLen } } - let resBuf = new ArrayBuffer(resLen * {{N}}Array.BYTES_PER_ELEMENT) + let resBuf = {{N}}Array.allocNativeArrayBuffer(resLen * {{N}}Array.BYTES_PER_ELEMENT) let res = new {{N}}Array(resBuf, 0) for (let i = 0, j = 0; i < this.lengthInt; ++i) { if (markers[i]) { @@ -1765,23 +1765,25 @@ export final class {{N}}Array implements Iterable<{{subsetTypeValues}}>, ArrayLi return this } - private final sliceImpl(begin: int, end: int): {{N}}Array { + private sliceImpl(begin: int, end: int): {{N}}Array { return new {{N}}Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): {{N}}Array { + private toReversedImpl(): {{N}}Array { return new {{N}}Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: {{T}}): {{N}}Array { + private withImpl(index: int, value: {{T}}): {{N}}Array { return new {{N}}Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: {{T}}): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: {{T}}): ArrayBuffer - private final native getUnsafe(index: int): {{T}} + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer + + private native getUnsafe(index: int): {{T}} private setUnsafe(insertPos: int, val: {{T}}): void { const BPE = {{N}}Array.BYTES_PER_ELEMENT.toInt() diff --git a/static_core/plugins/ets/templates/stdlib/typedUArray.ets.j2 b/static_core/plugins/ets/templates/stdlib/typedUArray.ets.j2 index 4ba79a75d7f8ad2a20d18cd89d368aadaaea6159..ad6f55e0028be6b6356cdcbb7789e8da1859ecc4 100644 --- a/static_core/plugins/ets/templates/stdlib/typedUArray.ets.j2 +++ b/static_core/plugins/ets/templates/stdlib/typedUArray.ets.j2 @@ -133,7 +133,7 @@ export final class {{element['name']}}Array implements Iterable<{{element['subse const arr = Types.identity_cast<{{element['subsetTypeValues']}}>(items as ArrayLike<{{element['subsetTypeValues']}}>) this.byteLengthInt = arr.length * {{element['name']}}Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = {{element['name']}}Array.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { {%- if element.get('name') == 'BigUint64' %} @@ -266,7 +266,7 @@ export final class {{element['name']}}Array implements Iterable<{{element['subse let arr = Array.from((buf as ArrayLike)) this.byteLengthInt = arr.length * {{element['name']}}Array.BYTES_PER_ELEMENT this.lengthInt = arr.length - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = {{element['name']}}Array.allocNativeArrayBuffer(this.byteLengthInt) this.byteOffsetInt = 0 for (let i: int = 0; i < this.lengthInt; ++i) { {%- if element.get('clamped', False) %} @@ -301,7 +301,7 @@ export final class {{element['name']}}Array implements Iterable<{{element['subse this.lengthInt = length.toInt() this.byteLengthInt = this.lengthInt * {{element['name']}}Array.BYTES_PER_ELEMENT this.byteOffsetInt = 0 - this.buffer = new ArrayBuffer(this.byteLengthInt) + this.buffer = {{element['name']}}Array.allocNativeArrayBuffer(this.byteLengthInt) } /** @@ -891,7 +891,7 @@ export final class {{element['name']}}Array implements Iterable<{{element['subse if (index[0] + 1 > temp.lengthInt) { // NOTE (templin.konstantin): Progressive reallocation const curLength = (temp.buffer as Buffer).getByteLength() - const tb = new ArrayBuffer(curLength * 2) + const tb = {{element['name']}}Array.allocNativeArrayBuffer(curLength * 2) for (let i = 0; i < curLength; ++i) { tb.set(i, (temp.buffer as Buffer).at(i)) } @@ -1552,7 +1552,7 @@ export final class {{element['name']}}Array implements Iterable<{{element['subse * @returns a new {{element['name']}}Array where for each element from current {{element['name']}}Array fn was applied */ public map(fn: (val: {{elType}}, index: {{idxType}}, array: {{element['name']}}Array) => {{elType}}): {{element['name']}}Array { - let resBuf = new ArrayBuffer(this.lengthInt * {{element['name']}}Array.BYTES_PER_ELEMENT) + let resBuf = {{element['name']}}Array.allocNativeArrayBuffer(this.lengthInt * {{element['name']}}Array.BYTES_PER_ELEMENT) let res = new {{element['name']}}Array(resBuf) for (let i = 0; i < this.lengthInt; i++) { const fnRes = fn({{castToEl % 'this.getUnsafe(i)'}}, i{{castToIdx}}, this) @@ -1726,21 +1726,23 @@ export final class {{element['name']}}Array implements Iterable<{{element['subse /** String \"{{element['name']}}Array\" */ public readonly name = "{{element['name']}}Array" - private final sliceImpl(begin: int, end: int): {{element['name']}}Array { + private sliceImpl(begin: int, end: int): {{element['name']}}Array { return new {{element['name']}}Array(this.allocSlicedBuffer(begin, end)) } - private final toReversedImpl(): {{element['name']}}Array { + private toReversedImpl(): {{element['name']}}Array { return new {{element['name']}}Array(this.allocReversedBuffer()) } - private final withImpl(index: int, value: {{element['primitiveType']}}): {{element['name']}}Array { + private withImpl(index: int, value: {{element['primitiveType']}}): {{element['name']}}Array { return new {{element['name']}}Array(this.allocBufferWith(index, value)) } - private final native allocSlicedBuffer(beg: int, end: int): ArrayBuffer - private final native allocReversedBuffer(): ArrayBuffer - private final native allocBufferWith(index: int, value: {{element['primitiveType']}}): ArrayBuffer + private native allocSlicedBuffer(beg: int, end: int): ArrayBuffer + private native allocReversedBuffer(): ArrayBuffer + private native allocBufferWith(index: int, value: {{element['primitiveType']}}): ArrayBuffer + + private native static allocNativeArrayBuffer(byteLen: int): ArrayBuffer private static clamp(val: {{element['primitiveType']}}): {{element['primitiveType']}} { {%- if element.get('clamped', False) %} diff --git a/static_core/plugins/ets/tests/runtime/CMakeLists.txt b/static_core/plugins/ets/tests/runtime/CMakeLists.txt index a96e9527131d9165c628441f5d1e6b2dac37c70d..919e4f4483577493c8f6c38a4624ae39d8881b61 100644 --- a/static_core/plugins/ets/tests/runtime/CMakeLists.txt +++ b/static_core/plugins/ets/tests/runtime/CMakeLists.txt @@ -72,10 +72,21 @@ panda_ets_add_gtest( DEPS_TARGETS etsstdlib ) +panda_ets_add_gtest( + NO_CORES + NAME native_allocator_test + SOURCES mem/native_allocator_test.cpp + LIBRARIES arkbase arkfile arkruntime + INCLUDE_DIRS ${PANDA_ETS_PLUGIN_SOURCE}/runtime + SANITIZERS ${PANDA_SANITIZERS_LIST} +) + + add_dependencies(ets_tests_runtime_gtests ets_vm_test_gtests static_object_accessor_test_gtests - static_type_converter_test_gtests) + static_type_converter_test_gtests + native_allocator_test_gtests) add_subdirectory(types) add_subdirectory(tooling) diff --git a/static_core/plugins/ets/tests/runtime/mem/native_allocator_test.cpp b/static_core/plugins/ets/tests/runtime/mem/native_allocator_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5241889e40d50beced80b4fdd8cd1b010443e6e8 --- /dev/null +++ b/static_core/plugins/ets/tests/runtime/mem/native_allocator_test.cpp @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2025 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 +#include "libpandabase/utils/logger.h" +#include "plugins/ets/runtime/mem/native_allocator.h" +#include "plugins/ets/runtime/platform/os.h" + +namespace ark::mem::test { + +// Test fixture for NativeAllocator tests +class NativeAllocatorTest : public testing::Test { +protected: + NativeAllocator allocator_; +}; + +// Test case for basic allocation and successful deallocation +TEST_F(NativeAllocatorTest, AllocateAndFree) +{ + const size_t ALLOC_SIZE = 128; + void *mem = allocator_.AllocateBuffer(ALLOC_SIZE); + ASSERT_NE(mem, nullptr); + + // Check that the usable size is at least what we requested + size_t usableSize = ark::os::MallocUsableSize(mem); + EXPECT_GE(usableSize, ALLOC_SIZE); + EXPECT_EQ(allocator_.GetNativeMemoryUsage(), usableSize); + + allocator_.FreeBuffer(mem); + EXPECT_EQ(allocator_.GetNativeMemoryUsage(), 0); +} + +// Test case for memory usage tracking +TEST_F(NativeAllocatorTest, MemoryTracking) +{ + const size_t SIZE1 = 64; + const size_t SIZE2 = 256; + + // Initial state should be zero + EXPECT_EQ(allocator_.GetNativeMemoryUsage(), 0); + EXPECT_EQ(allocator_.GetMaxNativeMemoryUsage(), 0); + + // First allocation + void *mem1 = allocator_.AllocateBuffer(SIZE1); + size_t usableSize1 = ark::os::MallocUsableSize(mem1); + EXPECT_EQ(allocator_.GetNativeMemoryUsage(), usableSize1); + EXPECT_EQ(allocator_.GetMaxNativeMemoryUsage(), usableSize1); + + // Second allocation + void *mem2 = allocator_.AllocateBuffer(SIZE2); + size_t usableSize2 = ark::os::MallocUsableSize(mem2); + EXPECT_EQ(allocator_.GetNativeMemoryUsage(), usableSize1 + usableSize2); + EXPECT_EQ(allocator_.GetMaxNativeMemoryUsage(), usableSize1 + usableSize2); + + // Free first buffer + allocator_.FreeBuffer(mem1); + EXPECT_EQ(allocator_.GetNativeMemoryUsage(), usableSize2); + EXPECT_EQ(allocator_.GetMaxNativeMemoryUsage(), usableSize1 + usableSize2); + + // Free second buffer + allocator_.FreeBuffer(mem2); + EXPECT_EQ(allocator_.GetNativeMemoryUsage(), 0); + EXPECT_EQ(allocator_.GetMaxNativeMemoryUsage(), usableSize1 + usableSize2); +} + +// Test case for freeing a null pointer, which should be a safe no-op +TEST_F(NativeAllocatorTest, FreeNull) +{ + EXPECT_EQ(allocator_.GetNativeMemoryUsage(), 0); +} + +// Test case for allocating a buffer of size 0 +TEST_F(NativeAllocatorTest, AllocateZeroSize) +{ + // Allocating a zero-sized buffer should return a nullptr and not affect memory usage. + void *mem = allocator_.AllocateBuffer(0); + EXPECT_EQ(mem, nullptr); + EXPECT_EQ(allocator_.GetNativeMemoryUsage(), 0); +} + +} // namespace ark::mem::test \ No newline at end of file diff --git a/static_core/runtime/BUILD.gn b/static_core/runtime/BUILD.gn index 28912c1143a41af12033f3797f9a6c45dfd37b20..e7bc67cd102808ccdc3d6b03bf644bb434fea6fc 100644 --- a/static_core/runtime/BUILD.gn +++ b/static_core/runtime/BUILD.gn @@ -33,6 +33,7 @@ config("arkruntime_public_config") { # The line below needed only for stdlib. It must be removed after stdlib separation from runtime is implemented(#18135). "$ark_root/plugins/ets/runtime/ani/", + "$ark_root/plugins/ets/runtime/platform/", "$ark_root/runtime/tooling/inspector", get_label_info( "$ark_root/cross_values:cross_values_getters_generate(${default_toolchain})", @@ -320,6 +321,14 @@ template("libarkruntime_set_static_template") { "vtable_builder_base.cpp", ] + if (is_mingw || is_win) { + sources += [ "$ark_root/plugins/ets/runtime/platform/windows/os.cpp" ] + } else if (is_mac) { + sources += [ "$ark_root/plugins/ets/runtime/platform/mac/os.cpp" ] + } else { + sources += [ "$ark_root/plugins/ets/runtime/platform/linux/os.cpp" ] + } + if (!is_mingw) { sources += [ "dprofiler/dprofiler.cpp",