diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index 4962c89386b6eec4224c2055dc202716323f4cbc..fa1210b0d76c78690e45b3fd831436ab113887db 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -33,6 +33,7 @@ #include "ecmascript/js_invoker.h" #include "ecmascript/js_thread.h" #include "ecmascript/mem/heap.h" +#include "ecmascript/tagged_dictionary.h" #include "ecmascript/object_factory.h" #include "ecmascript/regexp/regexp_parser_cache.h" #include "ecmascript/runtime_call_id.h" @@ -151,6 +152,7 @@ bool EcmaVM::Initialize() globalEnv->SetEmptyArray(thread_, factory_->NewEmptyArray()); globalEnv->SetEmptyLayoutInfo(thread_, factory_->CreateLayoutInfo(0)); globalEnv->SetRegisterSymbols(thread_, JSTaggedValue(SymbolTable::Create(thread_))); + globalEnv->SetGlobalRecord(thread_, JSTaggedValue(NameDictionary::Create(thread_))); JSTaggedValue emptyStr = thread_->GlobalConstants()->GetEmptyString(); stringTable_->InternEmptyString(EcmaString::Cast(emptyStr.GetTaggedObject())); globalEnv->SetEmptyTaggedQueue(thread_, factory_->NewTaggedQueue(0)); diff --git a/ecmascript/global_env.h b/ecmascript/global_env.h index 6ea196415bca3bc5c052409a65d7dce24afffa25..3d5dc234aa1bd0c279babb5f93273a974d993b20 100644 --- a/ecmascript/global_env.h +++ b/ecmascript/global_env.h @@ -137,7 +137,8 @@ class JSThread; V(JSTaggedValue, JSIntlBoundFunctionClass, JS_INTL_BOUND_FUNCTION_CLASS) \ V(JSTaggedValue, NumberFormatLocales, NUMBER_FORMAT_LOCALES_INDEX) \ V(JSTaggedValue, DateTimeFormatLocales, DATE_TIMEFORMAT_LOCALES_INDEX) \ - V(JSTaggedValue, JSNativeObjectClass, JS_NATIVE_OBJECT_CLASS) + V(JSTaggedValue, JSNativeObjectClass, JS_NATIVE_OBJECT_CLASS) \ + V(JSTaggedValue, GlobalRecord, GLOBAL_RECORD) class GlobalEnv : public TaggedObject { public: diff --git a/ecmascript/interpreter/interpreter-inl.h b/ecmascript/interpreter/interpreter-inl.h index aec2acf5d2cd51be1408b73960b7292390de83b9..ab5e01d7c031313f3c1166d2623f88dca27d594a 100644 --- a/ecmascript/interpreter/interpreter-inl.h +++ b/ecmascript/interpreter/interpreter-inl.h @@ -2623,9 +2623,12 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool bool found = false; FastRuntimeStub::GetGlobalOwnProperty(globalObj, propKey, &found); if (!found) { - // slow path will throw exception - JSTaggedValue res = SlowRuntimeStub::TryStGlobalByName(thread, propKey); + // find globalreord + JSTaggedValue value = GET_ACC(); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::UpdateGlobalRecord(thread, propKey, value); INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); } else { JSTaggedValue value = GET_ACC(); SAVE_ACC(); @@ -2635,6 +2638,45 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool } DISPATCH(BytecodeInstruction::Format::IMM8_ID32_IMM16); } + HANDLE_OPCODE(HANDLE_BUILTIN_STCONSTTOGLOBALRECORD_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + LOG_INST() << "intrinsics::stconsttoglobalrecord" + << " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())); + + JSTaggedValue value = GET_ACC(); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, true); + INTERPRETER_RETURN_IF_ABRUPT(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + + HANDLE_OPCODE(HANDLE_BUILTIN_STLETTOGLOBALRECORD_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + LOG_INST() << "intrinsics::stlettoglobalrecord" + << " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())); + + JSTaggedValue value = GET_ACC(); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, false); + INTERPRETER_RETURN_IF_ABRUPT(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + + HANDLE_OPCODE(HANDLE_BUILTIN_STCLASSTOGLOBALRECORD_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + LOG_INST() << "intrinsics::stclasstoglobalrecord" + << " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())); + + JSTaggedValue value = GET_ACC(); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, false); + INTERPRETER_RETURN_IF_ABRUPT(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + HANDLE_OPCODE(HANDLE_BUILTIN_LDGLOBALVAR_IMM8_ID32_IMM16) { 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 d3ba2aa5d1c18b543d723d558efb41896b9ba115..f6be3d6c2dec583940b10009480cfc371a14f09c 100644 --- a/ecmascript/interpreter/interpreter.h +++ b/ecmascript/interpreter/interpreter.h @@ -213,6 +213,9 @@ enum EcmaOpcode { DEFINEMETHOD_IMM8_ID16_V8, TRYLDGLOBALBYNAME_IMM8_ID32_IMM16, TRYSTGLOBALBYNAME_IMM8_ID32_IMM16, + STCONSTTOGLOBALRECORD_PREF_ID32; + STLETTOGLOBALRECORD_PREF_ID32; + STCLASSTOGLOBALRECORD_PREF_ID32; LDGLOBALVAR_IMM8_ID32_IMM16, STGLOBALVAR_IMM8_ID32_IMM16, LDOBJBYNAME_IMM8_ID32_IMM16_V8, diff --git a/ecmascript/interpreter/slow_runtime_stub.cpp b/ecmascript/interpreter/slow_runtime_stub.cpp index 8e5c86d631c12beda922fb63408732cd1f3e85ab..c789455a189e1f97cc92c31960967a414f34caf0 100644 --- a/ecmascript/interpreter/slow_runtime_stub.cpp +++ b/ecmascript/interpreter/slow_runtime_stub.cpp @@ -36,6 +36,7 @@ #include "ecmascript/js_proxy.h" #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/js_thread.h" +#include "ecmascript/tagged_dictionary.h" #include "ecmascript/runtime_call_id.h" #include "ecmascript/template_string.h" #include "ecmascript/vmstat/runtime_stat.h" @@ -1243,10 +1244,18 @@ JSTaggedValue SlowRuntimeStub::TryLdGlobalByName(JSThread *thread, JSTaggedValue JSHandle obj(thread, global.GetTaggedObject()->GetClass()->GetPrototype()); JSHandle propHandle(thread, prop); OperationResult res = JSTaggedValue::GetProperty(thread, obj, propHandle); - if (!res.GetPropertyMetaData().IsFound()) { + if (res.GetPropertyMetaData().IsFound()) { + return res.GetValue().GetTaggedValue(); + } + + EcmaVM *vm = thread->GetEcmaVM(); + JSHandle env = vm->GetGlobalEnv(); + NameDictionary *dict = NameDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); + int entry = dict->FindEntry(propHandle.GetTaggedValue()); + if (entry == -1) { return ThrowReferenceError(thread, prop, " is not defined"); } - return res.GetValue().GetTaggedValue(); + return dict->GetValue(entry); } JSTaggedValue SlowRuntimeStub::TryStGlobalByName(JSThread *thread, JSTaggedValue prop) @@ -1279,6 +1288,45 @@ JSTaggedValue SlowRuntimeStub::StGlobalVar(JSThread *thread, JSTaggedValue prop, return JSTaggedValue::True(); } +JSTaggedValue SlowRuntimeStub::UpdateGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value) +{ + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + EcmaVM *vm = thread->GetEcmaVM(); + JSHandle env = vm->GetGlobalEnv(); + NameDictionary *dict = NameDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); + + int entry = dict->FindEntry(prop); + if (entry == -1) { + return ThrowReferenceError(thread, prop, " is not defined"); + } + if (!dict->GetAttributes(entry).IsConstField()) { + dict->UpdateValue(thread, entry, value); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + return JSTaggedValue::True(); +} + +JSTaggedValue SlowRuntimeStub::StGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value, bool isConst) +{ + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + EcmaVM *vm = thread->GetEcmaVM(); + JSHandle env = vm->GetGlobalEnv(); + NameDictionary *dict = NameDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); + + int entry = dict->FindEntry(prop); + if (entry == -1) { + return ThrowReferenceError(thread, prop, " is not defined"); + } + + PropertyAttributes attributes; + attributes.SetIsConstField(isConst); + dict->SetEntry(thread, entry, prop, value, attributes); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return JSTaggedValue::True(); +} + JSTaggedValue SlowRuntimeStub::ThrowReferenceError(JSThread *thread, JSTaggedValue prop, const char *desc) { [[maybe_unused]] EcmaHandleScope handleScope(thread); diff --git a/ecmascript/interpreter/slow_runtime_stub.h b/ecmascript/interpreter/slow_runtime_stub.h index b67e7d3fc39684b432e6fc591e47f971962fad7f..ecacb260a112a8283686cc6573dba1529e89509b 100644 --- a/ecmascript/interpreter/slow_runtime_stub.h +++ b/ecmascript/interpreter/slow_runtime_stub.h @@ -120,6 +120,8 @@ public: static JSTaggedValue TryStGlobalByName(JSThread *thread, JSTaggedValue prop); static JSTaggedValue LdGlobalVar(JSThread *thread, JSTaggedValue global, JSTaggedValue prop); static JSTaggedValue StGlobalVar(JSThread *thread, JSTaggedValue prop, JSTaggedValue value); + static JSTaggedValue StGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value, bool isConst); + static JSTaggedValue UpdateGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value); static JSTaggedValue StArraySpread(JSThread *thread, JSTaggedValue dst, JSTaggedValue index, JSTaggedValue src); static JSTaggedValue DefineGeneratorFunc(JSThread *thread, JSFunction *func); diff --git a/ecmascript/property_attributes.h b/ecmascript/property_attributes.h index 0dae6320a7fc42c3d7c12d78d23548544ecb8b2a..5aada1faa3e33ba17575c0be61047dd4affe35cf 100644 --- a/ecmascript/property_attributes.h +++ b/ecmascript/property_attributes.h @@ -76,7 +76,7 @@ public: static constexpr uint32_t NORMAL_ATTR_BITS = 18; using NormalAttrField = BitField; using SortedIndexField = OffsetField::NextField; // 28 - + using IsConstField = SortedIndexField::NextFlag; // 29 // dictionary mode, include global using PropertyBoxTypeField = PropertyMetaDataField::NextField; // 2: 2 bits, 5-6 using DictionaryOrderField = PropertyBoxTypeField::NextField; // 26 @@ -217,10 +217,21 @@ public: return IsInlinedPropsField::Get(value_); } + inline void SetIsConstField(bool flag) + { + IsConstField::Set(flag, &value_); + } + + inline bool IsConstField() const + { + return IsConstField::Get(value_); + } + inline void SetRepresentation(Representation representation) { RepresentationField::Set(representation, &value_); } + inline Representation GetRepresentation() const { return RepresentationField::Get(value_);