From 824d65cce930e27d04b4a14c50503374241860a0 Mon Sep 17 00:00:00 2001 From: Malinin Andrey Date: Thu, 7 Mar 2024 18:32:29 +0800 Subject: [PATCH] Map and Set Constructors IR implementation Issue: #I95RB9 Change-Id: I1f3f60e4fecbb731008d4e86e054a6f4e1c219b9 Signed-off-by: Malinin Andrey --- ecmascript/builtins/builtins.cpp | 6 +- .../builtins/builtins_call_signature.h | 4 +- .../compiler/builtins/builtins_stubs.cpp | 15 +++ .../linked_hashtable_stub_builder.cpp | 94 +++++++++++++++++++ .../builtins/linked_hashtable_stub_builder.h | 3 + ecmascript/message_string.h | 3 +- 6 files changed, 121 insertions(+), 4 deletions(-) diff --git a/ecmascript/builtins/builtins.cpp b/ecmascript/builtins/builtins.cpp index e2e79610c3..46a96a32de 100644 --- a/ecmascript/builtins/builtins.cpp +++ b/ecmascript/builtins/builtins.cpp @@ -1365,7 +1365,8 @@ void Builtins::InitializeSet(const JSHandle &env, JSHandleNewEcmaHClass(JSSet::SIZE, JSType::JS_SET, setFuncPrototypeValue); // Set() = new Function() JSHandle setFunction( - NewBuiltinConstructor(env, setFuncPrototype, BuiltinsSet::SetConstructor, "Set", FunctionLength::ZERO)); + NewBuiltinConstructor(env, setFuncPrototype, BuiltinsSet::SetConstructor, "Set", FunctionLength::ZERO, + BUILTINS_STUB_ID(SetConstructor))); JSFunction::SetFunctionPrototypeOrInstanceHClass(thread_, JSHandle(setFunction), setFuncInstanceHClass.GetTaggedValue()); @@ -1441,7 +1442,8 @@ void Builtins::InitializeMap(const JSHandle &env, JSHandleNewEcmaHClass(JSMap::SIZE, JSType::JS_MAP, mapFuncPrototypeValue); // Map() = new Function() JSHandle mapFunction( - NewBuiltinConstructor(env, mapFuncPrototype, BuiltinsMap::MapConstructor, "Map", FunctionLength::ZERO)); + NewBuiltinConstructor(env, mapFuncPrototype, BuiltinsMap::MapConstructor, "Map", FunctionLength::ZERO, + BUILTINS_STUB_ID(MapConstructor))); // Map().prototype = Map.Prototype & Map.prototype.constructor = Map() JSFunction::SetFunctionPrototypeOrInstanceHClass(thread_, JSHandle(mapFunction), diff --git a/ecmascript/compiler/builtins/builtins_call_signature.h b/ecmascript/compiler/builtins/builtins_call_signature.h index 5368bd2173..7b16109869 100644 --- a/ecmascript/compiler/builtins/builtins_call_signature.h +++ b/ecmascript/compiler/builtins/builtins_call_signature.h @@ -106,7 +106,9 @@ namespace panda::ecmascript::kungfu { V(BooleanConstructor) \ V(NumberConstructor) \ V(DateConstructor) \ - V(ArrayConstructor) + V(ArrayConstructor) \ + V(SetConstructor) \ + V(MapConstructor) #define AOT_AND_BUILTINS_STUB_LIST(V) \ V(LocaleCompare) \ diff --git a/ecmascript/compiler/builtins/builtins_stubs.cpp b/ecmascript/compiler/builtins/builtins_stubs.cpp index f15c2cf13e..01aa59165d 100644 --- a/ecmascript/compiler/builtins/builtins_stubs.cpp +++ b/ecmascript/compiler/builtins/builtins_stubs.cpp @@ -34,6 +34,9 @@ #include "ecmascript/compiler/variable_type.h" #include "ecmascript/js_date.h" #include "ecmascript/js_primitive_ref.h" +#include "ecmascript/linked_hash_table.h" +#include "ecmascript/js_set.h" +#include "ecmascript/js_map.h" namespace panda::ecmascript::kungfu { #if ECMASCRIPT_ENABLE_BUILTIN_LOG @@ -750,6 +753,18 @@ DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, HasOwnProperty, VariableType::JS_AN DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, Keys, VariableType::JS_ANY(), Undefined()); #undef DECLARE_BUILTINS_OBJECT_STUB_BUILDER +DECLARE_BUILTINS(MapConstructor) +{ + LinkedHashTableStubBuilder hashTableBuilder(this, glue); + hashTableBuilder.GenMapSetConstructor(nativeCode, func, newTarget, thisValue, numArgs); +} + +DECLARE_BUILTINS(SetConstructor) +{ + LinkedHashTableStubBuilder hashTableBuilder(this, glue); + hashTableBuilder.GenMapSetConstructor(nativeCode, func, newTarget, thisValue, numArgs); +} + #define DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(type, method, retType, retDefaultValue) \ DECLARE_BUILTINS(type##method) \ { \ diff --git a/ecmascript/compiler/builtins/linked_hashtable_stub_builder.cpp b/ecmascript/compiler/builtins/linked_hashtable_stub_builder.cpp index 0738e7a726..b0d54e3c50 100644 --- a/ecmascript/compiler/builtins/linked_hashtable_stub_builder.cpp +++ b/ecmascript/compiler/builtins/linked_hashtable_stub_builder.cpp @@ -643,4 +643,98 @@ template GateRef LinkedHashTableStubBuilder: GateRef linkedTable, GateRef key); template GateRef LinkedHashTableStubBuilder::Has( GateRef linkedTable, GateRef key); + +template +void LinkedHashTableStubBuilder::StoreHashTableToNewObject( + GateRef newTargetHClass, Variable& returnValue) +{ + NewObjectStubBuilder newBuilder(this); + GateRef res = newBuilder.NewJSObject(glue_, newTargetHClass); + returnValue.WriteVariable(res); + GateRef table; + if constexpr (std::is_same_v) { + table = Create(Int32(LinkedHashMap::MIN_CAPACITY)); + Store(VariableType::JS_ANY(), glue_, *returnValue, Int32(JSMap::LINKED_MAP_OFFSET), table); + } else if constexpr (std::is_same_v) { + table = Create(Int32(LinkedHashSet::MIN_CAPACITY)); + Store(VariableType::JS_ANY(), glue_, *returnValue, Int32(JSSet::LINKED_SET_OFFSET), table); + } +} + +template void LinkedHashTableStubBuilder::StoreHashTableToNewObject( + GateRef newTargetHClass, Variable& returnValue); +template void LinkedHashTableStubBuilder::StoreHashTableToNewObject( + GateRef newTargetHClass, Variable& returnValue); + +template +void LinkedHashTableStubBuilder::GenMapSetConstructor( + GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs) +{ + auto env = GetEnvironment(); + DEFVARIABLE(returnValue, VariableType::JS_ANY(), Undefined()); + + Label newTargetObject(env); + Label newTargetNotObject(env); + Label newTargetFunction(env); + Label slowPath(env); + Label exit(env); + + // 1.If NewTarget is undefined, throw a TypeError exception + Branch(TaggedIsHeapObject(newTarget), &newTargetObject, &newTargetNotObject); + + Bind(&newTargetObject); + Branch(IsJSFunction(newTarget), &newTargetFunction, &slowPath); + + Bind(&newTargetFunction); + Label fastGetHClass(env); + Label intialHClassIsHClass(env); + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue_, glueGlobalEnvOffset); + GateRef mapOrSetFunc; + if constexpr (std::is_same_v) { + mapOrSetFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::BUILTINS_MAP_FUNCTION_INDEX); + } else if constexpr (std::is_same_v) { + mapOrSetFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::BUILTINS_SET_FUNCTION_INDEX); + } + GateRef funcEq = Equal(mapOrSetFunc, newTarget); + GateRef newTargetHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + GateRef isHClass = IsJSHClass(newTargetHClass); + Branch(BoolAnd(funcEq, isHClass), &fastGetHClass, &slowPath); + + Bind(&fastGetHClass); + Label isUndefinedOrNull(env); + Branch(TaggedIsUndefinedOrNull(GetCallArg0(numArgs)), &isUndefinedOrNull, &slowPath); + + Bind(&isUndefinedOrNull); + StoreHashTableToNewObject(newTargetHClass, returnValue); + Jump(&exit); + + Bind(&newTargetNotObject); + GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InvalidNewTarget)); + CallRuntime(glue_, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) }); + returnValue = Exception(); + Jump(&exit); + + Bind(&slowPath); + std::string name; + if constexpr (std::is_same_v) { + name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(MapConstructor)); + } else if constexpr (std::is_same_v) { + name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(SetConstructor)); + } + returnValue = CallBuiltinRuntimeWithNewTarget(glue_, {glue_, nativeCode, func, thisValue, + numArgs, GetArgv(), newTarget}, name.c_str()); + Jump(&exit); + + Bind(&exit); + Return(*returnValue); +} + +template void LinkedHashTableStubBuilder::GenMapSetConstructor( + GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs); +template void LinkedHashTableStubBuilder::GenMapSetConstructor( + GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs); + } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/builtins/linked_hashtable_stub_builder.h b/ecmascript/compiler/builtins/linked_hashtable_stub_builder.h index 707adff226..5481a0a695 100644 --- a/ecmascript/compiler/builtins/linked_hashtable_stub_builder.h +++ b/ecmascript/compiler/builtins/linked_hashtable_stub_builder.h @@ -36,6 +36,8 @@ public: GateRef Delete(GateRef linkedTable, GateRef key); GateRef Has(GateRef linkedTable, GateRef key); + void GenMapSetConstructor(GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs); + private: GateRef IsKey(GateRef key) { @@ -198,6 +200,7 @@ private: void Rehash(GateRef linkedTable, GateRef newTable); GateRef ComputeCapacity(GateRef atLeastSpaceFor); void RemoveEntry(GateRef linkedTable, GateRef entry); + void StoreHashTableToNewObject(GateRef newTargetHClass, Variable& returnValue); GateRef glue_; }; diff --git a/ecmascript/message_string.h b/ecmascript/message_string.h index c3cb94bf41..093d18de01 100644 --- a/ecmascript/message_string.h +++ b/ecmascript/message_string.h @@ -55,7 +55,8 @@ namespace panda::ecmascript { V(CanNotConvertUnknowObject, "Cannot convert a Unknown object value to a JSObject") \ V(CanNotConvertNotValidObject, "Obj is not a valid object") \ V(CanNotConvertContainerObject, "Can not delete property in Container Object") \ - V(InvalidStringLength, "Invalid string length") + V(InvalidStringLength, "Invalid string length") \ + V(InvalidNewTarget, "new.target is not an object") #define DEBUG_CHECK_MESSAGE_STRING_LIST(V) \ V(IsCallable) \ -- Gitee