mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-06 23:54:03 +00:00
[新需求]: Function.prototype.bind IR化
对 Function.prototype.bind IR化,以提升性能 Issue: #I9QCI5 Signed-off-by: lichenshuai <lichenshuai@huawei.com> Change-Id: I2bc7df27a3cdba7baf895dc9064ad0d4c873f4e4
This commit is contained in:
parent
9cff288511
commit
cdb629a9b9
@ -135,7 +135,8 @@ namespace panda::ecmascript::kungfu {
|
||||
V(Get, Map, Undefined())
|
||||
|
||||
#define BUILTINS_WITH_FUNCTION_STUB_BUILDER(V) \
|
||||
V(PrototypeApply, Function, Undefined())
|
||||
V(PrototypeApply, Function, Undefined()) \
|
||||
V(PrototypeBind, Function, Undefined())
|
||||
|
||||
#define BUILTINS_WITH_NUMBER_STUB_BUILDER(V) \
|
||||
V(ParseFloat, Number, Undefined()) \
|
||||
@ -287,7 +288,6 @@ namespace panda::ecmascript::kungfu {
|
||||
V(ReflectHas) \
|
||||
V(ReflectConstruct) \
|
||||
V(ReflectApply) \
|
||||
V(FunctionPrototypeBind) \
|
||||
V(FunctionPrototypeCall) \
|
||||
V(FunctionPrototypeHasInstance) \
|
||||
V(TYPED_BUILTINS_INLINE_FIRST = MathAcos) \
|
||||
|
@ -109,6 +109,62 @@ void BuiltinsFunctionStubBuilder::PrototypeApply(GateRef glue, GateRef thisValue
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltinsFunctionStubBuilder::PrototypeBind(GateRef glue, GateRef thisValue,
|
||||
GateRef numArgs, Variable* res, Label *exit, Label *slowPath)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label targetIsHeapObject(env);
|
||||
Label targetIsCallable(env);
|
||||
Label targetIsJSFunctionOrBound(env);
|
||||
Label targetNameAndLengthNotChange(env);
|
||||
|
||||
// 1. Let Target be the this value.
|
||||
GateRef target = thisValue;
|
||||
// 2. If IsCallable(Target) is false, throw a TypeError exception.
|
||||
BRANCH(TaggedIsHeapObject(target), &targetIsHeapObject, slowPath);
|
||||
Bind(&targetIsHeapObject);
|
||||
BRANCH(IsCallable(target), &targetIsCallable, slowPath);
|
||||
Bind(&targetIsCallable);
|
||||
BRANCH(BoolOr(IsJSFunction(target), IsBoundFunction(target)), &targetIsJSFunctionOrBound, slowPath);
|
||||
Bind(&targetIsJSFunctionOrBound);
|
||||
{
|
||||
GateRef hclass = LoadHClass(target);
|
||||
GateRef nameProperty = GetPropertyInlinedProps(target, hclass,
|
||||
Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX));
|
||||
GateRef lengthProperty = GetPropertyInlinedProps(target, hclass,
|
||||
Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX));
|
||||
GateRef nameAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
|
||||
ConstantIndex::FUNCTION_NAME_ACCESSOR);
|
||||
GateRef lengthAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
|
||||
ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
|
||||
BRANCH(BoolAnd(IntPtrEqual(nameProperty, nameAccessor), IntPtrEqual(lengthProperty, lengthAccessor)),
|
||||
&targetNameAndLengthNotChange, slowPath);
|
||||
Bind(&targetNameAndLengthNotChange);
|
||||
{
|
||||
Label numArgsMoreThan1(env);
|
||||
Label createTaggedArray(env);
|
||||
GateRef thisArg = GetCallArg0(numArgs);
|
||||
DEFVARIABLE(argsLength, VariableType::INT32(), Int32(0));
|
||||
BRANCH(Int64GreaterThan(numArgs, Int64(1)), &numArgsMoreThan1, &createTaggedArray);
|
||||
Bind(&numArgsMoreThan1);
|
||||
{
|
||||
argsLength = Int32Sub(TruncInt64ToInt32(numArgs), Int32(1));
|
||||
Jump(&createTaggedArray);
|
||||
}
|
||||
Bind(&createTaggedArray);
|
||||
// 3. Let args be a new (possibly empty) List consisting of all of the argument
|
||||
// values provided after thisArg in order.
|
||||
GateRef argsArray = NewTaggedArrayFromArgs(glue, Int32(1), *argsLength, numArgs);
|
||||
// 4. Let F be BoundFunctionCreate(Target, thisArg, args).
|
||||
NewObjectStubBuilder newBuilder(this);
|
||||
GateRef boundFunction = newBuilder.NewJSBoundFunction(glue, target, thisArg, argsArray);
|
||||
// use default name and length property because they are not changed
|
||||
res->WriteVariable(boundFunction);
|
||||
Jump(exit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return elements
|
||||
GateRef BuiltinsFunctionStubBuilder::BuildArgumentsListFastElements(GateRef glue, GateRef arrayObj)
|
||||
{
|
||||
@ -286,4 +342,70 @@ GateRef BuiltinsFunctionStubBuilder::MakeArgListWithHole(GateRef glue, GateRef a
|
||||
env->SubCfgExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef BuiltinsFunctionStubBuilder::NewTaggedArrayFromArgs(GateRef glue, GateRef startIndex, GateRef length,
|
||||
GateRef numArgs)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label subentry(env);
|
||||
env->SubCfgEntry(&subentry);
|
||||
|
||||
DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
|
||||
DEFVARIABLE(i, VariableType::INT32(), Int32(0));
|
||||
DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
|
||||
NewObjectStubBuilder newBuilder(this);
|
||||
res = newBuilder.NewTaggedArray(glue, length);
|
||||
Label loopHead(env);
|
||||
Label loopEnd(env);
|
||||
Label afterLoop(env);
|
||||
BRANCH(Int32LessThan(*i, length), &loopHead, &afterLoop);
|
||||
LoopBegin(&loopHead);
|
||||
{
|
||||
Label valueArg0(env);
|
||||
Label valueNotArg0(env);
|
||||
Label valueArg1(env);
|
||||
Label valueNotArg1(env);
|
||||
Label valueArg2(env);
|
||||
Label valueNotArg2(env);
|
||||
Label valueSet(env);
|
||||
GateRef index = Int32Add(*i, startIndex);
|
||||
BRANCH(Int32Equal(index, Int32(0)), &valueArg0, &valueNotArg0); // 0: get arg0
|
||||
Bind(&valueArg0);
|
||||
{
|
||||
value = GetCallArg0(numArgs);
|
||||
Jump(&valueSet);
|
||||
}
|
||||
Bind(&valueNotArg0);
|
||||
BRANCH(Int32Equal(index, Int32(1)), &valueArg1, &valueNotArg1); // 1: get arg1
|
||||
Bind(&valueArg1);
|
||||
{
|
||||
value = GetCallArg1(numArgs);
|
||||
Jump(&valueSet);
|
||||
}
|
||||
Bind(&valueNotArg1);
|
||||
BRANCH(Int32Equal(index, Int32(2)), &valueArg2, &valueNotArg2); // 2: get arg2
|
||||
Bind(&valueArg2);
|
||||
{
|
||||
value = GetCallArg2(numArgs);
|
||||
Jump(&valueSet);
|
||||
}
|
||||
Bind(&valueNotArg2);
|
||||
{
|
||||
// currently argv will not be used in builtins IR except constructor
|
||||
value = GetArgFromArgv(ZExtInt32ToPtr(index));
|
||||
Jump(&valueSet);
|
||||
}
|
||||
Bind(&valueSet);
|
||||
SetValueToTaggedArray(VariableType::JS_ANY(), glue, *res, *i, *value);
|
||||
i = Int32Add(*i, Int32(1));
|
||||
BRANCH(Int32LessThan(*i, length), &loopEnd, &afterLoop);
|
||||
}
|
||||
Bind(&loopEnd);
|
||||
LoopEnd(&loopHead);
|
||||
|
||||
Bind(&afterLoop);
|
||||
auto ret = *res;
|
||||
env->SubCfgExit();
|
||||
return ret;
|
||||
}
|
||||
} // namespace panda::ecmascript::kungfu
|
||||
|
@ -34,6 +34,7 @@ BUILTINS_WITH_FUNCTION_STUB_BUILDER(DECLARE_BUILTINS_FUNCTION_STUB_BUILDER)
|
||||
GateRef BuildArgumentsListFastElements(GateRef glue, GateRef arrayObj);
|
||||
private:
|
||||
GateRef MakeArgListWithHole(GateRef glue, GateRef argv, GateRef length);
|
||||
GateRef NewTaggedArrayFromArgs(GateRef glue, GateRef startIndex, GateRef length, GateRef numArgs);
|
||||
};
|
||||
} // namespace panda::ecmascript::kungfu
|
||||
#endif // ECMASCRIPT_COMPILER_BUILTINS_FUNCTION_STUB_BUILDER_H
|
@ -868,6 +868,51 @@ void NewObjectStubBuilder::InitializeJSFunction(GateRef glue, GateRef func, Gate
|
||||
return;
|
||||
}
|
||||
|
||||
GateRef NewObjectStubBuilder::NewJSBoundFunction(GateRef glue, GateRef target, GateRef boundThis, GateRef args)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
Label subentry(env);
|
||||
env->SubCfgEntry(&subentry);
|
||||
Label exit(env);
|
||||
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
|
||||
|
||||
GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
|
||||
GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
|
||||
GateRef hclass = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::BOUND_FUNCTION_CLASS);
|
||||
result = NewJSObject(glue, hclass);
|
||||
GateRef nameAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
|
||||
ConstantIndex::FUNCTION_NAME_ACCESSOR);
|
||||
SetPropertyInlinedProps(glue, *result, hclass, nameAccessor,
|
||||
Int32(JSFunction::NAME_INLINE_PROPERTY_INDEX));
|
||||
GateRef lengthAccessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
|
||||
ConstantIndex::FUNCTION_LENGTH_ACCESSOR);
|
||||
SetPropertyInlinedProps(glue, *result, hclass, lengthAccessor,
|
||||
Int32(JSFunction::LENGTH_INLINE_PROPERTY_INDEX));
|
||||
SetJSObjectTaggedField(glue, *result, JSBoundFunction::BOUND_TARGET_OFFSET, target);
|
||||
SetJSObjectTaggedField(glue, *result, JSBoundFunction::BOUND_THIS_OFFSET, boundThis);
|
||||
SetJSObjectTaggedField(glue, *result, JSBoundFunction::BOUND_ARGUMENTS_OFFSET, args);
|
||||
GateRef method = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
|
||||
ConstantIndex::BOUND_FUNCTION_METHOD_INDEX);
|
||||
SetMethodToFunction(glue, *result, method);
|
||||
|
||||
Label targetIsHeapObject(env);
|
||||
Label targetIsConstructor(env);
|
||||
BRANCH(TaggedIsHeapObject(target), &targetIsHeapObject, &exit);
|
||||
Bind(&targetIsHeapObject);
|
||||
BRANCH(IsConstructor(target), &targetIsConstructor, &exit);
|
||||
Bind(&targetIsConstructor);
|
||||
{
|
||||
GateRef resultHClass = LoadHClass(*result);
|
||||
SetHClassBit<JSHClass::ConstructorBit>(glue, resultHClass, Int32(1));
|
||||
Jump(&exit);
|
||||
}
|
||||
|
||||
Bind(&exit);
|
||||
auto ret = *result;
|
||||
env->SubCfgExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
GateRef NewObjectStubBuilder::EnumerateObjectProperties(GateRef glue, GateRef obj)
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
|
@ -70,6 +70,7 @@ public:
|
||||
FunctionKind targetKind = FunctionKind::LAST_FUNCTION_KIND);
|
||||
void InitializeJSFunction(GateRef glue, GateRef func, GateRef kind,
|
||||
FunctionKind getKind = FunctionKind::LAST_FUNCTION_KIND);
|
||||
GateRef NewJSBoundFunction(GateRef glue, GateRef target, GateRef boundThis, GateRef args);
|
||||
GateRef EnumerateObjectProperties(GateRef glue, GateRef obj);
|
||||
void NewArgumentsList(Variable *result, Label *exit, GateRef sp, GateRef startIdx, GateRef numArgs);
|
||||
void NewArgumentsObj(Variable *result, Label *exit, GateRef argumentsList, GateRef numArgs);
|
||||
|
@ -2637,14 +2637,15 @@ inline GateRef StubBuilder::SetTaggedRepInPropAttr(GateRef attr)
|
||||
return newVal;
|
||||
}
|
||||
|
||||
inline void StubBuilder::SetHasConstructorToHClass(GateRef glue, GateRef hClass, GateRef value)
|
||||
template<class T>
|
||||
void StubBuilder::SetHClassBit(GateRef glue, GateRef hClass, GateRef value)
|
||||
{
|
||||
GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
|
||||
GateRef mask = Int32LSL(
|
||||
Int32((1LU << JSHClass::HasConstructorBits::SIZE) - 1),
|
||||
Int32(JSHClass::HasConstructorBits::START_BIT));
|
||||
Int32((1LU << T::SIZE) - 1),
|
||||
Int32(T::START_BIT));
|
||||
GateRef newVal = Int32Or(Int32And(bitfield, Int32Not(mask)),
|
||||
Int32LSL(value, Int32(JSHClass::HasConstructorBits::START_BIT)));
|
||||
Int32LSL(value, Int32(T::START_BIT)));
|
||||
Store(VariableType::INT32(), glue, hClass, IntPtr(JSHClass::BIT_FIELD_OFFSET), newVal);
|
||||
}
|
||||
|
||||
@ -2899,6 +2900,11 @@ inline void StubBuilder::UpdateProfileTypeInfoCellType(GateRef glue, GateRef pro
|
||||
env->SubCfgExit();
|
||||
}
|
||||
|
||||
inline void StubBuilder::SetJSObjectTaggedField(GateRef glue, GateRef object, size_t offset, GateRef value)
|
||||
{
|
||||
Store(VariableType::JS_ANY(), glue, object, IntPtr(offset), value);
|
||||
}
|
||||
|
||||
inline GateRef StubBuilder::GetGlobalObject(GateRef glue)
|
||||
{
|
||||
GateRef offset = IntPtr(JSThread::GlueData::GetGlobalObjOffset(env_->Is32Bit()));
|
||||
|
@ -1203,7 +1203,7 @@ GateRef StubBuilder::AddPropertyByName(GateRef glue, GateRef receiver, GateRef k
|
||||
BRANCH(SetHasConstructorCondition(glue, receiver, key), &setHasCtor, ¬SetHasCtor);
|
||||
{
|
||||
Bind(&setHasCtor);
|
||||
SetHasConstructorToHClass(glue, hclass, Int32(1));
|
||||
SetHClassBit<JSHClass::HasConstructorBits>(glue, hclass, Int32(1));
|
||||
Jump(&afterCtorCon);
|
||||
Bind(¬SetHasCtor);
|
||||
Jump(&afterCtorCon);
|
||||
|
@ -650,7 +650,8 @@ public:
|
||||
GateRef IsIntRepInPropAttr(GateRef attr);
|
||||
GateRef IsDoubleRepInPropAttr(GateRef attr);
|
||||
GateRef SetTaggedRepInPropAttr(GateRef attr);
|
||||
void SetHasConstructorToHClass(GateRef glue, GateRef hClass, GateRef value);
|
||||
template<class T>
|
||||
void SetHClassBit(GateRef glue, GateRef hClass, GateRef value);
|
||||
template<typename DictionaryT>
|
||||
void UpdateValueInDict(GateRef glue, GateRef elements, GateRef index, GateRef value);
|
||||
GateRef GetBitMask(GateRef bitoffset);
|
||||
@ -701,6 +702,7 @@ public:
|
||||
void SetRawProfileTypeInfoToFunction(GateRef glue, GateRef function, GateRef value);
|
||||
void SetValueToProfileTypeInfoCell(GateRef glue, GateRef profileTypeInfoCell, GateRef value);
|
||||
void UpdateProfileTypeInfoCellType(GateRef glue, GateRef profileTypeInfoCell);
|
||||
void SetJSObjectTaggedField(GateRef glue, GateRef object, size_t offset, GateRef value);
|
||||
GateRef GetGlobalObject(GateRef glue);
|
||||
GateRef GetMethodFromFunction(GateRef function);
|
||||
GateRef GetModuleFromFunction(GateRef function);
|
||||
|
@ -891,6 +891,17 @@ void EcmaVM::GenerateInternalNativeMethods()
|
||||
method->SetFunctionKind(FunctionKind::NORMAL_FUNCTION);
|
||||
internalNativeMethods_.emplace_back(method.GetTaggedValue());
|
||||
}
|
||||
// cache to global constants shared because context may change
|
||||
CacheToGlobalConstants(GetMethodByIndex(MethodIndex::BUILTINS_GLOBAL_CALL_JS_BOUND_FUNCTION),
|
||||
ConstantIndex::BOUND_FUNCTION_METHOD_INDEX);
|
||||
}
|
||||
|
||||
void EcmaVM::CacheToGlobalConstants(JSTaggedValue value, ConstantIndex idx)
|
||||
{
|
||||
auto thread = GetJSThread();
|
||||
auto context = thread->GetCurrentEcmaContext();
|
||||
auto constants = const_cast<GlobalEnvConstants *>(context->GlobalConstants());
|
||||
constants->SetConstant(idx, value);
|
||||
}
|
||||
|
||||
JSTaggedValue EcmaVM::GetMethodByIndex(MethodIndex idx)
|
||||
|
@ -795,6 +795,7 @@ private:
|
||||
|
||||
// For Internal Native MethodLiteral.
|
||||
void GenerateInternalNativeMethods();
|
||||
void CacheToGlobalConstants(JSTaggedValue value, ConstantIndex constant);
|
||||
|
||||
NO_MOVE_SEMANTIC(EcmaVM);
|
||||
NO_COPY_SEMANTIC(EcmaVM);
|
||||
|
@ -630,7 +630,8 @@ class ObjectFactory;
|
||||
V(JSTaggedValue, EmptyMutantArray, EMPTY_MUTANT_ARRAY_OBJECT_INDEX, ecma_roots_special) \
|
||||
V(JSTaggedValue, Uint64MaxBigInt, UINT64_MAX_BIGINT_INDEX, ecma_roots_special) \
|
||||
V(JSTaggedValue, Int64MaxBigInt, INT64_MAX_BIGINT_INDEX, ecma_roots_special) \
|
||||
V(JSTaggedValue, EmptyProfileTypeInfoCell, EMPTY_PROFILE_TYPE_INFO_CELL_INDEX, ecma_roots_special)
|
||||
V(JSTaggedValue, EmptyProfileTypeInfoCell, EMPTY_PROFILE_TYPE_INFO_CELL_INDEX, ecma_roots_special) \
|
||||
V(JSTaggedValue, BoundFunctionMethod, BOUND_FUNCTION_METHOD_INDEX, ecma_roots_special)
|
||||
|
||||
#define GLOBAL_ENV_CACHES(V) \
|
||||
V(JSTaggedValue, CachedJSCollatorLocales, CACHED_JSCOLLATOR_LOCALES_INDEX, cachedCollatorLocales)
|
||||
@ -661,7 +662,7 @@ enum class ConstantIndex : size_t {
|
||||
CONSTANT_END = CONSTANT_COUNT,
|
||||
|
||||
SHARED_BEGIN = HCLASS_CLASS_INDEX,
|
||||
SHARED_END = EMPTY_PROFILE_TYPE_INFO_CELL_INDEX,
|
||||
SHARED_END = BOUND_FUNCTION_METHOD_INDEX,
|
||||
|
||||
SHARED_HCLASS_BEGIN = HCLASS_CLASS_INDEX,
|
||||
SHARED_HCLASS_END = VTABLE_CLASS_INDEX,
|
||||
|
@ -102,4 +102,16 @@ try {
|
||||
new t9()
|
||||
} catch(err) {
|
||||
print(err);
|
||||
}
|
||||
}
|
||||
|
||||
function testFunc(...args) {
|
||||
print(this);
|
||||
print(args);
|
||||
print(args.length);
|
||||
}
|
||||
let testFuncBound = testFunc.bind(0, 1, 2);
|
||||
testFuncBound(3, 4, 5);
|
||||
print(testFuncBound.name);
|
||||
Object.defineProperty(testFunc, "name", {value: "testFuncChanged"});
|
||||
testFuncBound = testFunc.bind();
|
||||
print(testFuncBound.name);
|
||||
|
@ -23,3 +23,8 @@ function bound Float32Array() { [native code] }
|
||||
0,1,2,3,4,5,6,7,8,9,
|
||||
11
|
||||
TypeError: Constructor is false
|
||||
0
|
||||
1,2,3,4,5
|
||||
5
|
||||
bound testFunc
|
||||
bound testFuncChanged
|
||||
|
Loading…
Reference in New Issue
Block a user