* Copyright (c) 2024 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.
*/
#ifndef ECMASCRIPT_COMPILER_BASELINE_BASELINE_STUBS_INL_H
#define ECMASCRIPT_COMPILER_BASELINE_BASELINE_STUBS_INL_H
#include "ecmascript/compiler/baseline/baseline_stubs.h"
#include "ecmascript/js_function.h"
#include "ecmascript/js_generator_object.h"
#include "ecmascript/js_async_generator_object.h"
namespace panda::ecmascript::kungfu {
using namespace panda::ecmascript;
void BaselineStubBuilder::SetEnvToFrame(GateRef glue, GateRef frame, GateRef value)
{
Store(VariableType::INT64(), glue, frame,
IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())), value);
}
void BaselineStubBuilder::CheckExceptionWithVar(GateRef glue, GateRef sp, GateRef res, GateRef acc)
{
auto env = GetEnvironment();
Label isException(env);
Label notException(env);
Branch(TaggedIsException(res), &isException, ¬Exception);
Bind(&isException);
{
DispatchLast(glue, sp, acc);
Return(acc);
}
Bind(¬Exception);
{
Return(res);
}
}
void BaselineStubBuilder::CheckException(GateRef glue, GateRef sp, GateRef res)
{
auto env = GetEnvironment();
Label isException(env);
Label notException(env);
Branch(TaggedIsException(res), &isException, ¬Exception);
Bind(&isException);
{
GateRef frame = GetFrame(sp);
GateRef acc = GetAccFromFrame(glue, frame);
DispatchLast(glue, sp, acc);
Return();
}
Bind(¬Exception);
{
Return();
}
}
void BaselineStubBuilder::CheckExceptionReturn(GateRef glue, GateRef sp, GateRef res)
{
auto env = GetEnvironment();
Label isException(env);
Label notException(env);
Branch(TaggedIsException(res), &isException, ¬Exception);
Bind(&isException);
{
GateRef frame = GetFrame(sp);
GateRef acc = GetAccFromFrame(glue, frame);
DispatchLast(glue, sp, acc);
Return(acc);
}
Bind(¬Exception);
{
Return(res);
}
}
void BaselineStubBuilder::CheckExceptionWithJump(GateRef glue, GateRef sp, GateRef res, GateRef acc, Label *jump)
{
auto env = GetEnvironment();
Label isException(env);
Label notException(env);
Branch(TaggedIsException(res), &isException, ¬Exception);
Bind(&isException);
{
DispatchLast(glue, sp, acc);
Return();
}
Bind(¬Exception);
{
Jump(jump);
}
}
void BaselineStubBuilder::CheckExceptionWithJumpAndReturn(GateRef glue, GateRef sp, GateRef res, GateRef acc,
Label *jump)
{
auto env = GetEnvironment();
Label isException(env);
Label notException(env);
Branch(TaggedIsException(res), &isException, ¬Exception);
Bind(&isException);
{
DispatchLast(glue, sp, acc);
Return(acc);
}
Bind(¬Exception);
{
Jump(jump);
}
}
void BaselineStubBuilder::CheckPendingException(GateRef glue, GateRef sp, GateRef res, GateRef acc)
{
auto env = GetEnvironment();
Label isException(env);
Label notException(env);
Branch(HasPendingException(glue), &isException, ¬Exception);
Bind(&isException);
{
DispatchLast(glue, sp, acc);
Return(acc);
}
Bind(¬Exception);
{
Return(res);
}
}
void BaselineStubBuilder::DispatchLast(GateRef glue, GateRef sp, GateRef acc)
{
GateRef baselineEHIndex = BaselineStubCSigns::BaselineExceptionHandler;
CallBaselineStub(glue, baselineEHIndex, { glue, sp, acc });
}
GateRef BaselineStubBuilder::CallBaselineStub(GateRef glue, int index, const std::initializer_list<GateRef>& args)
{
auto env = GetEnvironment();
const std::string name = BaselineStubCSigns::GetName(index);
GateRef result = env->GetBuilder()->CallStub(glue, Circuit::NullGate(), index, args, name.c_str());
return result;
}
GateRef BaselineStubBuilder::GetFunctionFromFrame(GateRef glue, GateRef frame)
{
return Load(VariableType::JS_POINTER(), glue, frame,
IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())));
}
GateRef BaselineStubBuilder::GetEnvFromFrame(GateRef glue, GateRef frame)
{
return Load(VariableType::JS_POINTER(), glue, frame,
IntPtr(AsmInterpretedFrame::GetEnvOffset(GetEnvironment()->IsArch32Bit())));
}
GateRef BaselineStubBuilder::GetAccFromFrame(GateRef glue, GateRef frame)
{
return Load(VariableType::JS_ANY(), glue, frame,
IntPtr(AsmInterpretedFrame::GetAccOffset(GetEnvironment()->IsArch32Bit())));
}
GateRef BaselineStubBuilder::GetConstpoolFromMethod(GateRef glue, GateRef method)
{
return Load(VariableType::JS_POINTER(), glue, method, IntPtr(Method::CONSTANT_POOL_OFFSET));
}
GateRef BaselineStubBuilder::GetProfileTypeInfoFromFunction(GateRef glue, GateRef function)
{
GateRef raw = Load(VariableType::JS_POINTER(), glue, function, IntPtr(JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET));
return Load(VariableType::JS_POINTER(), glue, raw, IntPtr(ProfileTypeInfoCell::VALUE_OFFSET));
}
GateRef BaselineStubBuilder::GetHotnessCounterFromMethod(GateRef method)
{
GateRef x = LoadPrimitive(VariableType::INT16(), method, IntPtr(Method::LITERAL_INFO_OFFSET));
return GetEnvironment()->GetBuilder()->SExtInt1ToInt32(x);
}
GateRef BaselineStubBuilder::GetModuleFromFunction(GateRef glue, GateRef function)
{
return Load(VariableType::JS_POINTER(), glue, function, IntPtr(JSFunction::ECMA_MODULE_OFFSET));
}
GateRef BaselineStubBuilder::GetHomeObjectFromFunction(GateRef glue, GateRef function)
{
return Load(VariableType::JS_POINTER(), glue, function, IntPtr(JSFunction::HOME_OBJECT_OFFSET));
}
GateRef BaselineStubBuilder::GetModule(GateRef glue, GateRef sp)
{
GateRef currentFunc = GetFunctionFromFrame(glue, GetFrame(sp));
return GetModuleFromFunction(glue, currentFunc);
}
GateRef BaselineStubBuilder::GetCurrentFrame(GateRef glue)
{
return GetLastLeaveFrame(glue);
}
GateRef BaselineStubBuilder::GetFrame(GateRef CurrentSp)
{
return PtrSub(CurrentSp, IntPtr(AsmInterpretedFrame::GetSize(GetEnvironment()->IsArch32Bit())));
}
GateRef BaselineStubBuilder::GetPcFromFrame(GateRef frame)
{
return LoadPrimitive(VariableType::NATIVE_POINTER(), frame,
IntPtr(AsmInterpretedFrame::GetPcOffset(GetEnvironment()->IsArch32Bit())));
}
GateRef BaselineStubBuilder::GetCallSizeFromFrame(GateRef frame)
{
return LoadPrimitive(VariableType::NATIVE_POINTER(), frame,
IntPtr(AsmInterpretedFrame::GetCallSizeOffset(GetEnvironment()->IsArch32Bit())));
}
GateRef BaselineStubBuilder::GetThisFromFrame(GateRef glue, GateRef frame)
{
return Load(VariableType::JS_POINTER(), glue, frame,
IntPtr(AsmInterpretedFrame::GetThisOffset(GetEnvironment()->IsArch32Bit())));
}
GateRef BaselineStubBuilder::GetNewTarget(GateRef glue, GateRef sp)
{
GateRef function = Load(VariableType::JS_POINTER(), glue, GetFrame(sp),
IntPtr(AsmInterpretedFrame::GetFunctionOffset(GetEnvironment()->IsArch32Bit())));
GateRef method = GetMethodFromFunction(glue, function);
GateRef callField = GetCallFieldFromMethod(method);
GateRef numVregs =
TruncInt64ToInt32(Int64And(Int64LSR(callField, Int64(Method::NumVregsBits::START_BIT)),
Int64((1LLU << Method::NumVregsBits::SIZE) - 1)));
GateRef haveFunc =
ZExtInt1ToInt32(Int64NotEqual(Int64And(Int64LSR(callField, Int64(Method::HaveFuncBit::START_BIT)),
Int64((1LLU << Method::HaveFuncBit::SIZE) - 1)), Int64(0)));
GateRef idx = ZExtInt32ToPtr(Int32Add(numVregs, haveFunc));
return Load(VariableType::JS_ANY(), glue, sp, PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()), idx));
}
GateRef BaselineStubBuilder::GetStartIdxAndNumArgs(GateRef glue, GateRef sp, GateRef restIdx)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
DEFVARIABLE(numArgs, VariableType::INT32(), Int32(0));
GateRef state = PtrSub(sp, IntPtr(AsmInterpretedFrame::GetSize(env->IsArch32Bit())));
GateRef function = GetFunctionFromFrame(glue, state);
GateRef method = GetMethodFromJSFunctionOrProxy(glue, function);
GateRef callField = GetCallFieldFromMethod(method);
GateRef numVregs = TruncInt64ToInt32(Int64And(
Int64LSR(callField, Int64(Method::NumVregsBits::START_BIT)),
Int64((1LLU << Method::NumVregsBits::SIZE) - 1)));
GateRef haveFunc = Int64NotEqual(Int64And(Int64LSR(callField, Int64(Method::HaveFuncBit::START_BIT)),
Int64((1LLU << Method::HaveFuncBit::SIZE) - 1)), Int64(0));
GateRef haveNewTarget = Int64NotEqual(
Int64And(Int64LSR(callField, Int64(Method::HaveNewTargetBit::START_BIT)),
Int64((1LLU << Method::HaveNewTargetBit::SIZE) - 1)), Int64(0));
GateRef haveThis = Int64NotEqual(Int64And(Int64LSR(callField, Int64(Method::HaveThisBit::START_BIT)),
Int64((1LLU << Method::HaveThisBit::SIZE) - 1)), Int64(0));
GateRef copyArgs = Int32Add(Int32Add(ZExtInt1ToInt32(haveFunc), ZExtInt1ToInt32(haveNewTarget)),
ZExtInt1ToInt32(haveThis));
numArgs = TruncInt64ToInt32(Int64And(Int64LSR(callField, Int64(Method::NumArgsBits::START_BIT)),
Int64((1LLU << Method::NumArgsBits::SIZE) - 1)));
GateRef fp = LoadPrimitive(VariableType::NATIVE_POINTER(), state,
IntPtr(AsmInterpretedFrame::GetFpOffset(env->IsArch32Bit())));
Label actualEqualDeclared(env);
Label actualNotEqualDeclared(env);
Branch(Int32UnsignedGreaterThan(ChangeIntPtrToInt32(PtrSub(fp, sp)),
Int32Mul(Int32Add(Int32Add(numVregs, copyArgs), *numArgs),
Int32(sizeof(JSTaggedType)))),
&actualNotEqualDeclared, &actualEqualDeclared);
Bind(&actualNotEqualDeclared);
{
numArgs = GetInt32OfTInt(Load(VariableType::JS_ANY(), glue, fp,
IntPtr(static_cast<int64_t>(-sizeof(JSTaggedType)))));
Jump(&actualEqualDeclared);
}
Bind(&actualEqualDeclared);
GateRef startIdx = Int32Add(Int32Add(numVregs, copyArgs), restIdx);
Label numArgsGreater(env);
Label numArgsNotGreater(env);
Label exit(env);
Branch(Int32UnsignedGreaterThan(*numArgs, restIdx), &numArgsGreater, &numArgsNotGreater);
Bind(&numArgsGreater);
{
numArgs = Int32Sub(*numArgs, restIdx);
Jump(&exit);
}
Bind(&numArgsNotGreater);
{
numArgs = Int32(0);
Jump(&exit);
}
Bind(&exit);
GateRef ret = Int64Or(Int64LSL(ZExtInt32ToInt64(startIdx), Int64(32)), ZExtInt32ToInt64(*numArgs));
env->SubCfgExit();
return ret;
}
void BaselineStubBuilder::SetVregValue(GateRef glue, GateRef sp, GateRef idx, GateRef val)
{
Store(VariableType::INT64(), glue, sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx), val);
}
GateRef BaselineStubBuilder::GetVregValue(GateRef glue, GateRef sp, GateRef idx)
{
return Load(VariableType::JS_ANY(), glue, sp, PtrMul(IntPtr(sizeof(JSTaggedType)), idx));
}
GateRef BaselineStubBuilder::GetResumeModeFromGeneratorObject(GateRef obj)
{
GateRef bitfieldOffset = IntPtr(JSGeneratorObject::BIT_FIELD_OFFSET);
GateRef bitfield = LoadPrimitive(VariableType::INT32(), obj, bitfieldOffset);
return Int32And(
Int32LSR(bitfield, Int32(JSGeneratorObject::ResumeModeBits::START_BIT)),
Int32((1LU << JSGeneratorObject::ResumeModeBits::SIZE) - 1));
}
GateRef BaselineStubBuilder::GetResumeModeFromAsyncGeneratorObject(GateRef obj)
{
GateRef bitfieldOffset = IntPtr(JSAsyncGeneratorObject::BIT_FIELD_OFFSET);
GateRef bitfield = LoadPrimitive(VariableType::INT32(), obj, bitfieldOffset);
return Int32And(
Int32LSR(bitfield, Int32(JSAsyncGeneratorObject::ResumeModeBits::START_BIT)),
Int32((1LU << JSAsyncGeneratorObject::ResumeModeBits::SIZE) - 1));
}
GateRef BaselineStubBuilder::GetLastLeaveFrame(GateRef glue)
{
bool isArch32 = GetEnvironment()->Is32Bit();
GateRef spOffset = IntPtr(JSThread::GlueData::GetLeaveFrameOffset(isArch32));
return LoadPrimitive(VariableType::NATIVE_POINTER(), glue, spOffset);
}
}
#endif