diff --git a/BUILD.gn b/BUILD.gn index bea20a7536327ea350d4a783d3a49699ed79edf5..49a8fcc0c0dac9c8101af2aec17b7e387b168244 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -65,7 +65,7 @@ group("ark_js_host_unittest") { deps += [ "//ark/js_runtime:libark_jsruntime(${host_toolchain})", "//ark/js_runtime/ecmascript/builtins/tests:host_unittest", - "//ark/js_runtime/ecmascript/hprof/tests:host_unittest", + #"//ark/js_runtime/ecmascript/hprof/tests:host_unittest", "//ark/js_runtime/ecmascript/js_vm:ark_js_vm(${host_toolchain})", "//ark/js_runtime/ecmascript/napi/test:host_unittest", "//ark/js_runtime/ecmascript/regexp/tests:host_unittest", diff --git a/ecmascript/base/config.h b/ecmascript/base/config.h index 229c2eba8c86adcd58d0b1a37a2789183fc93626..72f60cb0778854aaf5f23da13f8c9d8a902ec8f1 100644 --- a/ecmascript/base/config.h +++ b/ecmascript/base/config.h @@ -20,9 +20,37 @@ namespace panda::ecmascript { #define ARK_INLINE __attribute__((always_inline)) #define ARK_NOINLINE __attribute__((noinline)) +#define ECMASCRIPT_ENABLE_DEBUG_MODE 0 #define ECMASCRIPT_ENABLE_RUNTIME_STAT 0 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define ECMASCRIPT_ENABLE_IC 1 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define ECMASCRIPT_ENABLE_THREAD_CHECK 0 + +/*** + * 1. close ic + * 2. close parallel gc + * 3. enable gc logs + * 4. enable handle-scope zap, zap reclaimed regions + * 5. switch gc mode to full gc + * 6. enable Cast() check + * 7. enable verify heap + */ +#if ECMASCRIPT_ENABLE_DEBUG_MODE + #define ECMASCRIPT_ENABLE_IC 0 + #define ECMASCRIPT_DISABLE_PARALLEL_GC 1 + #define ECMASCRIPT_ENABLE_GC_LOG 1 + #define ECMASCRIPT_ENABLE_ZAP_MEM 1 + #define ECMASCRIPT_SWITCH_GC_MODE_TO_COMPRESS_GC 1 + #define ECMASCRIPT_ENABLE_CAST_CHECK 1 + #define ECMASCRIPT_ENABLE_HEAP_VERIFY 1 + #define ECMASCRIPT_ENABLE_THREAD_CHECK 1 +#else + #define ECMASCRIPT_ENABLE_IC 1 + #define ECMASCRIPT_DISABLE_PARALLEL_GC 0 + #define ECMASCRIPT_ENABLE_GC_LOG 0 + #define ECMASCRIPT_ENABLE_ZAP_MEM 0 + #define ECMASCRIPT_SWITCH_GC_MODE_TO_COMPRESS_GC 0 + #define ECMASCRIPT_ENABLE_CAST_CHECK 0 + #define ECMASCRIPT_ENABLE_HEAP_VERIFY 0 + #define ECMASCRIPT_ENABLE_THREAD_CHECK 0 +#endif } // namespace panda::ecmascript #endif // ECMASCRIPT_BASE_CONFIG_H diff --git a/ecmascript/ecma_macros.h b/ecmascript/ecma_macros.h index b13285f0a5336d52b3b38fea8a94a2285664b763..eb749d73271232ddb4fe0a931146be70fe8da0c0 100644 --- a/ecmascript/ecma_macros.h +++ b/ecmascript/ecma_macros.h @@ -371,14 +371,14 @@ // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECL_VISIT_OBJECT(BEGIN_OFFSET, SIZE) \ - void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ + void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ { \ visitor(this, ObjectSlot(ToUintPtr(this) + BEGIN_OFFSET), ObjectSlot(ToUintPtr(this) + SIZE)); \ } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECL_VISIT_OBJECT_FOR_JS_OBJECT(PARENTCLASS, BEGIN_OFFSET, SIZE) \ - void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ + void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ { \ VisitObjects(visitor); \ /* visit in object fields */ \ @@ -396,4 +396,52 @@ visitor(this, ObjectSlot(ToUintPtr(this) + BEGIN_OFFSET), ObjectSlot(ToUintPtr(this) + SIZE)); \ } +#if ECMASCRIPT_ENABLE_CAST_CHECK + #define CAST_CHECK(CAST_TYPE, CHECK_METHOD) \ + static inline CAST_TYPE *Cast(ObjectHeader *object) \ + { \ + if (!JSTaggedValue(object).CHECK_METHOD()) { \ + std::abort(); \ + } \ + return static_cast(object); \ + } \ + static inline const CAST_TYPE *ConstCast(const ObjectHeader *object) \ + { \ + if (!JSTaggedValue(object).CHECK_METHOD()) { \ + std::abort(); \ + } \ + return static_cast(object); \ + } +# else + #define CAST_CHECK(CAST_TYPE, CHECK_METHOD) \ + static inline CAST_TYPE *Cast(ObjectHeader *object) \ + { \ + ASSERT(JSTaggedValue(object).CHECK_METHOD()); \ + return static_cast(object); \ + } \ + static const inline CAST_TYPE *ConstCast(const ObjectHeader *object) \ + { \ + ASSERT(JSTaggedValue(object).CHECK_METHOD()); \ + return static_cast(object); \ + } +#endif + +#if ECMASCRIPT_ENABLE_CAST_CHECK + #define CAST_CHECK_TAGGEDVALUE(CAST_TYPE, CHECK_METHOD) \ + static inline CAST_TYPE *Cast(JSTaggedValue value) \ + { \ + if (value.IsHeapObject() && value.GetTaggedObject()->GetClass()->CHECK_METHOD()) { \ + return static_cast(value.GetTaggedObject()); \ + } \ + std::abort(); \ + } +# else + #define CAST_CHECK_TAGGEDVALUE(CAST_TYPE, CHECK_METHOD) \ + static inline CAST_TYPE *Cast(JSTaggedValue value) \ + { \ + ASSERT(value.IsHeapObject() && value.GetTaggedObject()->GetClass()->CHECK_METHOD()); \ + return static_cast(value.GetTaggedObject()); \ + } +#endif + #endif // ECMASCRIPT_ECMA_MACROS_H diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index fd4b50b2c722b23b3b1d57640e208a8aebd1a2c8..54cf9ca40740d8a6b50fddde8c20286e513484a1 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -242,7 +242,6 @@ EcmaVM::~EcmaVM() ClearBufferData(); if (gcStats_ != nullptr) { - gcStats_->PrintStatisticResult(); chunk_.Delete(gcStats_); gcStats_ = nullptr; } @@ -722,4 +721,4 @@ void EcmaVM::SetupRegExpResultCache() { regexpCache_ = builtins::RegExpExecResultCache::CreateCacheTable(thread_); } -} // namespace panda::ecmascript +} // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/js_arguments.h b/ecmascript/js_arguments.h index ba69c599d5450d3169f77fa0bae8ed6cf0ae6be2..2c2d0f949eaae60951e8feaeab1bbcdd22686f51 100644 --- a/ecmascript/js_arguments.h +++ b/ecmascript/js_arguments.h @@ -30,10 +30,7 @@ public: static constexpr int CALLER_INLINE_PROPERTY_INDEX = 2; static constexpr int CALLEE_INLINE_PROPERTY_INDEX = 3; - static JSArguments *Cast(ObjectHeader *object) - { - return static_cast(object); - } + CAST_CHECK(JSArguments, IsArguments); // 9.4.4.1 [[GetOwnProperty]] (P) static bool GetOwnProperty(JSThread *thread, const JSHandle &args, const JSHandle &key, diff --git a/ecmascript/js_array.h b/ecmascript/js_array.h index 9a15eb47a41d81f1373c54cf1195bbce84afc9e8..16e60f26b2e6d99c8a4e91992cd816ab1adba9f7 100644 --- a/ecmascript/js_array.h +++ b/ecmascript/js_array.h @@ -28,11 +28,7 @@ class JSArray : public JSObject { public: static constexpr int LENGTH_INLINE_PROPERTY_INDEX = 0; - static JSArray *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSArray()); - return static_cast(object); - } + CAST_CHECK(JSArray, IsJSArray); static JSHandle ArrayCreate(JSThread *thread, JSTaggedNumber length); static JSHandle ArrayCreate(JSThread *thread, JSTaggedNumber length, diff --git a/ecmascript/js_array_iterator.h b/ecmascript/js_array_iterator.h index 7c8427869b7718caebe0ad605afadcb8eeea8241..77e7d84371a1341f71cfc4213e14eab238983873 100644 --- a/ecmascript/js_array_iterator.h +++ b/ecmascript/js_array_iterator.h @@ -22,11 +22,8 @@ namespace panda::ecmascript { class JSArrayIterator : public JSObject { public: - static JSArrayIterator *Cast(ObjectHeader *obj) - { - ASSERT(JSTaggedValue(obj).IsJSArrayIterator()); - return static_cast(obj); - } + CAST_CHECK(JSArrayIterator, IsJSArrayIterator); + static JSTaggedValue Next(EcmaRuntimeCallInfo *argv); static constexpr size_t ITERATED_ARRAY_OFFSET = JSObject::SIZE; diff --git a/ecmascript/js_arraybuffer.h b/ecmascript/js_arraybuffer.h index 18afaf06c33f50bb85b774e0d0308738d715fcba..7b7c7baf03a81dbf2305e3bc104af29f7316e440 100644 --- a/ecmascript/js_arraybuffer.h +++ b/ecmascript/js_arraybuffer.h @@ -21,10 +21,8 @@ namespace panda::ecmascript { class JSArrayBuffer final : public JSObject { public: - static JSArrayBuffer *Cast(ObjectHeader *object) - { - return static_cast(object); - } + CAST_CHECK(JSArrayBuffer, IsArrayBuffer); + // 6.2.6.2 static void CopyDataBlockBytes(JSTaggedValue toBlock, JSTaggedValue fromBlock, int32_t fromIndex, int32_t count); diff --git a/ecmascript/js_async_function.h b/ecmascript/js_async_function.h index a79b7bf136bd26c59f16c31b8dd04168e4c20492..7e94d15bb9e174ee9e2855cb105f619d9707e314 100644 --- a/ecmascript/js_async_function.h +++ b/ecmascript/js_async_function.h @@ -23,11 +23,7 @@ namespace panda::ecmascript { class JSAsyncAwaitStatusFunction : public JSFunction { public: - static JSAsyncAwaitStatusFunction *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSAsyncAwaitStatusFunction()); - return static_cast(object); - } + CAST_CHECK(JSAsyncAwaitStatusFunction, IsJSAsyncAwaitStatusFunction); static JSHandle AsyncFunctionAwaitFulfilled(JSThread *thread, const JSHandle &func, diff --git a/ecmascript/js_collator.h b/ecmascript/js_collator.h index 77b21885bf3eb8111eab861d78b7d5be3e2d174f..da7fe9614fc7331f528fc984b767ea385a628fe2 100644 --- a/ecmascript/js_collator.h +++ b/ecmascript/js_collator.h @@ -34,11 +34,7 @@ public: static const std::map uColAttributeValueMap; - static JSCollator *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSCollator()); - return reinterpret_cast(object); - } + CAST_CHECK(JSCollator, IsJSCollator); static constexpr size_t ICU_FIELD_OFFSET = JSObject::SIZE; diff --git a/ecmascript/js_dataview.h b/ecmascript/js_dataview.h index 4afef0b855e2a9a9f20412e99a69c3f571cabbf0..9d48627096316f01fd5e8fa26b5d705eb5844ff1 100644 --- a/ecmascript/js_dataview.h +++ b/ecmascript/js_dataview.h @@ -22,10 +22,8 @@ namespace panda::ecmascript { enum class DataViewType : uint8_t { FLOAT32 = 0, FLOAT64, INT8, INT16, INT32, UINT8, UINT16, UINT32, UINT8_CLAMPED }; class JSDataView : public JSObject { public: - static JSDataView *Cast(ObjectHeader *object) - { - return static_cast(object); - } + CAST_CHECK(JSDataView, IsDataView); + static int32_t GetElementSize(DataViewType type); static constexpr size_t DATA_VIEW_OFFSET = JSObject::SIZE; diff --git a/ecmascript/js_date.h b/ecmascript/js_date.h index c0040e6cdf5af1a8fd148e047f8f29f98f535613..a9341fe9e89ec69e0539caab8cea63797d75386c 100644 --- a/ecmascript/js_date.h +++ b/ecmascript/js_date.h @@ -63,10 +63,8 @@ public: }; class JSDate : public JSObject { public: - static JSDate *Cast(ObjectHeader *object) - { - return static_cast(object); - } + CAST_CHECK(JSDate, IsDate); + static constexpr size_t TIME_VALUE_OFFSET = JSObject::SIZE; ACCESSORS(TimeValue, TIME_VALUE_OFFSET, LOCAL_TIME_OFFSET) ACCESSORS(LocalOffset, LOCAL_TIME_OFFSET, SIZE) // localoffset in min diff --git a/ecmascript/js_date_time_format.h b/ecmascript/js_date_time_format.h index eaedd7f34c8734bfaedf19a239695627f4e725b1..85c9d1126fd4b0fb81166484ddc5a2dd84220a5e 100644 --- a/ecmascript/js_date_time_format.h +++ b/ecmascript/js_date_time_format.h @@ -86,11 +86,7 @@ private: class JSDateTimeFormat : public JSObject { public: - static JSDateTimeFormat *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSDateTimeFormat()); - return reinterpret_cast(object); - } + CAST_CHECK(JSDateTimeFormat, IsJSDateTimeFormat); static constexpr size_t LOCALE_OFFSET = JSObject::SIZE; diff --git a/ecmascript/js_for_in_iterator.h b/ecmascript/js_for_in_iterator.h index a33690a249383cf9287a4668696053df8b2e2130..328c940d5ed6476786200629fe53c01f46b0199e 100644 --- a/ecmascript/js_for_in_iterator.h +++ b/ecmascript/js_for_in_iterator.h @@ -24,10 +24,7 @@ namespace panda::ecmascript { class JSForInIterator : public JSObject { public: - static JSForInIterator *Cast(ObjectHeader *object) - { - return static_cast(object); - } + CAST_CHECK(JSForInIterator, IsForinIterator); static std::pair NextInternal(JSThread *thread, const JSHandle &it); diff --git a/ecmascript/js_function.h b/ecmascript/js_function.h index 316399e1aaeb4c8b2894f4406506734c3750dba0..663ef51a303b0e73970d4a91f9fca257415be740 100644 --- a/ecmascript/js_function.h +++ b/ecmascript/js_function.h @@ -29,17 +29,7 @@ class JSThread; class JSFunctionBase : public JSObject { public: - static JSFunctionBase *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSFunctionBase()); - return static_cast(object); - } - - static const JSFunctionBase *ConstCast(const ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSFunctionBase()); - return static_cast(object); - } + CAST_CHECK(JSFunctionBase, IsJSFunctionBase); inline void SetConstructor(bool flag) { @@ -71,11 +61,7 @@ public: static constexpr int CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX = 1; /* -------------- Common API Begin, Don't change those interface!!! ----------------- */ - static JSFunction *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSFunction()); - return static_cast(object); - } + CAST_CHECK(JSFunction, IsJSFunction); static void InitializeJSFunction(JSThread *thread, const JSHandle &env, const JSHandle &func, FunctionKind kind = FunctionKind::NORMAL_FUNCTION, bool strict = true); @@ -303,11 +289,7 @@ private: class JSGeneratorFunction : public JSFunction { public: - static JSGeneratorFunction *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsGeneratorFunction()); - return static_cast(object); - } + CAST_CHECK(JSGeneratorFunction, IsGeneratorFunction); static constexpr size_t SIZE = JSFunction::SIZE; @@ -318,11 +300,7 @@ public: class JSBoundFunction : public JSFunctionBase { public: - static JSBoundFunction *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsBoundFunction()); - return static_cast(object); - } + CAST_CHECK(JSBoundFunction, IsBoundFunction); // 9.4.1.1[[Call]](thisArgument, argumentsList) static JSTaggedValue CallInternal(JSThread *thread, const JSHandle &func); @@ -343,11 +321,7 @@ public: class JSProxyRevocFunction : public JSFunction { public: - static JSProxyRevocFunction *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsProxyRevocFunction()); - return static_cast(object); - } + CAST_CHECK(JSProxyRevocFunction, IsProxyRevocFunction); static void ProxyRevocFunctions(const JSThread *thread, const JSHandle &revoker); @@ -362,11 +336,7 @@ public: // ResolveFunction/RejectFunction class JSPromiseReactionsFunction : public JSFunction { public: - static JSPromiseReactionsFunction *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSPromiseReactionFunction()); - return static_cast(object); - } + CAST_CHECK(JSPromiseReactionsFunction, IsJSPromiseReactionFunction); static constexpr size_t PROMISE_OFFSET = JSFunction::SIZE; ACCESSORS(Promise, PROMISE_OFFSET, ALREADY_RESOLVED_OFFSET); @@ -380,11 +350,7 @@ public: // ExecutorFunction class JSPromiseExecutorFunction : public JSFunction { public: - static JSPromiseExecutorFunction *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSPromiseExecutorFunction()); - return static_cast(object); - } + CAST_CHECK(JSPromiseExecutorFunction, IsJSPromiseExecutorFunction); static constexpr size_t CAPABILITY_OFFSET = JSFunction::SIZE; ACCESSORS(Capability, CAPABILITY_OFFSET, SIZE); @@ -396,11 +362,7 @@ public: class JSPromiseAllResolveElementFunction : public JSFunction { public: - static JSPromiseAllResolveElementFunction *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSPromiseAllResolveElementFunction()); - return static_cast(object); - } + CAST_CHECK(JSPromiseAllResolveElementFunction, IsJSPromiseAllResolveElementFunction); static constexpr size_t INDEX_OFFSET = JSFunction::SIZE; ACCESSORS(Index, INDEX_OFFSET, VALUES_OFFSET); @@ -416,11 +378,7 @@ public: class JSIntlBoundFunction : public JSFunction { public: - static JSIntlBoundFunction *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSIntlBoundFunction()); - return static_cast(object); - } + CAST_CHECK(JSIntlBoundFunction, IsJSIntlBoundFunction); static JSTaggedValue IntlNameGetter(JSThread *thread, const JSHandle &self); diff --git a/ecmascript/js_generator_object.h b/ecmascript/js_generator_object.h index faf1796618f7251ff848ef378747d3250f8813c7..4365d6f811f7c49c6fdce34bc8bc88894a7d249b 100644 --- a/ecmascript/js_generator_object.h +++ b/ecmascript/js_generator_object.h @@ -30,11 +30,7 @@ enum class JSGeneratorState { class GeneratorContext : TaggedObject { public: - static GeneratorContext *Cast(ObjectHeader *object) - { - ASSERT(!JSTaggedValue(object).IsJSHClass()); - return static_cast(object); - } + CAST_CHECK(GeneratorContext, IsGeneratorContext); static constexpr size_t GENERATOR_REGS_ARRAY_OFFSET = TaggedObjectSize(); ACCESSORS(RegsArray, GENERATOR_REGS_ARRAY_OFFSET, GENERATOR_METHOD_OFFSET) @@ -50,11 +46,7 @@ public: class JSGeneratorObject : public JSObject { public: - static JSGeneratorObject *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsGeneratorObject()); - return static_cast(object); - } + CAST_CHECK(JSGeneratorObject, IsGeneratorObject); static constexpr size_t GENERATOR_STATE_OFFSET = JSObject::SIZE; ACCESSORS(GeneratorState, GENERATOR_STATE_OFFSET, GENERATOR_CONTEXT_OFFSET) @@ -88,11 +80,7 @@ public: class JSAsyncFuncObject : public JSGeneratorObject { public: - static JSAsyncFuncObject *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsAsyncFuncObject()); - return static_cast(object); - } + CAST_CHECK(JSAsyncFuncObject, IsAsyncFuncObject); static constexpr size_t GENERATOR_PROMISE_OFFSET = JSGeneratorObject::SIZE; ACCESSORS(Promise, GENERATOR_PROMISE_OFFSET, SIZE); diff --git a/ecmascript/js_hclass.h b/ecmascript/js_hclass.h index 7f29a4976a82fc03ea09532c689d0f1a5d39347e..d9c2a9475971a422e7c7ce93418d3c28652a87ad 100644 --- a/ecmascript/js_hclass.h +++ b/ecmascript/js_hclass.h @@ -722,6 +722,11 @@ public: return jsType == JSType::JS_GENERATOR_OBJECT || jsType == JSType::JS_ASYNC_FUNC_OBJECT; } + inline bool IsGeneratorContext() const + { + return GetObjectType() == JSType::JS_GENERATOR_CONTEXT; + } + inline bool IsAsyncFuncObject() const { return GetObjectType() == JSType::JS_ASYNC_FUNC_OBJECT; diff --git a/ecmascript/js_map.h b/ecmascript/js_map.h index 7b2a90e3479c023a1904ba3d0bd9df8690d6e383..aa0e4ba4b23ab79c2cabb7613424be24767fa6d3 100644 --- a/ecmascript/js_map.h +++ b/ecmascript/js_map.h @@ -23,10 +23,8 @@ namespace panda::ecmascript { class JSMap : public JSObject { public: - static JSMap *Cast(ObjectHeader *object) - { - return static_cast(object); - } + CAST_CHECK(JSMap, IsJSMap); + static bool Delete(const JSThread *thread, const JSHandle &map, const JSHandle &key); static void Set(JSThread *thread, const JSHandle &map, const JSHandle &key, diff --git a/ecmascript/js_number_format.h b/ecmascript/js_number_format.h index bf0791b9c87366711cdbac0d3c715e19c881580f..8f7c97b6da5da2ebc7ab0d8a0a6dbff267a1071a 100644 --- a/ecmascript/js_number_format.h +++ b/ecmascript/js_number_format.h @@ -51,11 +51,7 @@ static const std::set sanctionedUnit({ "acre", "bit", "byte", "cels class JSNumberFormat : public JSObject { public: - static JSNumberFormat *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSNumberFormat()); - return reinterpret_cast(object); - } + CAST_CHECK(JSNumberFormat, IsJSNumberFormat); static constexpr size_t LOCALE_OFFSET = JSObject::SIZE; diff --git a/ecmascript/js_object-inl.h b/ecmascript/js_object-inl.h index fdf6bb49e44e4b6b7084aef083db1cbc51e40662..7208fa4581fbe46937574e6ebdc6f1c104521e1f 100644 --- a/ecmascript/js_object-inl.h +++ b/ecmascript/js_object-inl.h @@ -23,12 +23,6 @@ #include "ecmascript/tagged_array-inl.h" namespace panda::ecmascript { -inline ECMAObject *ECMAObject::Cast(ObjectHeader *object) -{ - ASSERT(JSTaggedValue(object).IsECMAObject()); - return static_cast(object); -} - inline void ECMAObject::SetBuiltinsCtorMode() { GetClass()->SetBuiltinsCtor(true); diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h index 9030b10ef678b22ae3c335ce8fd41b5e2fec85e8..e9a95dd860a86cbefc0d41435c4f5dd02f670d2a 100644 --- a/ecmascript/js_object.h +++ b/ecmascript/js_object.h @@ -327,7 +327,8 @@ private: class ECMAObject : public TaggedObject { public: - static ECMAObject *Cast(ObjectHeader *object); + CAST_CHECK(ECMAObject, IsECMAObject); + void SetBuiltinsCtorMode(); bool IsBuiltinsConstructor() const; void SetCallable(bool flag); @@ -372,17 +373,8 @@ public: static constexpr int MAX_GAP = 1024; static constexpr uint32_t MAX_ELEMENT_INDEX = std::numeric_limits::max(); - static inline JSObject *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsECMAObject()); - return static_cast(object); - } - - static inline JSObject *Cast(JSTaggedValue value) - { - ASSERT(value.IsHeapObject() && value.GetTaggedObject()->GetClass()->IsECMAObject()); - return static_cast(value.GetTaggedObject()); - } + CAST_CHECK(JSObject, IsECMAObject); + CAST_CHECK_TAGGEDVALUE(JSObject, IsECMAObject); // ecma6.0 6.2.4.4 static JSHandle FromPropertyDescriptor(JSThread *thread, const PropertyDescriptor &desc); diff --git a/ecmascript/js_plural_rules.h b/ecmascript/js_plural_rules.h index 1e87fa0287fb286b4b24fb7c30923d17f1e595d0..42b033ff40baa0721d14576438b0449f16e20bac 100644 --- a/ecmascript/js_plural_rules.h +++ b/ecmascript/js_plural_rules.h @@ -29,11 +29,7 @@ constexpr int MXFD_DEFAULT = 3; class JSPluralRules : public JSObject { public: - static JSPluralRules *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSPluralRules()); - return reinterpret_cast(object); - } + CAST_CHECK(JSPluralRules, IsJSPluralRules); static constexpr size_t LOCALE_OFFSET = JSObject::SIZE; diff --git a/ecmascript/js_primitive_ref.h b/ecmascript/js_primitive_ref.h index 7564629ec5496f6fc3f4468b610579c8c280588a..d6348a65d64a180606b9ba5a58c8d71eccdd4c5c 100644 --- a/ecmascript/js_primitive_ref.h +++ b/ecmascript/js_primitive_ref.h @@ -31,11 +31,7 @@ enum class PrimitiveType : uint8_t { class JSPrimitiveRef : public JSObject { public: - static JSPrimitiveRef *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSPrimitiveRef()); - return static_cast(object); - } + CAST_CHECK(JSPrimitiveRef, IsJSPrimitiveRef); JSPrimitiveRef() = delete; diff --git a/ecmascript/js_promise.h b/ecmascript/js_promise.h index f70561f7cbcef0e5a5b8f7441c6948318337d149..d66ac3e81d60314de49ae43063e35812395c587f 100644 --- a/ecmascript/js_promise.h +++ b/ecmascript/js_promise.h @@ -30,11 +30,7 @@ enum class PromiseType : uint32_t { RESOLVE = 0, REJECT }; class PromiseReaction final : public Record { public: - static PromiseReaction *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsPromiseReaction()); - return static_cast(object); - } + CAST_CHECK(PromiseReaction, IsPromiseReaction); static constexpr size_t PROMISE_CAPABILITY_OFFSET = Record::SIZE; ACCESSORS(PromiseCapability, PROMISE_CAPABILITY_OFFSET, TYPE_OFFSET); @@ -48,11 +44,7 @@ public: class PromiseCapability final : public Record { public: - static PromiseCapability *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsPromiseCapability()); - return static_cast(object); - } + CAST_CHECK(PromiseCapability, IsPromiseCapability); static constexpr size_t PROMISE_OFFSET = Record::SIZE; ACCESSORS(Promise, PROMISE_OFFSET, RESOLVE_OFFSET); @@ -66,11 +58,7 @@ public: class PromiseIteratorRecord final : public Record { public: - static PromiseIteratorRecord *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsPromiseIteratorRecord()); - return static_cast(object); - } + CAST_CHECK(PromiseIteratorRecord, IsPromiseIteratorRecord); static constexpr size_t ITERATOR_OFFSET = Record::SIZE; ACCESSORS(Iterator, ITERATOR_OFFSET, DONE_OFFSET); @@ -83,11 +71,8 @@ public: class PromiseRecord final : public Record { public: - static PromiseRecord *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsPromiseRecord()); - return static_cast(object); - } + CAST_CHECK(PromiseRecord, IsPromiseRecord); + static constexpr size_t VALUE_OFFSET = Record::SIZE; ACCESSORS(Value, VALUE_OFFSET, SIZE); DECL_DUMP() @@ -97,11 +82,8 @@ public: class ResolvingFunctionsRecord final : public Record { public: - static ResolvingFunctionsRecord *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsResolvingFunctionsRecord()); - return static_cast(object); - } + CAST_CHECK(ResolvingFunctionsRecord, IsResolvingFunctionsRecord); + static constexpr size_t RESOLVE_FUNCTION_OFFSET = Record::SIZE; ACCESSORS(ResolveFunction, RESOLVE_FUNCTION_OFFSET, REJECT_FUNCTION_OFFSET); ACCESSORS(RejectFunction, REJECT_FUNCTION_OFFSET, SIZE); @@ -113,11 +95,7 @@ public: class JSPromise final : public JSObject { public: - static JSPromise *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSPromise()); - return static_cast(object); - } + CAST_CHECK(JSPromise, IsJSPromise); // ES6 25.4.1.3 CreateResolvingFunctions ( promise ) static JSHandle CreateResolvingFunctions(JSThread *thread, diff --git a/ecmascript/js_proxy.h b/ecmascript/js_proxy.h index fd6dfb5ec0de8e5f560e72ff3754e7ea7edae395..9297a214f1b4f91e5029d2d7318fbd4f1c593458 100644 --- a/ecmascript/js_proxy.h +++ b/ecmascript/js_proxy.h @@ -22,15 +22,7 @@ namespace panda::ecmascript { class JSProxy final : public ECMAObject { public: - static JSProxy *Cast(ObjectHeader *object) - { - return static_cast(object); - } - - static const JSProxy *ConstCast(const TaggedObject *object) - { - return static_cast(object); - } + CAST_CHECK(JSProxy, IsJSProxy); // ES6 9.5.15 ProxyCreate(target, handler) static JSHandle ProxyCreate(JSThread *thread, const JSHandle &target, diff --git a/ecmascript/js_regexp.h b/ecmascript/js_regexp.h index ef8560df12adc4f4e87c50e44ab2a2034e84a2ea..47fb41a016368890a20fc0f3a28580824a0ed871 100644 --- a/ecmascript/js_regexp.h +++ b/ecmascript/js_regexp.h @@ -24,11 +24,7 @@ namespace panda::ecmascript { class JSRegExp : public JSObject { public: - static JSRegExp *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSRegExp()); - return static_cast(object); - } + CAST_CHECK(JSRegExp, IsJSRegExp); static constexpr size_t LAST_INDEX_OFFSET = JSObject::SIZE; ACCESSORS(LastIndex, LAST_INDEX_OFFSET, REGEXP_BYTE_CODE_OFFSET); diff --git a/ecmascript/js_relative_time_format.h b/ecmascript/js_relative_time_format.h index 2c5fdc261906cb362c6e224494ac07d4cc550fe2..029e244bfaf8a61985a429860b4091a74d63e5f0 100644 --- a/ecmascript/js_relative_time_format.h +++ b/ecmascript/js_relative_time_format.h @@ -36,11 +36,7 @@ namespace panda::ecmascript { class JSRelativeTimeFormat : public JSObject { public: - static JSRelativeTimeFormat *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsJSRelativeTimeFormat()); - return reinterpret_cast(object); - } + CAST_CHECK(JSRelativeTimeFormat, IsJSRelativeTimeFormat); static constexpr size_t LOCALE_OFFSET = JSObject::SIZE; diff --git a/ecmascript/js_set.h b/ecmascript/js_set.h index 0412ecf9a1535a6aad7f86f1d3982f530992d35c..e20e41866dab0b08fb864063f99c3bbe0a14fa75 100644 --- a/ecmascript/js_set.h +++ b/ecmascript/js_set.h @@ -23,10 +23,7 @@ namespace panda::ecmascript { class JSSet : public JSObject { public: - static JSSet *Cast(ObjectHeader *object) - { - return static_cast(object); - } + CAST_CHECK(JSSet, IsJSSet); static bool Delete(const JSThread *thread, const JSHandle &set, const JSHandle &value); diff --git a/ecmascript/js_set_iterator.h b/ecmascript/js_set_iterator.h index 279f5c2021f1afbc3f954ee8428134941de9972b..dec9aa26662de5adc574dcb07a5120f30f20837d 100644 --- a/ecmascript/js_set_iterator.h +++ b/ecmascript/js_set_iterator.h @@ -22,11 +22,7 @@ namespace panda::ecmascript { class JSSetIterator : public JSObject { public: - static JSSetIterator *Cast(ObjectHeader *obj) - { - ASSERT(JSTaggedValue(obj).IsJSSetIterator()); - return static_cast(obj); - } + CAST_CHECK(JSSetIterator, IsJSSetIterator); static JSHandle CreateSetIterator(JSThread *thread, const JSHandle &obj, IterationKind kind); diff --git a/ecmascript/js_string_iterator.h b/ecmascript/js_string_iterator.h index d13304be5967fc22ca5890d2a33985b2637a2601..b20e9a554cc1cce549994dad212d2d242fc68f51 100644 --- a/ecmascript/js_string_iterator.h +++ b/ecmascript/js_string_iterator.h @@ -25,11 +25,7 @@ namespace panda { namespace ecmascript { class JSStringIterator : public JSObject { public: - static JSStringIterator *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsStringIterator()); - return static_cast(object); - } + CAST_CHECK(JSStringIterator, IsStringIterator); static JSHandle CreateStringIterator(const JSThread *thread, const JSHandle &string); diff --git a/ecmascript/js_symbol.h b/ecmascript/js_symbol.h index b1f4ecb18e5646388faa89632559ffebe6b0c261..9fa2f748544814bc9ac59cde41bb99140493964c 100644 --- a/ecmascript/js_symbol.h +++ b/ecmascript/js_symbol.h @@ -39,11 +39,7 @@ public: static constexpr const uint32_t LINEAR_SEED = 987654321U; public: - static JSSymbol *Cast(ObjectHeader *object) - { - ASSERT(JSTaggedValue(object).IsSymbol()); - return static_cast(object); - } + CAST_CHECK(JSSymbol, IsSymbol); static inline uint32_t ComputeHash() { diff --git a/ecmascript/js_tagged_value-inl.h b/ecmascript/js_tagged_value-inl.h index 27d6f86f29bebe0707ff1c7341510edef4681a8b..da452fa1b3e01a58b7b36c944a9cb05fa77cf9b5 100644 --- a/ecmascript/js_tagged_value-inl.h +++ b/ecmascript/js_tagged_value-inl.h @@ -789,11 +789,17 @@ inline bool JSTaggedValue::IsGeneratorFunction() const { return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorFunction(); } + inline bool JSTaggedValue::IsGeneratorObject() const { return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorObject(); } +inline bool JSTaggedValue::IsGeneratorContext() const +{ + return IsHeapObject() && GetTaggedObject()->GetClass()->IsGeneratorContext(); +} + inline bool JSTaggedValue::IsAsyncFuncObject() const { return IsHeapObject() && GetTaggedObject()->GetClass()->IsAsyncFuncObject(); diff --git a/ecmascript/js_tagged_value.h b/ecmascript/js_tagged_value.h index 1cd220490dd6fc7d75ad3c795751300579a5a017..b7773759e89d21c1f663716271cd2285afb7d916 100644 --- a/ecmascript/js_tagged_value.h +++ b/ecmascript/js_tagged_value.h @@ -286,6 +286,7 @@ public: bool IsIterator() const; bool IsGeneratorFunction() const; bool IsGeneratorObject() const; + bool IsGeneratorContext() const; bool IsAsyncFuncObject() const; bool IsJSPromise() const; bool IsRecord() const; diff --git a/ecmascript/js_thread.cpp b/ecmascript/js_thread.cpp index 5ed583444cebe147c94114f43939bf83e09da12e..88b1a280e00b4bced915dd05274860111d5c1703 100644 --- a/ecmascript/js_thread.cpp +++ b/ecmascript/js_thread.cpp @@ -190,6 +190,16 @@ uintptr_t *JSThread::ExpandHandleStorage() void JSThread::ShrinkHandleStorage(int prevIndex) { currentHandleStorageIndex_ = prevIndex; + +#if ECMASCRIPT_ENABLE_ZAP_MEM + uintptr_t size = ToUintPtr(handleScopeStorageEnd_) - ToUintPtr(handleScopeStorageNext_); + memset_s(handleScopeStorageNext_, size, 0, size); + + int32_t lastIndex = handleStorageNodes_.size() - 1; + for (int32_t i = currentHandleStorageIndex_ + 1; i < lastIndex; i++) { + memset_s(handleStorageNodes_[i], NODE_BLOCK_SIZE * sizeof(JSTaggedType), 0, NODE_BLOCK_SIZE * sizeof(JSTaggedType)); + } +#endif } void JSThread::NotifyStableArrayElementsGuardians(JSHandle receiver) diff --git a/ecmascript/js_typed_array.h b/ecmascript/js_typed_array.h index ab8a36cce6db869d731492e2424661cd373956cc..506f1474f7cb38bdb02718767c31579a396bd052 100644 --- a/ecmascript/js_typed_array.h +++ b/ecmascript/js_typed_array.h @@ -24,7 +24,13 @@ class JSTypedArray : public JSObject { public: static JSTypedArray *Cast(ObjectHeader *object) { + #if ECMASCRIPT_ENABLE_CAST_CHECK + if (!(JSTaggedValue(object).IsTypedArray() || JSTaggedValue(object).IsJSTypedArray())) { + std::abort(); + } + #else ASSERT(JSTaggedValue(object).IsTypedArray() || JSTaggedValue(object).IsJSTypedArray()); + #endif return static_cast(object); } diff --git a/ecmascript/mem/caddress_allocator.h b/ecmascript/mem/caddress_allocator.h index 3a08b03775bdda96a6726370fc6799c964781dd3..e7eb1e24f1099273972da20de8025c05d1997ce6 100644 --- a/ecmascript/mem/caddress_allocator.h +++ b/ecmascript/mem/caddress_allocator.h @@ -155,7 +155,6 @@ public: return; } // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) - os::memory::LockHolder lock(staticResourceLock_); free(mem); } }; diff --git a/ecmascript/mem/clock_scope.h b/ecmascript/mem/clock_scope.h index de76aac3101a61c051b6bc93d46d294f8d02cd5e..53e7a6b035b4004bf18599753af078d635198a73 100644 --- a/ecmascript/mem/clock_scope.h +++ b/ecmascript/mem/clock_scope.h @@ -39,8 +39,10 @@ public: ~ClockScope() { end_ = Clock::now(); + # if ECMASCRIPT_ENABLE_GC_LOG auto duration = std::chrono::duration_cast(end_ - start_); - LOG(DEBUG, RUNTIME) << str_ << " spent time: " << (float) duration.count() / MILLION_TIME << "ms"; + LOG(ERROR, RUNTIME) << str_ << " spent time: " << (float) duration.count() / MILLION_TIME << "ms"; + # endif } NO_COPY_SEMANTIC(ClockScope); diff --git a/ecmascript/mem/compress_collector.cpp b/ecmascript/mem/compress_collector.cpp index db3759594c3e193fd0be8a585f48de9cd9037310..aa3f8b60fda3470b6c62e5d751fed09cb25f1561 100644 --- a/ecmascript/mem/compress_collector.cpp +++ b/ecmascript/mem/compress_collector.cpp @@ -42,6 +42,7 @@ CompressCollector::~CompressCollector() void CompressCollector::RunPhases() { + LOG_GC() << "CompressCollector::RunPhases"; [[maybe_unused]] ecmascript::JSThread *thread = heap_->GetEcmaVM()->GetJSThread(); INTERPRETER_TRACE(thread, CompressCollector_RunPhases); trace::ScopedTrace scoped_trace("CompressCollector::RunPhases"); diff --git a/ecmascript/mem/compress_gc_marker-inl.h b/ecmascript/mem/compress_gc_marker-inl.h index 1f52bfc10f15479744e8fc754bf88695585c1331..d6319319289e72f96d02f9cc3821e82b3e039222 100644 --- a/ecmascript/mem/compress_gc_marker-inl.h +++ b/ecmascript/mem/compress_gc_marker-inl.h @@ -54,7 +54,7 @@ inline void CompressGCMarker::EvacuateObject(uint32_t threadId, TaggedObject *ob auto size = klass->SizeFromJSHClass(jsType, object); uintptr_t forwardAddress = collector_->workList_->GetTlabAllocator(threadId)->Allocate(size, SpaceAlloc::OLD_SPACE); if (UNLIKELY(forwardAddress == 0)) { - LOG_ECMA_MEM(FATAL) << "alloc failed"; + LOG_ECMA_MEM(FATAL) << "CompressGCMarker::EvacuateObject alloc failed: "; UNREACHABLE(); } @@ -81,7 +81,8 @@ inline void CompressGCMarker::CopyObjectWithoutHeader(TaggedObject *object, uint { if (memcpy_s(ToVoidPtr(address + HEAD_SIZE), size - HEAD_SIZE, ToVoidPtr(ToUintPtr(object) + HEAD_SIZE), size - HEAD_SIZE) != EOK) { - LOG_ECMA(FATAL) << "memcpy_s failed"; + LOG_ECMA_MEM(FATAL) << "CompressGCMarker::CopyObjectWithoutHeader memcpy_s failed: " << " dst: " << address + << " src: " << ToUintPtr(object) << " size: " << size; UNREACHABLE(); } } diff --git a/ecmascript/mem/ecma_heap_manager-inl.h b/ecmascript/mem/ecma_heap_manager-inl.h index 4b65d6c33767a955b2ca0a60e62c019c37e0d961..1b32ed63cb04e121a1e3bd4b63b12ee90451527e 100644 --- a/ecmascript/mem/ecma_heap_manager-inl.h +++ b/ecmascript/mem/ecma_heap_manager-inl.h @@ -59,7 +59,7 @@ TaggedObject *EcmaHeapManager::AllocateYoungGenerationOrHugeObject(JSHClass *hcl heap_->CollectGarbage(TriggerGCType::OLD_GC); object = reinterpret_cast(newSpaceAllocator_.Allocate(size)); if (UNLIKELY(object == nullptr)) { - heap_->ThrowOutOfMemoryError(size); + heap_->ThrowOutOfMemoryError(size, "AllocateYoungGenerationOrHugeObject"); UNREACHABLE(); } } @@ -96,7 +96,7 @@ TaggedObject *EcmaHeapManager::AllocateNonMovableOrHugeObject(JSHClass *hclass, } object = reinterpret_cast(nonMovableAllocator_.Allocate(size)); if (UNLIKELY(object == nullptr)) { - heap_->ThrowOutOfMemoryError(size); + heap_->ThrowOutOfMemoryError(size, "AllocateNonMovableOrHugeObject"); UNREACHABLE(); } } @@ -153,7 +153,7 @@ TaggedObject *EcmaHeapManager::AllocateOldGenerationOrHugeObject(JSHClass *hclas } object = reinterpret_cast(oldSpaceAllocator_.Allocate(size)); if (UNLIKELY(object == nullptr)) { - heap_->ThrowOutOfMemoryError(size); + heap_->ThrowOutOfMemoryError(size, "AllocateOldGenerationOrHugeObject"); UNREACHABLE(); } } @@ -175,7 +175,7 @@ TaggedObject *EcmaHeapManager::AllocateHugeObject(JSHClass *hclass, size_t size) object = reinterpret_cast( const_cast(heap_->GetHugeObjectSpace())->Allocate(size)); if (UNLIKELY(object == nullptr)) { - heap_->ThrowOutOfMemoryError(size); + heap_->ThrowOutOfMemoryError(size, "AllocateHugeObject"); UNREACHABLE(); } } @@ -193,7 +193,7 @@ TaggedObject *EcmaHeapManager::AllocateMachineCodeSpaceObject(JSHClass *hclass, } object = reinterpret_cast(machineCodeSpaceAllocator_.Allocate(size)); if (UNLIKELY(object == nullptr)) { - heap_->ThrowOutOfMemoryError(size); + heap_->ThrowOutOfMemoryError(size, "AllocateMachineCodeSpaceObject"); return nullptr; } } diff --git a/ecmascript/mem/gc_stats.cpp b/ecmascript/mem/gc_stats.cpp index 811707dd6cd1bbfae53eaebcddeb05e9148c2d76..c7ad5e13804dfc10bc0e576bd1cf6d01dfe9ec85 100644 --- a/ecmascript/mem/gc_stats.cpp +++ b/ecmascript/mem/gc_stats.cpp @@ -21,10 +21,10 @@ namespace panda::ecmascript { void GCStats::PrintStatisticResult() { - LOG(DEBUG, RUNTIME) << "GCStats statistic: "; + LOG(ERROR, RUNTIME) << "GCStats statistic: "; if (semiGCCount_ != 0) { - LOG(DEBUG, RUNTIME) << " SemiCollector statistic: total semi gc count " << semiGCCount_; - LOG(DEBUG, RUNTIME) << " MIN pause time: " << PrintTimeMilliseconds(semiGCMinPause_) << "ms" + LOG(ERROR, RUNTIME) << " SemiCollector statistic: total semi gc count " << semiGCCount_; + LOG(ERROR, RUNTIME) << " MIN pause time: " << PrintTimeMilliseconds(semiGCMinPause_) << "ms" << " MAX pause time: " << PrintTimeMilliseconds(semiGCMAXPause_) << "ms" << " total pause time: " << PrintTimeMilliseconds(semiGCTotalPause_) << "ms" << " average pause time: " << PrintTimeMilliseconds(semiGCTotalPause_ / semiGCCount_) @@ -39,8 +39,8 @@ void GCStats::PrintStatisticResult() } if (oldGCCount_ != 0) { - LOG(DEBUG, RUNTIME) << " oldCollector statistic: total old gc count " << oldGCCount_; - LOG(DEBUG, RUNTIME) << " MIN pause time: " << PrintTimeMilliseconds(oldGCMinPause_) << "ms" + LOG(ERROR, RUNTIME) << " oldCollector statistic: total old gc count " << oldGCCount_; + LOG(ERROR, RUNTIME) << " MIN pause time: " << PrintTimeMilliseconds(oldGCMinPause_) << "ms" << " MAX pause time: " << PrintTimeMilliseconds(oldGCMAXPause_) << "ms" << " total pause time: " << PrintTimeMilliseconds(oldGCTotalPause_) << "ms" << " average pause time: " << PrintTimeMilliseconds(oldGCTotalPause_ / oldGCCount_) << "ms" @@ -57,8 +57,8 @@ void GCStats::PrintStatisticResult() } if (compressGCCount_ != 0) { - LOG(DEBUG, RUNTIME) << " compressCollector statistic: total compress gc count " << compressGCCount_; - LOG(DEBUG, RUNTIME) + LOG(ERROR, RUNTIME) << " compressCollector statistic: total compress gc count " << compressGCCount_; + LOG(ERROR, RUNTIME) << " MIN pause time: " << PrintTimeMilliseconds(compressGCMinPause_) << "ms" << " MAX pause time: " << PrintTimeMilliseconds(compressGCMaxPause_) << "ms" << " total pause time: " << PrintTimeMilliseconds(compressGCTotalPause_) << "ms" @@ -79,7 +79,7 @@ void GCStats::PrintStatisticResult() if (heap_ != nullptr) { RegionFactory *regionFactory = const_cast(heap_->GetRegionFactory()); - LOG(DEBUG, RUNTIME) << "pool statistic:: " + LOG(ERROR, RUNTIME) << "pool statistic:: " << "anno memory usage size:" << regionFactory->GetAnnoMemoryUsage() << "anno memory max usage size:" << regionFactory->GetMaxAnnoMemoryUsage() << "native memory usage size:" << regionFactory->GetNativeMemoryUsage() diff --git a/ecmascript/mem/heap.cpp b/ecmascript/mem/heap.cpp index 61aba40a8b2ae6d2c76e280ddf0ad80c42dda48f..c9e2a18400dba9a8578abc893c6e47f6ef91d293 100644 --- a/ecmascript/mem/heap.cpp +++ b/ecmascript/mem/heap.cpp @@ -57,6 +57,9 @@ void Heap::Initialize() markStack_ = new MarkStack(this); weakProcessQueue_ = new ProcessQueue(this); bool paralledGc = ecmaVm_->GetOptions().IsEnableParalledYoungGc(); +#if ECMASCRIPT_DISABLE_PARALLEL_GC + paralledGc = false; +#endif if (paralledGc) { int numOfCpuCore = get_nprocs(); int numThread = std::min(numOfCpuCore, THREAD_NUM_FOR_YOUNG_GC); @@ -135,15 +138,21 @@ void Heap::Destroy() void Heap::CollectGarbage(TriggerGCType gcType) { CHECK_NO_GC +#if ECMASCRIPT_ENABLE_HEAP_VERIFY // pre gc heap verify - { - if (ecmaVm_->GetOptions().IsPreGcHeapVerifyEnabled()) { - auto failCount = Verification(this).VerifyAll(); - if (failCount > 0) { - LOG(FATAL, GC) << "Before gc heap corrupted and " << failCount << " corruptions"; - } - } + auto failCount = Verification(this).VerifyAll(); + if (failCount > 0) { + LOG(FATAL, GC) << "Before gc heap corrupted and " << failCount << " corruptions"; + } + // verify need semiGC or fullGC + if (gcType != TriggerGCType::SEMI_GC) { + gcType = TriggerGCType::COMPRESS_FULL_GC; } +#endif + +# if ECMASCRIPT_SWITCH_GC_MODE_TO_COMPRESS_GC + gcType = TriggerGCType::COMPRESS_FULL_GC; +#endif switch (gcType) { case TriggerGCType::SEMI_GC: if (GetMemController()->IsInAppStartup()) { @@ -180,25 +189,33 @@ void Heap::CollectGarbage(TriggerGCType gcType) break; } +# if ECMASCRIPT_ENABLE_GC_LOG + ecmaVm_->GetEcmaGCStats()->PrintStatisticResult(); +#endif + +#if ECMASCRIPT_ENABLE_HEAP_VERIFY // post gc heap verify - { - if (ecmaVm_->GetOptions().IsPreGcHeapVerifyEnabled()) { - auto failCount = Verification(this).VerifyAll(); - if (failCount > 0) { - LOG(FATAL, GC) << "After gc heap corrupted and " << failCount << " corruptions"; - } - } + failCount = Verification(this).VerifyAll(); + if (failCount > 0) { + LOG(FATAL, GC) << "After gc heap corrupted and " << failCount << " corruptions"; } +#endif } -void Heap::ThrowOutOfMemoryError(size_t size) +void Heap::ThrowOutOfMemoryError(size_t size, std::string functionName) { - LOG_ECMA_MEM(FATAL) << "OOM when trying to allocate " << size << " bytes"; + LOG_ECMA_MEM(FATAL) << "OOM when trying to allocate " << size << " bytes" + << " function name: " << functionName.c_str(); } size_t Heap::VerifyHeapObjects() const { size_t failCount = 0; + { + VerifyObjectVisitor verifier(this, &failCount); + toSpace_->IterateOverObjects(verifier); + } + { VerifyObjectVisitor verifier(this, &failCount); oldSpace_->IterateOverObjects(verifier); diff --git a/ecmascript/mem/heap.h b/ecmascript/mem/heap.h index bc112f2f877b7714dab00ce70cf545c5d8276cb2..112d947be525480530bf306f40fad882ae5fe86d 100644 --- a/ecmascript/mem/heap.h +++ b/ecmascript/mem/heap.h @@ -155,7 +155,7 @@ public: inline bool FillSnapShotSpace(BumpPointerAllocator *spaceAllocator); inline bool FillMachineCodeSpaceAndTryGC(FreeListAllocator *spaceAllocator, bool allowGc = true); - void ThrowOutOfMemoryError(size_t size); + void ThrowOutOfMemoryError(size_t size, std::string functionName); void SetHeapManager(EcmaHeapManager *heapManager) { diff --git a/ecmascript/mem/mem.h b/ecmascript/mem/mem.h index 83742742adb1a5261cb6e19dfa9fb471d21e4c34..2cbd4c08e556e6132f3be369ee1c9573df1aaa76 100644 --- a/ecmascript/mem/mem.h +++ b/ecmascript/mem/mem.h @@ -87,8 +87,6 @@ static constexpr size_t MAX_CHUNK_AREA_SIZE = 1 * 1024 * 1024; static constexpr uintptr_t PANDA_32BITS_HEAP_START_ADDRESS_256 = 256_KB; -static os::memory::Mutex staticResourceLock_; - template constexpr inline bool IsAligned(T value, size_t alignment) { diff --git a/ecmascript/mem/old_space_collector.cpp b/ecmascript/mem/old_space_collector.cpp index 3572760030bc5a72f1440173fb54d5204987a955..7e681dae11faabdd50fed25eebda06f77bd8508a 100644 --- a/ecmascript/mem/old_space_collector.cpp +++ b/ecmascript/mem/old_space_collector.cpp @@ -31,6 +31,7 @@ OldSpaceCollector::OldSpaceCollector(Heap *heap) : heap_(heap), rootManager_(hea void OldSpaceCollector::RunPhases() { + LOG_GC() << "OldSpaceCollector::RunPhases"; [[maybe_unused]] ecmascript::JSThread *thread = heap_->GetEcmaVM()->GetJSThread(); INTERPRETER_TRACE(thread, OldSpaceCollector_RunPhases); trace::ScopedTrace scoped_trace("OldSpaceCollector::RunPhases"); diff --git a/ecmascript/mem/region_factory.cpp b/ecmascript/mem/region_factory.cpp index 757babbd7f1939c9bed150a7ada3d578b82120cc..6d29122d5d214403f5653a85f91439e71e877bfc 100644 --- a/ecmascript/mem/region_factory.cpp +++ b/ecmascript/mem/region_factory.cpp @@ -37,6 +37,9 @@ Region *RegionFactory::AllocateAlignedRegion(Space *space, size_t capacity) auto pool = PoolManager::GetMmapMemPool()->AllocPool(commitSize, panda::SpaceType::SPACE_TYPE_OBJECT, AllocatorType::RUNSLOTS_ALLOCATOR, nullptr); void *mapMem = pool.GetMem(); +#if ECMASCRIPT_ENABLE_ZAP_MEM + memset_s(mapMem, commitSize, 0, commitSize); +#endif if (mapMem == nullptr) { LOG_ECMA_MEM(FATAL) << "pool is empty"; UNREACHABLE(); @@ -58,6 +61,9 @@ void RegionFactory::FreeRegion(Region *region) { auto size = region->GetCapacity(); DecreaseAnnoMemoryUsage(size); +#if ECMASCRIPT_ENABLE_ZAP_MEM + memset_s(ToVoidPtr(region->GetAllocateBase()), size, 0, size); +#endif PoolManager::GetMmapMemPool()->FreePool(ToVoidPtr(region->GetAllocateBase()), size); } @@ -75,6 +81,9 @@ Area *RegionFactory::AllocateArea(size_t capacity) } // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) void *mem = malloc(capacity); +#if ECMASCRIPT_ENABLE_ZAP_MEM + memset_s(mem, capacity, 0, capacity); +#endif if (mem == nullptr) { LOG_ECMA_MEM(FATAL) << "malloc failed"; UNREACHABLE(); @@ -97,7 +106,9 @@ void RegionFactory::FreeArea(Area *area) } auto size = area->GetSize() + sizeof(Area); DecreaseNativeMemoryUsage(size); - os::memory::LockHolder lock(staticResourceLock_); +#if ECMASCRIPT_ENABLE_ZAP_MEM + memset_s(area, size, 0, size); +#endif // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) free(reinterpret_cast(area)); } @@ -110,6 +121,9 @@ void *RegionFactory::Allocate(size_t size) } // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) void *ptr = malloc(size); +#if ECMASCRIPT_ENABLE_ZAP_MEM + memset_s(ptr, size, 0, size); +#endif if (ptr == nullptr) { LOG_ECMA_MEM(FATAL) << "malloc failed"; UNREACHABLE(); @@ -124,7 +138,9 @@ void RegionFactory::Free(void *mem, size_t size) return; } DecreaseNativeMemoryUsage(size); - os::memory::LockHolder lock(staticResourceLock_); +#if ECMASCRIPT_ENABLE_ZAP_MEM + memset_s(mem, size, 0, size); +#endif // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) free(mem); } @@ -141,6 +157,9 @@ void *RegionFactory::AllocateBuffer(size_t size) LOG_ECMA_MEM(FATAL) << "malloc failed"; UNREACHABLE(); } +#if ECMASCRIPT_ENABLE_ZAP_MEM + memset_s(ptr, size, 0, size); +#endif IncreaseNativeMemoryUsage(size); return ptr; } @@ -151,7 +170,9 @@ void RegionFactory::FreeBuffer(void *mem) return; } DecreaseNativeMemoryUsage(malloc_usable_size(mem)); - os::memory::LockHolder lock(staticResourceLock_); +#if ECMASCRIPT_ENABLE_ZAP_MEM + memset_s(mem, size, 0, size); +#endif // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) free(mem); } diff --git a/ecmascript/mem/semi_space_collector.cpp b/ecmascript/mem/semi_space_collector.cpp index ef6975066f4328a0f4a42b5b9701b7fd21bfccc2..3f8f3b06572b7af013c5230b490fb373fa25f96a 100644 --- a/ecmascript/mem/semi_space_collector.cpp +++ b/ecmascript/mem/semi_space_collector.cpp @@ -44,6 +44,7 @@ SemiSpaceCollector::~SemiSpaceCollector() void SemiSpaceCollector::RunPhases() { + LOG_GC() << "SemiSpaceCollector::RunPhases"; [[maybe_unused]] ecmascript::JSThread *thread = heap_->GetEcmaVM()->GetJSThread(); INTERPRETER_TRACE(thread, SemiSpaceCollector_RunPhases); trace::ScopedTrace scoped_trace("SemiSpaceCollector::RunPhases"); diff --git a/ecmascript/mem/semi_space_collector.h b/ecmascript/mem/semi_space_collector.h index 6e5a31f62468b10c25ffdcd70d77bb02382042f0..2b14350c14303d49bf0149e294dacc34245a95f7 100644 --- a/ecmascript/mem/semi_space_collector.h +++ b/ecmascript/mem/semi_space_collector.h @@ -40,6 +40,12 @@ class Heap; class JSHClass; class SemiSpaceWorker; +#if ECMASCRIPT_ENABLE_GC_LOG + #define LOG_GC() LOG(ERROR, RUNTIME) << ": " +#else + #define LOG_GC() LOG(DEBUG, RUNTIME) << ": " +#endif + class GarbageCollector { public: GarbageCollector() = default; diff --git a/ecmascript/mem/semi_space_marker.cpp b/ecmascript/mem/semi_space_marker.cpp index d4ca483813349e67596c0695b56f0d5b2324511c..f367ca0c62cd5d3889c4c8c0608f1c508e3f5878 100644 --- a/ecmascript/mem/semi_space_marker.cpp +++ b/ecmascript/mem/semi_space_marker.cpp @@ -61,7 +61,8 @@ SlotStatus SemiSpaceMarker::EvacuateObject(uint32_t threadId, TaggedObject *obje if (UNLIKELY(forwardAddress == 0)) { forwardAddress = collector_->workList_->GetTlabAllocator(threadId)->Allocate(size, SpaceAlloc::YOUNG_SPACE); if (UNLIKELY(forwardAddress == 0)) { - LOG_ECMA_MEM(FATAL) << "alloc failed"; + LOG_ECMA_MEM(FATAL) << "SemiSpaceMarker::EvacuateObject alloc failed: " << " jstype: " + << (uint16_t)jsType << " size: " << size << " obj address: " << ToUintPtr(object); UNREACHABLE(); } isPromoted = false; @@ -71,7 +72,8 @@ SlotStatus SemiSpaceMarker::EvacuateObject(uint32_t threadId, TaggedObject *obje if (UNLIKELY(forwardAddress == 0)) { forwardAddress = collector_->workList_->GetTlabAllocator(threadId)->Allocate(size, SpaceAlloc::OLD_SPACE); if (UNLIKELY(forwardAddress == 0)) { - LOG_ECMA_MEM(FATAL) << "alloc failed"; + LOG_ECMA_MEM(FATAL) << "SemiSpaceMarker::EvacuateObject alloc failed: " << " jstype: " + << (uint16_t)jsType << " size: " << size << " obj address: " << ToUintPtr(object); UNREACHABLE(); } isPromoted = true; @@ -106,7 +108,8 @@ void SemiSpaceMarker::CopyObjectWithoutHeader(TaggedObject *object, uintptr_t ad { if (memcpy_s(ToVoidPtr(address + HEAD_SIZE), size - HEAD_SIZE, ToVoidPtr(ToUintPtr(object) + HEAD_SIZE), size - HEAD_SIZE) != EOK) { - LOG_ECMA(FATAL) << "memcpy_s failed"; + LOG_ECMA_MEM(FATAL) << "SemiSpaceMarker::CopyObjectWithoutHeader memcpy_s failed: " << " dst: " + << address << " src: " << ToUintPtr(object) << " size: " << size; UNREACHABLE(); } } diff --git a/ecmascript/mem/space.cpp b/ecmascript/mem/space.cpp index cb83b9416ccd5e0552e14a65bf76a0db9880fe05..81dddea6075bb5db9c7a17aa221e9fb1b3f4bb2e 100644 --- a/ecmascript/mem/space.cpp +++ b/ecmascript/mem/space.cpp @@ -131,7 +131,15 @@ bool SemiSpace::ContainObject(TaggedObject *object) const bool SemiSpace::IsLive(TaggedObject *object) const { - return ContainObject(object); + auto region = GetRegionList().GetFirst(); + while (region != nullptr) { + if (region->InRange(ToUintPtr(object))) { + auto freeObject = FreeObject::Cast(ToUintPtr(object)); + return !freeObject->IsFreeObject(); + } + region = region->GetNext(); + } + return false; } void SemiSpace::IterateOverObjects(const std::function &visitor) const @@ -157,8 +165,10 @@ void SemiSpace::IterateOverObjects(const std::functionAvailable(); } - LOG_IF(objSize == 0, FATAL, RUNTIME) << "SemiSpace IterateOverObjects objSize==0 invalid: " << curPtr; curPtr += AlignUp(objSize, sizeof(JSTaggedType)); + LOG_IF(objSize == 0, FATAL, RUNTIME) << "SemiSpace IterateOverObjects objSize==0 invalid: " << curPtr; + LOG_IF(curPtr > endPtr, FATAL, RUNTIME) << "SemiSpace IterateOverObjects size is invalid curPtr: " + << curPtr << " endPtr: " << endPtr; } }); } @@ -221,8 +231,10 @@ void OldSpace::IterateOverObjects(const std::functionAvailable(); } - LOG_IF(objSize == 0, FATAL, RUNTIME) << "OldSpace IterateOverObjects objSize==0 invalid: " << curPtr; curPtr += AlignUp(objSize, sizeof(JSTaggedType)); + LOG_IF(objSize == 0, FATAL, RUNTIME) << "OldSpace IterateOverObjects objSize==0 invalid: " << curPtr; + LOG_IF(curPtr > endPtr, FATAL, RUNTIME) << "OldSpace IterateOverObjects size is invalid curPtr: " + << curPtr << " endPtr: " << endPtr; } }); } @@ -327,8 +339,10 @@ void NonMovableSpace::IterateOverObjects(const std::functionAvailable(); } - LOG_IF(objSize == 0, FATAL, RUNTIME) << "NonMovableSpace IterateOverObjects objSize==0 invalid: " << curPtr; curPtr += AlignUp(objSize, sizeof(JSTaggedType)); + LOG_IF(objSize == 0, FATAL, RUNTIME) << "NonMovableSpace IterateOverObjects objSize==0 invalid: " << curPtr; + LOG_IF(curPtr > endPtr, FATAL, RUNTIME) << "NonMovableSpace IterateOverObjects size is invalid curPtr: " + << curPtr << " endPtr: " << endPtr; } }); } diff --git a/ecmascript/mem/verification.cpp b/ecmascript/mem/verification.cpp index dac8f084b86398b5a8de3c2e946474418667caad..6df379906ce44262e590ed89cfaa4ceba32c0557 100644 --- a/ecmascript/mem/verification.cpp +++ b/ecmascript/mem/verification.cpp @@ -29,14 +29,14 @@ void VerifyObjectVisitor::VisitAllObjects(TaggedObject *obj) for (ObjectSlot slot = start; slot < end; slot++) { JSTaggedValue value(slot.GetTaggedType()); if (value.IsWeak()) { - if (!HEAP->IsLive(value.GetTaggedWeakRef())) { + if (!heap_->IsLive(value.GetTaggedWeakRef())) { LOG(ERROR, RUNTIME) << "Heap verify detected a dead object at " << value.GetTaggedObject(); - ++(*FAIL_COUNT); + ++(*failCount_); } } else if (value.IsHeapObject()) { - if (!HEAP->IsLive(value.GetTaggedObject())) { + if (!heap_->IsLive(value.GetTaggedObject())) { LOG(ERROR, RUNTIME) << "Heap verify detected a dead object at " << value.GetTaggedObject(); - ++(*FAIL_COUNT); + ++(*failCount_); } } } diff --git a/ecmascript/mem/verification.h b/ecmascript/mem/verification.h index 99e6cba7ebbee02173cdc5dcba2b69f3e2a7ee09..49af334faac61af9715cab23e4ed76b7a3ced9f0 100644 --- a/ecmascript/mem/verification.h +++ b/ecmascript/mem/verification.h @@ -29,7 +29,7 @@ namespace panda::ecmascript { class VerifyObjectVisitor { public: VerifyObjectVisitor(const Heap *heap, size_t *failCount) - : HEAP(heap), FAIL_COUNT(failCount), rootManager_(heap->GetEcmaVM()) + : heap_(heap), failCount_(failCount), rootManager_(heap->GetEcmaVM()) { } ~VerifyObjectVisitor() = default; @@ -41,14 +41,14 @@ public: size_t GetFailedCount() const { - return *FAIL_COUNT; + return *failCount_; } +private: void VisitAllObjects(TaggedObject *obj); -private: - const Heap * const HEAP{nullptr}; - size_t * const FAIL_COUNT{nullptr}; + const Heap * const heap_{nullptr}; + size_t * const failCount_{nullptr}; HeapRootManager rootManager_; }; @@ -57,20 +57,20 @@ public: explicit Verification(const Heap *heap) : heap_(heap), rootManager_(heap->GetEcmaVM()) {} ~Verification() = default; - bool IsHeapAddress(void *addr) const; - size_t VerifyRoot() const; - - size_t VerifyHeap() const; - size_t VerifyAll() const { - return VerifyRoot() + VerifyHeap(); + size_t result = VerifyRoot(); + result += VerifyHeap(); + return result; } + bool IsHeapAddress(void *addr) const; + size_t VerifyRoot() const; + size_t VerifyHeap() const; +private: NO_COPY_SEMANTIC(Verification); NO_MOVE_SEMANTIC(Verification); -private: const Heap *heap_{nullptr}; HeapRootManager rootManager_; };