diff --git a/ecmascript/builtins/builtins.cpp b/ecmascript/builtins/builtins.cpp index e2e79610c35ddd254201fa1553e82aec599333f1..46a96a32de2c6cddccc721b8c0e61e6885899975 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 5368bd2173c9996e071f561f2bae4952d4556936..7b1610986951d1ff64104ba9dab6f539c38f4392 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 f15c2cf13eb9e7d8d204752180055f8fa333b27c..01aa59165d8fcb3bbab997ea4bcee080a526b5c5 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 0738e7a7268fc659fc4cd97d3a467d209e46439c..b0d54e3c50a92af3c7c166d022bd8447aba0f2cb 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 707adff2264566a3c88d8e664f627298ba526802..5481a0a695b3e4111373ecc4193c62b248fc48e3 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 c3cb94bf4123dcda3184b86beae895069806502f..093d18de0154f370342cd6081757cb4faa8da044 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) \