diff --git a/ecmascript/compiler/interpreter_stub-inl.h b/ecmascript/compiler/interpreter_stub-inl.h index d9ef4de51d..35cd7840b6 100644 --- a/ecmascript/compiler/interpreter_stub-inl.h +++ b/ecmascript/compiler/interpreter_stub-inl.h @@ -197,6 +197,11 @@ GateRef InterpreterStub::GetEnvFromFrame(GateRef frame) GetIntPtrConstant(InterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit()))); } +GateRef InterpreterStub::GetEnvFromFunction(GateRef function) +{ + return Load(VariableType::JS_POINTER(), function, GetIntPtrConstant(JSFunction::LEXICAL_ENV_OFFSET)); +} + GateRef InterpreterStub::GetProfileTypeInfoFromFunction(GateRef function) { return Load(VariableType::JS_POINTER(), function, GetIntPtrConstant(JSFunction::PROFILE_TYPE_INFO_OFFSET)); diff --git a/ecmascript/compiler/interpreter_stub.cpp b/ecmascript/compiler/interpreter_stub.cpp index ea86792d2c..b77782a47f 100644 --- a/ecmascript/compiler/interpreter_stub.cpp +++ b/ecmascript/compiler/interpreter_stub.cpp @@ -74,8 +74,8 @@ void name##Stub::GenerateCircuitImpl(GateRef glue, GateRef pc, GateRef sp, #define DISPATCH_LAST() \ DispatchLast(glue, pc, sp, constpool, profileTypeInfo, acc, hotnessCounter) \ -#define DISPATCH_LAST() \ - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, acc, hotnessCounter) \ +#define DISPATCH_LAST_WITH_ACC() \ + DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter) \ #define UPDATE_HOTNESS(_sp) \ varHotnessCounter = Int32Add(offset, *varHotnessCounter); \ @@ -83,7 +83,7 @@ void name##Stub::GenerateCircuitImpl(GateRef glue, GateRef pc, GateRef sp, Bind(&slowPath); \ { \ varProfileTypeInfo = CallRuntimeTrampoline(glue, \ - GetInt64Constant(RUNTIME_CALL_ID(UpdateHotnessCounter)), {}); \ + GetInt64Constant(RUNTIME_CALL_ID(UpdateHotnessCounter)), {}); \ varHotnessCounter = GetInt32Constant(EcmaInterpreter::METHOD_HOTNESS_THRESHOLD); \ Jump(&dispatch); \ } \ @@ -869,7 +869,7 @@ DECLARE_ASM_HANDLER(HandleGetPropIteratorPref) Branch(TaggedIsException(res), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); varAcc = res; @@ -887,7 +887,7 @@ DECLARE_ASM_HANDLER(HandleAsyncFunctionEnterPref) Branch(TaggedIsException(res), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); varAcc = res; @@ -941,7 +941,7 @@ DECLARE_ASM_HANDLER(HandleGetIteratorPref) Branch(TaggedIsException(res), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); varAcc = res; @@ -2781,7 +2781,7 @@ DECLARE_ASM_HANDLER(HandleLdSuperByNamePrefId32V8) Branch(TaggedIsException(result), &isException, &dispatch); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(&dispatch); varAcc = result; @@ -2953,7 +2953,7 @@ DECLARE_ASM_HANDLER(HandleStConstToGlobalRecordPrefId32) Branch(TaggedIsException(result), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); DISPATCH_WITH_ACC(PREF_ID32); @@ -2974,7 +2974,7 @@ DECLARE_ASM_HANDLER(HandleStLetToGlobalRecordPrefId32) Branch(TaggedIsException(result), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); DISPATCH_WITH_ACC(PREF_ID32); @@ -2995,7 +2995,7 @@ DECLARE_ASM_HANDLER(HandleStClassToGlobalRecordPrefId32) Branch(TaggedIsException(result), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); DISPATCH_WITH_ACC(PREF_ID32); @@ -3052,7 +3052,7 @@ DECLARE_ASM_HANDLER(HandleNegDynPrefV8) Branch(TaggedIsException(result), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); varAcc = result; @@ -3104,7 +3104,7 @@ DECLARE_ASM_HANDLER(HandleNotDynPrefV8) Branch(TaggedIsException(result), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); varAcc = result; @@ -3193,7 +3193,7 @@ DECLARE_ASM_HANDLER(HandleAnd2DynPrefV8) Branch(TaggedIsException(taggedNumber), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); { @@ -3286,7 +3286,7 @@ DECLARE_ASM_HANDLER(HandleOr2DynPrefV8) Branch(TaggedIsException(taggedNumber), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); { @@ -3379,7 +3379,7 @@ DECLARE_ASM_HANDLER(HandleXOr2DynPrefV8) Branch(TaggedIsException(taggedNumber), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); { @@ -3472,7 +3472,7 @@ DECLARE_ASM_HANDLER(HandleAshr2DynPrefV8) Branch(TaggedIsException(taggedNumber), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); { @@ -3566,7 +3566,7 @@ DECLARE_ASM_HANDLER(HandleShr2DynPrefV8) Branch(TaggedIsException(taggedNumber), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); { @@ -3659,7 +3659,7 @@ DECLARE_ASM_HANDLER(HandleShl2DynPrefV8) Branch(TaggedIsException(taggedNumber), &IsException, &NotException); Bind(&IsException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(&NotException); { @@ -3717,7 +3717,7 @@ DECLARE_ASM_HANDLER(HandleDefineClassWithBufferPrefId16Imm16Imm16V8V8) Branch(TaggedIsException(*res), &isException, &isNotException); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(&isNotException); GateRef newLexicalEnv = GetVregValue(sp, ZExtInt8ToPtr(v0)); // slow runtime may gc @@ -3807,7 +3807,7 @@ DECLARE_ASM_HANDLER(HandleLdObjByNamePrefId32V8) Branch(TaggedIsException(result), &isException, &noException); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(&noException); varAcc = result; @@ -4598,7 +4598,7 @@ DECLARE_ASM_HANDLER(HandleTryLdGlobalByNamePrefId32) Branch(TaggedIsException(*icResult), &isException, &isNotException); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(&isNotException); varAcc = *icResult; @@ -4630,7 +4630,7 @@ DECLARE_ASM_HANDLER(HandleTryLdGlobalByNamePrefId32) Branch(TaggedIsException(slowResult), &isException, &isNotException); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(&isNotException); varAcc = slowResult; @@ -4791,7 +4791,7 @@ DECLARE_ASM_HANDLER(HandleLdGlobalVarPrefId32) Branch(TaggedIsException(*result), &isException, &dispatch); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } } Bind(&dispatch); @@ -4973,7 +4973,7 @@ DECLARE_ASM_HANDLER(HandleToNumberPrefV8) Branch(TaggedIsException(res), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); { @@ -5078,7 +5078,7 @@ DECLARE_ASM_HANDLER(HandleAdd2DynPrefV8) Branch(TaggedIsException(taggedNumber), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); { @@ -5188,7 +5188,7 @@ DECLARE_ASM_HANDLER(HandleSub2DynPrefV8) Branch(TaggedIsException(taggedNumber), &isException, ¬Exception); Bind(&isException); { - DispatchLast(glue, pc, sp, constpool, profileTypeInfo, *varAcc, hotnessCounter); + DISPATCH_LAST_WITH_ACC(); } Bind(¬Exception); { @@ -5200,9 +5200,475 @@ DECLARE_ASM_HANDLER(HandleSub2DynPrefV8) Bind(&accDispatch); DISPATCH_WITH_ACC(PREF_V8); } + +#define CALL_INITIALIZE() \ + SetPcToFrame(glue, GetFrame(sp), pc); \ + GateRef func = GetVregValue(sp, ZExtInt8ToPtr(funcReg)); \ + Label funcIsHeapObject(env); \ + Label funcIsCallable(env); \ + Label funcNotCallable(env); \ + Branch(TaggedIsHeapObject(func), &funcIsHeapObject, &funcNotCallable); \ + Bind(&funcIsHeapObject); \ + Branch(IsCallable(func), &funcIsCallable, &funcNotCallable); \ + Bind(&funcNotCallable); \ + { \ + CallRuntimeTrampoline(glue, GetInt64Constant(RUNTIME_CALL_ID(SetNotCallableException)), {}); \ + DISPATCH_LAST(); \ + } \ + Bind(&funcIsCallable); \ + DEFVARIABLE(methodOffset, VariableType::INT32(), GetInt32Constant(0)); \ + /* method = func->GetCallTarget() */ \ + /* ASSERT(JSTaggedValue(func).IsJSFunctionBase() || JSTaggedValue(func).IsJSProxy()) */ \ + Label funcIsJSFunctionBase(env); \ + Label funcIsJSProxy(env); \ + Label getMethod(env); \ + Branch(IsJSFunctionBase(func), &funcIsJSFunctionBase, &funcIsJSProxy); \ + Bind(&funcIsJSFunctionBase); \ + { \ + methodOffset = GetInt32Constant(JSFunctionBase::METHOD_OFFSET); \ + Jump(&getMethod); \ + } \ + Bind(&funcIsJSProxy); \ + { \ + methodOffset = GetInt32Constant(JSProxy::METHOD_OFFSET); \ + Jump(&getMethod); \ + } \ + Bind(&getMethod); \ + GateRef method = Load(VariableType::POINTER(), func, ChangeInt32ToIntPtr(*methodOffset)); \ + GateRef callFieldOffset = GetIntPtrConstant(JSMethod::GetCallFieldOffset(env->IsArch32Bit())); \ + GateRef callField = Load(VariableType::INT64(), method, callFieldOffset); \ + DEFVARIABLE(newSp, VariableType::POINTER(), \ + PointerSub(sp, GetIntPtrConstant(InterpretedFrame::GetSize(env->IsArch32Bit())))) + +#define CALL_PUSH_UNDEFINED(n) \ + i = GetInt32Constant(0); \ + Label pushUndefined(env); \ + Label pushUndefinedAgain(env); \ + Label pushUndefinedEnd(env); \ + Branch(Int32LessThan(*i, n), &pushUndefined, &pushUndefinedEnd); \ + LoopBegin(&pushUndefined); \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), \ + GetInt64Constant(JSTaggedValue::VALUE_UNDEFINED)); \ + i = Int32Add(*i, GetInt32Constant(1)); \ + Branch(Int32LessThan(*i, n), &pushUndefinedAgain, &pushUndefinedEnd); \ + Bind(&pushUndefinedAgain); \ + LoopEnd(&pushUndefined); \ + Bind(&pushUndefinedEnd) + +#define CALL_PUSH_ARGS(format) \ + DEFVARIABLE(i, VariableType::INT32(), GetInt32Constant(0)); \ + GateRef isNativeMask = GetInt64Constant(static_cast(1) << JSMethod::IsNativeBit::START_BIT); \ + Label methodIsNative(env); \ + Label methodNotNative(env); \ + Branch(Int64NotEqual(Int64And(callField, isNativeMask), GetInt64Constant(0)), &methodIsNative, &methodNotNative); \ + Bind(&methodIsNative); \ + { \ + CALL_PUSH_ARGS_##format(); \ + SET_VREGS_AND_FRAME_NATIVE(format); \ + } \ + Bind(&methodNotNative); \ + GateRef numArgsOffset = GetInt64Constant(JSMethod::NumArgsBits::START_BIT); \ + GateRef numArgsMask = GetInt64Constant((static_cast(1) << JSMethod::NumArgsBits::SIZE) - 1); \ + GateRef declaredNumArgs = ChangeInt64ToInt32(Int64And(UInt64LSR(callField, numArgsOffset), numArgsMask)); \ + Label fastPath(env); \ + Label slowPath(env); \ + Label setVregsAndFrameNotNative(env); \ + Branch(Int32Equal(actualNumArgs, declaredNumArgs), &fastPath, &slowPath); \ + Bind(&fastPath); \ + { \ + CALL_PUSH_ARGS_##format(); \ + Jump(&setVregsAndFrameNotNative); \ + } \ + Bind(&slowPath); \ + GateRef haveExtraMask = GetInt64Constant(static_cast(1) << JSMethod::HaveExtraBit::START_BIT); \ + Label methodNoExtra(env); \ + Label methodHaveExtra(env); \ + Branch(Int64NotEqual(Int64And(callField, haveExtraMask), GetInt64Constant(0)), &methodHaveExtra, &methodNoExtra); \ + Bind(&methodNoExtra); \ + { \ + GateRef undefinedNumArgs = Int32Sub(declaredNumArgs, actualNumArgs); \ + CALL_PUSH_UNDEFINED(undefinedNumArgs); \ + CALL_PUSH_ARGS_NO_EXTRA_##format(); \ + Jump(&setVregsAndFrameNotNative); \ + } \ + Bind(&methodHaveExtra); \ + { \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), IntBuildTaggedTypeWithNoGC(actualNumArgs)); \ + GateRef undefinedNumArgs = Int32Sub(declaredNumArgs, actualNumArgs); \ + CALL_PUSH_UNDEFINED(undefinedNumArgs); \ + CALL_PUSH_ARGS_##format(); \ + Jump(&setVregsAndFrameNotNative); \ + } \ + Bind(&setVregsAndFrameNotNative); \ + SET_VREGS_AND_FRAME_NOT_NATIVE(format) + +#define SET_VREGS_AND_FRAME_NATIVE(format) \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Label pushThis(env); \ + Label pushThisUndefined(env); \ + Label pushNewTarget(env); \ + Branch(callThis, &pushThis, &pushThisUndefined); \ + Bind(&pushThis); \ + { \ + GateRef thisValue = GetVregValue(sp, IntPtrAdd(ZExtInt8ToPtr(funcReg), GetIntPtrConstant(1))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), thisValue); \ + Jump(&pushNewTarget); \ + } \ + Bind(&pushThisUndefined); \ + { \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), \ + GetInt64Constant(JSTaggedValue::VALUE_UNDEFINED)); \ + Jump(&pushNewTarget); \ + } \ + Bind(&pushNewTarget); \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), \ + GetInt64Constant(JSTaggedValue::VALUE_UNDEFINED)); \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), func); \ + /* ASSERT(JSMethod::NumVregsBits::Decode(callField) == 0) */ \ + /* thread->DoStackOverflowCheck(newSp) */ \ + GateRef frameBaseOffset = GetIntPtrConstant(JSThread::GlueData::GetFrameBaseOffset(env->IsArch32Bit())); \ + GateRef frameBase = Load(VariableType::POINTER(), glue, frameBaseOffset); \ + Label stackOverflow(env); \ + Label stackNotOverflow(env); \ + Branch(UInt64LessThanOrEqual(*newSp, IntPtrAdd(frameBase, \ + /* 2: double size in case */ \ + GetIntPtrConstant(JSThread::RESERVE_STACK_SIZE * sizeof(JSTaggedType) * 2))), \ + &stackOverflow, &stackNotOverflow); \ + Bind(&stackOverflow); \ + { \ + CallRuntimeTrampoline(glue, GetInt64Constant(RUNTIME_CALL_ID(SetStackOverflowException)), {}); \ + DISPATCH_LAST(); \ + } \ + Bind(&stackNotOverflow); \ + GateRef state = GetFrame(*newSp); \ + GateRef prevOffset = GetIntPtrConstant(InterpretedFrame::GetBaseOffset(env->IsArch32Bit())); \ + Store(VariableType::POINTER(), glue, state, prevOffset, sp); \ + GateRef frameTypeOffset = IntPtrAdd(prevOffset, GetIntPtrSize()); \ + Store(VariableType::INT64(), glue, state, frameTypeOffset, \ + GetInt64Constant(static_cast(FrameType::INTERPRETER_FRAME))); \ + SetPcToFrame(glue, state, GetIntPtrConstant(0)); \ + SetFunctionToFrame(glue, state, func); \ + SetCurrentSpFrame(glue, *newSp); \ + GateRef numArgs = Int32Add(GetInt32Constant(NUM_MANDATORY_JSFUNC_ARGS), actualNumArgs); \ + GateRef retValue = CallRuntimeTrampoline(glue, GetInt64Constant(RUNTIME_CALL_ID(CallNative)), \ + {IntBuildTaggedTypeWithNoGC(numArgs), *newSp, method}); \ + SetCurrentSpFrame(glue, sp); \ + DEFVARIABLE(varAcc, VariableType::JS_ANY(), retValue); \ + DISPATCH_WITH_ACC(format) + +#define SET_VREGS_AND_FRAME_NOT_NATIVE(format) \ + Label funcIsClassConstructor(env); \ + Label funcNotClassConstructor(env); \ + Branch(IsClassConstructor(func), &funcIsClassConstructor, &funcNotClassConstructor); \ + Bind(&funcIsClassConstructor); \ + { \ + CallRuntimeTrampoline(glue, GetInt64Constant(RUNTIME_CALL_ID(SetCallConstructorException)), {}); \ + DISPATCH_LAST(); \ + } \ + Bind(&funcNotClassConstructor); \ + Label notNormalCallType(env); \ + Label isNormalCallType(env); \ + Branch(Int64Equal(Int64And(callField, GetInt64Constant(CALL_TYPE_MASK)), GetInt64Constant(0)), \ + &isNormalCallType, ¬NormalCallType); \ + Bind(¬NormalCallType); \ + { \ + GateRef haveThisMask = GetInt64Constant(static_cast(1) << JSMethod::HaveThisBit::START_BIT); \ + Label methodHaveThis(env); \ + Label methodNoThis(env); \ + Branch(Int64NotEqual(Int64And(callField, haveThisMask), GetInt64Constant(0)), \ + &methodHaveThis, &methodNoThis); \ + Bind(&methodHaveThis); \ + { \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Label pushThis(env); \ + Label pushThisUndefined(env); \ + Branch(callThis, &pushThis, &pushThisUndefined); \ + Bind(&pushThis); \ + { \ + GateRef thisValue = GetVregValue(sp, IntPtrAdd(ZExtInt8ToPtr(funcReg), GetIntPtrConstant(1))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), thisValue); \ + Jump(&methodNoThis); \ + } \ + Bind(&pushThisUndefined); \ + { \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), \ + GetInt64Constant(JSTaggedValue::VALUE_UNDEFINED)); \ + Jump(&methodNoThis); \ + } \ + } \ + Bind(&methodNoThis); \ + GateRef haveNewTargetMask = GetInt64Constant(static_cast(1) << \ + JSMethod::HaveNewTargetBit::START_BIT); \ + Label methodHaveNewTarget(env); \ + Label methodNoNewTarget(env); \ + Branch(Int64NotEqual(Int64And(callField, haveNewTargetMask), GetInt64Constant(0)), \ + &methodHaveNewTarget, &methodNoNewTarget); \ + Bind(&methodHaveNewTarget); \ + { \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), \ + GetInt64Constant(JSTaggedValue::VALUE_UNDEFINED)); \ + Jump(&methodNoNewTarget); \ + } \ + Bind(&methodNoNewTarget); \ + GateRef haveFuncMask = GetInt64Constant(static_cast(1) << JSMethod::HaveFuncBit::START_BIT); \ + Label methodHaveFunc(env); \ + Label methodNoFunc(env); \ + Branch(Int64NotEqual(Int64And(callField, haveFuncMask), GetInt64Constant(0)), \ + &methodHaveFunc, &methodNoFunc); \ + Bind(&methodHaveFunc); \ + { \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), func); \ + Jump(&methodNoFunc); \ + } \ + Bind(&methodNoFunc); \ + Jump(&isNormalCallType); \ + } \ + Bind(&isNormalCallType); \ + { \ + GateRef numVregsOffset = GetInt64Constant(JSMethod::NumVregsBits::START_BIT); \ + GateRef numVregsMask = GetInt64Constant((static_cast(1) << JSMethod::NumVregsBits::SIZE) - 1); \ + GateRef numVregs = ChangeInt64ToInt32(Int64And(UInt64LSR(callField, numVregsOffset), numVregsMask)); \ + CALL_PUSH_UNDEFINED(numVregs); \ + /* thread->DoStackOverflowCheck(newSp) */ \ + GateRef frameBaseOffset = GetIntPtrConstant(JSThread::GlueData::GetFrameBaseOffset(env->IsArch32Bit())); \ + GateRef frameBase = Load(VariableType::POINTER(), glue, frameBaseOffset); \ + Label stackOverflow(env); \ + Label stackNotOverflow(env); \ + Branch(UInt64LessThanOrEqual(*newSp, IntPtrAdd(frameBase, \ + /* 2: double size in case */ \ + GetIntPtrConstant(JSThread::RESERVE_STACK_SIZE * sizeof(JSTaggedType) * 2))), \ + &stackOverflow, &stackNotOverflow); \ + Bind(&stackOverflow); \ + { \ + CallRuntimeTrampoline(glue, GetInt64Constant(RUNTIME_CALL_ID(SetStackOverflowException)), {}); \ + DISPATCH_LAST(); \ + } \ + Bind(&stackNotOverflow); \ + SetPcToFrame(glue, GetFrame(sp), \ + IntPtrAdd(pc, GetIntPtrConstant(BytecodeInstruction::Size(BytecodeInstruction::Format::format)))); \ + GateRef state = GetFrame(*newSp); \ + GateRef prevOffset = GetIntPtrConstant(InterpretedFrame::GetBaseOffset(env->IsArch32Bit())); \ + Store(VariableType::POINTER(), glue, state, prevOffset, sp); \ + GateRef frameTypeOffset = IntPtrAdd(prevOffset, GetIntPtrConstant( \ + env->IsArch32Bit() ? InterpretedFrameBase::TYPE_OFFSET_32 : InterpretedFrameBase::TYPE_OFFSET_64)); \ + Store(VariableType::INT64(), glue, state, frameTypeOffset, \ + GetInt64Constant(static_cast(FrameType::INTERPRETER_FRAME))); \ + GateRef bytecodeArrayOffset = GetIntPtrConstant(JSMethod::GetBytecodeArrayOffset(env->IsArch32Bit())); \ + GateRef bytecodeArray = Load(VariableType::POINTER(), method, bytecodeArrayOffset); \ + SetPcToFrame(glue, state, bytecodeArray); \ + SetFunctionToFrame(glue, state, func); \ + SetAccToFrame(glue, state, GetHoleConstant(VariableType::JS_ANY())); \ + GateRef newEnv = GetEnvFromFunction(func); \ + SetEnvToFrame(glue, state, newEnv); \ + SetCurrentSpFrame(glue, *newSp); \ + GateRef newConstpool = GetConstpoolFromFunction(func); \ + GateRef newProfileTypeInfo = GetProfileTypeInfoFromFunction(func); \ + GateRef newHotnessCounter = Load(VariableType::INT32(), method, \ + GetIntPtrConstant(JSMethod::HOTNESS_COUNTER_OFFSET)); \ + Dispatch(glue, bytecodeArray, *newSp, newConstpool, newProfileTypeInfo, \ + GetHoleConstant(VariableType::JS_ANY()), newHotnessCounter, GetIntPtrConstant(0)); \ + } + +#define CALL_PUSH_ARGS_PREF_V8() \ + static_cast(0) // do nothing when 0 arg + +#define CALL_PUSH_ARGS_NO_EXTRA_PREF_V8() \ + static_cast(0) // do nothing when 0 arg + +#define CALL_PUSH_ARGS_PREF_V8_V8() \ + GateRef a0Value = GetVregValue(sp, ZExtInt8ToPtr(a0)); \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), a0Value) + +#define CALL_PUSH_ARGS_NO_EXTRA_PREF_V8_V8() \ + Label push0(env); \ + Label skip0(env); \ + Branch(Int32GreaterThanOrEqual(declaredNumArgs, \ + GetInt32Constant(EcmaInterpreter::ActualNumArgsOfCall::CALLARG1)), &push0, &skip0); \ + Bind(&push0); \ + { \ + GateRef a0Value = GetVregValue(sp, ZExtInt8ToPtr(a0)); \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), a0Value); \ + Jump(&skip0); \ + } \ + Bind(&skip0) + +#define CALL_PUSH_ARGS_PREF_V8_V8_V8() \ + GateRef a1Value = GetVregValue(sp, ZExtInt8ToPtr(a1)); \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), a1Value); \ + CALL_PUSH_ARGS_PREF_V8_V8() + +#define CALL_PUSH_ARGS_NO_EXTRA_PREF_V8_V8_V8() \ + Label push1(env); \ + Label skip1(env); \ + Branch(Int32GreaterThanOrEqual(declaredNumArgs, \ + GetInt32Constant(EcmaInterpreter::ActualNumArgsOfCall::CALLARGS2)), &push1, &skip1); \ + Bind(&push1); \ + { \ + GateRef a1Value = GetVregValue(sp, ZExtInt8ToPtr(a1)); \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), a1Value); \ + Jump(&skip1); \ + } \ + Bind(&skip1); \ + CALL_PUSH_ARGS_NO_EXTRA_PREF_V8_V8() + +#define CALL_PUSH_ARGS_PREF_V8_V8_V8_V8() \ + GateRef a2Value = GetVregValue(sp, ZExtInt8ToPtr(a2)); \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), a2Value); \ + CALL_PUSH_ARGS_PREF_V8_V8_V8() + +#define CALL_PUSH_ARGS_NO_EXTRA_PREF_V8_V8_V8_V8() \ + Label push2(env); \ + Label skip2(env); \ + Branch(Int32GreaterThanOrEqual(declaredNumArgs, \ + GetInt32Constant(EcmaInterpreter::ActualNumArgsOfCall::CALLARGS3)), &push2, &skip2); \ + Bind(&push2); \ + { \ + GateRef a2Value = GetVregValue(sp, ZExtInt8ToPtr(a2)); \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), a2Value); \ + Jump(&skip2); \ + } \ + Bind(&skip2); \ + CALL_PUSH_ARGS_NO_EXTRA_PREF_V8_V8_V8() + +#define CALL_PUSH_ARGS_PREF_IMM16_V8() \ + i = actualNumArgs; \ + CALL_PUSH_ARGS_I() + +#define CALL_PUSH_ARGS_NO_EXTRA_PREF_IMM16_V8() \ + /* i = std::min(actualNumArgs, declaredNumArgs) */ \ + i = actualNumArgs; \ + Label declaredNumArgsSmaller(env); \ + Label callPushArgsI(env); \ + Branch(Int32LessThan(*i, declaredNumArgs), &callPushArgsI, &declaredNumArgsSmaller); \ + Bind(&declaredNumArgsSmaller); \ + i = declaredNumArgs; \ + Jump(&callPushArgsI); \ + Bind(&callPushArgsI); \ + CALL_PUSH_ARGS_I() + +#define CALL_PUSH_ARGS_I() \ + Label pushWithThis(env); \ + Label pushWithoutThis(env); \ + Label pushArgsEnd(env); \ + Branch(callThis, &pushWithThis, &pushWithoutThis); \ + Bind(&pushWithThis); \ + { \ + i = Int32Add(*i, GetInt32Constant(1)); /* 1: skip this */ \ + Label pushArgs(env); \ + Label pushArgsAgain(env); \ + Branch(Int32GreaterThan(*i, GetInt32Constant(1)), &pushArgs, &pushArgsEnd); \ + LoopBegin(&pushArgs); \ + GateRef aValue = GetVregValue(sp, IntPtrAdd(ZExtInt8ToPtr(funcReg), ChangeInt32ToIntPtr(*i))); \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), aValue); \ + i = Int32Sub(*i, GetInt32Constant(1)); \ + Branch(Int32GreaterThan(*i, GetInt32Constant(1)), &pushArgsAgain, &pushArgsEnd); \ + Bind(&pushArgsAgain); \ + LoopEnd(&pushArgs); \ + } \ + Bind(&pushWithoutThis); \ + { \ + Label pushArgs(env); \ + Label pushArgsAgain(env); \ + Branch(Int32GreaterThan(*i, GetInt32Constant(0)), &pushArgs, &pushArgsEnd); \ + LoopBegin(&pushArgs); \ + GateRef aValue = GetVregValue(sp, IntPtrAdd(ZExtInt8ToPtr(funcReg), ChangeInt32ToIntPtr(*i))); \ + newSp = PointerSub(*newSp, GetIntPtrConstant(sizeof(JSTaggedType))); \ + Store(VariableType::INT64(), glue, *newSp, GetIntPtrConstant(0), aValue); \ + i = Int32Sub(*i, GetInt32Constant(1)); \ + Branch(Int32GreaterThan(*i, GetInt32Constant(0)), &pushArgsAgain, &pushArgsEnd); \ + Bind(&pushArgsAgain); \ + LoopEnd(&pushArgs); \ + } \ + Bind(&pushArgsEnd) + +DECLARE_ASM_HANDLER(HandleCallArg0DynPrefV8) +{ + auto env = GetEnvironment(); + + GateRef actualNumArgs = GetInt32Constant(EcmaInterpreter::ActualNumArgsOfCall::CALLARG0); + GateRef funcReg = ReadInst8_1(pc); + CALL_INITIALIZE(); + GateRef callThis = FalseConstant(); + CALL_PUSH_ARGS(PREF_V8); +} + +DECLARE_ASM_HANDLER(HandleCallArg1DynPrefV8V8) +{ + auto env = GetEnvironment(); + + GateRef actualNumArgs = GetInt32Constant(EcmaInterpreter::ActualNumArgsOfCall::CALLARG1); + GateRef funcReg = ReadInst8_1(pc); + GateRef a0 = ReadInst8_2(pc); + CALL_INITIALIZE(); + GateRef callThis = FalseConstant(); + CALL_PUSH_ARGS(PREF_V8_V8); +} + +DECLARE_ASM_HANDLER(HandleCallArgs2DynPrefV8V8V8) +{ + auto env = GetEnvironment(); + + GateRef actualNumArgs = GetInt32Constant(EcmaInterpreter::ActualNumArgsOfCall::CALLARGS2); + GateRef funcReg = ReadInst8_1(pc); + GateRef a0 = ReadInst8_2(pc); + GateRef a1 = ReadInst8_3(pc); + CALL_INITIALIZE(); + GateRef callThis = FalseConstant(); + CALL_PUSH_ARGS(PREF_V8_V8_V8); +} + +DECLARE_ASM_HANDLER(HandleCallArgs3DynPrefV8V8V8V8) +{ + auto env = GetEnvironment(); + + GateRef actualNumArgs = GetInt32Constant(EcmaInterpreter::ActualNumArgsOfCall::CALLARGS3); + GateRef funcReg = ReadInst8_1(pc); + GateRef a0 = ReadInst8_2(pc); + GateRef a1 = ReadInst8_3(pc); + GateRef a2 = ReadInst8_4(pc); + CALL_INITIALIZE(); + GateRef callThis = FalseConstant(); + CALL_PUSH_ARGS(PREF_V8_V8_V8_V8); +} + +DECLARE_ASM_HANDLER(HandleCallIRangeDynPrefImm16V8) +{ + auto env = GetEnvironment(); + + GateRef actualNumArgs = ZExtInt16ToInt32(ReadInst16_1(pc)); + GateRef funcReg = ReadInst8_3(pc); + CALL_INITIALIZE(); + GateRef callThis = FalseConstant(); + CALL_PUSH_ARGS(PREF_IMM16_V8); +} + +DECLARE_ASM_HANDLER(HandleCallIThisRangeDynPrefImm16V8) +{ + auto env = GetEnvironment(); + + GateRef actualNumArgs = Int32Sub(ZExtInt16ToInt32(ReadInst16_1(pc)), GetInt32Constant(1)); // 1: exclude this + GateRef funcReg = ReadInst8_3(pc); + CALL_INITIALIZE(); + GateRef callThis = TrueConstant(); + CALL_PUSH_ARGS(PREF_IMM16_V8); +} #endif #undef DECLARE_ASM_HANDLER #undef DISPATCH #undef DISPATCH_WITH_ACC #undef DISPATCH_LAST +#undef DISPATCH_LAST_WITH_ACC } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/interpreter_stub.h b/ecmascript/compiler/interpreter_stub.h index 8121ea974a..432165d4e9 100644 --- a/ecmascript/compiler/interpreter_stub.h +++ b/ecmascript/compiler/interpreter_stub.h @@ -64,6 +64,7 @@ public: inline GateRef GetFunctionFromFrame(GateRef frame); inline GateRef GetAccFromFrame(GateRef frame); inline GateRef GetEnvFromFrame(GateRef frame); + inline GateRef GetEnvFromFunction(GateRef frame); inline GateRef GetConstpoolFromFunction(GateRef function); inline GateRef GetProfileTypeInfoFromFunction(GateRef function); diff --git a/ecmascript/compiler/interpreter_stub_define.h b/ecmascript/compiler/interpreter_stub_define.h index a4e69b902e..1299ddc5ef 100644 --- a/ecmascript/compiler/interpreter_stub_define.h +++ b/ecmascript/compiler/interpreter_stub_define.h @@ -24,12 +24,15 @@ namespace panda::ecmascript::kungfu { #define IGNORE_STUB(...) #define INTERPRETER_STUB_LIST(V) \ - ASM_INTERPRETER_STUB_LIST(IGNORE_STUB, V) + ASM_INTERPRETER_STUB_LIST(IGNORE_STUB, V, V) + +#define INTERPRETER_IGNORE_STUB_LIST(V) \ + ASM_INTERPRETER_STUB_LIST(IGNORE_STUB, IGNORE_STUB, V) #define ASM_INTERPRETER_ID_LIST(V) \ - ASM_INTERPRETER_STUB_LIST(V, V) + ASM_INTERPRETER_STUB_LIST(V, V, V) -#define ASM_INTERPRETER_STUB_LIST(V, T) \ +#define ASM_INTERPRETER_STUB_LIST(V, T, I) \ T(HandleLdNanPref, 7) \ T(HandleLdInfinityPref, 7) \ T(HandleLdGlobalThisPref, 7) \ @@ -89,7 +92,7 @@ namespace panda::ecmascript::kungfu { T(HandleThrowConstAssignmentPrefV8, 7) \ T(HandleGetTemplateObjectPrefV8, 7) \ T(HandleGetNextPropNamePrefV8, 7) \ - V(HandleCallArg0DynPrefV8, 7) \ + I(HandleCallArg0DynPrefV8, 7) \ T(HandleThrowIfNotObjectPrefV8, 7) \ T(HandleIterNextPrefV8, 7) \ T(HandleCloseIteratorPrefV8, 7) \ @@ -101,7 +104,7 @@ namespace panda::ecmascript::kungfu { T(HandleSuspendGeneratorPrefV8V8, 7) \ T(HandleAsyncFunctionAwaitUncaughtPrefV8V8, 7) \ T(HandleThrowUndefinedIfHolePrefV8V8, 7) \ - V(HandleCallArg1DynPrefV8V8, 7) \ + I(HandleCallArg1DynPrefV8V8, 7) \ T(HandleCopyDataPropertiesPrefV8V8, 7) \ T(HandleStArraySpreadPrefV8V8, 7) \ T(HandleGetIteratorNextPrefV8V8, 7) \ @@ -117,12 +120,12 @@ namespace panda::ecmascript::kungfu { T(HandleCallSpreadDynPrefV8V8V8, 7) \ T(HandleAsyncFunctionResolvePrefV8V8V8, 7) \ T(HandleAsyncFunctionRejectPrefV8V8V8, 7) \ - V(HandleCallArgs2DynPrefV8V8V8, 7) \ - V(HandleCallArgs3DynPrefV8V8V8V8, 7) \ + I(HandleCallArgs2DynPrefV8V8V8, 7) \ + I(HandleCallArgs3DynPrefV8V8V8V8, 7) \ T(HandleDefineGetterSetterByValuePrefV8V8V8V8, 7) \ T(HandleNewObjDynRangePrefImm16V8, 7) \ - V(HandleCallIRangeDynPrefImm16V8, 7) \ - V(HandleCallIThisRangeDynPrefImm16V8, 7) \ + I(HandleCallIRangeDynPrefImm16V8, 7) \ + I(HandleCallIThisRangeDynPrefImm16V8, 7) \ T(HandleSuperCallPrefImm16V8, 7) \ T(HandleCreateObjectWithExcludedKeysPrefImm16V8V8, 7) \ T(HandleDefineFuncDynPrefId16Imm16V8, 7) \ diff --git a/ecmascript/compiler/llvm_ir_builder.cpp b/ecmascript/compiler/llvm_ir_builder.cpp index 66a30f3167..2447f9b426 100644 --- a/ecmascript/compiler/llvm_ir_builder.cpp +++ b/ecmascript/compiler/llvm_ir_builder.cpp @@ -126,8 +126,11 @@ void LLVMIRBuilder::AssignHandleMap() {OpCode::SLT, &LLVMIRBuilder::HandleCmp}, {OpCode::ULT, &LLVMIRBuilder::HandleCmp}, {OpCode::SLE, &LLVMIRBuilder::HandleCmp}, + {OpCode::ULE, &LLVMIRBuilder::HandleCmp}, {OpCode::SGT, &LLVMIRBuilder::HandleCmp}, + {OpCode::UGT, &LLVMIRBuilder::HandleCmp}, {OpCode::SGE, &LLVMIRBuilder::HandleCmp}, + {OpCode::UGE, &LLVMIRBuilder::HandleCmp}, {OpCode::NE, &LLVMIRBuilder::HandleCmp}, {OpCode::EQ, &LLVMIRBuilder::HandleCmp}, {OpCode::LOAD, &LLVMIRBuilder::HandleLoad}, @@ -1264,7 +1267,8 @@ void LLVMIRBuilder::VisitSub(GateRef gate, GateRef e1, GateRef e2) COMPILER_LOG(DEBUG) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = nullptr; auto machineType = circuit_->LoadGatePtrConst(gate)->GetMachineType(); - if (machineType == MachineType::I16 || machineType == MachineType::I32 || machineType == MachineType::I64) { + if (machineType == MachineType::I16 || machineType == MachineType::I32 || + machineType == MachineType::I64 || machineType == MachineType::ARCH) { result = LLVMBuildSub(builder_, e1Value, e2Value, ""); } else if (machineType == MachineType::F64) { result = LLVMBuildFSub(builder_, e1Value, e2Value, ""); @@ -1384,16 +1388,31 @@ void LLVMIRBuilder::VisitCmp(GateRef gate, GateRef e1, GateRef e2) realOpcode = LLVMRealOLE; break; } + case OpCode::ULE: { + intOpcode = LLVMIntULE; + realOpcode = LLVMRealOLE; + break; + } case OpCode::SGT: { intOpcode = LLVMIntSGT; realOpcode = LLVMRealOGT; break; } + case OpCode::UGT: { + intOpcode = LLVMIntUGT; + realOpcode = LLVMRealOGT; + break; + } case OpCode::SGE: { intOpcode = LLVMIntSGE; realOpcode = LLVMRealOGE; break; } + case OpCode::UGE: { + intOpcode = LLVMIntUGE; + realOpcode = LLVMRealOGE; + break; + } case OpCode::NE: { intOpcode = LLVMIntNE; realOpcode = LLVMRealONE; diff --git a/ecmascript/compiler/stub-inl.h b/ecmascript/compiler/stub-inl.h index c4b94f5fdc..03af7db8be 100644 --- a/ecmascript/compiler/stub-inl.h +++ b/ecmascript/compiler/stub-inl.h @@ -477,6 +477,11 @@ GateRef Stub::IntPtrSub(GateRef x, GateRef y) return Int64Sub(x, y); } +GateRef Stub::PointerSub(GateRef x, GateRef y) +{ + return env_.GetCircuitBuilder().NewArithmeticGate(OpCode(OpCode::SUB), MachineType::ARCH, x, y); +} + GateRef Stub::Int16Sub(GateRef x, GateRef y) { return env_.GetCircuitBuilder().NewArithmeticGate(OpCode(OpCode::SUB), MachineType::I16, x, y); diff --git a/ecmascript/compiler/stub.h b/ecmascript/compiler/stub.h index 77ff0d69a2..037d27da78 100644 --- a/ecmascript/compiler/stub.h +++ b/ecmascript/compiler/stub.h @@ -452,6 +452,7 @@ public: inline GateRef DoubleAdd(GateRef x, GateRef y); inline GateRef IntPtrAdd(GateRef x, GateRef y); inline GateRef IntPtrSub(GateRef x, GateRef y); + inline GateRef PointerSub(GateRef x, GateRef y); inline GateRef IntPtrEqual(GateRef x, GateRef y); inline GateRef Int16Sub(GateRef x, GateRef y); inline GateRef Int32Sub(GateRef x, GateRef y); diff --git a/ecmascript/frames.h b/ecmascript/frames.h index ee22b02227..5ad68c5eec 100644 --- a/ecmascript/frames.h +++ b/ecmascript/frames.h @@ -312,8 +312,10 @@ public: ~InterpretedFrameBase() = default; JSTaggedType *prev; // for llvm :c-fp ; for interrupt: thread-fp for gc FrameType type; - static constexpr size_t SizeArch32 = sizeof(JSTaggedType *) + sizeof(FrameType); - static constexpr size_t SizeArch64 = sizeof(JSTaggedType *) + sizeof(FrameType); + static constexpr size_t TYPE_OFFSET_32 = sizeof(uint32_t); + static constexpr size_t TYPE_OFFSET_64 = sizeof(uint64_t); + static constexpr size_t SizeArch32 = TYPE_OFFSET_32 + sizeof(FrameType); + static constexpr size_t SizeArch64 = TYPE_OFFSET_64 + sizeof(FrameType); }; STATIC_ASSERT_EQ_ARCH(sizeof(InterpretedFrameBase), InterpretedFrameBase::SizeArch32, InterpretedFrameBase::SizeArch64); diff --git a/ecmascript/interpreter/interpreter-inl.h b/ecmascript/interpreter/interpreter-inl.h index 86842e5220..ac3d234f7e 100644 --- a/ecmascript/interpreter/interpreter-inl.h +++ b/ecmascript/interpreter/interpreter-inl.h @@ -3792,7 +3792,7 @@ uint32_t EcmaInterpreter::GetNumArgs(JSTaggedType *sp, uint32_t restIdx, uint32_ uint32_t numArgs = method->GetNumArgsWithCallField(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) JSTaggedType *lastFrame = state->base.prev - FRAME_STATE_SIZE; - if (lastFrame - sp > numVregs + copyArgs + numArgs) { + if (static_cast(lastFrame - sp) > numVregs + copyArgs + numArgs) { // In this case, actualNumArgs is in the end // If not, then actualNumArgs == declaredNumArgs, therefore do nothing // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) diff --git a/ecmascript/js_method.h b/ecmascript/js_method.h index cba6475075..a690edc2c3 100755 --- a/ecmascript/js_method.h +++ b/ecmascript/js_method.h @@ -35,10 +35,10 @@ static constexpr size_t STORAGE_PTR_NUM = 3; V(CODEID, FILEID, sizeof(uint32_t), sizeof(uint32_t)) \ V(SHORTY, CODEID, sizeof(uint32_t), sizeof(uint32_t)) \ V(PROFILINGDATA, SHORTY, sizeof(uint32_t), sizeof(uint64_t)) \ - V(BYTECODEARRAY, PROFILINGDATA, sizeof(uint32_t), sizeof(uint64_t)) \ + V(CALLFIELD, PROFILINGDATA, sizeof(uint32_t), sizeof(uint64_t)) \ + V(BYTECODEARRAY, CALLFIELD, sizeof(uint64_t), sizeof(uint64_t)) \ V(BYTECODEARRAYSIZE, BYTECODEARRAY, sizeof(uint32_t), sizeof(uint64_t)) \ V(SLOTSIZE, BYTECODEARRAYSIZE, sizeof(uint32_t), sizeof(uint32_t)) \ - V(CALLFIELD, SLOTSIZE, sizeof(uint8_t), sizeof(uint8_t)) \ static constexpr uint32_t JS_METHOD_STOR32_OFFSET_32 = 0U; static constexpr uint32_t JS_METHOD_STOR32_OFFSET_64 = 0U; @@ -131,6 +131,14 @@ public: return callField_; } + static constexpr uint32_t GetCallFieldOffset(bool isArm32) + { + if (isArm32) { + return JS_METHOD_CALLFIELD_OFFSET_32; + } + return JS_METHOD_CALLFIELD_OFFSET_64; + } + void SetNativeBit(bool isNative) { callField_ = IsNativeBit::Update(callField_, isNative); @@ -180,10 +188,10 @@ public: } private: + uint64_t callField_ {0}; const uint8_t *bytecodeArray_ {nullptr}; uint32_t bytecodeArraySize_ {0}; uint8_t slotSize_ {0}; - uint64_t callField_ {0}; }; } // namespace panda::ecmascript diff --git a/ecmascript/js_thread.cpp b/ecmascript/js_thread.cpp index cd11b115bb..2f1cde6785 100644 --- a/ecmascript/js_thread.cpp +++ b/ecmascript/js_thread.cpp @@ -31,9 +31,9 @@ JSThread *JSThread::Create(Runtime *runtime, PandaVM *vm) jsThread->nativeAreaAllocator_ = EcmaVM::Cast(vm)->GetNativeAreaAllocator(); jsThread->heapRegionAllocator_ = EcmaVM::Cast(vm)->GetHeapRegionAllocator(); // algin with 16 - jsThread->frameBase_ = static_cast( + jsThread->glueData_.frameBase_ = static_cast( EcmaVM::Cast(vm)->GetNativeAreaAllocator()->Allocate(sizeof(JSTaggedType) * MAX_STACK_SIZE)); - jsThread->glueData_.currentFrame_ = jsThread->frameBase_ + MAX_STACK_SIZE; + jsThread->glueData_.currentFrame_ = jsThread->glueData_.frameBase_ + MAX_STACK_SIZE; JSThread::SetCurrent(jsThread); EcmaInterpreter::InitStackFrame(jsThread); return jsThread; @@ -62,8 +62,8 @@ JSThread::~JSThread() handleScopeStorageNext_ = handleScopeStorageEnd_ = nullptr; EcmaVM::Cast(GetVM())->GetChunk()->Delete(globalStorage_); - GetNativeAreaAllocator()->Free(frameBase_, sizeof(JSTaggedType) * MAX_STACK_SIZE); - frameBase_ = nullptr; + GetNativeAreaAllocator()->Free(glueData_.frameBase_, sizeof(JSTaggedType) * MAX_STACK_SIZE); + glueData_.frameBase_ = nullptr; nativeAreaAllocator_ = nullptr; heapRegionAllocator_ = nullptr; if (internalCallParams_ != nullptr) { @@ -158,7 +158,7 @@ void JSThread::IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor) bool JSThread::DoStackOverflowCheck(const JSTaggedType *sp) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - if (UNLIKELY(sp <= frameBase_ + RESERVE_STACK_SIZE)) { + if (UNLIKELY(sp <= glueData_.frameBase_ + RESERVE_STACK_SIZE)) { ObjectFactory *factory = GetEcmaVM()->GetFactory(); JSHandle error = factory->GetJSError(base::ErrorType::RANGE_ERROR, "Stack overflow!"); if (LIKELY(!HasPendingException())) { @@ -247,7 +247,12 @@ void JSThread::LoadStubModule(const char *moduleFile) glueData_.bcHandlers_.Set(kungfu::InterpreterStubId::name##Id, \ stubModule.GetStubEntry(kungfu::StubId::STUB_##name)); INTERPRETER_STUB_LIST(DEF_STUB) +#define UNDEF_STUB(name, counter) \ + glueData_.bcHandlers_.Set(kungfu::InterpreterStubId::name##Id, \ + stubModule.GetStubEntry(kungfu::StubId::STUB_SingleStepDebugging)); + INTERPRETER_IGNORE_STUB_LIST(UNDEF_STUB) #undef DEF_STUB +#undef UNDEF_STUB #endif #ifdef NDEBUG diff --git a/ecmascript/js_thread.h b/ecmascript/js_thread.h index 1151376ef8..655a5df988 100644 --- a/ecmascript/js_thread.h +++ b/ecmascript/js_thread.h @@ -96,6 +96,7 @@ STATIC_ASSERT_EQ_ARCH(sizeof(StubEntries), StubEntries::SizeArch32, StubEntries: class JSThread : public ManagedThread { public: static constexpr int CONCURRENT_MARKING_BITFIELD_NUM = 2; + static constexpr uint32_t RESERVE_STACK_SIZE = 128; using MarkStatusBits = BitField; static JSThread *Cast(ManagedThread *thread) @@ -356,6 +357,7 @@ public: RTInterfaces, StubEntries, base::AlignedUint64, + base::AlignedPointer, GlobalEnvConstants> { enum class Index : size_t { ExceptionIndex = 0, @@ -366,6 +368,7 @@ public: RTInterfacesIndex, StubEntriesIndex, StateBitFieldIndex, + FrameBaseIndex, GlobalConstIndex, NumOfMembers }; @@ -416,6 +419,11 @@ public: return GetOffset(Index::StubEntriesIndex)>(isArch32); } + static size_t GetFrameBaseOffset(bool isArch32) + { + return GetOffset(Index::FrameBaseIndex)>(isArch32); + } + alignas(EAS) JSTaggedValue exception_ {JSTaggedValue::Hole()}; alignas(EAS) JSTaggedValue globalObject_ {JSTaggedValue::Hole()}; alignas(EAS) JSTaggedType *currentFrame_ {nullptr}; @@ -424,6 +432,7 @@ public: alignas(EAS) RTInterfaces rtInterfaces_; alignas(EAS) StubEntries stubEntries_; alignas(EAS) volatile uint64_t threadStateBitField_ {0ULL}; + alignas(EAS) JSTaggedType *frameBase_ {nullptr}; alignas(EAS) GlobalEnvConstants globalConst_; }; static_assert(MEMBER_OFFSET(GlueData, rtInterfaces_) == ASM_GLUE_RUNTIME_FUNCTIONS_OFFSET); @@ -438,7 +447,6 @@ private: void DumpStack() DUMP_API_ATTR; static constexpr uint32_t MAX_STACK_SIZE = 128 * 1024; - static constexpr uint32_t RESERVE_STACK_SIZE = 128; static const uint32_t NODE_BLOCK_SIZE_LOG2 = 10; static const uint32_t NODE_BLOCK_SIZE = 1U << NODE_BLOCK_SIZE_LOG2; static constexpr int32_t MIN_HANDLE_STORAGE_SIZE = 2; @@ -462,7 +470,6 @@ private: bool gcState_ {false}; VmThreadControl *vmThreadControl_ {nullptr}; - JSTaggedType *frameBase_ {nullptr}; bool stableArrayElementsGuardians_ {true}; InternalCallParams *internalCallParams_ {nullptr}; GlueData glueData_; diff --git a/ecmascript/message_string.cpp b/ecmascript/message_string.cpp index 38c059d7b7..ab3bff47b7 100644 --- a/ecmascript/message_string.cpp +++ b/ecmascript/message_string.cpp @@ -26,7 +26,8 @@ static std::array g_messageString #undef DEF_COMMON_MESSAGE #define DEF_ASM_INTERPRETER_STUB_MESSAGE(name, count) #name, INTERPRETER_STUB_HELPER_LIST(DEF_ASM_INTERPRETER_STUB_MESSAGE) - ASM_INTERPRETER_STUB_LIST(DEF_ASM_INTERPRETER_STUB_MESSAGE, DEF_ASM_INTERPRETER_STUB_MESSAGE) + ASM_INTERPRETER_STUB_LIST(DEF_ASM_INTERPRETER_STUB_MESSAGE, DEF_ASM_INTERPRETER_STUB_MESSAGE, + DEF_ASM_INTERPRETER_STUB_MESSAGE) #undef DEF_ASM_INTERPRETER_STUB_MESSAGE }; diff --git a/ecmascript/message_string.h b/ecmascript/message_string.h index 102895f22d..85e01df522 100644 --- a/ecmascript/message_string.h +++ b/ecmascript/message_string.h @@ -38,7 +38,7 @@ public: #define DEF_MESSAGE_ID(name, string) Message_##name, COMMON_MESSAGE_STRING_LIST(DEF_MESSAGE_ID) INTERPRETER_STUB_HELPER_LIST(DEF_MESSAGE_ID) - ASM_INTERPRETER_STUB_LIST(DEF_MESSAGE_ID, DEF_MESSAGE_ID) + ASM_INTERPRETER_STUB_LIST(DEF_MESSAGE_ID, DEF_MESSAGE_ID, DEF_MESSAGE_ID) #undef DEF_MESSAGE_ID MAX_MESSAGE_COUNT }; diff --git a/ecmascript/trampoline/runtime_define.h b/ecmascript/trampoline/runtime_define.h index f0e1a3be06..4005a9c6a0 100644 --- a/ecmascript/trampoline/runtime_define.h +++ b/ecmascript/trampoline/runtime_define.h @@ -157,6 +157,10 @@ namespace panda::ecmascript { V(DefineGeneratorFunc, 2) \ V(DefineAsyncFunc, 2) \ V(DefineMethod, 3) \ + V(SetNotCallableException, 0) \ + V(SetCallConstructorException, 0) \ + V(SetStackOverflowException, 0) \ + V(CallNative, 3) \ V(CallSpreadDyn, 4) \ V(DefineGetterSetterByValue, 6) \ V(SuperCall, 5) diff --git a/ecmascript/trampoline/runtime_trampolines.cpp b/ecmascript/trampoline/runtime_trampolines.cpp index 4e8cea70b4..150a7341dd 100644 --- a/ecmascript/trampoline/runtime_trampolines.cpp +++ b/ecmascript/trampoline/runtime_trampolines.cpp @@ -884,14 +884,13 @@ DEF_RUNTIME_TRAMPOLINES(UpdateHotnessCounter) RUNTIME_TRAMPOLINES_HEADER(UpdateHotnessCounter); InterpretedFrame *state = GET_FRAME(const_cast(thread->GetCurrentSPFrame())); thread->CheckSafepoint(); - if (state->profileTypeInfo == JSTaggedValue::Undefined()) { - auto thisFunc = state->function; - auto method = ECMAObject::Cast(thisFunc.GetTaggedObject())->GetCallTarget(); - auto res = SlowRuntimeStub::NotifyInlineCache( - thread, JSFunction::Cast(thisFunc.GetHeapObject()), method); - state->profileTypeInfo = res; + auto thisFunc = JSFunction::Cast(state->function.GetTaggedObject()); + if (thisFunc->GetProfileTypeInfo() == JSTaggedValue::Undefined()) { + auto method = thisFunc->GetCallTarget(); + auto res = SlowRuntimeStub::NotifyInlineCache(thread, thisFunc, method); + return res.GetRawData(); } - return state->profileTypeInfo.GetRawData(); + return thisFunc->GetProfileTypeInfo().GetRawData(); } DEF_RUNTIME_TRAMPOLINES(LoadICByName) @@ -1523,6 +1522,52 @@ DEF_RUNTIME_TRAMPOLINES(SuperCall) static_cast(length.GetInt())).GetRawData(); } +DEF_RUNTIME_TRAMPOLINES(SetNotCallableException) +{ + RUNTIME_TRAMPOLINES_HEADER(SetNotCallableException); + EcmaVM *ecmaVm = thread->GetEcmaVM(); + ObjectFactory *factory = ecmaVm->GetFactory(); + JSHandle error = factory->GetJSError(ErrorType::TYPE_ERROR, "is not callable"); + thread->SetException(error.GetTaggedValue()); + return JSTaggedValue::Hole().GetRawData(); +} + +DEF_RUNTIME_TRAMPOLINES(SetCallConstructorException) +{ + RUNTIME_TRAMPOLINES_HEADER(SetCallConstructorException); + EcmaVM *ecmaVm = thread->GetEcmaVM(); + ObjectFactory *factory = ecmaVm->GetFactory(); + JSHandle error = factory->GetJSError(ErrorType::TYPE_ERROR, + "class constructor cannot called without 'new'"); + thread->SetException(error.GetTaggedValue()); + return JSTaggedValue::Hole().GetRawData(); +} + +DEF_RUNTIME_TRAMPOLINES(SetStackOverflowException) +{ + RUNTIME_TRAMPOLINES_HEADER(SetStackOverflowException); + EcmaVM *ecmaVm = thread->GetEcmaVM(); + ObjectFactory *factory = ecmaVm->GetFactory(); + JSHandle error = factory->GetJSError(base::ErrorType::RANGE_ERROR, "Stack overflow!"); + if (LIKELY(!thread->HasPendingException())) { + thread->SetException(error.GetTaggedValue()); + } + return JSTaggedValue::Hole().GetRawData(); +} + +DEF_RUNTIME_TRAMPOLINES(CallNative) +{ + RUNTIME_TRAMPOLINES_HEADER(CallNative); + CONVERT_ARG_TAGGED_CHECKED(numArgs, 0); + CONVERT_ARG_PTR_CHECKED(JSTaggedValue *, sp, 1); + CONVERT_ARG_PTR_CHECKED(JSMethod *, method, 2); + + EcmaRuntimeCallInfo ecmaRuntimeCallInfo(thread, numArgs.GetInt(), sp); + JSTaggedValue retValue = reinterpret_cast( + const_cast(method->GetNativePointer()))(&ecmaRuntimeCallInfo); + return retValue.GetRawData(); +} + int32_t RuntimeTrampolines::DoubleToInt(double x) { return base::NumberHelper::DoubleToInt(x, base::INT32_BITS);