diff --git a/BUILD.gn b/BUILD.gn
index 0f8e7fe84d7bd8d9216411a4bd284f2846d65196..7f1300c2ec9f50bb5138312e3ce71796fd05749c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -51,7 +51,8 @@ group("ark_js_unittest") {
"//ark/js_runtime/ecmascript/regexp/tests:unittest",
"//ark/js_runtime/ecmascript/snapshot/tests:unittest",
"//ark/js_runtime/ecmascript/tests:unittest",
- "//ark/js_runtime/ecmascript/tooling/test:unittest",
+
+ # "//ark/js_runtime/ecmascript/tooling/test:unittest",
]
}
}
@@ -68,7 +69,8 @@ group("ark_js_host_unittest") {
"//ark/js_runtime/ecmascript/regexp/tests:host_unittest",
"//ark/js_runtime/ecmascript/snapshot/tests:host_unittest",
"//ark/js_runtime/ecmascript/tests:host_unittest",
- "//ark/js_runtime/ecmascript/tooling/test:host_unittest",
+
+ # "//ark/js_runtime/ecmascript/tooling/test:host_unittest",
]
if (current_cpu == "x86_64" || current_cpu == "x64") {
deps += [ "//ark/js_runtime/ecmascript/compiler:libark_jsoptimizer(${host_toolchain})" ]
@@ -325,6 +327,7 @@ ecma_source = [
"ecmascript/mem/c_string.cpp",
"ecmascript/mem/chunk.cpp",
"ecmascript/mem/compress_collector.cpp",
+ "ecmascript/mem/concurrent_sweeper.cpp",
"ecmascript/mem/ecma_heap_manager.cpp",
"ecmascript/mem/free_object_kind.cpp",
"ecmascript/mem/free_object_list.cpp",
@@ -342,6 +345,9 @@ ecma_source = [
"ecmascript/napi/jsnapi.cpp",
"ecmascript/object_factory.cpp",
"ecmascript/object_operator.cpp",
+ "ecmascript/platform/platform.cpp",
+ "ecmascript/platform/runner.cpp",
+ "ecmascript/platform/task_queue.cpp",
"ecmascript/layout_info.cpp",
"ecmascript/regexp/dyn_chunk.cpp",
"ecmascript/regexp/regexp_executor.cpp",
diff --git a/README.md b/README.md
index 99fc3c478191561e49881bf1067da31c7c9e361e..f9ba018a5a762f705effa0b9ac403c06702956fa 100644
--- a/README.md
+++ b/README.md
@@ -53,7 +53,7 @@ For more infomation, see: [ARK Runtime Subsystem](https://gitee.com/openharmony/
## Build
```
-./build.sh --product-name Hi3516DV300 --build-target ark\_js\_runtime
+./build.sh --product-name Hi3516DV300 --build-target ark_js_runtime
```
### Available APIs
@@ -66,9 +66,9 @@ For details about how to generate JS bytecodes, see [Using the Toolchain](docs/
To run bytecodes:
```
-cd out/release
-LD\_LIBRARY\_PATH=clang\_x64/ark/ark\_js\_runtime:clang\_x64/ark/ark:clang\_x64/global/i18n:../../prebuilts/clang/ohos/linux-x86\_64/llvm/lib/
-./clang\_x64/ark/ark\_js\_runtime/ark\_js\_vm helloworld.abc
+$ cd out/release
+$ export LD_LIBRARY_PATH=clang_x64/ark/ark_js_runtime:clang_x64/ark/ark:clang_x64/global/i18n:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib/
+$ ./clang_x64/ark/ark_js_runtime/ark_js_vm helloworld.abc
```
For more infomation, please see: [ARK-Runtime-Usage-Guide](https://gitee.com/openharmony/ark_js_runtime/blob/master/docs/ARK-Runtime-Usage-Guide.md).
diff --git a/README_zh.md b/README_zh.md
index d7adae57ad981a1cb639d9666c14f950b526a1bc..952dce67e1393ec9b688c15538cf37a0872e2618 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -53,7 +53,7 @@
## 编译构建
```
-./build.sh --product-name Hi3516DV300 --build-target ark\_js\_runtime
+$ ./build.sh --product-name Hi3516DV300 --build-target ark_js_runtime
```
### 接口说明
@@ -66,11 +66,9 @@ JS生成字节码参考[工具链使用](docs/using-the-toolchain-zh.md)
字节码执行:
```
-cd out/release
-
-LD\_LIBRARY\_PATH=clang\_x64/ark/ark\_js\_runtime:clang\_x64/ark/ark:clang\_x64/global/i18n:../../prebuilts/clang/ohos/linux-x86\_64/llvm/lib/
-
-./clang\_x64/ark/ark\_js\_runtime/ark\_js\_vm helloworld.abc
+$ cd out/release
+$ export LD_LIBRARY_PATH=clang_x64/ark/ark_js_runtime:clang_x64/ark/ark:clang_x64/global/i18n:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib/
+$ ./clang_x64/ark/ark_js_runtime/ark_js_vm helloworld.abc
```
更多使用说明请参考:[方舟运行时使用指南](https://gitee.com/openharmony/ark_js_runtime/blob/master/docs/ARK-Runtime-Usage-Guide-zh.md)
diff --git a/ecmascript/compiler/stub_interface.h b/ecmascript/compiler/stub_interface.h
index 758fb6f1faa9f6c1473d9965c35556e20fe86350..529c9db47a4b8b0b1f73511b8f0a02e9fb97bec7 100644
--- a/ecmascript/compiler/stub_interface.h
+++ b/ecmascript/compiler/stub_interface.h
@@ -121,13 +121,13 @@ public:
}
private:
- CallStubKind kind_{CODE_STUB};
- int flags_{0};
- int paramCounter_{0};
- ArgumentsOrder order_{DEFAULT_ORDER};
+ CallStubKind kind_ {CODE_STUB};
+ int flags_ {0};
+ int paramCounter_ {0};
+ ArgumentsOrder order_ {DEFAULT_ORDER};
- MachineType returnType_{MachineType::NONE_TYPE};
- std::unique_ptr> paramsType_{nullptr};
+ MachineType returnType_ {MachineType::NONE_TYPE};
+ std::unique_ptr> paramsType_ {nullptr};
};
class CallStubsImplement {
@@ -160,9 +160,9 @@ public:
}
private:
- std::array llvmCallStubs_{nullptr};
- std::array llvm_fuction_type_{nullptr};
- LLVMModuleRef stubsModule_{nullptr};
+ std::array llvmCallStubs_ {nullptr};
+ std::array llvm_fuction_type_ {nullptr};
+ LLVMModuleRef stubsModule_ {nullptr};
};
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define FAST_STUB_ID(name) NAME_##name
@@ -219,8 +219,8 @@ private:
~FastStubs() {}
NO_MOVE_SEMANTIC(FastStubs);
NO_COPY_SEMANTIC(FastStubs);
- std::unique_ptr stubsImpl_{nullptr};
- std::array callStubsDescriptor_{};
+ std::unique_ptr stubsImpl_ {nullptr};
+ std::array callStubsDescriptor_ {};
};
} // namespace kungfu
#endif // ECMASCRIPT_COMPILER_STUB_INTERFACE_H
\ No newline at end of file
diff --git a/ecmascript/compiler/stub_optimizer.h b/ecmascript/compiler/stub_optimizer.h
index cedc09c784a7c3843610fcee56d315260158b4a4..16846802c7b66606522e46706bbc0c36d9cacf1b 100644
--- a/ecmascript/compiler/stub_optimizer.h
+++ b/ecmascript/compiler/stub_optimizer.h
@@ -707,9 +707,8 @@ public:
Word64Equal(Word64And(x, GetWord64Constant(~panda::ecmascript::JSTaggedValue::TAG_SPECIAL_MASK)),
GetWord64Constant(0))),
WordLogicOr(SExtInt1ToInt32(Word64NotEqual(
- Word64And(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::TAG_SPECIAL_MASK)),
- GetWord64Constant(0))),
- SExtInt1ToInt32(TaggedIsHole(x)))));
+ Word64And(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::TAG_SPECIAL_MASK)),
+ GetWord64Constant(0))), SExtInt1ToInt32(TaggedIsHole(x)))));
}
AddrShift TaggedIsHeapObject(AddrShift x)
@@ -994,7 +993,7 @@ public:
Word64Or(Word64And(oldValue,
GetWord64Constant(~panda::ecmascript::JSHClass::ElementRepresentationBits::Mask())),
Word64LSR(value, GetWord64Constant(
- panda::ecmascript::JSHClass::ElementRepresentationBits::START_BIT))));
+ panda::ecmascript::JSHClass::ElementRepresentationBits::START_BIT))));
}
void UpdateValueAndDetails(AddrShift elements, AddrShift index, AddrShift value, AddrShift attr)
diff --git a/ecmascript/ecma_handle_scope.h b/ecmascript/ecma_handle_scope.h
index 13604c45550f81960b1767c9f9a1e16c5a3e6a59..b0b88d52e20d83385ab0165717f9c93791ed4a06 100644
--- a/ecmascript/ecma_handle_scope.h
+++ b/ecmascript/ecma_handle_scope.h
@@ -42,7 +42,7 @@ private:
JSThread *thread_;
JSTaggedType *prevNext_;
JSTaggedType *prevEnd_;
- int prevHandleStorageIndex_{-1};
+ int prevHandleStorageIndex_ {-1};
NO_COPY_SEMANTIC(EcmaHandleScope);
NO_MOVE_SEMANTIC(EcmaHandleScope);
diff --git a/ecmascript/ecma_isa.yaml b/ecmascript/ecma_isa.yaml
index 3a59436ab3b7b3ce20cf8fa6358a7efb6f6fb073..26a06b0b2fc03230b739a2ec86ffa15d701d3960 100644
--- a/ecmascript/ecma_isa.yaml
+++ b/ecmascript/ecma_isa.yaml
@@ -577,3 +577,12 @@ groups:
prefix: ecma
format: [pref_op_id_32]
properties: [string_id]
+ - sig: ecma.stownbyvaluewithnameset v1:in:top, v2:in:top
+ acc: in:top
+ prefix: ecma
+ format: [pref_op_v1_8_v2_8]
+ - sig: ecma.stownbynamewithnameset string_id, v:in:top
+ acc: in:top
+ prefix: ecma
+ format: [pref_op_id_32_v_8]
+ properties: [string_id]
diff --git a/ecmascript/ecma_string.h b/ecmascript/ecma_string.h
index 499295787b1dc9e21cf603ddf98a1ca1da7f96d4..2781094489365c86b2687175fe269371a00a8cc5 100644
--- a/ecmascript/ecma_string.h
+++ b/ecmascript/ecma_string.h
@@ -65,9 +65,7 @@ public:
return length * sizeof(dataUtf16_[0]);
}
- /**
- * Methods for uncompressed strings (UTF16):
- */
+ // Methods for uncompressed strings (UTF16):
static size_t ComputeSizeUtf16(uint32_t utf16Len)
{
return sizeof(EcmaString) + ComputeDataSizeUtf16(utf16Len);
@@ -79,17 +77,13 @@ public:
return dataUtf16_;
}
- /**
- * Methods for compresses strings (UTF8 or LATIN1):
- */
+ // Methods for compresses strings (UTF8 or LATIN1):
static size_t ComputeSizeUtf8(uint32_t utf8Len)
{
return sizeof(EcmaString) + utf8Len;
}
- /**
- * It's Utf8 format, but without 0 in the end.
- */
+ // It's Utf8 format, but without 0 in the end.
const uint8_t *GetDataUtf8() const
{
LOG_IF(IsUtf16(), FATAL, RUNTIME) << "EcmaString: Read data as utf8 for utf16 string";
diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp
index 31bb8274e624a0672003da22504623473a4e518e..33b1a4b0d6986adbeebed7d544a08873638a0744 100644
--- a/ecmascript/ecma_vm.cpp
+++ b/ecmascript/ecma_vm.cpp
@@ -35,6 +35,7 @@
#include "ecmascript/mem/heap.h"
#include "ecmascript/tagged_dictionary.h"
#include "ecmascript/object_factory.h"
+#include "ecmascript/platform/platform.h"
#include "ecmascript/regexp/regexp_parser_cache.h"
#include "ecmascript/runtime_call_id.h"
#include "ecmascript/runtime_trampolines.h"
@@ -116,6 +117,7 @@ EcmaVM::EcmaVM(RuntimeOptions options)
bool EcmaVM::Initialize()
{
trace::ScopedTrace scoped_trace("EcmaVM::Initialize");
+ Platform::GetCurrentPlatform()->Initialize();
RuntimeTrampolines::InitializeRuntimeTrampolines(thread_);
@@ -231,6 +233,7 @@ bool EcmaVM::InitializeFinish()
}
EcmaVM::~EcmaVM()
{
+ Platform::GetCurrentPlatform()->Destory();
vmInitialized_ = false;
ClearNativeMethodsData();
diff --git a/ecmascript/internal_call_params.h b/ecmascript/internal_call_params.h
index 2d979140379d99ad842f2f62e30d174fb754a342..b873d28ad3d22303d9030a79d35161aa21d6b3ef 100644
--- a/ecmascript/internal_call_params.h
+++ b/ecmascript/internal_call_params.h
@@ -213,11 +213,11 @@ private:
variable_data_.insert(variable_data_.begin(), val.GetRawData());
}
- std::array fixed_data_{};
- CVector variable_data_{};
- uint32_t fixed_length_{0};
- uint32_t variable_length_{0};
- bool variable_mode_{false};
+ std::array fixed_data_ {};
+ CVector variable_data_ {};
+ uint32_t fixed_length_ {0};
+ uint32_t variable_length_ {0};
+ bool variable_mode_ {false};
};
} // namespace panda::ecmascript
diff --git a/ecmascript/interpreter/interpreter-inl.h b/ecmascript/interpreter/interpreter-inl.h
index 99efe62c898a8b9f80112c357b8041fd98da66a2..f70d136fca7c8a04709d7f98edd2fdebac469d66 100644
--- a/ecmascript/interpreter/interpreter-inl.h
+++ b/ecmascript/interpreter/interpreter-inl.h
@@ -2303,9 +2303,6 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
value = GET_ACC();
if (!res.IsHole()) {
INTERPRETER_RETURN_IF_ABRUPT(res);
- if (value.IsJSFunction()) {
- JSFunction::SetFunctionNameNoPrefix(thread, JSFunction::Cast(value.GetTaggedObject()), propKey);
- }
RESTORE_ACC();
DISPATCH(BytecodeInstruction::Format::PREF_V8_V8);
}
@@ -2745,6 +2742,73 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
DISPATCH(BytecodeInstruction::Format::PREF_ID32);
}
+ HANDLE_OPCODE(HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8) {
+ uint32_t v0 = READ_INST_8_1();
+ uint32_t v1 = READ_INST_8_2();
+ LOG_INST() << "intrinsics::stownbyvaluewithnameset"
+ << " v" << v0 << " v" << v1;
+ JSTaggedValue receiver = GET_VREG_VALUE(v0);
+ if (receiver.IsHeapObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) {
+ SAVE_ACC();
+ JSTaggedValue propKey = GET_VREG_VALUE(v1);
+ JSTaggedValue value = GET_ACC();
+ // fast path
+ JSTaggedValue res = FastRuntimeStub::SetPropertyByValue(thread, receiver, propKey, value);
+
+ // SetPropertyByValue maybe gc need update the value
+ RESTORE_ACC();
+ propKey = GET_VREG_VALUE(v1);
+ value = GET_ACC();
+ if (!res.IsHole()) {
+ INTERPRETER_RETURN_IF_ABRUPT(res);
+ JSFunction::SetFunctionNameNoPrefix(thread, JSFunction::Cast(value.GetTaggedObject()), propKey);
+ RESTORE_ACC();
+ DISPATCH(BytecodeInstruction::Format::PREF_V8_V8);
+ }
+ }
+
+ // slow path
+ SAVE_ACC();
+ receiver = GET_VREG_VALUE(v0); // Maybe moved by GC
+ auto propKey = GET_VREG_VALUE(v1); // Maybe moved by GC
+ auto value = GET_ACC(); // Maybe moved by GC
+ JSTaggedValue res = SlowRuntimeStub::StOwnByValueWithNameSet(thread, receiver, propKey, value);
+ RESTORE_ACC();
+ INTERPRETER_RETURN_IF_ABRUPT(res);
+ DISPATCH(BytecodeInstruction::Format::PREF_V8_V8);
+ }
+ HANDLE_OPCODE(HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8) {
+ uint32_t stringId = READ_INST_32_1();
+ uint32_t v0 = READ_INST_8_5();
+ LOG_INST() << "intrinsics::stownbynamewithnameset "
+ << "v" << v0 << " stringId:" << stringId;
+
+ JSTaggedValue receiver = GET_VREG_VALUE(v0);
+ if (receiver.IsJSObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) {
+ JSTaggedValue propKey = constpool->GetObjectFromCache(stringId);
+ JSTaggedValue value = GET_ACC();
+ // fast path
+ SAVE_ACC();
+ JSTaggedValue res = FastRuntimeStub::SetPropertyByName(thread, receiver, propKey, value);
+ if (!res.IsHole()) {
+ INTERPRETER_RETURN_IF_ABRUPT(res);
+ JSFunction::SetFunctionNameNoPrefix(thread, JSFunction::Cast(value.GetTaggedObject()), propKey);
+ RESTORE_ACC();
+ DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8);
+ }
+ RESTORE_ACC();
+ }
+
+ SAVE_ACC();
+ receiver = GET_VREG_VALUE(v0); // Maybe moved by GC
+ auto propKey = constpool->GetObjectFromCache(stringId); // Maybe moved by GC
+ auto value = GET_ACC(); // Maybe moved by GC
+ JSTaggedValue res = SlowRuntimeStub::StOwnByNameWithNameSet(thread, receiver, propKey, value);
+ RESTORE_ACC();
+ INTERPRETER_RETURN_IF_ABRUPT(res);
+ DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8);
+ }
+
HANDLE_OPCODE(HANDLE_LDGLOBALVAR_PREF_ID32) {
uint32_t stringId = READ_INST_32_1();
JSTaggedValue propKey = constpool->GetObjectFromCache(stringId);
diff --git a/ecmascript/interpreter/interpreter.h b/ecmascript/interpreter/interpreter.h
index 62964b5a7da72604bcc56228f5b9b2e7ada53de2..cb988f370138aae771da0c4d057671abfa2a8989 100644
--- a/ecmascript/interpreter/interpreter.h
+++ b/ecmascript/interpreter/interpreter.h
@@ -214,6 +214,8 @@ enum EcmaOpcode {
STCONSTTOGLOBALRECORD_PREF_ID32,
STLETTOGLOBALRECORD_PREF_ID32,
STCLASSTOGLOBALRECORD_PREF_ID32,
+ STOWNBYVALUEWITHNAMESET_PREF_V8_V8,
+ STOWNBYNAMEWITHNAMESET_PREF_ID32_V8,
MOV_DYN_V8_V8,
MOV_DYN_V16_V16,
LDA_STR_ID32,
diff --git a/ecmascript/interpreter/slow_runtime_stub.cpp b/ecmascript/interpreter/slow_runtime_stub.cpp
index 5874bcd6cb94543c838b29b4afb366a02a4967a6..2c08c94165340c862ecee1a520f9a4b10a8dc32f 100644
--- a/ecmascript/interpreter/slow_runtime_stub.cpp
+++ b/ecmascript/interpreter/slow_runtime_stub.cpp
@@ -740,6 +740,32 @@ JSTaggedValue SlowRuntimeStub::StOwnByName(JSThread *thread, JSTaggedValue obj,
return JSTaggedValue::True();
}
+JSTaggedValue SlowRuntimeStub::StOwnByNameWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop,
+ JSTaggedValue value)
+{
+ INTERPRETER_TRACE(thread, StOwnByNameDyn);
+ [[maybe_unused]] EcmaHandleScope handleScope(thread);
+
+ JSHandle objHandle(thread, obj);
+ JSHandle propHandle(thread, prop);
+ JSHandle valueHandle(thread, value);
+ ASSERT(propHandle->IsStringOrSymbol());
+
+ JSHandle propKey = JSTaggedValue::ToPropertyKey(thread, propHandle);
+
+ // property in class is non-enumerable
+ bool enumerable = !(objHandle->IsClassPrototype() || objHandle->IsClassConstructor());
+
+ PropertyDescriptor desc(thread, valueHandle, true, enumerable, true);
+ bool ret = JSTaggedValue::DefineOwnProperty(thread, objHandle, propHandle, desc);
+ if (!ret) {
+ return ThrowTypeError(thread, "SetOwnByNameWithNameSet failed");
+ }
+ JSFunctionBase::SetFunctionName(thread, JSHandle::Cast(valueHandle), propKey,
+ JSHandle(thread, JSTaggedValue::Undefined()));
+ return JSTaggedValue::True();
+}
+
JSTaggedValue SlowRuntimeStub::StOwnByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, JSTaggedValue value)
{
INTERPRETER_TRACE(thread, StOwnByIdDyn);
@@ -763,6 +789,7 @@ JSTaggedValue SlowRuntimeStub::StOwnByIndex(JSThread *thread, JSTaggedValue obj,
JSTaggedValue SlowRuntimeStub::StOwnByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue value)
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
+
INTERPRETER_TRACE(thread, StOwnByValueDyn);
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
JSHandle objHandle(thread, obj);
@@ -783,6 +810,33 @@ JSTaggedValue SlowRuntimeStub::StOwnByValue(JSThread *thread, JSTaggedValue obj,
if (!ret) {
return ThrowTypeError(thread, "StOwnByValue failed");
}
+ return JSTaggedValue::True();
+}
+
+JSTaggedValue SlowRuntimeStub::StOwnByValueWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue key,
+ JSTaggedValue value)
+{
+ [[maybe_unused]] EcmaHandleScope handleScope(thread);
+ INTERPRETER_TRACE(thread, StOwnByValueDyn);
+ const GlobalEnvConstants *globalConst = thread->GlobalConstants();
+ JSHandle objHandle(thread, obj);
+ JSHandle keyHandle(thread, key);
+ JSHandle valueHandle(thread, value);
+
+ if (objHandle->IsClassConstructor() &&
+ JSTaggedValue::SameValue(keyHandle, globalConst->GetHandledPrototypeString())) {
+ return ThrowTypeError(thread, "In a class, static property named 'prototype' throw a TypeError");
+ }
+
+ // property in class is non-enumerable
+ bool enumerable = !(objHandle->IsClassPrototype() || objHandle->IsClassConstructor());
+
+ PropertyDescriptor desc(thread, valueHandle, true, enumerable, true);
+ JSMutableHandle propKey(JSTaggedValue::ToPropertyKey(thread, keyHandle));
+ bool ret = JSTaggedValue::DefineOwnProperty(thread, objHandle, propKey, desc);
+ if (!ret) {
+ return ThrowTypeError(thread, "StOwnByValueWithNameSet failed");
+ }
if (valueHandle->IsJSFunction()) {
if (propKey->IsNumber()) {
propKey.Update(base::NumberHelper::NumberToString(thread, propKey.GetTaggedValue()).GetTaggedValue());
diff --git a/ecmascript/interpreter/slow_runtime_stub.h b/ecmascript/interpreter/slow_runtime_stub.h
index 5523c60564e922c08ed50a2d90c3bb170215671e..afa120f0ce5363cf0377931671767a785f508afd 100644
--- a/ecmascript/interpreter/slow_runtime_stub.h
+++ b/ecmascript/interpreter/slow_runtime_stub.h
@@ -79,8 +79,12 @@ public:
static void ThrowDeleteSuperProperty(JSThread *thread);
static JSTaggedValue StOwnByName(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, JSTaggedValue value);
+ static JSTaggedValue StOwnByNameWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop,
+ JSTaggedValue value);
static JSTaggedValue StOwnByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, JSTaggedValue value);
static JSTaggedValue StOwnByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue value);
+ static JSTaggedValue StOwnByValueWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue key,
+ JSTaggedValue value);
static JSTaggedValue CreateEmptyArray(JSThread *thread, ObjectFactory *factory, JSHandle globalEnv);
static JSTaggedValue CreateEmptyObject(JSThread *thread, ObjectFactory *factory, JSHandle globalEnv);
static JSTaggedValue CreateObjectWithBuffer(JSThread *thread, ObjectFactory *factory, JSObject *literal);
diff --git a/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl b/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl
index bb5386e842a7b1828d9389d546d363f3dfcfdbdd..5aaacdc93266af639b912df0b1ad5162fc3a554f 100644
--- a/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl
+++ b/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl
@@ -144,6 +144,8 @@
&&DEBUG_HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32,
&&DEBUG_HANDLE_STLETTOGLOBALRECORD_PREF_ID32,
&&DEBUG_HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32,
+ &&DEBUG_HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8,
+ &&DEBUG_HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8,
&&DEBUG_HANDLE_MOV_DYN_V8_V8,
&&DEBUG_HANDLE_MOV_DYN_V16_V16,
&&DEBUG_HANDLE_LDA_STR_ID32,
@@ -266,6 +268,4 @@
&&DEBUG_HANDLE_OVERFLOW,
&&DEBUG_HANDLE_OVERFLOW,
&&DEBUG_HANDLE_OVERFLOW,
- &&DEBUG_HANDLE_OVERFLOW,
- &&DEBUG_HANDLE_OVERFLOW,
- &&DEBUG_HANDLE_OVERFLOW,
+ &&DEBUG_HANDLE_OVERFLOW,
\ No newline at end of file
diff --git a/ecmascript/interpreter/templates/debugger_instruction_handler.inl b/ecmascript/interpreter/templates/debugger_instruction_handler.inl
index 60d3cac4a82b366bd14e74e1ef0b85a7bf6e0a19..e578e5cfebc0112b1cc23d32b2a883ac7b3c05a8 100644
--- a/ecmascript/interpreter/templates/debugger_instruction_handler.inl
+++ b/ecmascript/interpreter/templates/debugger_instruction_handler.inl
@@ -668,6 +668,16 @@
NOTIFY_DEBUGGER_EVENT();
REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STCLASSTOGLOBALRECORD_PREF_ID32);
}
+ HANDLE_OPCODE(DEBUG_HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8)
+ {
+ NOTIFY_DEBUGGER_EVENT();
+ REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STOWNBYVALUEWITHNAMESET_PREF_V8_V8);
+ }
+ HANDLE_OPCODE(DEBUG_HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8)
+ {
+ NOTIFY_DEBUGGER_EVENT();
+ REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STOWNBYNAMEWITHNAMESET_PREF_ID32_V8);
+ }
HANDLE_OPCODE(DEBUG_HANDLE_MOV_DYN_V8_V8)
{
NOTIFY_DEBUGGER_EVENT();
diff --git a/ecmascript/interpreter/templates/instruction_dispatch.inl b/ecmascript/interpreter/templates/instruction_dispatch.inl
index a9599b0c7a085d7ba8a7a26e8808d2bf800d9b1a..2462b523597738826ddbf06720d5c4543b814e4c 100644
--- a/ecmascript/interpreter/templates/instruction_dispatch.inl
+++ b/ecmascript/interpreter/templates/instruction_dispatch.inl
@@ -144,6 +144,8 @@
&&HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32,
&&HANDLE_STLETTOGLOBALRECORD_PREF_ID32,
&&HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32,
+ &&HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8,
+ &&HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8,
&&HANDLE_MOV_DYN_V8_V8,
&&HANDLE_MOV_DYN_V16_V16,
&&HANDLE_LDA_STR_ID32,
@@ -267,5 +269,4 @@
&&HANDLE_OVERFLOW,
&&HANDLE_OVERFLOW,
&&HANDLE_OVERFLOW,
- &&HANDLE_OVERFLOW,
- &&HANDLE_OVERFLOW,
+
diff --git a/ecmascript/js_date_time_format.h b/ecmascript/js_date_time_format.h
index eaedd7f34c8734bfaedf19a239695627f4e725b1..e1121b37d7013a63bcc931c535a66ee6d37c2631 100644
--- a/ecmascript/js_date_time_format.h
+++ b/ecmascript/js_date_time_format.h
@@ -79,7 +79,7 @@ public:
}
private:
- std::vector data{};
+ std::vector data {};
NO_COPY_SEMANTIC(Pattern);
NO_MOVE_SEMANTIC(Pattern);
};
diff --git a/ecmascript/js_locale.h b/ecmascript/js_locale.h
index e553afef86fe6b1543abc97ad6e6c941bbde3a0e..ccb87729a942e9f702b599fdef85661483b66d08 100644
--- a/ecmascript/js_locale.h
+++ b/ecmascript/js_locale.h
@@ -111,10 +111,10 @@ public:
}
private:
- std::vector data_{};
- array_size_t length_{0};
- array_size_t curIdx_{0};
- icu::Locale locale_{};
+ std::vector data_ {};
+ array_size_t length_ {0};
+ array_size_t curIdx_ {0};
+ icu::Locale locale_ {};
};
struct ResolvedLocale {
diff --git a/ecmascript/js_number_format.h b/ecmascript/js_number_format.h
index bf0791b9c87366711cdbac0d3c715e19c881580f..5bb865212dceb8509be7a2e664c7eb663edf85e6 100644
--- a/ecmascript/js_number_format.h
+++ b/ecmascript/js_number_format.h
@@ -41,13 +41,15 @@ struct FractionDigitsOption {
int32_t mxfdDefault = 0;
};
-static const std::set sanctionedUnit({ "acre", "bit", "byte", "celsius", "centimeter", "day", "degree",
- "fahrenheit", "fluid-ounce", "foot", "gallon", "gigabit", "gigabyte",
- "gram", "hectare", "hour", "inch", "kilobit", "kilobyte", "kilogram",
- "kilometer", "liter", "megabit", "megabyte", "meter", "mile",
- "mile-scandinavian", "millimeter", "milliliter", "millisecond",
- "minute", "month", "ounce", "percent", "petabyte", "pound", "second",
- "stone", "terabit", "terabyte", "week", "yard", "year" });
+static const std::set sanctionedUnit({
+ "acre", "bit", "byte", "celsius", "centimeter", "day", "degree",
+ "fahrenheit", "fluid-ounce", "foot", "gallon", "gigabit", "gigabyte",
+ "gram", "hectare", "hour", "inch", "kilobit", "kilobyte", "kilogram",
+ "kilometer", "liter", "megabit", "megabyte", "meter", "mile",
+ "mile-scandinavian", "millimeter", "milliliter", "millisecond",
+ "minute", "month", "ounce", "percent", "petabyte", "pound", "second",
+ "stone", "terabit", "terabyte", "week", "yard", "year"
+});
class JSNumberFormat : public JSObject {
public:
diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h
index 127658b16b22c08e96218626b778c752bbb04b9f..061d6e2c209f41303da8c65d3061eb458702a08a 100644
--- a/ecmascript/js_object.h
+++ b/ecmascript/js_object.h
@@ -339,6 +339,10 @@ public:
void SetHash(int32_t hash);
int32_t GetHash() const;
+ void InitializeHash()
+ {
+ Barriers::SetDynPrimitive(this, ECMAObject::HASH_OFFSET, JSTaggedValue(0).GetRawData());
+ }
void* GetNativePointerField(int32_t index) const;
void SetNativePointerField(int32_t index, void *data);
@@ -353,7 +357,7 @@ public:
void VisitObjects([[maybe_unused]] const EcmaObjectRangeVisitor &visitor) const
{
- // no field in this object
+ Visitor(visitor);
}
};
diff --git a/ecmascript/js_tagged_value.cpp b/ecmascript/js_tagged_value.cpp
index b86a3f164ad775970c1e680665035206b5d3f282..3b7ca1440ae3b7413a2f083f9c33af36a77ae5ea 100644
--- a/ecmascript/js_tagged_value.cpp
+++ b/ecmascript/js_tagged_value.cpp
@@ -261,11 +261,10 @@ JSTaggedValue JSTaggedValue::ToPrimitive(JSThread *thread, const JSHandleIsECMAObject()) {
- JSHandle object(tagged);
EcmaVM *vm = thread->GetEcmaVM();
JSHandle keyString = vm->GetGlobalEnv()->GetToPrimitiveSymbol();
- JSHandle exoticToprim = JSObject::GetProperty(thread, object, keyString).GetValue();
+ JSHandle exoticToprim = GetProperty(thread, tagged, keyString).GetValue();
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
if (!exoticToprim->IsUndefined()) {
JSTaggedValue value = GetTypeString(thread, type).GetTaggedValue();
@@ -298,7 +297,7 @@ JSTaggedValue JSTaggedValue::OrdinaryToPrimitive(JSThread *thread, const JSHandl
} else {
keyString = globalConst->GetHandledValueOfString();
}
- JSHandle entryfunc = JSObject::GetProperty(thread, tagged, keyString).GetValue();
+ JSHandle entryfunc = GetProperty(thread, tagged, keyString).GetValue();
if (entryfunc->IsCallable()) {
JSTaggedValue valueResult = JSFunction::Call(thread, entryfunc, tagged, 0, nullptr);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
diff --git a/ecmascript/mem/allocator-inl.h b/ecmascript/mem/allocator-inl.h
index bf0d150fcbc0a28e2fc5243701bd585e0dee33a7..0117a740a935a854378ee542fd82986b9ebef590 100644
--- a/ecmascript/mem/allocator-inl.h
+++ b/ecmascript/mem/allocator-inl.h
@@ -19,6 +19,7 @@
#include
#include "ecmascript/mem/allocator.h"
+#include "ecmascript/mem/concurrent_sweeper.h"
#include "ecmascript/mem/heap-inl.h"
#include "ecmascript/mem/space.h"
#include "ecmascript/free_object.h"
@@ -67,13 +68,13 @@ uintptr_t BumpPointerAllocator::Allocate(size_t size)
return result;
}
-FreeListAllocator::FreeListAllocator(const Space *space)
+FreeListAllocator::FreeListAllocator(const Space *space) : heap_(space->GetHeap()), type_(space->GetSpaceType())
{
freeList_ = std::make_unique();
- heap_ = space->GetHeap();
uintptr_t begin = space->GetCurrentRegion()->GetBegin();
size_t size = space->GetCurrentRegion()->GetSize();
FreeObject::Cast(begin)->SetAvailable(size);
+ FreeObject::Cast(begin)->SetNext(nullptr);
freeList_->Free(begin, size);
}
@@ -96,18 +97,39 @@ uintptr_t FreeListAllocator::Allocate(size_t size)
}
FreeObject *object = freeList_->Allocator(size);
if (LIKELY(object != nullptr && !object->IsEmpty())) {
- FreeBumpPoint();
- bpAllocator_.Reset(object->GetBegin(), object->GetEnd());
- ret = bpAllocator_.Allocate(size);
- if (ret != 0 && bpAllocator_.Available() > 0) {
- FreeObject::FillFreeObject(heap_->GetEcmaVM(), bpAllocator_.GetTop(), bpAllocator_.Available());
+ return Allocate(object, size);
+ }
+
+ if (sweeping_) {
+ // Concurrent sweep maybe sweep same region
+ heap_->GetSweeper()->FillSweptRegion(type_);
+ object = freeList_->Allocator(size);
+ if (LIKELY(object != nullptr && !object->IsEmpty())) {
+ return Allocate(object, size);
+ }
+
+ // Parallel
+ heap_->GetSweeper()->ParallelSweepSpace(type_);
+ object = freeList_->Allocator(size);
+ if (LIKELY(object != nullptr && !object->IsEmpty())) {
+ return Allocate(object, size);
}
- return ret;
}
return 0;
}
+uintptr_t FreeListAllocator::Allocate(FreeObject *object, size_t size)
+{
+ FreeBumpPoint();
+ bpAllocator_.Reset(object->GetBegin(), object->GetEnd());
+ auto ret = bpAllocator_.Allocate(size);
+ if (ret != 0 && bpAllocator_.Available() > 0) {
+ FreeObject::FillFreeObject(heap_->GetEcmaVM(), bpAllocator_.GetTop(), bpAllocator_.Available());
+ }
+ return ret;
+}
+
void FreeListAllocator::FreeBumpPoint()
{
auto begin = bpAllocator_.GetTop();
@@ -116,7 +138,7 @@ void FreeListAllocator::FreeBumpPoint()
bpAllocator_.Reset();
}
-void FreeListAllocator::Free(uintptr_t begin, uintptr_t end)
+void FreeListAllocator::Free(uintptr_t begin, uintptr_t end, bool isAdd)
{
ASSERT(heap_ != nullptr);
size_t size = end - begin;
@@ -125,7 +147,7 @@ void FreeListAllocator::Free(uintptr_t begin, uintptr_t end)
}
FreeObject::FillFreeObject(heap_->GetEcmaVM(), begin, size);
- freeList_->Free(begin, static_cast(end - begin));
+ freeList_->Free(begin, size, isAdd);
}
void FreeListAllocator::RebuildFreeList()
@@ -133,5 +155,18 @@ void FreeListAllocator::RebuildFreeList()
bpAllocator_.Reset();
freeList_->Rebuild();
}
+
+void FreeListAllocator::FillFreeList(FreeObjectKind *kind)
+{
+ freeList_->AddKind(kind);
+}
+
+size_t FreeListAllocator::GetAvailableSize() const
+{
+ if (sweeping_) {
+ heap_->GetSweeper()->WaitingTaskFinish(type_);
+ }
+ return freeList_->GetFreeObjectSize();
+}
} // namespace panda::ecmascript
#endif // ECMASCRIPT_MEM_ALLOCATOR_INL_H
diff --git a/ecmascript/mem/allocator.h b/ecmascript/mem/allocator.h
index 25b3d3d4cc8841bdc9475f92e0af6125b9978c59..0ea0cf0f086e2a42e943e59a71aea7e8d5c45c78 100644
--- a/ecmascript/mem/allocator.h
+++ b/ecmascript/mem/allocator.h
@@ -91,28 +91,37 @@ public:
inline void AddFree(Region *region);
inline void RebuildFreeList();
+ inline void FillFreeList(FreeObjectKind *kind);
void Swap(FreeListAllocator &other)
{
heap_ = other.heap_;
bpAllocator_.Swap(other.bpAllocator_);
freeList_.swap(other.freeList_);
+ type_ = other.type_;
+ sweeping_ = other.sweeping_;
}
inline void FreeBumpPoint();
- inline void Free(uintptr_t begin, uintptr_t end);
+ inline void Free(uintptr_t begin, uintptr_t end, bool isAdd = true);
inline void SplitFreeObject(FreeObject *current, size_t allocateSize);
- size_t GetAvailableSize() const
+ inline size_t GetAvailableSize() const;
+
+ void SetSweeping(bool sweeping)
{
- return freeList_->GetFreeObjectSize();
+ sweeping_ = sweeping;
}
private:
+ inline uintptr_t Allocate(FreeObject *object, size_t size);
+
BumpPointerAllocator bpAllocator_;
std::unique_ptr freeList_;
Heap *heap_{nullptr};
+ MemSpaceType type_ = OLD_SPACE;
+ bool sweeping_ = false;
};
} // namespace panda::ecmascript
diff --git a/ecmascript/mem/compress_collector.cpp b/ecmascript/mem/compress_collector.cpp
index db3759594c3e193fd0be8a585f48de9cd9037310..fe0ac9997facf15551c10b6f5e81479ef4b62b63 100644
--- a/ecmascript/mem/compress_collector.cpp
+++ b/ecmascript/mem/compress_collector.cpp
@@ -13,9 +13,10 @@
* limitations under the License.
*/
+#include "ecmascript/mem/compress_collector.h"
+
#include "ecmascript/ecma_vm.h"
#include "ecmascript/mem/clock_scope.h"
-#include "ecmascript/mem/compress_collector.h"
#include "ecmascript/mem/compress_gc_marker-inl.h"
#include "ecmascript/mem/ecma_heap_manager.h"
#include "ecmascript/mem/heap-inl.h"
@@ -58,6 +59,7 @@ void CompressCollector::RunPhases()
void CompressCollector::InitializePhase()
{
heap_->GetThreadPool()->WaitTaskFinish();
+ heap_->GetSweeper()->EnsureAllTaskFinish();
auto compressSpace = const_cast(heap_->GetCompressSpace());
if (compressSpace->GetCommittedSize() == 0) {
compressSpace->Initialize();
@@ -70,8 +72,6 @@ void CompressCollector::InitializePhase()
FreeListAllocator compressAllocator(compressSpace);
oldSpaceAllocator_.Swap(compressAllocator);
fromSpaceAllocator_.Reset(fromSpace);
- auto heapManager = heap_->GetHeapManager();
- nonMovableAllocator_.Swap(heapManager->GetNonMovableSpaceAllocator());
auto callback = [](Region *current) {
// ensure mark bitmap
@@ -116,7 +116,6 @@ void CompressCollector::FinishPhase()
workList_->Finish(youngAndOldAliveSize_);
auto heapManager = heap_->GetHeapManager();
heapManager->GetOldSpaceAllocator().Swap(oldSpaceAllocator_);
- heapManager->GetNonMovableSpaceAllocator().Swap(nonMovableAllocator_);
heapManager->GetNewSpaceAllocator().Swap(fromSpaceAllocator_);
}
@@ -230,60 +229,7 @@ void CompressCollector::SweepPhases()
heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak);
heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak);
- SweepSpace(const_cast(heap_->GetNonMovableSpace()), nonMovableAllocator_);
- SweepSpace(const_cast(heap_->GetHugeObjectSpace()));
-}
-
-void CompressCollector::SweepSpace(HugeObjectSpace *space)
-{
- Region *currentRegion = space->GetRegionList().GetFirst();
- while (currentRegion != nullptr) {
- Region *next = currentRegion->GetNext();
- auto markBitmap = currentRegion->GetMarkBitmap();
- bool isMarked = false;
- markBitmap->IterateOverMarkedChunks([&isMarked]([[maybe_unused]] void *mem) { isMarked = true; });
- if (!isMarked) {
- space->GetRegionList().RemoveNode(currentRegion);
- space->ClearAndFreeRegion(currentRegion);
- }
- currentRegion = next;
- }
-}
-
-void CompressCollector::SweepSpace(Space *space, FreeListAllocator &allocator)
-{
- allocator.RebuildFreeList();
- space->EnumerateRegions([this, &allocator](Region *current) {
- auto markBitmap = current->GetMarkBitmap();
- ASSERT(markBitmap != nullptr);
- uintptr_t freeStart = current->GetBegin();
- markBitmap->IterateOverMarkedChunks([this, ¤t, &freeStart, &allocator](void *mem) {
- ASSERT(current->InRange(ToUintPtr(mem)));
- auto header = reinterpret_cast(mem);
- auto klass = header->GetClass();
- JSType jsType = klass->GetObjectType();
- auto size = klass->SizeFromJSHClass(jsType, header);
- size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT));
-
- uintptr_t freeEnd = ToUintPtr(mem);
- if (freeStart != freeEnd) {
- FreeLiveRange(allocator, current, freeStart, freeEnd);
- }
- freeStart = freeEnd + size;
- });
- uintptr_t freeEnd = current->GetEnd();
- if (freeStart != freeEnd) {
- FreeLiveRange(allocator, current, freeStart, freeEnd);
- }
- });
-}
-
-void CompressCollector::FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart,
- uintptr_t freeEnd)
-{
- allocator.Free(freeStart, freeEnd);
- nonMoveSpaceFreeSize_ += freeEnd - freeStart;
- heap_->ClearSlotsRange(current, freeStart, freeEnd);
+ heap_->GetSweeper()->SweepPhases(true);
}
uintptr_t CompressCollector::AllocateOld(size_t size)
diff --git a/ecmascript/mem/compress_collector.h b/ecmascript/mem/compress_collector.h
index 535a3f47a05f1a9942922a8ec2cc5bb6e114a874..8cfb405ed12ae38dd66b517404d5e390ae5bcdb3 100644
--- a/ecmascript/mem/compress_collector.h
+++ b/ecmascript/mem/compress_collector.h
@@ -61,7 +61,6 @@ private:
os::memory::Mutex mtx_;
BumpPointerAllocator fromSpaceAllocator_{};
FreeListAllocator oldSpaceAllocator_{};
- FreeListAllocator nonMovableAllocator_{};
size_t youngAndOldAliveSize_ = 0;
size_t nonMoveSpaceFreeSize_ = 0;
diff --git a/ecmascript/mem/compress_gc_marker-inl.h b/ecmascript/mem/compress_gc_marker-inl.h
index 1f52bfc10f15479744e8fc754bf88695585c1331..5363bb362ac900da33ee82b087dfb31c0ff63a7e 100644
--- a/ecmascript/mem/compress_gc_marker-inl.h
+++ b/ecmascript/mem/compress_gc_marker-inl.h
@@ -80,7 +80,7 @@ inline void CompressGCMarker::EvacuateObject(uint32_t threadId, TaggedObject *ob
inline void CompressGCMarker::CopyObjectWithoutHeader(TaggedObject *object, uintptr_t address, size_t size)
{
if (memcpy_s(ToVoidPtr(address + HEAD_SIZE), size - HEAD_SIZE, ToVoidPtr(ToUintPtr(object) + HEAD_SIZE),
- size - HEAD_SIZE) != EOK) {
+ size - HEAD_SIZE) != EOK) {
LOG_ECMA(FATAL) << "memcpy_s failed";
UNREACHABLE();
}
diff --git a/ecmascript/mem/concurrent_sweeper.cpp b/ecmascript/mem/concurrent_sweeper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6430f4d50f9ccbe85e037e95b198d594979db6ad
--- /dev/null
+++ b/ecmascript/mem/concurrent_sweeper.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2021 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/mem/concurrent_sweeper.h"
+
+#include "ecmascript/js_hclass-inl.h"
+#include "ecmascript/mem/allocator-inl.h"
+#include "ecmascript/mem/ecma_heap_manager.h"
+#include "ecmascript/mem/free_object_list.h"
+#include "ecmascript/mem/heap.h"
+#include "ecmascript/platform/platform.h"
+
+namespace panda::ecmascript {
+ConcurrentSweeper::ConcurrentSweeper(Heap *heap, bool concurrentSweep)
+ : heap_(heap), concurrentSweep_(concurrentSweep)
+{
+}
+
+void ConcurrentSweeper::SweepPhases(bool compressGC)
+{
+ if (concurrentSweep_) {
+ // Add all region to region list. Ensure all task finish
+ trace::ScopedTrace scoped_trace("ConcurrentSweeper::SweepPhases");
+ if (!compressGC) {
+ heap_->GetOldSpace()->EnumerateRegions([this](Region *current) { AddRegion(OLD_SPACE, current); });
+ }
+ heap_->GetNonMovableSpace()->EnumerateRegions([this](Region *current) { AddRegion(NON_MOVABLE, current); });
+ heap_->GetMachineCodeSpace()->EnumerateRegions([this](Region *current) { AddRegion(MACHINE_CODE_SPACE, current); });
+
+ // Prepare
+ isSweeping_ = true;
+ startSpaceType_ = compressGC ? NON_MOVABLE : OLD_SPACE;
+ for (int type = startSpaceType_; type < FREE_LIST_NUM; type++) {
+ auto spaceType = static_cast(type);
+ FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(spaceType);
+ remainderTaskNum_[type] = FREE_LIST_NUM - startSpaceType_;
+ allocator.SetSweeping(true);
+ allocator.RebuildFreeList();
+ }
+
+ if (!compressGC) {
+ Platform::GetCurrentPlatform()->PostTask(std::make_unique(this, OLD_SPACE));
+ }
+ Platform::GetCurrentPlatform()->PostTask(std::make_unique(this, NON_MOVABLE));
+ Platform::GetCurrentPlatform()->PostTask(std::make_unique(this, MACHINE_CODE_SPACE));
+ } else {
+ if (!compressGC) {
+ SweepSpace(const_cast(heap_->GetOldSpace()), heap_->GetHeapManager()->GetOldSpaceAllocator());
+ }
+ SweepSpace(const_cast(heap_->GetNonMovableSpace()),
+ heap_->GetHeapManager()->GetNonMovableSpaceAllocator());
+ SweepSpace(const_cast(heap_->GetMachineCodeSpace()),
+ heap_->GetHeapManager()->GetMachineCodeSpaceAllocator());
+ }
+ SweepHugeSpace();
+}
+
+void ConcurrentSweeper::SweepSpace(MemSpaceType type, bool isMain)
+{
+ trace::ScopedTrace scoped_trace("Sweeper::SweepSpace");
+ FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(type);
+ Region *current = GetRegionSafe(type);
+ while (current != nullptr) {
+ FreeRegion(current, allocator, isMain);
+ // Main thread sweeping region is added;
+ if (!isMain) {
+ AddSweptRegionSafe(type, current);
+ }
+ current = GetRegionSafe(type);
+ }
+
+ if (!isMain) {
+ os::memory::LockHolder holder(mutexs_[type]);
+ remainderTaskNum_[type]--;
+ if (remainderTaskNum_[type] == 0) {
+ cvs_[type].SignalAll();
+ }
+ }
+}
+
+void ConcurrentSweeper::SweepSpace(Space *space, FreeListAllocator &allocator)
+{
+ allocator.RebuildFreeList();
+ space->EnumerateRegions([this, &allocator](Region *current) { FreeRegion(current, allocator); });
+}
+
+void ConcurrentSweeper::SweepHugeSpace()
+{
+ trace::ScopedTrace scoped_trace("SweepSpace HugeObject");
+ HugeObjectSpace *space = const_cast(heap_->GetHugeObjectSpace());
+ Region *currentRegion = space->GetRegionList().GetFirst();
+
+ while (currentRegion != nullptr) {
+ Region *next = currentRegion->GetNext();
+ auto markBitmap = currentRegion->GetMarkBitmap();
+ bool isMarked = false;
+ markBitmap->IterateOverMarkedChunks([&isMarked]([[maybe_unused]] void *mem) { isMarked = true; });
+ if (!isMarked) {
+ space->GetRegionList().RemoveNode(currentRegion);
+ space->ClearAndFreeRegion(currentRegion);
+ }
+ currentRegion = next;
+ }
+}
+
+void ConcurrentSweeper::FreeRegion(Region *current, FreeListAllocator &allocator, bool isMain)
+{
+ auto markBitmap = current->GetMarkBitmap();
+ ASSERT(markBitmap != nullptr);
+ uintptr_t freeStart = current->GetBegin();
+ markBitmap->IterateOverMarkedChunks([this, ¤t, &freeStart, &allocator, isMain](void *mem) {
+ ASSERT(current->InRange(ToUintPtr(mem)));
+ auto header = reinterpret_cast(mem);
+ auto klass = header->GetClass();
+ JSType jsType = klass->GetObjectType();
+ auto size = klass->SizeFromJSHClass(jsType, header);
+ size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT));
+
+ uintptr_t freeEnd = ToUintPtr(mem);
+ if (freeStart != freeEnd) {
+ FreeLiveRange(allocator, current, freeStart, freeEnd, isMain);
+ }
+ freeStart = freeEnd + size;
+ });
+ uintptr_t freeEnd = current->GetEnd();
+ if (freeStart != freeEnd) {
+ FreeLiveRange(allocator, current, freeStart, freeEnd, isMain);
+ }
+}
+
+void ConcurrentSweeper::FillSweptRegion(MemSpaceType type)
+{
+ trace::ScopedTrace scoped_trace("Sweeper::FillSweptRegion");
+ if (sweptList_[type].empty()) {
+ return;
+ }
+ FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(type);
+ Region *region = nullptr;
+ while ((region = GetSweptRegionSafe(type)) != nullptr) {
+ region->EnumerateKinds([&allocator](FreeObjectKind *kind) {
+ if (kind == nullptr || kind->Empty()) {
+ return;
+ }
+ allocator.FillFreeList(kind);
+ });
+ }
+}
+
+void ConcurrentSweeper::FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart,
+ uintptr_t freeEnd, bool isMain)
+{
+ allocator.Free(freeStart, freeEnd, isMain);
+ heap_->ClearSlotsRange(current, freeStart, freeEnd);
+}
+
+void ConcurrentSweeper::AddRegion(MemSpaceType type, Region *region)
+{
+ sweepingList_[type].emplace_back(region);
+}
+
+Region *ConcurrentSweeper::GetRegionSafe(MemSpaceType type)
+{
+ os::memory::LockHolder holder(mutexs_[type]);
+ Region *region = nullptr;
+ if (!sweepingList_[type].empty()) {
+ region = sweepingList_[type].back();
+ sweepingList_[type].pop_back();
+ }
+ return region;
+}
+
+void ConcurrentSweeper::AddSweptRegionSafe(MemSpaceType type, Region *region)
+{
+ os::memory::LockHolder holder(mutexs_[type]);
+ sweptList_[type].emplace_back(region);
+}
+
+Region *ConcurrentSweeper::GetSweptRegionSafe(MemSpaceType type)
+{
+ os::memory::LockHolder holder(mutexs_[type]);
+ Region *region = nullptr;
+ if (!sweptList_[type].empty()) {
+ region = sweptList_[type].back();
+ sweptList_[type].pop_back();
+ }
+ return region;
+}
+
+void ConcurrentSweeper::EnsureAllTaskFinish()
+{
+ if (!isSweeping_) {
+ return;
+ }
+ for (int i = startSpaceType_; i < FREE_LIST_NUM; i++) {
+ WaitingTaskFinish(static_cast(i));
+ }
+ isSweeping_ = false;
+}
+
+void ConcurrentSweeper::WaitingTaskFinish(MemSpaceType type)
+{
+ if (remainderTaskNum_[type] > 0) {
+ SweepSpace(type);
+ {
+ os::memory::LockHolder holder(mutexs_[type]);
+ while (remainderTaskNum_[type] > 0) {
+ cvs_[type].Wait(&mutexs_[type]);
+ }
+ }
+ }
+ FinishSweeping(type);
+}
+
+void ConcurrentSweeper::ParallelSweepSpace(MemSpaceType type)
+{
+ if (remainderTaskNum_[type] > 0) {
+ SweepSpace(type);
+ }
+
+ if (remainderTaskNum_[type] <= 0) {
+ FinishSweeping(type);
+ } else {
+ FillSweptRegion(type);
+ }
+}
+
+void ConcurrentSweeper::FinishSweeping(MemSpaceType type)
+{
+ FillSweptRegion(type);
+ FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(type);
+ allocator.SetSweeping(false);
+ if (type == OLD_SPACE) {
+ heap_->RecomputeLimits();
+ }
+}
+
+bool ConcurrentSweeper::SweeperTask::Run()
+{
+ for (size_t i = 0; i < FREE_LIST_NUM - sweeper_->startSpaceType_; i++) {
+ auto type = static_cast((i + type_) % FREE_LIST_NUM);
+ sweeper_->SweepSpace(type, false);
+ }
+ return true;
+}
+} // namespace panda::ecmascript
diff --git a/ecmascript/mem/concurrent_sweeper.h b/ecmascript/mem/concurrent_sweeper.h
new file mode 100644
index 0000000000000000000000000000000000000000..fb83c35b25d7d65f68c99048e5b54d1e8354b660
--- /dev/null
+++ b/ecmascript/mem/concurrent_sweeper.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2021 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_ECMASCRIPT_MEM_CONCURRENT_SWEEPER_H
+#define PANDA_ECMASCRIPT_MEM_CONCURRENT_SWEEPER_H
+
+#include
+#include
+
+#include "ecmascript/mem/space.h"
+#include "ecmascript/platform/task.h"
+#include "os/mutex.h"
+
+namespace panda::ecmascript {
+class FreeListAllocator;
+
+class ConcurrentSweeper {
+public:
+ ConcurrentSweeper(Heap *heap, bool concurrentSweep);
+ ~ConcurrentSweeper() = default;
+
+ NO_COPY_SEMANTIC(ConcurrentSweeper);
+ NO_MOVE_SEMANTIC(ConcurrentSweeper);
+
+ void SweepPhases(bool compressGC = false);
+
+ void EnsureAllTaskFinish();
+ // Ensure task finish
+ void WaitingTaskFinish(MemSpaceType type);
+ // Parallel sweep space, does not guarantee the end of the task
+ void ParallelSweepSpace(MemSpaceType type);
+
+ void FillSweptRegion(MemSpaceType type);
+
+ bool IsConcurrentSweepEnabled()
+ {
+ return concurrentSweep_;
+ }
+
+private:
+ class SweeperTask : public Task {
+ public:
+ SweeperTask(ConcurrentSweeper *sweeper, MemSpaceType type) : sweeper_(sweeper), type_(type){};
+ ~SweeperTask() override = default;
+ bool Run() override;
+
+ NO_COPY_SEMANTIC(SweeperTask);
+ NO_MOVE_SEMANTIC(SweeperTask);
+
+ private:
+ ConcurrentSweeper *sweeper_;
+ MemSpaceType type_;
+ };
+
+ void SweepSpace(MemSpaceType type, bool isMain = true);
+ void SweepSpace(Space *space, FreeListAllocator &allocator);
+ void SweepHugeSpace();
+ void FinishSweeping(MemSpaceType type);
+
+ void FreeRegion(Region *current, FreeListAllocator &allocator, bool isMain = true);
+ void FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, uintptr_t freeEnd,
+ bool isMain);
+
+ void AddRegion(MemSpaceType type, Region *region);
+ Region *GetRegionSafe(MemSpaceType type);
+
+ void AddSweptRegionSafe(MemSpaceType type, Region *region);
+ Region *GetSweptRegionSafe(MemSpaceType type);
+
+ std::array mutexs_;
+ std::array cvs_;
+ std::array remainderTaskNum_ = {0, 0, 0};
+
+ std::array, FREE_LIST_NUM> sweepingList_;
+ std::array, FREE_LIST_NUM> sweptList_;
+
+ Heap *heap_;
+ bool concurrentSweep_ = false;
+ bool isSweeping_ = false;
+ MemSpaceType startSpaceType_ = MemSpaceType::OLD_SPACE;
+};
+} // namespace panda::ecmascript
+#endif // PANDA_ECMASCRIPT_MEM_CONCURRENT_SWEEPER_H
diff --git a/ecmascript/mem/ecma_heap_manager-inl.h b/ecmascript/mem/ecma_heap_manager-inl.h
index 4b65d6c33767a955b2ca0a60e62c019c37e0d961..8b9f0e146b9b9784bfcd1ec0a351bef472ae806f 100644
--- a/ecmascript/mem/ecma_heap_manager-inl.h
+++ b/ecmascript/mem/ecma_heap_manager-inl.h
@@ -83,18 +83,18 @@ TaggedObject *EcmaHeapManager::AllocateNonMovableOrHugeObject(JSHClass *hclass,
if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) {
return AllocateHugeObject(hclass, size);
}
- auto object = reinterpret_cast(nonMovableAllocator_.Allocate(size));
+ auto object = reinterpret_cast(GetNonMovableSpaceAllocator().Allocate(size));
if (UNLIKELY(object == nullptr)) {
if (heap_->CheckAndTriggerNonMovableGC()) {
- object = reinterpret_cast(nonMovableAllocator_.Allocate(size));
+ object = reinterpret_cast(GetNonMovableSpaceAllocator().Allocate(size));
}
if (UNLIKELY(object == nullptr)) {
// hclass must be nonmovable
- if (!heap_->FillNonMovableSpaceAndTryGC(&nonMovableAllocator_)) {
+ if (!heap_->FillNonMovableSpaceAndTryGC(&GetNonMovableSpaceAllocator())) {
LOG_ECMA_MEM(FATAL) << "OOM : extend failed";
UNREACHABLE();
}
- object = reinterpret_cast(nonMovableAllocator_.Allocate(size));
+ object = reinterpret_cast(GetNonMovableSpaceAllocator().Allocate(size));
if (UNLIKELY(object == nullptr)) {
heap_->ThrowOutOfMemoryError(size);
UNREACHABLE();
@@ -140,18 +140,18 @@ TaggedObject *EcmaHeapManager::AllocateOldGenerationOrHugeObject(JSHClass *hclas
if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) {
return AllocateHugeObject(hclass, size);
}
- auto object = reinterpret_cast(oldSpaceAllocator_.Allocate(size));
+ auto object = reinterpret_cast(GetOldSpaceAllocator().Allocate(size));
if (UNLIKELY(object == nullptr)) {
if (heap_->CheckAndTriggerOldGC()) {
- object = reinterpret_cast(oldSpaceAllocator_.Allocate(size));
+ object = reinterpret_cast(GetOldSpaceAllocator().Allocate(size));
}
if (UNLIKELY(object == nullptr)) {
// hclass must nonmovable
- if (!heap_->FillOldSpaceAndTryGC(&oldSpaceAllocator_)) {
+ if (!heap_->FillOldSpaceAndTryGC(&GetOldSpaceAllocator())) {
LOG_ECMA_MEM(FATAL) << "OOM : extend failed";
UNREACHABLE();
}
- object = reinterpret_cast(oldSpaceAllocator_.Allocate(size));
+ object = reinterpret_cast(GetOldSpaceAllocator().Allocate(size));
if (UNLIKELY(object == nullptr)) {
heap_->ThrowOutOfMemoryError(size);
UNREACHABLE();
@@ -186,12 +186,12 @@ TaggedObject *EcmaHeapManager::AllocateHugeObject(JSHClass *hclass, size_t size)
TaggedObject *EcmaHeapManager::AllocateMachineCodeSpaceObject(JSHClass *hclass, size_t size)
{
- auto object = reinterpret_cast(machineCodeSpaceAllocator_.Allocate(size));
+ auto object = reinterpret_cast(GetMachineCodeSpaceAllocator().Allocate(size));
if (UNLIKELY(object == nullptr)) {
- if (!heap_->FillMachineCodeSpaceAndTryGC(&machineCodeSpaceAllocator_)) {
+ if (!heap_->FillMachineCodeSpaceAndTryGC(&GetMachineCodeSpaceAllocator())) {
return nullptr;
}
- object = reinterpret_cast(machineCodeSpaceAllocator_.Allocate(size));
+ object = reinterpret_cast(GetMachineCodeSpaceAllocator().Allocate(size));
if (UNLIKELY(object == nullptr)) {
heap_->ThrowOutOfMemoryError(size);
return nullptr;
diff --git a/ecmascript/mem/ecma_heap_manager.cpp b/ecmascript/mem/ecma_heap_manager.cpp
index ea3d0b982696759e6cf968acb841bb36268aec9f..43148826728a9e35ce159758e9eb85aca02962b3 100644
--- a/ecmascript/mem/ecma_heap_manager.cpp
+++ b/ecmascript/mem/ecma_heap_manager.cpp
@@ -20,9 +20,8 @@ namespace panda::ecmascript {
EcmaHeapManager::EcmaHeapManager(Heap *heap)
: heap_(heap),
newSpaceAllocator_(heap->GetNewSpace()),
- nonMovableAllocator_(heap->GetNonMovableSpace()),
- oldSpaceAllocator_(heap->GetOldSpace()),
- machineCodeSpaceAllocator_(heap->GetMachineCodeSpace())
+ freeListAllocator_ { FreeListAllocator(heap->GetOldSpace()), FreeListAllocator(heap_->GetNonMovableSpace()),
+ FreeListAllocator(heap->GetMachineCodeSpace()) }
{
ASSERT(heap != nullptr);
heap->SetHeapManager(this);
diff --git a/ecmascript/mem/ecma_heap_manager.h b/ecmascript/mem/ecma_heap_manager.h
index 6bfd120149acc41d73eeeccef3f94f125b9fcfb2..82ec7bc71d7a14cf1e2c6ceadc288ecc5ee7963e 100644
--- a/ecmascript/mem/ecma_heap_manager.h
+++ b/ecmascript/mem/ecma_heap_manager.h
@@ -48,9 +48,14 @@ public:
return heap_;
}
- FreeListAllocator &GetOldSpaceAllocator()
+ FreeListAllocator &GetFreeListAllocator(MemSpaceType type)
{
- return oldSpaceAllocator_;
+ return freeListAllocator_[type];
+ }
+
+ inline FreeListAllocator &GetOldSpaceAllocator()
+ {
+ return freeListAllocator_[OLD_SPACE];
}
BumpPointerAllocator &GetNewSpaceAllocator()
@@ -58,9 +63,9 @@ public:
return newSpaceAllocator_;
}
- FreeListAllocator &GetNonMovableSpaceAllocator()
+ inline FreeListAllocator &GetNonMovableSpaceAllocator()
{
- return nonMovableAllocator_;
+ return freeListAllocator_[NON_MOVABLE];
}
const BumpPointerAllocator &GetSnapShotSpaceAllocator() const
@@ -68,18 +73,16 @@ public:
return snapshotSpaceAllocator_;
}
- FreeListAllocator &GetMachineCodeSpaceAllocator()
+ inline FreeListAllocator &GetMachineCodeSpaceAllocator()
{
- return machineCodeSpaceAllocator_;
+ return freeListAllocator_[MACHINE_CODE_SPACE];
}
private:
Heap *heap_{nullptr};
BumpPointerAllocator newSpaceAllocator_;
- FreeListAllocator nonMovableAllocator_;
- FreeListAllocator oldSpaceAllocator_;
+ std::array freeListAllocator_;
BumpPointerAllocator snapshotSpaceAllocator_;
- FreeListAllocator machineCodeSpaceAllocator_;
};
} // namespace panda::ecmascript
diff --git a/ecmascript/mem/free_object_kind.cpp b/ecmascript/mem/free_object_kind.cpp
index 951871f25276b489301f68b343c81a5cb7d650c0..94829d653a0a83d7dd4a93bf0dcad83f9ac7c791 100644
--- a/ecmascript/mem/free_object_kind.cpp
+++ b/ecmascript/mem/free_object_kind.cpp
@@ -31,6 +31,9 @@ void FreeObjectKind::Rebuild()
{
freeObject_ = nullptr;
available_ = 0;
+ isAdded_ = false;
+ next_ = nullptr;
+ prev_ = nullptr;
}
FreeObject *FreeObjectKind::SearchSmallFreeObject(size_t size)
diff --git a/ecmascript/mem/free_object_kind.h b/ecmascript/mem/free_object_kind.h
index 869689c5fb87a2e109e96d34b1f1ce770dadb99d..057968a16d1ed4c98c9b5cb1941c33b0fb766859 100644
--- a/ecmascript/mem/free_object_kind.h
+++ b/ecmascript/mem/free_object_kind.h
@@ -27,9 +27,9 @@ class FreeObject;
class FreeObjectKind {
public:
- FreeObjectKind(KindType type, uintptr_t begin, size_t size) : kindType_(type)
+ FreeObjectKind(KindType type) : kindType_(type)
{
- Free(begin, size);
+ Rebuild();
}
~FreeObjectKind() = default;
@@ -60,6 +60,7 @@ private:
FreeObjectKind *prev_ = nullptr;
KindType kindType_ = INVALID_KIND_TYPE;
size_t available_ = 0;
+ bool isAdded_ = false;
FreeObject *freeObject_ = nullptr;
friend class FreeObjectList;
diff --git a/ecmascript/mem/free_object_list.cpp b/ecmascript/mem/free_object_list.cpp
index 43e220f78e4fa0f7dc54117e286f06528e31be06..e25e2880a71744d243efc8fdf1de0642254d6f39 100644
--- a/ecmascript/mem/free_object_list.cpp
+++ b/ecmascript/mem/free_object_list.cpp
@@ -20,17 +20,16 @@
#include "ecmascript/mem/mem.h"
namespace panda::ecmascript {
-FreeObjectList::FreeObjectList()
+FreeObjectList::FreeObjectList() : kinds_(new FreeObjectKind *[NUMBER_OF_KINDS](), NUMBER_OF_KINDS)
{
- kinds_ = Span(new FreeObjectKind *[NUMBER_OF_KINDS](), NUMBER_OF_KINDS);
+ for (int i = 0; i < NUMBER_OF_KINDS; i++) {
+ kinds_[i] = nullptr;
+ }
noneEmptyKindBitMap_ = 0;
}
FreeObjectList::~FreeObjectList()
{
- for (auto it : kinds_) {
- delete it;
- }
delete[] kinds_.data();
noneEmptyKindBitMap_ = 0;
}
@@ -49,33 +48,39 @@ FreeObject *FreeObjectList::Allocator(size_t size)
KindType lastType = type - 1;
for (type = CalcNextNoneEmptyIndex(type); type > lastType && type < NUMBER_OF_KINDS;
- type = CalcNextNoneEmptyIndex(type + 1)) {
+ type = CalcNextNoneEmptyIndex(type + 1)) {
lastType = type;
- FreeObjectKind *top = kinds_[type];
- if (top == nullptr || top->Available() < size) {
- continue;
- }
- FreeObject *current = nullptr;
- if (type <= SMALL_KIND_MAX_INDEX) {
- current = top->SearchSmallFreeObject(size);
- } else {
- current = top->SearchLargeFreeObject(size);
- }
- if (top->Empty()) {
- RemoveKind(top);
- }
- if (current != nullptr) {
- size_t currentSize = current->Available();
- available_ -= currentSize;
- if (currentSize >= size) {
- return current;
+ FreeObjectKind *current = kinds_[type];
+ while (current != nullptr) {
+ if (current->Available() < size) {
+ current = current->next_;
+ continue;
}
+ FreeObjectKind *next = nullptr;
+ FreeObject *object = nullptr;
+ if (type <= SMALL_KIND_MAX_INDEX) {
+ object = current->SearchSmallFreeObject(size);
+ } else {
+ next = current->next_;
+ object = current->SearchLargeFreeObject(size);
+ }
+ if (current->Empty()) {
+ RemoveKind(current);
+ }
+ if (object != nullptr) {
+ size_t objectSize = object->Available();
+ available_ -= objectSize;
+ if (objectSize >= size) {
+ return object;
+ }
+ }
+ current = next;
}
}
return nullptr;
}
-void FreeObjectList::Free(uintptr_t start, size_t size)
+void FreeObjectList::Free(uintptr_t start, size_t size, bool isAdd)
{
if (start == 0 || size == 0) {
return;
@@ -86,26 +91,28 @@ void FreeObjectList::Free(uintptr_t start, size_t size)
return;
}
- auto kind = kinds_[type];
+ Region *region = Region::ObjectAddressToRange(reinterpret_cast(start));
+ auto kind = region->GetFreeObjectKind(type);
if (kind == nullptr) {
- kind = new FreeObjectKind(type, start, size);
- if (!AddKind(kind)) {
- delete kind;
- return;
+ LOG_ECMA(FATAL) << "The kind of region is nullptr";
+ return;
+ }
+ kind->Free(start, size);
+
+ if (isAdd) {
+ if (kind->isAdded_) {
+ available_ += size;
+ } else {
+ AddKind(kind);
}
- } else {
- kind->Free(start, size);
}
- available_ += size;
}
void FreeObjectList::Rebuild()
{
- for (auto kind : kinds_) {
- if (kind != nullptr) {
- kind->Rebuild();
- RemoveKind(kind);
- }
+ EnumerateKinds([](FreeObjectKind *kind) { kind->Rebuild(); });
+ for (int i = 0; i < NUMBER_OF_KINDS; i++) {
+ kinds_[i] = nullptr;
}
available_ = 0;
noneEmptyKindBitMap_ = 0;
@@ -118,20 +125,22 @@ size_t FreeObjectList::GetFreeObjectSize() const
bool FreeObjectList::AddKind(FreeObjectKind *kind)
{
- if (kind == nullptr || kind->Empty()) {
+ if (kind == nullptr || kind->Empty() || kind->isAdded_) {
return false;
}
KindType type = kind->kindType_;
FreeObjectKind *top = kinds_[type];
if (kind == top) {
- return true;
+ return false;
}
if (top != nullptr) {
top->prev_ = kind;
}
+ kind->isAdded_ = true;
kind->next_ = top;
kinds_[type] = kind;
SetNoneEmptyBit(type);
+ available_ += kind->Available();
return true;
}
@@ -151,11 +160,30 @@ void FreeObjectList::RemoveKind(FreeObjectKind *kind)
if (kind->next_ != nullptr) {
kind->next_->prev_ = kind->prev_;
}
- kind->prev_ = nullptr;
- kind->next_ = nullptr;
if (kinds_[type] == nullptr) {
ClearNoneEmptyBit(type);
}
- delete kind;
+ available_ -= kind->Available();
+ kind->Rebuild();
+}
+
+template
+void FreeObjectList::EnumerateKinds(const Callback &cb) const
+{
+ for (KindType i = 0; i < NUMBER_OF_KINDS; i++) {
+ EnumerateKinds(i, cb);
+ }
+}
+
+template
+void FreeObjectList::EnumerateKinds(KindType type, const Callback &cb) const
+{
+ FreeObjectKind *current = kinds_[type];
+ while (current != nullptr) {
+ // maybe reset
+ FreeObjectKind *next = current->next_;
+ cb(current);
+ current = next;
+ }
}
} // namespace panda::ecmascript
diff --git a/ecmascript/mem/free_object_list.h b/ecmascript/mem/free_object_list.h
index c7db11126e86734ad79e2ac5cedcfa0837b2f150..553dd5d4c4722e867e9e033faffc63b710b86022 100644
--- a/ecmascript/mem/free_object_list.h
+++ b/ecmascript/mem/free_object_list.h
@@ -29,15 +29,30 @@ public:
FreeObject *Allocator(size_t size);
- void Free(uintptr_t start, size_t size);
+ void Free(uintptr_t start, size_t size, bool isAdd = true);
void Rebuild();
+ bool AddKind(FreeObjectKind *kind);
+
+ void RemoveKind(FreeObjectKind *kind);
+
+ template
+ void EnumerateKinds(const Callback &cb) const;
+
+ template
+ void EnumerateKinds(KindType type, const Callback &cb) const;
+
NO_COPY_SEMANTIC(FreeObjectList);
NO_MOVE_SEMANTIC(FreeObjectList);
size_t GetFreeObjectSize() const;
+ static int NumberOfKinds()
+ {
+ return NUMBER_OF_KINDS;
+ }
+
private:
static constexpr int NUMBER_OF_KINDS = 39;
static constexpr size_t MIN_SIZE = 16;
@@ -58,9 +73,6 @@ private:
inline void ClearNoneEmptyBit(KindType type);
inline size_t CalcNextNoneEmptyIndex(KindType start);
- bool AddKind(FreeObjectKind *kind);
- void RemoveKind(FreeObjectKind *kind);
-
size_t available_ = 0;
uint64_t noneEmptyKindBitMap_;
Span kinds_ {};
diff --git a/ecmascript/mem/heap.cpp b/ecmascript/mem/heap.cpp
index 9294b267354982e618573b87620122b2fe07d67d..bfc7d90674aee4228075b412fa6bab893b7f552c 100644
--- a/ecmascript/mem/heap.cpp
+++ b/ecmascript/mem/heap.cpp
@@ -20,6 +20,7 @@
#include "ecmascript/ecma_vm.h"
#include "ecmascript/mem/assert_scope-inl.h"
#include "ecmascript/mem/compress_collector.h"
+#include "ecmascript/mem/concurrent_sweeper.h"
#include "ecmascript/mem/ecma_heap_manager.h"
#include "ecmascript/mem/mark_stack.h"
#include "ecmascript/mem/mem_controller.h"
@@ -63,12 +64,15 @@ void Heap::Initialize()
pool_ = new ThreadPool(numThread);
semiSpaceCollector_ = new SemiSpaceCollector(this, true);
compressCollector_ = new CompressCollector(this, true);
+ oldSpaceCollector_ = new OldSpaceCollector(this, true);
} else {
pool_ = new ThreadPool(1);
semiSpaceCollector_ = new SemiSpaceCollector(this, false);
compressCollector_ = new CompressCollector(this, false);
+ oldSpaceCollector_ = new OldSpaceCollector(this, false);
}
- oldSpaceCollector_ = new OldSpaceCollector(this);
+ bool concurrentSweep = ecmaVm_->GetOptions().IsEnableConcurrentSweepGc();
+ sweeper_ = new ConcurrentSweeper(this, concurrentSweep);
}
void Heap::FlipNewSpace()
@@ -87,6 +91,7 @@ void Heap::FlipCompressSpace()
void Heap::Destroy()
{
pool_->WaitTaskFinish();
+ sweeper_->EnsureAllTaskFinish();
toSpace_->Destroy();
delete toSpace_;
toSpace_ = nullptr;
@@ -156,18 +161,18 @@ void Heap::CollectGarbage(TriggerGCType gcType)
}
break;
case TriggerGCType::OLD_GC:
- if (oldSpace_->GetHeapObjectSize() < OLD_SPACE_LIMIT_BEGIN) {
- oldSpaceCollector_->RunPhases();
- } else {
- compressCollector_->RunPhases();
+ oldSpaceCollector_->RunPhases();
+ if (!sweeper_->IsConcurrentSweepEnabled()) {
+ RecomputeLimits();
}
- RecomputeLimits();
break;
case TriggerGCType::NON_MOVE_GC:
case TriggerGCType::HUGE_GC:
case TriggerGCType::MACHINE_CODE_GC:
oldSpaceCollector_->RunPhases();
- RecomputeLimits();
+ if (!sweeper_->IsConcurrentSweepEnabled()) {
+ RecomputeLimits();
+ }
break;
case TriggerGCType::COMPRESS_FULL_GC:
compressCollector_->RunPhases();
diff --git a/ecmascript/mem/heap.h b/ecmascript/mem/heap.h
index bc112f2f877b7714dab00ce70cf545c5d8276cb2..a15c9cfe0aa257562a64326b907be2abbbf6dea1 100644
--- a/ecmascript/mem/heap.h
+++ b/ecmascript/mem/heap.h
@@ -31,6 +31,7 @@ class FreeListAllocator;
class RegionFactory;
class HeapTracker;
class MemController;
+class ConcurrentSweeper;
class Heap {
public:
@@ -118,6 +119,11 @@ public:
return compressCollector_;
}
+ ConcurrentSweeper *GetSweeper() const
+ {
+ return sweeper_;
+ }
+
EcmaVM *GetEcmaVM() const
{
return ecmaVm_;
@@ -276,6 +282,7 @@ private:
SemiSpaceCollector *semiSpaceCollector_ {nullptr};
OldSpaceCollector *oldSpaceCollector_ {nullptr};
CompressCollector *compressCollector_ {nullptr};
+ ConcurrentSweeper *sweeper_ {nullptr};
EcmaHeapManager *heapManager_ {nullptr};
RegionFactory *regionFactory_ {nullptr};
HeapTracker *tracker_ {nullptr};
diff --git a/ecmascript/mem/old_space_collector-inl.h b/ecmascript/mem/old_space_collector-inl.h
index a8f88de5598d382c9d9a2786cbff2bc571958915..f5e4a958de8af2dd66c8af41b0bd802db3dac5fa 100644
--- a/ecmascript/mem/old_space_collector-inl.h
+++ b/ecmascript/mem/old_space_collector-inl.h
@@ -24,14 +24,13 @@
#include "ecmascript/js_hclass-inl.h"
namespace panda::ecmascript {
-void OldSpaceCollector::MarkObject(TaggedObject *object)
+void OldSpaceCollector::MarkObject(uint64_t threadId, TaggedObject *object)
{
Region *objectRegion = Region::ObjectAddressToRange(object);
auto markBitmap = objectRegion->GetMarkBitmap();
- if (!markBitmap->Test(object)) {
- markBitmap->Set(object);
- markStack_.PushBack(object);
+ if (!markBitmap->AtomicTestAndSet(object)) {
+ workList_->Push(threadId, object);
}
}
@@ -42,14 +41,6 @@ void OldSpaceCollector::RecordWeakReference(JSTaggedType *ref)
weakProcessQueue_.PushBack(ref);
}
}
-
-void OldSpaceCollector::FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart,
- uintptr_t freeEnd)
-{
- allocator.Free(freeStart, freeEnd);
- freeSize_ += freeEnd - freeStart;
- heap_->ClearSlotsRange(current, freeStart, freeEnd);
-}
} // namespace panda::ecmascript
#endif // ECMASCRIPT_MEM_SEMI_SAPACE_COLLECTOR_INL_H
diff --git a/ecmascript/mem/old_space_collector.cpp b/ecmascript/mem/old_space_collector.cpp
index 3572760030bc5a72f1440173fb54d5204987a955..a2a693a1f5e0d4396802da19cfb2c12f24f3bf66 100644
--- a/ecmascript/mem/old_space_collector.cpp
+++ b/ecmascript/mem/old_space_collector.cpp
@@ -15,6 +15,8 @@
#include "ecmascript/mem/old_space_collector-inl.h"
+#include "sys/time.h"
+
#include "ecmascript/ecma_vm.h"
#include "ecmascript/mem/clock_scope.h"
#include "ecmascript/mem/ecma_heap_manager.h"
@@ -27,7 +29,11 @@
#include "ecmascript/vmstat/runtime_stat.h"
namespace panda::ecmascript {
-OldSpaceCollector::OldSpaceCollector(Heap *heap) : heap_(heap), rootManager_(heap->GetEcmaVM()) {}
+OldSpaceCollector::OldSpaceCollector(Heap *heap, bool parallelGc) :
+ heap_(heap), rootManager_(heap->GetEcmaVM()), paralledGC_(parallelGc)
+{
+ workList_ = new OldGCWorker(heap_, heap_->GetThreadPool()->GetThreadNum());
+}
void OldSpaceCollector::RunPhases()
{
@@ -45,12 +51,9 @@ void OldSpaceCollector::RunPhases()
void OldSpaceCollector::InitializePhase()
{
+ heap_->GetThreadPool()->WaitTaskFinish();
markStack_.BeginMarking(heap_, heap_->GetMarkStack());
weakProcessQueue_.BeginMarking(heap_, heap_->GetProcessQueue());
- auto heapManager = heap_->GetHeapManager();
- oldSpaceAllocator_.Swap(heapManager->GetOldSpaceAllocator());
- nonMovableAllocator_.Swap(heapManager->GetNonMovableSpaceAllocator());
- machineCodeSpaceAllocator_.Swap(heapManager->GetMachineCodeSpaceAllocator());
heap_->EnumerateRegions([](Region *current) {
// ensure mark bitmap
auto bitmap = current->GetMarkBitmap();
@@ -60,6 +63,7 @@ void OldSpaceCollector::InitializePhase()
bitmap->ClearAllBits();
}
});
+ workList_->Initialize();
freeSize_ = 0;
hugeSpaceFreeSize_ = 0;
oldSpaceCommitSize_ = heap_->GetOldSpace()->GetCommittedSize();
@@ -69,12 +73,9 @@ void OldSpaceCollector::InitializePhase()
void OldSpaceCollector::FinishPhase()
{
// swap
- markStack_.FinishMarking(heap_->GetMarkStack());
weakProcessQueue_.FinishMarking(heap_->GetProcessQueue());
- auto heapManager = heap_->GetHeapManager();
- heapManager->GetOldSpaceAllocator().Swap(oldSpaceAllocator_);
- heapManager->GetNonMovableSpaceAllocator().Swap(nonMovableAllocator_);
- heapManager->GetMachineCodeSpaceAllocator().Swap(machineCodeSpaceAllocator_);
+ size_t aliveSize = 0;
+ workList_->Finish(aliveSize);
}
void OldSpaceCollector::MarkingPhase()
@@ -83,35 +84,38 @@ void OldSpaceCollector::MarkingPhase()
RootVisitor gcMarkYoung = [this]([[maybe_unused]] Root type, ObjectSlot slot) {
JSTaggedValue value(slot.GetTaggedType());
if (value.IsHeapObject()) {
- MarkObject(value.GetTaggedObject());
+ MarkObject(0, value.GetTaggedObject());
}
};
RootRangeVisitor gcMarkRangeYoung = [this]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) {
for (ObjectSlot slot = start; slot < end; slot++) {
JSTaggedValue value(slot.GetTaggedType());
if (value.IsHeapObject()) {
- MarkObject(value.GetTaggedObject());
+ MarkObject(0, value.GetTaggedObject());
}
}
};
rootManager_.VisitVMRoots(gcMarkYoung, gcMarkRangeYoung);
- ProcessMarkStack();
+ ProcessMarkStack(0);
+ if (paralledGC_) {
+ heap_->GetThreadPool()->WaitTaskFinish();
+ }
}
-void OldSpaceCollector::ProcessMarkStack()
+void OldSpaceCollector::ProcessMarkStack(uint64_t threadId)
{
while (true) {
- auto obj = markStack_.PopBack();
- if (UNLIKELY(obj == nullptr)) {
+ TaggedObject *obj = nullptr;
+ if (!workList_->Pop(threadId, &obj)) {
break;
}
auto jsHclass = obj->GetClass();
// mark dynClass
- MarkObject(jsHclass);
+ MarkObject(threadId, jsHclass);
rootManager_.MarkObjectBody(
- obj, jsHclass, [this]([[maybe_unused]] TaggedObject *root, ObjectSlot start, ObjectSlot end) {
+ obj, jsHclass, [this, &threadId]([[maybe_unused]] TaggedObject *root, ObjectSlot start, ObjectSlot end) {
for (ObjectSlot slot = start; slot < end; slot++) {
JSTaggedValue value(slot.GetTaggedType());
if (value.IsWeak()) {
@@ -119,59 +123,13 @@ void OldSpaceCollector::ProcessMarkStack()
continue;
}
if (value.IsHeapObject()) {
- MarkObject(value.GetTaggedObject());
+ MarkObject(threadId, value.GetTaggedObject());
}
}
});
}
}
-void OldSpaceCollector::SweepSpace(Space *space, FreeListAllocator &allocator)
-{
- allocator.RebuildFreeList();
- space->EnumerateRegions([this, &allocator](Region *current) {
- auto markBitmap = current->GetMarkBitmap();
- ASSERT(markBitmap != nullptr);
- uintptr_t freeStart = current->GetBegin();
- markBitmap->IterateOverMarkedChunks([this, ¤t, &freeStart, &allocator](void *mem) {
- ASSERT(current->InRange(ToUintPtr(mem)));
- auto header = reinterpret_cast(mem);
- auto klass = header->GetClass();
- JSType jsType = klass->GetObjectType();
- auto size = klass->SizeFromJSHClass(jsType, header);
- size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT));
-
- uintptr_t freeEnd = ToUintPtr(mem);
- if (freeStart != freeEnd) {
- FreeLiveRange(allocator, current, freeStart, freeEnd);
- }
- freeStart = freeEnd + size;
- });
- uintptr_t freeEnd = current->GetEnd();
- if (freeStart != freeEnd) {
- FreeLiveRange(allocator, current, freeStart, freeEnd);
- }
- });
-}
-
-void OldSpaceCollector::SweepSpace(HugeObjectSpace *space)
-{
- Region *currentRegion = space->GetRegionList().GetFirst();
-
- while (currentRegion != nullptr) {
- Region *next = currentRegion->GetNext();
- auto markBitmap = currentRegion->GetMarkBitmap();
- bool isMarked = false;
- markBitmap->IterateOverMarkedChunks([&isMarked]([[maybe_unused]] void *mem) { isMarked = true; });
- if (!isMarked) {
- space->GetRegionList().RemoveNode(currentRegion);
- hugeSpaceFreeSize_ += currentRegion->GetCapacity();
- space->ClearAndFreeRegion(currentRegion);
- }
- currentRegion = next;
- }
-}
-
void OldSpaceCollector::SweepPhases()
{
trace::ScopedTrace scoped_trace("OldSpaceCollector::SweepPhases");
@@ -209,9 +167,6 @@ void OldSpaceCollector::SweepPhases()
heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak);
heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak);
- SweepSpace(const_cast(heap_->GetOldSpace()), oldSpaceAllocator_);
- SweepSpace(const_cast(heap_->GetNonMovableSpace()), nonMovableAllocator_);
- SweepSpace(const_cast(heap_->GetHugeObjectSpace()));
- SweepSpace(const_cast(heap_->GetMachineCodeSpace()), machineCodeSpaceAllocator_);
+ heap_->GetSweeper()->SweepPhases();
}
} // namespace panda::ecmascript
diff --git a/ecmascript/mem/old_space_collector.h b/ecmascript/mem/old_space_collector.h
index 64940351b60214b02f4a9a2ac2d0653162e1fc07..cab6403afc5d51ca48bf359f9dd7b490dcd854c5 100644
--- a/ecmascript/mem/old_space_collector.h
+++ b/ecmascript/mem/old_space_collector.h
@@ -21,6 +21,7 @@
#include "ecmascript/mem/allocator.h"
#include "ecmascript/mem/mark_stack-inl.h"
#include "ecmascript/mem/mark_word.h"
+#include "ecmascript/mem/semi_space_worker.h"
#include "ecmascript/mem/slots.h"
#include "ecmascript/mem/heap_roots.h"
#include "ecmascript/mem/remembered_set.h"
@@ -33,7 +34,7 @@ class JSHClass;
class OldSpaceCollector : public GarbageCollector {
public:
- explicit OldSpaceCollector(Heap *heap);
+ explicit OldSpaceCollector(Heap *heap, bool parallelGc);
~OldSpaceCollector() override = default;
NO_COPY_SEMANTIC(OldSpaceCollector);
NO_MOVE_SEMANTIC(OldSpaceCollector);
@@ -50,26 +51,24 @@ private:
void SweepPhases();
void FinishPhase();
- void ProcessMarkStack();
+ void ProcessMarkStack(uint64_t threadId);
void MarkObjectBody(TaggedObject *object, JSHClass *klass, const EcmaObjectRangeVisitor &visitor);
- inline void MarkObject(TaggedObject *object);
- inline void FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, uintptr_t freeEnd);
+ inline void MarkObject(uint64_t threadId, TaggedObject *object);
inline void RecordWeakReference(JSTaggedType *ref);
- void SweepSpace(Space *space, FreeListAllocator &allocator);
- void SweepSpace(HugeObjectSpace *space); // Only sweep huge space.
Heap *heap_;
HeapRootManager rootManager_;
MarkStack markStack_;
+ bool paralledGC_{false};
+ OldGCWorker *workList_{nullptr};
ProcessQueue weakProcessQueue_;
- FreeListAllocator oldSpaceAllocator_ {};
- FreeListAllocator nonMovableAllocator_ {};
- FreeListAllocator machineCodeSpaceAllocator_ {};
size_t freeSize_{0};
size_t hugeSpaceFreeSize_ = 0;
size_t oldSpaceCommitSize_ = 0;
size_t nonMoveSpaceCommitSize_ = 0;
+
+ friend class OldGCWorker;
};
} // namespace ecmascript
} // namespace panda
diff --git a/ecmascript/mem/region.h b/ecmascript/mem/region.h
index c80d1a9c0159fba30ba3d60d4a041dfd0a7e2f80..fb6d71324c8b753f882aa1f77442563c669eebf7 100644
--- a/ecmascript/mem/region.h
+++ b/ecmascript/mem/region.h
@@ -16,6 +16,7 @@
#ifndef ECMASCRIPT_MEM_REGION_H
#define ECMASCRIPT_MEM_REGION_H
+#include "ecmascript/mem/free_object_list.h"
#include "ecmascript/mem/mem.h"
#include "mem/gc/bitmap.h"
@@ -41,9 +42,11 @@ enum RegionFlags {
// NOLINTNEXTLINE(hicpp-signed-bitwise)
IS_IN_OLD_GENERATION = 1 << 6,
// NOLINTNEXTLINE(hicpp-signed-bitwise)
+ IS_IN_NON_MOVABLE_GENERATION = 1 << 7,
+ // NOLINTNEXTLINE(hicpp-signed-bitwise)
IS_IN_YOUNG_OR_OLD_GENERATION = IS_IN_YOUNG_GENERATION | IS_IN_OLD_GENERATION,
// NOLINTNEXTLINE(hicpp-signed-bitwise)
- IS_INVALID = 1 << 7,
+ IS_INVALID = 1 << 8,
};
class Region {
@@ -220,6 +223,36 @@ public:
return res;
}
+ void InitializeKind()
+ {
+ kinds_ = Span(new FreeObjectKind *[FreeObjectList::NumberOfKinds()](),
+ FreeObjectList::NumberOfKinds());
+ for (int i = 0; i < FreeObjectList::NumberOfKinds(); i++) {
+ kinds_[i] = new FreeObjectKind(i);
+ }
+ }
+
+ void DestoryKind()
+ {
+ for (auto kind : kinds_) {
+ delete kind;
+ }
+ delete[] kinds_.data();
+ }
+
+ FreeObjectKind *GetFreeObjectKind(KindType type)
+ {
+ return kinds_[type];
+ }
+
+ template
+ void EnumerateKinds(Callback cb)
+ {
+ for (auto kind : kinds_) {
+ cb(kind);
+ }
+ }
+
private:
Space *space_;
uintptr_t flags_; // Memory alignment, only low 32bits are used now
@@ -232,6 +265,7 @@ private:
RangeBitmap *markBitmap_{nullptr};
RememberedSet *crossRegionSet_{nullptr};
RememberedSet *oldToNewSet_{nullptr};
+ Span kinds_;
friend class SnapShot;
};
} // namespace ecmascript
diff --git a/ecmascript/mem/region_factory.h b/ecmascript/mem/region_factory.h
index af2bf0438bfac47d29567c65aff2f83ac3d218a5..fa70e81a23c5c947b3382ef2ce474a1828e21bb4 100644
--- a/ecmascript/mem/region_factory.h
+++ b/ecmascript/mem/region_factory.h
@@ -124,11 +124,11 @@ private:
NO_COPY_SEMANTIC(RegionFactory);
NO_MOVE_SEMANTIC(RegionFactory);
- Area *cachedArea_{nullptr};
- std::atomic annoMemoryUsage_{0};
- std::atomic maxAnnoMemoryUsage_{0};
- std::atomic nativeMemoryUsage_{0};
- std::atomic maxNativeMemoryUsage_{0};
+ Area *cachedArea_ {nullptr};
+ std::atomic annoMemoryUsage_ {0};
+ std::atomic maxAnnoMemoryUsage_ {0};
+ std::atomic nativeMemoryUsage_ {0};
+ std::atomic maxNativeMemoryUsage_ {0};
};
} // namespace panda::ecmascript
diff --git a/ecmascript/mem/semi_space_collector.cpp b/ecmascript/mem/semi_space_collector.cpp
index ef6975066f4328a0f4a42b5b9701b7fd21bfccc2..0cc31fd8f1a21f1d3e0b579c66ab187d32c8464a 100644
--- a/ecmascript/mem/semi_space_collector.cpp
+++ b/ecmascript/mem/semi_space_collector.cpp
@@ -59,7 +59,7 @@ void SemiSpaceCollector::RunPhases()
void SemiSpaceCollector::InitializePhase()
{
heap_->GetThreadPool()->WaitTaskFinish();
- gcTime_++;
+ heap_->GetSweeper()->EnsureAllTaskFinish();
auto fromSpace = heap_->GetFromSpace();
if (fromSpace->GetCommittedSize() == 0) {
heap_->InitializeFromSpace();
diff --git a/ecmascript/mem/semi_space_collector.h b/ecmascript/mem/semi_space_collector.h
index 6e5a31f62468b10c25ffdcd70d77bb02382042f0..3a76149e5c181dabf648422ac28ecca3f1f6721f 100644
--- a/ecmascript/mem/semi_space_collector.h
+++ b/ecmascript/mem/semi_space_collector.h
@@ -91,7 +91,6 @@ private:
size_t semiCopiedSize_{0};
size_t commitSize_ = 0;
uintptr_t ageMark_{0};
- size_t gcTime_{0};
friend class TlabAllocator;
friend class SemiSpaceWorker;
friend class SemiSpaceMarker;
diff --git a/ecmascript/mem/semi_space_worker.cpp b/ecmascript/mem/semi_space_worker.cpp
index dbaa62b62335f572f5a05d69ff4b9923a8080017..0df831f442d5bac5585cb79ecb728c8a322e6c55 100644
--- a/ecmascript/mem/semi_space_worker.cpp
+++ b/ecmascript/mem/semi_space_worker.cpp
@@ -19,6 +19,7 @@
#include "ecmascript/mem/compress_collector.h"
#include "ecmascript/mem/heap.h"
#include "ecmascript/mem/mark_stack.h"
+#include "ecmascript/mem/old_space_collector.h"
#include "ecmascript/mem/region_factory.h"
#include "ecmascript/mem/tlab_allocator-inl.h"
@@ -197,4 +198,32 @@ void CompressGCWorker::Initialize()
holder.aliveSize_ = 0;
}
}
+
+void OldGCWorker::Initialize()
+{
+ spaceTop_ = markSpace_;
+ markSpaceEnd_ = markSpace_ + SPACE_SIZE;
+ for (uint32_t i = 0; i < threadNum_; i++) {
+ WorkNodeHolder &holder = workList_[i];
+ holder.pushNode_ = AllocalWorkNode();
+ holder.popNode_ = AllocalWorkNode();
+ holder.weakQueue_ = new ProcessQueue();
+ holder.weakQueue_->BeginMarking(heap_, continuousQueue_[i]);
+ }
+}
+
+void OldGCWorker::PushWorkNodeToGlobal(uint32_t threadId)
+{
+ WorkNode *&pushNode = workList_[threadId].pushNode_;
+ if (!pushNode->IsEmpty()) {
+ globalWork_.Push(pushNode);
+ pushNode = AllocalWorkNode();
+
+ auto pool = heap_->GetThreadPool();
+ if (pool->GetTaskCount() < pool->GetThreadNum() - 1) {
+ pool->Submit(std::bind(&OldSpaceCollector::ProcessMarkStack, heap_->GetOldSpaceCollector(),
+ std::placeholders::_1));
+ }
+ }
+}
} // namespace panda::ecmascript
diff --git a/ecmascript/mem/semi_space_worker.h b/ecmascript/mem/semi_space_worker.h
index 2572c475e1e2bb830f8aac2ea3e9c2fb668d3efa..0a88f31f0e07a0bfb273c4ed5da607778a92fa37 100644
--- a/ecmascript/mem/semi_space_worker.h
+++ b/ecmascript/mem/semi_space_worker.h
@@ -233,6 +233,19 @@ public:
NO_COPY_SEMANTIC(CompressGCWorker);
NO_MOVE_SEMANTIC(CompressGCWorker);
};
-} // namespace panda::ecmascript
+class OldGCWorker : public Worker {
+public:
+ OldGCWorker() = delete;
+ OldGCWorker(Heap *heap, uint32_t threadNum) : Worker(heap, threadNum) {}
+
+ ~OldGCWorker() override = default;
+
+ void PushWorkNodeToGlobal(uint32_t threadId) override;
+ void Initialize() override;
+
+ NO_COPY_SEMANTIC(OldGCWorker);
+ NO_MOVE_SEMANTIC(OldGCWorker);
+};
+} // namespace panda::ecmascript
#endif // ECMASCRIPT_MEM_SEMI_SPACE_WORKER_H
diff --git a/ecmascript/mem/space.cpp b/ecmascript/mem/space.cpp
index cb83b9416ccd5e0552e14a65bf76a0db9880fe05..452b358ac65ccb49093aa9e49f8a3da13e19fcc0 100644
--- a/ecmascript/mem/space.cpp
+++ b/ecmascript/mem/space.cpp
@@ -19,6 +19,7 @@
#include "ecmascript/mem/region_factory.h"
#include "ecmascript/mem/remembered_set.h"
#include "ecmascript/mem/space-inl.h"
+#include "ecmascript/mem/space.h"
#include "libpandabase/utils/logger.h"
namespace panda::ecmascript {
@@ -37,11 +38,16 @@ void Space::Initialize()
} else if (spaceType_ == MemSpaceType::SNAPSHOT_SPACE) {
region->SetFlag(RegionFlags::IS_IN_SNAPSHOT_GENERATION);
} else if (spaceType_ == MemSpaceType::OLD_SPACE) {
+ region->InitializeKind();
region->SetFlag(RegionFlags::IS_IN_OLD_GENERATION);
} else if (spaceType_ == MemSpaceType::MACHINE_CODE_SPACE) {
+ region->InitializeKind();
region->SetFlag(RegionFlags::IS_IN_OLD_GENERATION);
int res = region->SetCodeExecutableAndReadable();
LOG_ECMA_MEM(DEBUG) << "Initialize SetCodeExecutableAndReadable" << res;
+ } else if (spaceType_ == MemSpaceType::NON_MOVABLE) {
+ region->InitializeKind();
+ region->SetFlag(RegionFlags::IS_IN_NON_MOVABLE_GENERATION);
}
AddRegion(region);
@@ -75,6 +81,11 @@ void Space::ClearAndFreeRegion(Region *region)
delete rememberedSet;
}
DecrementCommitted(region->GetCapacity());
+ if (spaceType_ == MemSpaceType::OLD_SPACE ||
+ spaceType_ == MemSpaceType::NON_MOVABLE ||
+ spaceType_ == MemSpaceType::MACHINE_CODE_SPACE) {
+ region->DestoryKind();
+ }
const_cast(heap_->GetRegionFactory())->FreeRegion(region);
}
@@ -177,6 +188,7 @@ bool OldSpace::Expand()
Region *region =
const_cast(GetHeap()->GetRegionFactory())->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE);
region->SetFlag(RegionFlags::IS_IN_OLD_GENERATION);
+ region->InitializeKind();
AddRegion(region);
return true;
}
@@ -231,8 +243,7 @@ size_t OldSpace::GetHeapObjectSize() const
{
size_t result;
size_t availableSize = GetHeap()->GetHeapManager()->GetOldSpaceAllocator().GetAvailableSize();
- size_t regionSize = GetRegionList().GetLength() * DEFAULT_REGION_SIZE;
- result = regionSize - availableSize;
+ result = GetCommittedSize() - availableSize;
result += GetHeap()->GetHugeObjectSpace()->GetHeapObjectSize();
return result;
}
@@ -250,6 +261,8 @@ bool NonMovableSpace::Expand()
}
Region *region =
const_cast(GetHeap()->GetRegionFactory())->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE);
+ region->SetFlag(IS_IN_NON_MOVABLE_GENERATION);
+ region->InitializeKind();
AddRegion(region);
return true;
}
@@ -382,6 +395,12 @@ uintptr_t HugeObjectSpace::Allocate(size_t objectSize)
return region->GetBegin();
}
+void HugeObjectSpace::Free(Region *region)
+{
+ GetRegionList().RemoveNode(region);
+ ClearAndFreeRegion(region);
+}
+
bool HugeObjectSpace::ContainObject(TaggedObject *object) const
{
auto region = GetRegionList().GetFirst();
@@ -401,12 +420,7 @@ bool HugeObjectSpace::IsLive(TaggedObject *object) const
size_t HugeObjectSpace::GetHeapObjectSize() const
{
- size_t result = 0;
- EnumerateRegions([&result](Region *current) {
- auto obj = reinterpret_cast(current->GetBegin());
- result += obj->GetObjectSize();
- });
- return result;
+ return GetCommittedSize();
}
void HugeObjectSpace::IterateOverObjects(const std::function &objectVisitor) const
@@ -430,6 +444,7 @@ bool MachineCodeSpace::Expand()
}
Region *region =
const_cast(GetHeap()->GetRegionFactory())->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE);
+ region->InitializeKind();
AddRegion(region);
int res = region->SetCodeExecutableAndReadable();
LOG_ECMA_MEM(DEBUG) << "MachineCodeSpace::Expand() SetCodeExecutableAndReadable" << res;
diff --git a/ecmascript/mem/space.h b/ecmascript/mem/space.h
index 7e6012f538ac35246ea9bd61b406878eb6703e89..25f353e2538347b8b04619b35bf56d0240fa4917 100644
--- a/ecmascript/mem/space.h
+++ b/ecmascript/mem/space.h
@@ -29,13 +29,16 @@ class Heap;
class Program;
enum MemSpaceType {
- SEMI_SPACE,
- OLD_SPACE,
+ OLD_SPACE = 0,
NON_MOVABLE,
+ MACHINE_CODE_SPACE,
HUGE_OBJECT_SPACE,
+ SEMI_SPACE,
SNAPSHOT_SPACE,
- MACHINE_CODE_SPACE,
- SPACE_TYPE_LAST // Count of different types
+ COMPRESS_SPACE,
+ SPACE_TYPE_LAST, // Count of different types
+
+ FREE_LIST_NUM = MACHINE_CODE_SPACE - OLD_SPACE + 1,
};
enum TriggerGCType {
@@ -238,6 +241,7 @@ public:
NO_COPY_SEMANTIC(HugeObjectSpace);
NO_MOVE_SEMANTIC(HugeObjectSpace);
uintptr_t Allocate(size_t objectSize);
+ void Free(Region *region);
size_t GetHeapObjectSize() const;
bool ContainObject(TaggedObject *object) const;
bool IsLive(TaggedObject *object) const;
diff --git a/ecmascript/mem/tlab_allocator-inl.h b/ecmascript/mem/tlab_allocator-inl.h
index 3a36d26b60004c612f6447f9d85c872df0feccec..d269822c4d70331176baffd0fe2c9823476022ef 100644
--- a/ecmascript/mem/tlab_allocator-inl.h
+++ b/ecmascript/mem/tlab_allocator-inl.h
@@ -24,7 +24,7 @@
#include "ecmascript/mem/tlab_allocator.h"
namespace panda::ecmascript {
-static constexpr size_t SEMIGC_YOUNG_BUFFER_SIZE = 32 * 1024;
+static constexpr size_t SEMIGC_YOUNG_BUFFER_SIZE = 31 * 1024;
static constexpr size_t OLD_BUFFER_SIZE = 255 * 1024;
TlabAllocator::TlabAllocator(Heap *heap, TriggerGCType gcType)
diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h
index 4bf334dd88b8f6f6a223b5ce6004fb519431c144..01b2f65c93ad011fe373d669ecfe28dc52993649 100644
--- a/ecmascript/napi/include/jsnapi.h
+++ b/ecmascript/napi/include/jsnapi.h
@@ -525,10 +525,10 @@ public:
};
using FunctionCallback = Local (*)(EcmaVM *, Local,
- const Local[], // NOLINTNEXTLINE(modernize-avoid-c-arrays)
+ const Local [], // NOLINTNEXTLINE(modernize-avoid-c-arrays)
int32_t, void *);
using FunctionCallbackWithNewTarget =
- Local (*)(EcmaVM *, Local, Local, const Local[], int32_t, void *);
+ Local (*)(EcmaVM *, Local, Local, const Local [], int32_t, void *);
class PUBLIC_API FunctionRef : public ObjectRef {
public:
static Local New(EcmaVM *vm, FunctionCallback nativeFunc, void *data);
diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp
index 4ab3e3ad293b811593eb9c4ee31c9cf95affc24a..bc4c9f15368a775b4036fd96fffbdc997c0d4e05 100644
--- a/ecmascript/napi/jsnapi.cpp
+++ b/ecmascript/napi/jsnapi.cpp
@@ -580,7 +580,7 @@ Local ObjectRef::Get(const EcmaVM *vm, Local key)
OperationResult ret = JSTaggedValue::GetProperty(thread, obj, keyValue);
RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm));
if (!ret.GetPropertyMetaData().IsFound()) {
- return Local();
+ return JSValueRef::Undefined(vm);
}
return JSNApiHelper::ToLocal(ret.GetValue());
}
diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp
index 7282588009227f3e99881e2fcce43a598c034e9d..4bcc0fa3acdab4fd13182d999dc4d4e02436d34a 100644
--- a/ecmascript/object_factory.cpp
+++ b/ecmascript/object_factory.cpp
@@ -290,6 +290,7 @@ JSHandle ObjectFactory::NewJSObject(const JSHandle &jshclass
NewObjectHook();
JSHandle obj(thread_, JSObject::Cast(NewDynObject(jshclass, JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS)));
JSHandle emptyArray = EmptyArray();
+ obj->InitializeHash();
obj->SetElements(thread_, emptyArray, SKIP_BARRIER);
obj->SetProperties(thread_, emptyArray, SKIP_BARRIER);
return obj;
@@ -793,10 +794,12 @@ FreeObject *ObjectFactory::FillFreeObject(uintptr_t address, size_t size, Remove
if (size >= FreeObject::SIZE_OFFSET && size < FreeObject::SIZE) {
object = reinterpret_cast(address);
object->SetClass(freeObjectWithOneFieldClass_);
+ object->SetNext(nullptr);
} else if (size >= FreeObject::SIZE) {
object = reinterpret_cast(address);
object->SetClass(freeObjectWithTwoFieldClass_);
object->SetAvailable(size);
+ object->SetNext(nullptr);
} else if (size == FreeObject::NEXT_OFFSET) {
object = reinterpret_cast(address);
object->SetClass(freeObjectWithNoneFieldClass_);
diff --git a/ecmascript/platform/platform.cpp b/ecmascript/platform/platform.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f589f3807e9a1f370137a6b60e6c52deba0057db
--- /dev/null
+++ b/ecmascript/platform/platform.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021 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/platform/platform.h"
+
+#include "sys/sysinfo.h"
+
+namespace panda::ecmascript {
+void Platform::Initialize(int threadNum)
+{
+ os::memory::LockHolder lock(mutex_);
+ if (isInitialized_++ <= 0) {
+ runner_ = std::make_unique(TheMostSuitableThreadNum(threadNum));
+ }
+}
+
+void Platform::Destory()
+{
+ os::memory::LockHolder lock(mutex_);
+ if (--isInitialized_ <= 0) {
+ runner_->Terminate();
+ }
+}
+
+int Platform::TheMostSuitableThreadNum(int threadNum) const
+{
+ if (threadNum > 0) {
+ return std::min(threadNum, MAX_PLATFORM_THREAD_NUM);
+ }
+ int numOfCpuCore = get_nprocs() - 1;
+ return std::min(numOfCpuCore, MAX_PLATFORM_THREAD_NUM);
+}
+} // namespace panda::ecmascript
diff --git a/ecmascript/platform/platform.h b/ecmascript/platform/platform.h
new file mode 100644
index 0000000000000000000000000000000000000000..46411111fafc515ef5d9806d67b7734a4e402865
--- /dev/null
+++ b/ecmascript/platform/platform.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021 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_ECMASCRIPT_PALTFORM_PLATFORM_H
+#define PANDA_ECMASCRIPT_PALTFORM_PLATFORM_H
+
+#include
+
+#include "ecmascript/platform/runner.h"
+#include "os/mutex.h"
+
+namespace panda::ecmascript {
+class Platform {
+public:
+ static Platform *GetCurrentPlatform()
+ {
+ static Platform platform;
+ return &platform;
+ }
+
+ Platform() = default;
+ ~Platform() = default;
+
+ NO_COPY_SEMANTIC(Platform);
+ NO_MOVE_SEMANTIC(Platform);
+
+ void Initialize(int threadNum = DEFAULT_PLATFORM_THREAD_NUM);
+ void Destory();
+
+ void PostTask(std::unique_ptr task) const
+ {
+ ASSERT(isInitialized_ > 0);
+ runner_->PostTask(std::move(task));
+ }
+
+private:
+ static constexpr uint32_t MAX_PLATFORM_THREAD_NUM = 7;
+ static constexpr uint32_t DEFAULT_PLATFORM_THREAD_NUM = 0;
+
+ int TheMostSuitableThreadNum(int threadNum) const;
+
+ std::unique_ptr runner_;
+ int isInitialized_ = 0;
+ os::memory::Mutex mutex_;
+};
+} // namespace panda::ecmascript
+#endif // PANDA_ECMASCRIPT_PALTFORM_PLATFORM_H
diff --git a/ecmascript/platform/runner.cpp b/ecmascript/platform/runner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..12d7dcfcdaf93a3dd112ef6ade04cd028cb9bbb0
--- /dev/null
+++ b/ecmascript/platform/runner.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021 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/platform/runner.h"
+
+#include
+#include
+
+#include "os/thread.h"
+
+namespace panda::ecmascript {
+Runner::Runner(int threadNum)
+{
+ for (int i = 0; i < threadNum; i++) {
+ std::unique_ptr thread = std::make_unique(&Runner::Run, this);
+ os::thread::SetThreadName(thread->native_handle(), "GC_WorkerThread");
+ threadPool_.emplace_back(std::move(thread));
+ }
+}
+
+void Runner::Terminate()
+{
+ taskQueue_.Terminate();
+ int threadNum = threadPool_.size();
+ for (int i = 0; i < threadNum; i++) {
+ threadPool_.at(i)->join();
+ }
+ threadPool_.clear();
+}
+
+void Runner::Run()
+{
+ while (std::unique_ptr task = taskQueue_.PopTask()) {
+ task->Run();
+ }
+}
+} // namespace panda::ecmascript
diff --git a/ecmascript/platform/runner.h b/ecmascript/platform/runner.h
new file mode 100644
index 0000000000000000000000000000000000000000..eea822ecf025e12df9b23b61a041705c9626f530
--- /dev/null
+++ b/ecmascript/platform/runner.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021 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_ECMASCRIPT_PLATFORM_RUNNER_H
+#define PANDA_ECMASCRIPT_PLATFORM_RUNNER_H
+
+#include
+#include
+#include
+
+#include "ecmascript/platform/task_queue.h"
+
+namespace panda::ecmascript {
+class Runner {
+public:
+ explicit Runner(int threadNum);
+ ~Runner() = default;
+
+ NO_COPY_SEMANTIC(Runner);
+ NO_MOVE_SEMANTIC(Runner);
+
+ void PostTask(std::unique_ptr task)
+ {
+ taskQueue_.PostTask(std::move(task));
+ }
+
+ void Terminate();
+
+private:
+ void Run();
+
+ std::vector> threadPool_ {};
+ TaskQueue taskQueue_ {};
+};
+} // namespace panda::ecmascript
+#endif // PANDA_ECMASCRIPT_PLATFORM_RUNNER_H
diff --git a/ecmascript/platform/task.h b/ecmascript/platform/task.h
new file mode 100644
index 0000000000000000000000000000000000000000..e2bcc7b5f2d6596152ce652e1f794d79db6ca53e
--- /dev/null
+++ b/ecmascript/platform/task.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021 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_ECMASCRIPT_PLATFORM_TASK_H
+#define PANDA_ECMASCRIPT_PLATFORM_TASK_H
+
+#include "macros.h"
+
+namespace panda::ecmascript {
+class Task {
+public:
+ Task() = default;
+ virtual ~Task() = default;
+ virtual bool Run() = 0;
+
+ NO_COPY_SEMANTIC(Task);
+ NO_MOVE_SEMANTIC(Task);
+};
+} // namespace panda::ecmascript
+#endif // PANDA_ECMASCRIPT_PLATFORM_TASK_H
diff --git a/ecmascript/platform/task_queue.cpp b/ecmascript/platform/task_queue.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b90c20556984aafedb5315534488305cb2fc6a5a
--- /dev/null
+++ b/ecmascript/platform/task_queue.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021 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/platform/task_queue.h"
+
+namespace panda::ecmascript {
+void TaskQueue::PostTask(std::unique_ptr task)
+{
+ os::memory::LockHolder holder(mtx_);
+ ASSERT(!terminate_);
+ tasks_.push(std::move(task));
+ cv_.Signal();
+}
+
+std::unique_ptr TaskQueue::PopTask()
+{
+ os::memory::LockHolder holder(mtx_);
+ while (true) {
+ if (!tasks_.empty()) {
+ std::unique_ptr task = std::move(tasks_.front());
+ tasks_.pop();
+ return task;
+ }
+ if (terminate_) {
+ cv_.SignalAll();
+ return nullptr;
+ }
+ cv_.Wait(&mtx_);
+ }
+}
+
+void TaskQueue::Terminate()
+{
+ os::memory::LockHolder holder(mtx_);
+ terminate_ = true;
+ cv_.SignalAll();
+}
+} // namespace panda::ecmascript
diff --git a/ecmascript/platform/task_queue.h b/ecmascript/platform/task_queue.h
new file mode 100644
index 0000000000000000000000000000000000000000..121eb7cc51ee34b2f81ffae408dbcf889b0d84f6
--- /dev/null
+++ b/ecmascript/platform/task_queue.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021 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_ECMASCRIPT_PLATFORM_TASK_QUEUE_H
+#define PANDA_ECMASCRIPT_PLATFORM_TASK_QUEUE_H
+
+#include
+#include
+#include
+#include
+
+#include "ecmascript/platform/task.h"
+#include "os/mutex.h"
+
+namespace panda::ecmascript {
+class TaskQueue {
+public:
+ TaskQueue() = default;
+ ~TaskQueue() = default;
+
+ NO_COPY_SEMANTIC(TaskQueue);
+ NO_MOVE_SEMANTIC(TaskQueue);
+
+ void PostTask(std::unique_ptr task);
+ std::unique_ptr PopTask();
+
+ void Terminate();
+
+private:
+ std::queue> tasks_;
+
+ std::atomic_bool terminate_ = false;
+ os::memory::Mutex mtx_;
+ os::memory::ConditionVariable cv_;
+};
+} // namespace panda::ecmascript
+#endif // PANDA_ECMASCRIPT_PLATFORM_TASK_QUEUE_H
diff --git a/ecmascript/tests/BUILD.gn b/ecmascript/tests/BUILD.gn
index d87cbea2d3bbb9866ef4ae3609f73e332e8a7f9a..61227b4cd8f96c5e3836f224357db29510fceead 100644
--- a/ecmascript/tests/BUILD.gn
+++ b/ecmascript/tests/BUILD.gn
@@ -660,6 +660,7 @@ host_unittest_action("GcTest") {
sources = [
# test file
"gc_test.cpp",
+ "concurrent_sweep_test.cpp",
]
configs = [
diff --git a/ecmascript/tests/concurrent_sweep_test.cpp b/ecmascript/tests/concurrent_sweep_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6759428f34878ffb5e8e3043145ef54077f6bd4b
--- /dev/null
+++ b/ecmascript/tests/concurrent_sweep_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2021 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/tests/test_helper.h"
+
+#include "ecmascript/ecma_vm.h"
+#include "ecmascript/global_env.h"
+#include "ecmascript/js_handle.h"
+
+using namespace panda::ecmascript;
+
+namespace panda::test {
+class ConcurrentSweepTest : public testing::Test {
+public:
+ static void SetUpTestCase()
+ {
+ GTEST_LOG_(INFO) << "SetUpTestCase";
+ }
+
+ static void TearDownTestCase()
+ {
+ GTEST_LOG_(INFO) << "TearDownCase";
+ }
+
+ void SetUp() override
+ {
+ TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
+ }
+
+ void TearDown() override
+ {
+ TestHelper::DestroyEcmaVMWithScope(instance, scope);
+ }
+
+ PandaVM *instance {nullptr};
+ EcmaHandleScope *scope {nullptr};
+ JSThread *thread;
+};
+
+TEST_F(ConcurrentSweepTest, ConcurrentSweep)
+{
+ auto vm = EcmaVM::Cast(instance);
+ const uint8_t *utf8 = reinterpret_cast("test");
+ JSHandle test1(thread, EcmaString::CreateFromUtf8(utf8, 4, vm, false));
+ if (vm->IsInitialized()) {
+ vm->CollectGarbage(ecmascript::TriggerGCType::OLD_GC);
+ }
+ JSHandle test2(thread, EcmaString::CreateFromUtf8(utf8, 4, vm, false));
+ ASSERT_EQ(test1->GetLength(), 4);
+ ASSERT_NE(test1.GetTaggedValue().GetHeapObject(), test2.GetTaggedValue().GetHeapObject());
+}
+} // namespace panda::test
diff --git a/ecmascript/vmstat/caller_stat.h b/ecmascript/vmstat/caller_stat.h
index 88bc26f71cf524698f7d321d7f61701ac966f3f9..58db728f61f474b0313876fdee07f0e326d9f61e 100644
--- a/ecmascript/vmstat/caller_stat.h
+++ b/ecmascript/vmstat/caller_stat.h
@@ -66,10 +66,10 @@ public:
}
private:
- CString name_{};
- uint64_t totalCount_{0};
- uint64_t totalTime_{0};
- uint64_t maxTime_{0};
+ CString name_ {};
+ uint64_t totalCount_ {0};
+ uint64_t totalTime_ {0};
+ uint64_t maxTime_ {0};
};
class PandaRuntimeTimer {
@@ -109,10 +109,10 @@ private:
PandaRuntimeTimer *Stop();
void Pause(uint64_t now);
void Resume(uint64_t now);
- PandaRuntimeCallerStat *callerStat_{nullptr};
- PandaRuntimeTimer *parent_{nullptr};
- uint64_t start_{0};
- uint64_t elapsed_{0};
+ PandaRuntimeCallerStat *callerStat_ {nullptr};
+ PandaRuntimeTimer *parent_ {nullptr};
+ uint64_t start_ {0};
+ uint64_t elapsed_ {0};
friend class EcmaRuntimeStat;
};