diff --git a/compiler/ecmascript_extensions/ecmascript_compiler_interface.h b/compiler/ecmascript_extensions/ecmascript_compiler_interface.h index b65bc0bad43fe35bf2d49fb16779d5001aeab108..9f51df43ce547dc518bb5b89a597fe0339c17bb7 100644 --- a/compiler/ecmascript_extensions/ecmascript_compiler_interface.h +++ b/compiler/ecmascript_extensions/ecmascript_compiler_interface.h @@ -52,4 +52,15 @@ virtual bool GetProfileDataForNamedAccess( { return false; } + +virtual bool IsNonConfigurableGlobalVar([[maybe_unused]] MethodPtr method, [[maybe_unused]] size_t id) const +{ + return false; +} + +virtual uint64_t TryGetConstantGlobalVar([[maybe_unused]] MethodPtr method, [[maybe_unused]] size_t id) const +{ + return 0; +} + #endif // PANDA_COMPILER_ECMASCRIPT_COMPILER_INTERFACE_H \ No newline at end of file diff --git a/compiler/optimizer/optimizations/expand_intrinsics.cpp b/compiler/optimizer/optimizations/expand_intrinsics.cpp index 64f76c03e9d46c1263eafdff3b4280d9eb949927..ee9ad4cfd7ea3861fd2b469849b0f2ad237decb7 100644 --- a/compiler/optimizer/optimizations/expand_intrinsics.cpp +++ b/compiler/optimizer/optimizations/expand_intrinsics.cpp @@ -44,11 +44,15 @@ bool ExpandIntrinsics::RunImpl() bool ExpandIntrinsics::Expand(IntrinsicInst *inst) { auto id = inst->GetIntrinsicId(); - if (id == RuntimeInterface::IntrinsicId::INTRINSIC_NEWOBJ_DYNRANGE || - id == RuntimeInterface::IntrinsicId::INTRINSIC_NEWOBJ_DYNRANGE_HANDLED) { - return ExpandNewObjDynRange(inst); + switch (id) { + case RuntimeInterface::IntrinsicId::INTRINSIC_NEWOBJ_DYNRANGE: + case RuntimeInterface::IntrinsicId::INTRINSIC_NEWOBJ_DYNRANGE_HANDLED: + return ExpandNewObjDynRange(inst); + case RuntimeInterface::IntrinsicId::INTRINSIC_TRY_LD_GLOBAL_BY_NAME: + return ExpandTryLdGlobalByName(inst); + default: + return false; } - return false; } void ExpandIntrinsics::InstAppender::Append(std::initializer_list instructions) @@ -329,4 +333,49 @@ void ExpandIntrinsics::BuildGuard(Inst *inst, uintptr_t target) inst->InsertBefore(deopt_inst); } +bool ExpandIntrinsics::ExpandTryLdGlobalByName(IntrinsicInst *inst) +{ + if (GetGraph()->IsAotMode()) { + return false; + } + ASSERT(inst->GetSaveState() != nullptr); + auto runtime = GetGraph()->GetRuntime(); + auto type_id = inst->GetImms()[0]; + auto value = runtime->TryGetConstantGlobalVar(GetGraph()->GetMethod(), type_id); + if (value != 0) { + auto constant = GetGraph()->FindOrCreateConstant(DataType::Any(value)); + inst->ReplaceUsers(constant); + inst->GetBasicBlock()->RemoveInst(inst); + return true; + } + if (runtime->IsNonConfigurableGlobalVar(GetGraph()->GetMethod(), type_id)) { + ExpandTryLdGlobalFastPath(inst); + return true; + } + return false; +} + +void ExpandIntrinsics::ExpandTryLdGlobalFastPath(IntrinsicInst *inst) +{ + auto pc = inst->GetPc(); + auto save_state = inst->GetSaveState(); + auto get_address = GetGraph()->CreateInstGetGlobalVarAddress(DataType::REFERENCE, pc); + auto type_id = inst->GetImms()[0]; + + get_address->SetTypeId(type_id); + get_address->SetMethod(GetGraph()->GetMethod()); + get_address->SetInput(0, save_state); + + auto load_object = GetGraph()->CreateInstLoadObject(DataType::ANY, pc); + load_object->SetTypeId(type_id); + load_object->SetMethod(GetGraph()->GetMethod()); + load_object->SetObjField(nullptr); + load_object->SetObjectType(ObjectType::MEM_GLOBAL); + load_object->SetInput(0, get_address); + inst->InsertBefore(get_address); + inst->InsertBefore(load_object); + inst->ReplaceUsers(load_object); + inst->GetBasicBlock()->RemoveInst(inst); +} + } // namespace panda::compiler \ No newline at end of file diff --git a/compiler/optimizer/optimizations/expand_intrinsics.h b/compiler/optimizer/optimizations/expand_intrinsics.h index 1430b60396e103b6222bb05a8b5df5f9d6f0e90d..03964413653eeb80bc0ff45a7770680d3460b59b 100644 --- a/compiler/optimizer/optimizations/expand_intrinsics.h +++ b/compiler/optimizer/optimizations/expand_intrinsics.h @@ -67,6 +67,9 @@ private: uint32_t pc); void BuildGuard(Inst *inst, uintptr_t target); + bool ExpandTryLdGlobalByName(IntrinsicInst *inst); + void ExpandTryLdGlobalFastPath(IntrinsicInst *inst); + ArenaVector functions_; }; diff --git a/runtime/compiler/ecmascript_runtime_interface.cpp b/runtime/compiler/ecmascript_runtime_interface.cpp index 37bd3d6010ab44dcb41b8ca17d3a44b0be714886..087bfc12e1ea1bdb386b28946b8e06b19f2b6720 100644 --- a/runtime/compiler/ecmascript_runtime_interface.cpp +++ b/runtime/compiler/ecmascript_runtime_interface.cpp @@ -60,38 +60,16 @@ uint32_t EcmaRuntimeInterface::GetFunctionTargetOffset([[maybe_unused]] Arch arc uintptr_t EcmaRuntimeInterface::GetGlobalVarAddress(MethodPtr method, size_t id) { - if (ecma_vm_ == nullptr) { - return 0; - } - auto thread = ecma_vm_->GetJSThread(); + auto thread = TryGetJSThread(); // Thread can be removed during destroy runtime - if (thread == nullptr || !thread->IsThreadAlive()) { + if (thread == nullptr) { return 0; } ScopedMutatorLock lock; - auto panda_file = JsMethodCast(method)->GetPandaFile(); - JSTaggedValue constant_pool(JSTaggedValue::VALUE_HOLE); - - auto func = [&](Program *p) { constant_pool = p->GetConstantPool(); }; - ecma_vm_->EnumerateProgram(func, panda_file->GetFilename()); - if (constant_pool.IsUndefined()) { - return 0; - } - - ASSERT(!constant_pool.IsHole()); - - JSTaggedValue key = ConstantPool::Cast(constant_pool.GetHeapObject())->GetObjectFromCache(id); - auto global_obj = thread->GetGlobalObject(); - auto js_obj = JSObject::Cast(global_obj.GetTaggedObject()); - TaggedArray *array = TaggedArray::Cast(js_obj->GetProperties().GetTaggedObject()); - if (array->GetLength() == 0) { - return 0; - } - - GlobalDictionary *dict = GlobalDictionary::Cast(array); - int entry = dict->FindEntry(key); + GlobalDictionary *dict; + auto entry = GetGlobalDictionaryEntry(thread, method, id, &dict); if (entry == -1) { return 0; } @@ -373,4 +351,83 @@ void EcmaRuntimeInterface::CleanFunction(Method *method) ASSERT(ecma_vm_ != nullptr); ecma_vm_->GetGlobalObjectStorage()->Remove(func); } + +bool EcmaRuntimeInterface::IsNonConfigurableGlobalVar(MethodPtr method, size_t id) const +{ + auto thread = TryGetJSThread(); + if (thread == nullptr) { + return false; + } + + ScopedMutatorLock lock; + GlobalDictionary *dict; + auto entry = GetGlobalDictionaryEntry(thread, method, id, &dict); + if (entry == -1) { + return false; + } + PropertyAttributes attr = dict->GetAttributes(entry); + return !attr.IsConfigurable() && !attr.IsAccessor(); +} + +uint64_t EcmaRuntimeInterface::TryGetConstantGlobalVar(MethodPtr method, size_t id) const +{ + auto thread = TryGetJSThread(); + if (thread == nullptr) { + return 0; + } + + ScopedMutatorLock lock; + GlobalDictionary *dict; + auto entry = GetGlobalDictionaryEntry(thread, method, id, &dict); + if (entry == -1) { + return 0; + } + PropertyAttributes attr = dict->GetAttributes(entry); + if (attr.IsConfigurable() || attr.IsWritable() || attr.IsAccessor()) { + return 0; + } + auto value = dict->GetValue(entry); + if (value.IsHeapObject()) { + return 0; + } + return value.GetRawData(); +} + +JSThread *EcmaRuntimeInterface::TryGetJSThread() const +{ + if (ecma_vm_ == nullptr) { + return nullptr; + } + auto thread = ecma_vm_->GetJSThread(); + if (thread == nullptr || !thread->IsThreadAlive()) { + return nullptr; + } + return thread; +} + +int EcmaRuntimeInterface::GetGlobalDictionaryEntry(JSThread *thread, MethodPtr method, size_t id, + GlobalDictionary **dict) const +{ + auto panda_file = JsMethodCast(method)->GetPandaFile(); + JSTaggedValue constant_pool(JSTaggedValue::VALUE_HOLE); + + auto func = [&](Program *p) { constant_pool = p->GetConstantPool(); }; + ecma_vm_->EnumerateProgram(func, panda_file->GetFilename()); + if (constant_pool.IsUndefined()) { + return -1; + } + + ASSERT(!constant_pool.IsHole()); + + JSTaggedValue key = ConstantPool::Cast(constant_pool.GetHeapObject())->GetObjectFromCache(id); + auto global_obj = thread->GetGlobalObject(); + auto js_obj = JSObject::Cast(global_obj.GetTaggedObject()); + TaggedArray *array = TaggedArray::Cast(js_obj->GetProperties().GetTaggedObject()); + if (array->GetLength() == 0) { + return -1; + } + + *dict = GlobalDictionary::Cast(array); + return (*dict)->FindEntry(key); +} } // namespace panda::ecmascript diff --git a/runtime/compiler/ecmascript_runtime_interface.h b/runtime/compiler/ecmascript_runtime_interface.h index 31743db43787e3968524a2c59ca59adc4481fa1c..7a236053248e425ef184fd63d0d1c108cd5a207b 100644 --- a/runtime/compiler/ecmascript_runtime_interface.h +++ b/runtime/compiler/ecmascript_runtime_interface.h @@ -26,6 +26,7 @@ namespace panda::ecmascript { class EcmaVM; class ProfileTypeInfo; +class GlobalDictionary; enum class ObjectFieldType : uint8_t { INVALID = 0, ELEMENTS, COUNT }; @@ -135,6 +136,11 @@ public: bool AddProfileInfo(ArenaVector *profile, ProfileTypeInfo *profile_type_info, uint8_t slot); + bool IsNonConfigurableGlobalVar(MethodPtr method, size_t id) const override; + uint64_t TryGetConstantGlobalVar(MethodPtr method, size_t id) const override; + JSThread *TryGetJSThread() const; + int GetGlobalDictionaryEntry(JSThread *thread, MethodPtr method, size_t id, GlobalDictionary **dict) const; + private: const EcmaVM *ecma_vm_ {nullptr}; panda::ecmascript::EcmaProfileContainer profile_; diff --git a/runtime/global_dictionary-inl.h b/runtime/global_dictionary-inl.h index 566c062c2235945c809e383656e120bc6bb61198..301ed005a654f1696e4a5325321af88fb21c64aa 100644 --- a/runtime/global_dictionary-inl.h +++ b/runtime/global_dictionary-inl.h @@ -79,6 +79,9 @@ void GlobalDictionary::SetEntry(const JSThread *thread, int entry, const JSTagge void GlobalDictionary::ClearEntry(const JSThread *thread, int entry) { +#if ECMASCRIPT_ENABLE_IC + GetBox(entry)->Clear(thread); +#endif JSTaggedValue hole = JSTaggedValue::Hole(); PropertyAttributes meta_data; SetEntry(thread, entry, hole, hole, meta_data); diff --git a/runtime/ic/profile_type_info.cpp b/runtime/ic/profile_type_info.cpp index 2968e411605bc2203cb08484e9b4f55d5dae5464..4d372371f8e8bdd988a8f1941955ac2a26ce12cc 100644 --- a/runtime/ic/profile_type_info.cpp +++ b/runtime/ic/profile_type_info.cpp @@ -109,7 +109,9 @@ void ProfileTypeAccessor::AddGlobalHandlerKey(JSHandle key, JSHan void ProfileTypeAccessor::SetAsMega() const { profile_type_info_->Set(thread_, slot_id_, JSTaggedValue::Hole()); - profile_type_info_->Set(thread_, slot_id_ + 1, JSTaggedValue::Hole()); + if (!IsNamedGlobalIC(GetKind())) { + profile_type_info_->Set(thread_, slot_id_ + 1, JSTaggedValue::Hole()); + } } std::string ICKindToString(ICKind kind) diff --git a/runtime/object_operator.cpp b/runtime/object_operator.cpp index 061a7d97dae3bc3e14491ff2e82c5a765f0261a4..e1d54bba6e1b7d113a776fac1d5f1681483cf351 100644 --- a/runtime/object_operator.cpp +++ b/runtime/object_operator.cpp @@ -311,8 +311,8 @@ void ObjectOperator::LookupPropertyInlinedProps(const JSHandle &obj) } JSTaggedValue value(dict->GetBox(entry)); - uint32_t attr = dict->GetAttributes(entry).GetValue(); - SetFound(entry, value, attr, true); + PropertyAttributes attr = dict->GetAttributes(entry); + SetFound(entry, value, attr.GetValue(), !attr.IsAccessor()); return; } @@ -457,6 +457,10 @@ bool ObjectOperator::WriteDataProperty(const JSHandle &receiver, const attr_changed = true; } + if (IsAccessorDescriptor() && value_->IsPropertyBox()) { + value_.Update(PropertyBox::Cast(value_->GetTaggedObject())->GetValue()); + } + if (!desc.IsAccessorDescriptor()) { if (desc.HasWritable() && attr.IsWritable() != desc.IsWritable()) { attr.SetWritable(desc.IsWritable());