/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/compiler/builtins/builtins_stubs.h" #include "ecmascript/base/number_helper.h" #include "ecmascript/compiler/builtins/builtins_array_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_call_signature.h" #include "ecmascript/compiler/builtins/builtins_function_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_string_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_number_stub_builder.h" #include "ecmascript/compiler/builtins/containers_vector_stub_builder.h" #include "ecmascript/compiler/builtins/containers_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_collection_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_object_stub_builder.h" #include "ecmascript/compiler/typed_array_stub_builder.h" #include "ecmascript/compiler/interpreter_stub-inl.h" #include "ecmascript/compiler/llvm_ir_builder.h" #include "ecmascript/compiler/new_object_stub_builder.h" #include "ecmascript/compiler/stub_builder-inl.h" #include "ecmascript/compiler/stub_builder.h" #include "ecmascript/compiler/variable_type.h" #include "ecmascript/js_date.h" #include "ecmascript/js_primitive_ref.h" namespace panda::ecmascript::kungfu { #if ECMASCRIPT_ENABLE_BUILTIN_LOG #define DECLARE_BUILTINS(name) \ void name##StubBuilder::GenerateCircuit() \ { \ GateRef glue = PtrArgument(static_cast<size_t>(BuiltinsArgs::GLUE)); \ GateRef nativeCode = PtrArgument(static_cast<size_t>(BuiltinsArgs::NATIVECODE)); \ GateRef func = TaggedArgument(static_cast<size_t>(BuiltinsArgs::FUNC)); \ GateRef newTarget = TaggedArgument(static_cast<size_t>(BuiltinsArgs::NEWTARGET)); \ GateRef thisValue = TaggedArgument(static_cast<size_t>(BuiltinsArgs::THISVALUE)); \ GateRef numArgs = PtrArgument(static_cast<size_t>(BuiltinsArgs::NUMARGS)); \ DebugPrint(glue, { Int32(GET_MESSAGE_STRING_ID(name)) }); \ GenerateCircuitImpl(glue, nativeCode, func, newTarget, thisValue, numArgs); \ } \ void name##StubBuilder::GenerateCircuitImpl(GateRef glue, GateRef nativeCode, GateRef func, \ GateRef newTarget, GateRef thisValue, GateRef numArgs) #else #define DECLARE_BUILTINS(name) \ void name##StubBuilder::GenerateCircuit() \ { \ GateRef glue = PtrArgument(static_cast<size_t>(BuiltinsArgs::GLUE)); \ GateRef nativeCode = PtrArgument(static_cast<size_t>(BuiltinsArgs::NATIVECODE)); \ GateRef func = TaggedArgument(static_cast<size_t>(BuiltinsArgs::FUNC)); \ GateRef newTarget = TaggedArgument(static_cast<size_t>(BuiltinsArgs::NEWTARGET)); \ GateRef thisValue = TaggedArgument(static_cast<size_t>(BuiltinsArgs::THISVALUE)); \ GateRef numArgs = PtrArgument(static_cast<size_t>(BuiltinsArgs::NUMARGS)); \ GenerateCircuitImpl(glue, nativeCode, func, newTarget, thisValue, numArgs); \ } \ void name##StubBuilder::GenerateCircuitImpl(GateRef glue, GateRef nativeCode, GateRef func, \ GateRef newTarget, GateRef thisValue, GateRef numArgs) #endif GateRef BuiltinsStubBuilder::GetArg(GateRef numArgs, GateRef index) { auto env = GetEnvironment(); Label entry(env); env->SubCfgEntry(&entry); DEFVARIABLE(arg, VariableType::JS_ANY(), Undefined()); Label validIndex(env); Label exit(env); Branch(IntPtrGreaterThan(numArgs, index), &validIndex, &exit); Bind(&validIndex); { GateRef argv = GetArgv(); arg = Load(VariableType::JS_ANY(), argv, PtrMul(index, IntPtr(JSTaggedValue::TaggedTypeSize()))); Jump(&exit); } Bind(&exit); GateRef ret = *arg; env->SubCfgExit(); return ret; } GateRef BuiltinsStubBuilder::CallSlowPath(GateRef nativeCode, GateRef glue, GateRef thisValue, GateRef numArgs, GateRef func, GateRef newTarget, const char* comment) { auto env = GetEnvironment(); Label entry(env); env->SubCfgEntry(&entry); Label exit(env); Label callThis0(env); Label notcallThis0(env); Label notcallThis1(env); Label callThis1(env); Label callThis2(env); Label callThis3(env); DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); GateRef runtimeCallInfoArgs = PtrAdd(numArgs, IntPtr(NUM_MANDATORY_JSFUNC_ARGS)); Branch(Int64Equal(numArgs, IntPtr(0)), &callThis0, ¬callThis0); Bind(&callThis0); { auto args = { nativeCode, glue, runtimeCallInfoArgs, func, newTarget, thisValue }; result = CallBuiltinRuntime(glue, args, false, comment); Jump(&exit); } Bind(¬callThis0); { Branch(Int64Equal(numArgs, IntPtr(1)), &callThis1, ¬callThis1); Bind(&callThis1); { GateRef arg0 = GetCallArg0(numArgs); auto args = { nativeCode, glue, runtimeCallInfoArgs, func, newTarget, thisValue, arg0 }; result = CallBuiltinRuntime(glue, args, false, comment); Jump(&exit); } Bind(¬callThis1); { Branch(Int64Equal(numArgs, IntPtr(2)), &callThis2, &callThis3); // 2: args2 Bind(&callThis2); { GateRef arg0 = GetCallArg0(numArgs); GateRef arg1 = GetCallArg1(numArgs); auto args = { nativeCode, glue, runtimeCallInfoArgs, func, newTarget, thisValue, arg0, arg1 }; result = CallBuiltinRuntime(glue, args, false, comment); Jump(&exit); } Bind(&callThis3); { GateRef arg0 = GetCallArg0(numArgs); GateRef arg1 = GetCallArg1(numArgs); GateRef arg2 = GetCallArg2(numArgs); auto args = { nativeCode, glue, runtimeCallInfoArgs, func, newTarget, thisValue, arg0, arg1, arg2 }; result = CallBuiltinRuntime(glue, args, false, comment); Jump(&exit); } } } Bind(&exit); auto ret = *result; env->SubCfgExit(); return ret; } #define DECLARE_BUILTINS_WITH_STRING_STUB_BUILDER(method, resultVariableType, initValue) \ DECLARE_BUILTINS(String##method) \ { \ auto env = GetEnvironment(); \ DEFVARIABLE(res, VariableType::resultVariableType(), initValue); \ Label exit(env); \ Label slowPath(env); \ BuiltinsStringStubBuilder stringStubBuilder(this); \ stringStubBuilder.method(glue, thisValue, numArgs, &res, &exit, &slowPath); \ Bind(&slowPath); \ { \ auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(String##method)); \ res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ Jump(&exit); \ } \ Bind(&exit); \ Return(*res); \ } #define BUILTINS_WITH_STRING_STUB_BUILDER(V) \ V(CharAt, JS_POINTER, Hole()) \ V(FromCharCode, JS_ANY, Hole()) \ V(CharCodeAt, JS_ANY, DoubleToTaggedDoublePtr(Double(base::NAN_VALUE))) \ V(IndexOf, JS_ANY, IntToTaggedPtr(Int32(-1))) \ V(Substring, JS_ANY, IntToTaggedPtr(Int32(-1))) \ V(Replace, JS_ANY, Undefined()) \ V(Trim, JS_ANY, Undefined()) \ V(Slice, JS_ANY, Undefined()) DECLARE_BUILTINS(LocaleCompare) { auto env = GetEnvironment(); DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); Label exit(env); Label slowPath(env); BuiltinsStringStubBuilder stringStubBuilder(this); stringStubBuilder.LocaleCompare(glue, thisValue, numArgs, &res, &exit, &slowPath); Bind(&slowPath); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(LocaleCompare)); res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); Jump(&exit); } Bind(&exit); Return(*res); } BUILTINS_WITH_STRING_STUB_BUILDER(DECLARE_BUILTINS_WITH_STRING_STUB_BUILDER) #undef DECLARE_BUILTINS_WITH_STRING_STUB_BUILDER #undef BUILTINS_WITH_STRING_STUB_BUILDER DECLARE_BUILTINS(FunctionPrototypeApply) { auto env = GetEnvironment(); DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); Label exit(env); Label slowPath(env); BuiltinsFunctionStubBuilder functionStubBuilder(this); functionStubBuilder.Apply(glue, thisValue, numArgs, &res, &exit, &slowPath); Bind(&slowPath); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(FunctionPrototypeApply)); res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); Jump(&exit); } Bind(&exit); Return(*res); } #define DECLARE_BUILTINS_WITH_CONTAINERS_STUB_BUILDER(StubName, Method, methodType, resultVariableType) \ DECLARE_BUILTINS(StubName) \ { \ auto env = GetEnvironment(); \ DEFVARIABLE(res, VariableType::resultVariableType(), Undefined()); \ Label exit(env); \ Label slowPath(env); \ ContainersStubBuilder containersBuilder(this); \ containersBuilder.Method(glue, thisValue, numArgs, &res, &exit, &slowPath, ContainersType::methodType); \ Bind(&slowPath); \ { \ auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(StubName)); \ res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ Jump(&exit); \ } \ Bind(&exit); \ Return(*res); \ } #define BUILTINS_WITH_CONTAINERS_STUB_BUILDER(V) \ V(ArrayListForEach, ContainersCommonFuncCall, ARRAYLIST_FOREACH, JS_POINTER) \ V(DequeForEach, DequeCommonFuncCall, DEQUE_FOREACH, JS_POINTER) \ V(HashMapForEach, ContainersHashCall, HASHMAP_FOREACH, JS_POINTER) \ V(HashSetForEach, ContainersHashCall, HASHSET_FOREACH, JS_POINTER) \ V(LightWeightMapForEach, ContainersLightWeightCall, LIGHTWEIGHTMAP_FOREACH, JS_POINTER) \ V(LightWeightSetForEach, ContainersLightWeightCall, LIGHTWEIGHTSET_FOREACH, JS_POINTER) \ V(LinkedListForEach, ContainersLinkedListCall, LINKEDLIST_FOREACH, JS_POINTER) \ V(ListForEach, ContainersLinkedListCall, LIST_FOREACH, JS_POINTER) \ V(PlainArrayForEach, ContainersCommonFuncCall, PLAINARRAY_FOREACH, JS_POINTER) \ V(QueueForEach, QueueCommonFuncCall, QUEUE_FOREACH, JS_POINTER) \ V(StackForEach, ContainersCommonFuncCall, STACK_FOREACH, JS_POINTER) \ V(VectorForEach, ContainersCommonFuncCall, VECTOR_FOREACH, JS_POINTER) \ V(ArrayListReplaceAllElements, ContainersCommonFuncCall, ARRAYLIST_REPLACEALLELEMENTS, JS_POINTER) \ V(VectorReplaceAllElements, ContainersCommonFuncCall, VECTOR_REPLACEALLELEMENTS, JS_POINTER) BUILTINS_WITH_CONTAINERS_STUB_BUILDER(DECLARE_BUILTINS_WITH_CONTAINERS_STUB_BUILDER) #undef DECLARE_BUILTINS_WITH_CONTAINERS_STUB_BUILDER #undef BUILTINS_WITH_CONTAINERS_STUB_BUILDER #define DECLARE_BUILTINS_WITH_ARRAY_STUB_BUILDER(Method, resultVariableType) \ DECLARE_BUILTINS(Array##Method) \ { \ auto env = GetEnvironment(); \ DEFVARIABLE(res, VariableType::resultVariableType(), Undefined()); \ Label exit(env); \ Label slowPath(env); \ BuiltinsArrayStubBuilder arrayStubBuilder(this); \ arrayStubBuilder.Method(glue, thisValue, numArgs, &res, &exit, &slowPath); \ Bind(&slowPath); \ { \ auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(Array##Method)); \ res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ Jump(&exit); \ } \ Bind(&exit); \ Return(*res); \ } #define BUILTINS_WITH_ARRAY_STUB_BUILDER(V) \ V(Concat, JS_ANY) \ V(Filter, JS_POINTER) \ V(Find, JS_ANY) \ V(FindIndex, JS_ANY) \ V(From, JS_ANY) \ V(Splice, JS_ANY) \ V(ForEach, JS_ANY) \ V(IndexOf, JS_ANY) \ V(LastIndexOf, JS_ANY) \ V(Pop, JS_ANY) \ V(Slice, JS_POINTER) \ V(Reduce, JS_ANY) \ V(Reverse, JS_POINTER) \ V(Push, JS_ANY) \ V(Values, JS_POINTER) \ V(Includes, JS_ANY) DECLARE_BUILTINS(SORT) { auto env = GetEnvironment(); DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); Label exit(env); Label slowPath(env); BuiltinsArrayStubBuilder arrayStubBuilder(this); arrayStubBuilder.Sort(glue, thisValue, numArgs, &res, &exit, &slowPath); Bind(&slowPath); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(SORT)); res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); Jump(&exit); } Bind(&exit); Return(*res); } BUILTINS_WITH_ARRAY_STUB_BUILDER(DECLARE_BUILTINS_WITH_ARRAY_STUB_BUILDER) #undef DECLARE_BUILTINS_WITH_ARRAY_STUB_BUILDER #undef BUILTINS_WITH_ARRAY_STUB_BUILDER DECLARE_BUILTINS(BooleanConstructor) { auto env = GetEnvironment(); DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); Label newTargetIsHeapObject(env); Label newTargetIsJSFunction(env); Label slowPath(env); Label slowPath1(env); Label slowPath2(env); Label exit(env); Branch(TaggedIsHeapObject(newTarget), &newTargetIsHeapObject, &slowPath1); Bind(&newTargetIsHeapObject); Branch(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath); Bind(&newTargetIsJSFunction); { Label intialHClassIsHClass(env); GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); Branch(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath2); Bind(&intialHClassIsHClass); { NewObjectStubBuilder newBuilder(this); newBuilder.SetParameters(glue, 0); Label afterNew(env); newBuilder.NewJSObject(&res, &afterNew, intialHClass); Bind(&afterNew); { GateRef valueOffset = IntPtr(JSPrimitiveRef::VALUE_OFFSET); GateRef value = GetArg(numArgs, IntPtr(0)); Store(VariableType::INT64(), glue, *res, valueOffset, FastToBoolean(value)); Jump(&exit); } } Bind(&slowPath2); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(BooleanConstructor)); GateRef argv = GetArgv(); auto args = { glue, nativeCode, func, thisValue, numArgs, argv, newTarget }; res = CallBuiltinRuntimeWithNewTarget(glue, args, name.c_str()); Jump(&exit); } } Bind(&slowPath); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(BooleanConstructor)); GateRef argv = GetArgv(); auto args = { glue, nativeCode, func, thisValue, numArgs, argv }; res = CallBuiltinRuntime(glue, args, true, name.c_str()); Jump(&exit); } Bind(&slowPath1); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(BooleanConstructor)); res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); Jump(&exit); } Bind(&exit); Return(*res); } DECLARE_BUILTINS(NumberConstructor) { auto env = GetEnvironment(); DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); DEFVARIABLE(numberValue, VariableType::JS_ANY(), IntToTaggedPtr(IntPtr(0))); Label thisCollectionObj(env); Label slowPath(env); Label slowPath1(env); Label slowPath2(env); Label exit(env); Label hasArg(env); Label numberCreate(env); Label newTargetIsHeapObject(env); Branch(TaggedIsHeapObject(newTarget), &newTargetIsHeapObject, &slowPath1); Bind(&newTargetIsHeapObject); Branch(Int64GreaterThan(numArgs, IntPtr(0)), &hasArg, &numberCreate); Bind(&hasArg); { GateRef value = GetArgNCheck(Int32(0)); Label number(env); Branch(TaggedIsNumber(value), &number, &slowPath); Bind(&number); { numberValue = value; res = value; Jump(&numberCreate); } } Bind(&numberCreate); Label newObj(env); Label newTargetIsJSFunction(env); Branch(TaggedIsUndefined(newTarget), &exit, &newObj); Bind(&newObj); { Branch(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath); Bind(&newTargetIsJSFunction); { Label intialHClassIsHClass(env); GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); Branch(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath2); Bind(&intialHClassIsHClass); { NewObjectStubBuilder newBuilder(this); newBuilder.SetParameters(glue, 0); Label afterNew(env); newBuilder.NewJSObject(&res, &afterNew, intialHClass); Bind(&afterNew); { GateRef valueOffset = IntPtr(JSPrimitiveRef::VALUE_OFFSET); Store(VariableType::INT64(), glue, *res, valueOffset, *numberValue); Jump(&exit); } } Bind(&slowPath2); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(NumberConstructor)); GateRef argv = GetArgv(); res = CallBuiltinRuntimeWithNewTarget(glue, { glue, nativeCode, func, thisValue, numArgs, argv, newTarget }, name.c_str()); Jump(&exit); } } } Bind(&slowPath); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(NumberConstructor)); GateRef argv = GetArgv(); res = CallBuiltinRuntime(glue, { glue, nativeCode, func, thisValue, numArgs, argv }, true, name.c_str()); Jump(&exit); } Bind(&slowPath1); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(NumberConstructor)); res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); Jump(&exit); } Bind(&exit); Return(*res); } DECLARE_BUILTINS(DateConstructor) { auto env = GetEnvironment(); DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); Label newTargetIsHeapObject(env); Label newTargetIsJSFunction(env); Label slowPath(env); Label slowPath1(env); Label slowPath2(env); Label exit(env); Branch(TaggedIsHeapObject(newTarget), &newTargetIsHeapObject, &slowPath1); Bind(&newTargetIsHeapObject); Branch(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath); Bind(&newTargetIsJSFunction); { Label intialHClassIsHClass(env); GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); Branch(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath2); Bind(&intialHClassIsHClass); { Label oneArg(env); Label notOneArg(env); Label newJSDate(env); DEFVARIABLE(timeValue, VariableType::FLOAT64(), Double(0)); Branch(Int64Equal(numArgs, IntPtr(1)), &oneArg, ¬OneArg); Bind(&oneArg); { Label valueIsNumber(env); GateRef value = GetArgNCheck(IntPtr(0)); Branch(TaggedIsNumber(value), &valueIsNumber, &slowPath); Bind(&valueIsNumber); { timeValue = CallNGCRuntime(glue, RTSTUB_ID(TimeClip), {GetDoubleOfTNumber(value)}); Jump(&newJSDate); } } Bind(¬OneArg); { Label threeArgs(env); Branch(Int64Equal(numArgs, IntPtr(3)), &threeArgs, &slowPath); // 3: year month day Bind(&threeArgs); { Label numberYearMonthDay(env); GateRef year = GetArgNCheck(IntPtr(0)); GateRef month = GetArgNCheck(IntPtr(1)); GateRef day = GetArgNCheck(IntPtr(2)); Branch(IsNumberYearMonthDay(year, month, day), &numberYearMonthDay, &slowPath); Bind(&numberYearMonthDay); { GateRef y = GetDoubleOfTNumber(year); GateRef m = GetDoubleOfTNumber(month); GateRef d = GetDoubleOfTNumber(day); timeValue = CallNGCRuntime(glue, RTSTUB_ID(SetDateValues), {y, m, d}); Jump(&newJSDate); } } } Bind(&newJSDate); { NewObjectStubBuilder newBuilder(this); newBuilder.SetParameters(glue, 0); Label afterNew(env); newBuilder.NewJSObject(&res, &afterNew, intialHClass); Bind(&afterNew); { GateRef timeValueOffset = IntPtr(JSDate::TIME_VALUE_OFFSET); Store(VariableType::JS_NOT_POINTER(), glue, *res, timeValueOffset, DoubleToTaggedDoublePtr(*timeValue)); Jump(&exit); } } } Bind(&slowPath2); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(DateConstructor)); GateRef argv = GetArgv(); res = CallBuiltinRuntimeWithNewTarget(glue, { glue, nativeCode, func, thisValue, numArgs, argv, newTarget }, name.c_str()); Jump(&exit); } } Bind(&slowPath); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(DateConstructor)); GateRef argv = GetArgv(); res = CallBuiltinRuntime(glue, { glue, nativeCode, func, thisValue, numArgs, argv }, true, name.c_str()); Jump(&exit); } Bind(&slowPath1); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(DateConstructor)); res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); Jump(&exit); } Bind(&exit); Return(*res); } DECLARE_BUILTINS(ArrayConstructor) { auto env = GetEnvironment(); DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); Label newTargetIsHeapObject(env); Label newTargetIsJSFunction(env); Label slowPath(env); Label slowPath1(env); Label slowPath2(env); Label exit(env); Branch(TaggedIsHeapObject(newTarget), &newTargetIsHeapObject, &slowPath1); Bind(&newTargetIsHeapObject); Branch(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath); Bind(&newTargetIsJSFunction); { Label fastGetHclass(env); Label intialHClassIsHClass(env); GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); Branch(Equal(arrayFunc, newTarget), &fastGetHclass, &slowPath2); Bind(&fastGetHclass); GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); DEFVARIABLE(arrayLength, VariableType::INT64(), Int64(0)); Branch(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath2); Bind(&intialHClassIsHClass); { Label noArg(env); Label hasArg(env); Label arrayCreate(env); Branch(Int64Equal(numArgs, IntPtr(0)), &noArg, &hasArg); Bind(&noArg); { Jump(&arrayCreate); } Bind(&hasArg); { Label hasOneArg(env); Branch(Int64Equal(numArgs, IntPtr(1)), &hasOneArg, &slowPath); Bind(&hasOneArg); { Label argIsNumber(env); GateRef arg0 = GetArg(numArgs, IntPtr(0)); Branch(TaggedIsNumber(arg0), &argIsNumber, &slowPath); Bind(&argIsNumber); { Label argIsInt(env); Label argIsDouble(env); Branch(TaggedIsInt(arg0), &argIsInt, &argIsDouble); Bind(&argIsInt); { Label validIntLength(env); GateRef intLen = GetInt64OfTInt(arg0); GateRef isGEZero = Int64GreaterThanOrEqual(intLen, Int64(0)); GateRef isLEMaxLen = Int64LessThanOrEqual(intLen, Int64(JSArray::MAX_ARRAY_INDEX)); Branch(BoolAnd(isGEZero, isLEMaxLen), &validIntLength, &slowPath); Bind(&validIntLength); { arrayLength = intLen; Jump(&arrayCreate); } } Bind(&argIsDouble); { Label validDoubleLength(env); GateRef doubleLength = GetDoubleOfTDouble(arg0); GateRef doubleToInt = DoubleToInt(glue, doubleLength); GateRef intToDouble = CastInt64ToFloat64(SExtInt32ToInt64(doubleToInt)); GateRef doubleEqual = DoubleEqual(doubleLength, intToDouble); GateRef doubleLEMaxLen = DoubleLessThanOrEqual(doubleLength, Double(JSArray::MAX_ARRAY_INDEX)); Branch(BoolAnd(doubleEqual, doubleLEMaxLen), &validDoubleLength, &slowPath); Bind(&validDoubleLength); { arrayLength = SExtInt32ToInt64(doubleToInt); Jump(&arrayCreate); } } } } } Bind(&arrayCreate); { Label lengthValid(env); Branch(Int64GreaterThan(*arrayLength, Int64(JSObject::MAX_GAP)), &slowPath, &lengthValid); Bind(&lengthValid); { NewObjectStubBuilder newBuilder(this); newBuilder.SetParameters(glue, 0); res = newBuilder.NewJSArrayWithSize(intialHClass, *arrayLength); GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET); Store(VariableType::INT32(), glue, *res, lengthOffset, TruncInt64ToInt32(*arrayLength)); GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR); SetPropertyInlinedProps(glue, *res, intialHClass, accessor, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX)); SetExtensibleToBitfield(glue, *res, true); Jump(&exit); } } } Bind(&slowPath2); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(ArrayConstructor)); GateRef argv = GetArgv(); res = CallBuiltinRuntimeWithNewTarget(glue, { glue, nativeCode, func, thisValue, numArgs, argv, newTarget }, name.c_str()); Jump(&exit); } } Bind(&slowPath); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(ArrayConstructor)); GateRef argv = GetArgv(); res = CallBuiltinRuntime(glue, { glue, nativeCode, func, thisValue, numArgs, argv }, true, name.c_str()); Jump(&exit); } Bind(&slowPath1); { auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(ArrayConstructor)); res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); Jump(&exit); } Bind(&exit); Return(*res); } #define DECLARE_BUILTINS_OBJECT_STUB_BUILDER(type, method, retType, retDefaultValue) \ DECLARE_BUILTINS(type##method) \ { \ auto env = GetEnvironment(); \ DEFVARIABLE(res, retType, retDefaultValue); \ Label thisCollectionObj(env); \ Label slowPath(env); \ Label exit(env); \ BuiltinsObjectStubBuilder builder(this, glue, thisValue, numArgs); \ builder.method(&res, &exit, &slowPath); \ Bind(&slowPath); \ { \ auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ Jump(&exit); \ } \ Bind(&exit); \ Return(*res); \ } // Object.protetype.ToString DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, ToString, VariableType::JS_ANY(), Undefined()); // Object.protetype.Create DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, Create, VariableType::JS_ANY(), Undefined()); // Object.protetype.Assign DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, Assign, VariableType::JS_ANY(), Undefined()); // Object.protetype.HasOwnProperty DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, HasOwnProperty, VariableType::JS_ANY(), TaggedFalse()); // Object.protetype.Keys DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, Keys, VariableType::JS_ANY(), Undefined()); #undef DECLARE_BUILTINS_OBJECT_STUB_BUILDER #define DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(type, method, retType, retDefaultValue) \ DECLARE_BUILTINS(type##method) \ { \ auto env = GetEnvironment(); \ DEFVARIABLE(res, retType, retDefaultValue); \ Label slowPath(env); \ Label exit(env); \ BuiltinsCollectionStubBuilder<JS##type> builder(this, glue, thisValue, numArgs); \ builder.method(&res, &exit, &slowPath); \ Bind(&slowPath); \ { \ auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ Jump(&exit); \ } \ Bind(&exit); \ Return(*res); \ } // Set.protetype.Clear DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Clear, VariableType::JS_ANY(), Undefined()); // Set.protetype.Values DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Values, VariableType::JS_ANY(), Undefined()); // Set.protetype.Entries DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Entries, VariableType::JS_ANY(), Undefined()); // Set.protetype.ForEach DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, ForEach, VariableType::JS_ANY(), Undefined()); // Set.protetype.Add DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Add, VariableType::JS_ANY(), Undefined()); // Set.protetype.Delete DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Delete, VariableType::JS_ANY(), Undefined()); // Set.protetype.Has DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Has, VariableType::JS_ANY(), Undefined()); // Map.protetype.Clear DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Clear, VariableType::JS_ANY(), Undefined()); // Map.protetype.Values DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Values, VariableType::JS_ANY(), Undefined()); // Map.protetype.Entries DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Entries, VariableType::JS_ANY(), Undefined()); // Map.protetype.Keys DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Keys, VariableType::JS_ANY(), Undefined()); // Map.protetype.ForEach DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, ForEach, VariableType::JS_ANY(), Undefined()); // Map.protetype.set DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Set, VariableType::JS_ANY(), Undefined()); // Map.protetype.Delete DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Delete, VariableType::JS_ANY(), Undefined()); // Map.protetype.Has DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Has, VariableType::JS_ANY(), Undefined()); #undef DECLARE_BUILTINS_COLLECTION_STUB_BUILDER #define DECLARE_BUILTINS_NUMBER_STUB_BUILDER(type, method, retType, retDefaultValue) \ DECLARE_BUILTINS(type##method) \ { \ auto env = GetEnvironment(); \ DEFVARIABLE(res, retType, retDefaultValue); \ Label slowPath(env); \ Label exit(env); \ BuiltinsNumberStubBuilder builder(this, glue, thisValue, numArgs); \ builder.method(&res, &exit, &slowPath); \ Bind(&slowPath); \ { \ auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ Jump(&exit); \ } \ Bind(&exit); \ Return(*res); \ } // Number.ParseFloat DECLARE_BUILTINS_NUMBER_STUB_BUILDER(Number, ParseFloat, VariableType::JS_ANY(), Undefined()); #undef DECLARE_BUILTINS_NUMBER_STUB_BUILDER #define DECLARE_BUILTINS_TYPEDARRAY_STUB_BUILDER(type, method, retType, retDefaultValue) \ DECLARE_BUILTINS(type##method) \ { \ auto env = GetEnvironment(); \ DEFVARIABLE(res, retType, retDefaultValue); \ Label slowPath(env); \ Label exit(env); \ GateRef begin = GetCallArg0(numArgs); \ GateRef end = GetCallArg1(numArgs); \ TypedArrayStubBuilder builder(this); \ builder.method(glue, thisValue, begin, end, &res, &exit, &slowPath); \ Bind(&slowPath); \ { \ auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ Jump(&exit); \ } \ Bind(&exit); \ Return(*res); \ } // TypedArray.Subarray DECLARE_BUILTINS_TYPEDARRAY_STUB_BUILDER(TypedArray, SubArray, VariableType::JS_ANY(), Undefined()); #undef DECLARE_BUILTINS_TYPEDARRAY_STUB_BUILDER } // namespace panda::ecmascript::kungfu