!3592 AOT VTable Part2 && Part3

Merge pull request !3592 from dingding/vtable
This commit is contained in:
openharmony_ci 2023-03-17 10:34:08 +00:00 committed by Gitee
commit 4e19bae5bc
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
34 changed files with 600 additions and 108 deletions

View File

@ -715,7 +715,6 @@ bool JsonStringifier::SerializeKeys(const JSHandle<JSObject> &obj, const JSHandl
JSHandle<JSHClass> jsHclass(thread_, obj->GetJSHClass());
JSTaggedValue enumCache = jsHclass->GetEnumCache();
if (!enumCache.IsNull()) {
int propsNumber = static_cast<int>(jsHclass->NumberOfProps());
JSHandle<TaggedArray> cache(thread_, enumCache);
uint32_t length = cache->GetLength();
for (uint32_t i = 0; i < length; i++) {
@ -726,7 +725,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle<JSObject> &obj, const JSHandl
handleKey_.Update(key);
JSTaggedValue value;
LayoutInfo *layoutInfo = LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject());
int index = layoutInfo->FindElementWithCache(thread_, *jsHclass, key, propsNumber);
int index = JSHClass::FindPropertyEntry(thread_, *jsHclass, key);
PropertyAttributes attr(layoutInfo->GetAttr(index));
ASSERT(static_cast<int>(attr.GetOffset()) == index);
value = attr.IsInlinedProps()
@ -746,14 +745,13 @@ bool JsonStringifier::SerializeKeys(const JSHandle<JSObject> &obj, const JSHandl
if (end <= 0) {
return hasContent;
}
int propsNumber = static_cast<int>(jsHclass->NumberOfProps());
for (int i = 0; i < end; i++) {
LayoutInfo *layoutInfo = LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject());
JSTaggedValue key = layoutInfo->GetKey(i);
if (key.IsString() && layoutInfo->GetAttr(i).IsEnumerable()) {
handleKey_.Update(key);
JSTaggedValue value;
int index = layoutInfo->FindElementWithCache(thread_, *jsHclass, key, propsNumber);
int index = JSHClass::FindPropertyEntry(thread_, *jsHclass, key);
PropertyAttributes attr(layoutInfo->GetAttr(index));
ASSERT(static_cast<int>(attr.GetOffset()) == index);
value = attr.IsInlinedProps()

View File

@ -3443,6 +3443,7 @@ JSHandle<JSObject> Builtins::InitializeArkTools(const JSHandle<GlobalEnv> &env)
SetFunction(env, tools, "dumpHClass", builtins::BuiltinsArkTools::DumpHClass, FunctionLength::ONE);
SetFunction(env, tools, "isTSHClass", builtins::BuiltinsArkTools::IsTSHClass, FunctionLength::ONE);
SetFunction(env, tools, "getHClass", builtins::BuiltinsArkTools::GetHClass, FunctionLength::ONE);
SetFunction(env, tools, "hasTSSubtyping", builtins::BuiltinsArkTools::HasTSSubtyping, FunctionLength::ONE);
SetFunction(env, tools, "forceFullGC", builtins::BuiltinsArkTools::ForceFullGC, FunctionLength::ZERO);
SetFunction(env, tools, "removeAOTFlag", builtins::BuiltinsArkTools::RemoveAOTFlag, FunctionLength::ONE);
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)

View File

@ -61,8 +61,8 @@ JSTaggedValue BuiltinsArkTools::CompareHClass(EcmaRuntimeCallInfo *info)
JSHandle<JSTaggedValue> obj1 = GetCallArg(info, 0);
JSHandle<JSTaggedValue> obj2 = GetCallArg(info, 1);
JSHClass* obj1Hclass = obj1->GetTaggedObject()->GetClass();
JSHClass* obj2Hclass = obj2->GetTaggedObject()->GetClass();
JSHClass *obj1Hclass = obj1->GetTaggedObject()->GetClass();
JSHClass *obj2Hclass = obj2->GetTaggedObject()->GetClass();
std::ostringstream oss;
obj1Hclass->Dump(oss);
obj2Hclass->Dump(oss);
@ -80,7 +80,7 @@ JSTaggedValue BuiltinsArkTools::DumpHClass(EcmaRuntimeCallInfo *info)
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> obj = GetCallArg(info, 0);
JSHClass* objHclass = obj->GetTaggedObject()->GetClass();
JSHClass *objHclass = obj->GetTaggedObject()->GetClass();
std::ostringstream oss;
objHclass->Dump(oss);
@ -96,7 +96,7 @@ JSTaggedValue BuiltinsArkTools::IsTSHClass(EcmaRuntimeCallInfo *info)
ASSERT(info->GetArgsNumber() == 1);
JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
JSHClass* hclass = object->GetTaggedObject()->GetClass();
JSHClass *hclass = object->GetTaggedObject()->GetClass();
bool isTSHClass = hclass->IsTS();
return GetTaggedBoolean(isTSHClass);
}
@ -109,10 +109,22 @@ JSTaggedValue BuiltinsArkTools::GetHClass(EcmaRuntimeCallInfo *info)
ASSERT(info->GetArgsNumber() == 1);
JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
JSHClass* hclass = object->GetTaggedObject()->GetClass();
JSHClass *hclass = object->GetTaggedObject()->GetClass();
return JSTaggedValue(hclass);
}
JSTaggedValue BuiltinsArkTools::HasTSSubtyping(EcmaRuntimeCallInfo *info)
{
ASSERT(info);
JSThread *thread = info->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
ASSERT(info->GetArgsNumber() == 1);
JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
JSHClass *hclass = object->GetTaggedObject()->GetClass();
return GetTaggedBoolean(hclass->HasTSSubtyping());
}
JSTaggedValue BuiltinsArkTools::ForceFullGC(EcmaRuntimeCallInfo *info)
{
ASSERT(info);

View File

@ -35,6 +35,8 @@ public:
static JSTaggedValue GetHClass(EcmaRuntimeCallInfo *info);
static JSTaggedValue HasTSSubtyping(EcmaRuntimeCallInfo *info);
static JSTaggedValue ForceFullGC(EcmaRuntimeCallInfo *info);
static JSTaggedValue RemoveAOTFlag(EcmaRuntimeCallInfo *info);

View File

@ -123,6 +123,14 @@ public:
GATE_META_DATA_LIST_WITH_PC_OFFSET(DECLARE_GATE_META)
#undef DECLARE_GATE_META
#define DECLARE_GATE_META(NAME, OP, R, S, D, V) \
const GateMetaData* NAME(uint64_t pcOffset) const \
{ \
return metaBuilder_.NAME(pcOffset); \
}
GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(DECLARE_GATE_META)
#undef DECLARE_GATE_META
const GateMetaData* Nop()
{
return metaBuilder_.Nop();

View File

@ -510,6 +510,11 @@ GateRef CircuitBuilder::GetGlobalConstantString(ConstantIndex index)
return PtrMul(IntPtr(sizeof(JSTaggedValue)), IntPtr(static_cast<int>(index)));
}
GateRef CircuitBuilder::LoadObjectFromWeakRef(GateRef x)
{
return PtrAdd(x, IntPtr(-JSTaggedValue::TAG_WEAK));
}
// object operation
GateRef CircuitBuilder::LoadHClass(GateRef object)
{
@ -1074,4 +1079,4 @@ GateRef CircuitBuilder::Int32OverflowCheck(GateRef gate)
}
} // namespace panda::ecmascript::kungfu
#endif
#endif

View File

@ -635,25 +635,27 @@ GateRef CircuitBuilder::HeapAlloc(GateRef initialHClass, GateType type, RegionSp
return ret;
}
GateRef CircuitBuilder::LoadProperty(GateRef receiver, GateRef offset)
GateRef CircuitBuilder::LoadProperty(GateRef receiver, GateRef propertyLookupResult)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto ret = GetCircuit()->NewGate(circuit_->LoadProperty(), MachineType::I64,
{ currentControl, currentDepend, receiver, offset }, GateType::AnyType());
{ currentControl, currentDepend, receiver, propertyLookupResult },
GateType::AnyType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::StoreProperty(GateRef receiver, GateRef offset, GateRef value)
GateRef CircuitBuilder::StoreProperty(GateRef receiver, GateRef propertyLookupResult, GateRef value)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto ret = GetCircuit()->NewGate(circuit_->StoreProperty(), MachineType::I64,
{ currentControl, currentDepend, receiver, offset, value }, GateType::AnyType());
{ currentControl, currentDepend, receiver, propertyLookupResult, value },
GateType::AnyType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
@ -705,6 +707,38 @@ GateRef CircuitBuilder::TypedAotCall(GateRef hirGate, std::vector<GateRef> args)
return callGate;
}
GateRef CircuitBuilder::CallGetter(GateRef hirGate, GateRef receiver, GateRef propertyLookupResult)
{
ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
uint64_t pcOffset = acc_.GetPcOffset(hirGate);
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto callGate = GetCircuit()->NewGate(circuit_->CallGetter(pcOffset), MachineType::I64,
{ currentControl, currentDepend, receiver, propertyLookupResult },
GateType::AnyType());
currentLabel->SetControl(callGate);
currentLabel->SetDepend(callGate);
return callGate;
}
GateRef CircuitBuilder::CallSetter(GateRef hirGate, GateRef receiver, GateRef propertyLookupResult, GateRef value)
{
ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
uint64_t pcOffset = acc_.GetPcOffset(hirGate);
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto callGate = GetCircuit()->NewGate(circuit_->CallSetter(pcOffset), MachineType::I64,
{ currentControl, currentDepend, receiver, propertyLookupResult, value },
GateType::AnyType());
currentLabel->SetControl(callGate);
currentLabel->SetDepend(callGate);
return callGate;
}
GateRef CircuitBuilder::HasPendingException(GateRef glue)
{
GateRef exceptionOffset = IntPtr(JSThread::GlueData::GetExceptionOffset(env_->IsArch32Bit()));

View File

@ -412,6 +412,7 @@ public:
GateRef TaggedIsString(GateRef obj);
GateRef TaggedIsStringOrSymbol(GateRef obj);
inline GateRef GetGlobalConstantString(ConstantIndex index);
inline GateRef LoadObjectFromWeakRef(GateRef x);
GateRef IsJSHClass(GateRef obj);
GateRef HasPendingException(GateRef glue);
@ -432,12 +433,14 @@ public:
GateRef LoadElement(GateRef receiver, GateRef index);
template<TypedStoreOp Op>
GateRef StoreElement(GateRef receiver, GateRef index, GateRef value);
GateRef LoadProperty(GateRef receiver, GateRef offset);
GateRef StoreProperty(GateRef receiver, GateRef offset, GateRef value);
GateRef LoadProperty(GateRef receiver, GateRef propertyLookupResult);
GateRef StoreProperty(GateRef receiver, GateRef propertyLookupResult, GateRef value);
GateRef LoadArrayLength(GateRef array);
GateRef HeapAlloc(GateRef initialHClass, GateType type, RegionSpaceFlag flag);
GateRef Construct(GateRef hirGate, std::vector<GateRef> args);
GateRef TypedAotCall(GateRef hirGate, std::vector<GateRef> args);
GateRef CallGetter(GateRef hirGate, GateRef receiver, GateRef propertyLookupResult);
GateRef CallSetter(GateRef hirGate, GateRef receiver, GateRef propertyLookupResult, GateRef value);
// Object Operations
inline GateRef LoadHClass(GateRef object);
@ -484,6 +487,7 @@ public:
GateRef GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef jsFunc, GateRef index, ConstPoolType type);
GateRef GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool, GateRef module, GateRef index,
ConstPoolType type);
void SetEnvironment(Environment *env)
{
env_ = env;

View File

@ -186,6 +186,8 @@ uint32_t GateAccessor::GetPcOffset(GateRef gate) const
case OpCode::TYPED_CALL:
case OpCode::CONSTRUCT:
case OpCode::TYPEDAOTCALL:
case OpCode::CALL_GETTER:
case OpCode::CALL_SETTER:
return static_cast<uint32_t>(gatePtr->GetOneParameterMetaData()->GetValue());
default:
break;
@ -761,6 +763,13 @@ void GateAccessor::DeleteStateSplitAndFrameState(GateRef gate)
void GateAccessor::ReplaceGate(GateRef gate, GateRef state, GateRef depend, GateRef value)
{
if (value != Circuit::NullGate()) {
GateType type = GetGateType(gate);
if (!type.IsAnyType()) {
SetGateType(value, type);
}
}
auto uses = Uses(gate);
for (auto useIt = uses.begin(); useIt != uses.end();) {
if (IsStateIn(useIt)) {

View File

@ -52,6 +52,7 @@ std::string GateMetaData::Str(OpCode opcode)
GATE_META_DATA_LIST_WITH_SIZE(GATE_NAME_MAP)
GATE_META_DATA_LIST_WITH_ONE_PARAMETER(GATE_NAME_MAP)
GATE_META_DATA_LIST_WITH_PC_OFFSET(GATE_NAME_MAP)
GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(GATE_NAME_MAP)
#undef GATE_NAME_MAP
#define GATE_NAME_MAP(OP) { OpCode::OP, #OP },
GATE_OPCODE_LIST(GATE_NAME_MAP)
@ -281,6 +282,16 @@ const GateMetaData* GateMetaBuilder::NAME(uint64_t value, uint64_t pcOffset)
GATE_META_DATA_LIST_WITH_PC_OFFSET(DECLARE_GATE_META)
#undef DECLARE_GATE_META
#define DECLARE_GATE_META(NAME, OP, R, S, D, V) \
const GateMetaData* GateMetaBuilder::NAME(uint64_t pcOffset) const \
{ \
auto meta = new (chunk_) OneParameterMetaData(OpCode::OP, R, S, D, V, pcOffset); \
meta->SetKind(GateMetaData::Kind::MUTABLE_ONE_PARAMETER); \
return meta; \
}
GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(DECLARE_GATE_META)
#undef DECLARE_GATE_META
const GateMetaData* GateMetaBuilder::Arg(uint64_t value)
{
switch (value) {

View File

@ -81,7 +81,7 @@ enum class DeoptType : uint8_t {
NOTARRAY,
NOTSARRAY,
NOTF32ARRAY,
WRONGHCLASS,
INCONSISTENTHCLASS,
NOTNEWOBJ,
NOTARRAYIDX,
NOTF32ARRAYIDX,
@ -222,12 +222,16 @@ std::string MachineTypeToStr(MachineType machineType);
V(DebuggerBytecodeCall, DEBUGGER_BYTECODE_CALL, GateFlags::NONE_FLAG, 0, 1, value) \
V(BuiltinsCallWithArgv, BUILTINS_CALL_WITH_ARGV, GateFlags::NONE_FLAG, 0, 1, value) \
V(BuiltinsCall, BUILTINS_CALL, GateFlags::NONE_FLAG, 0, 1, value) \
V(SaveRegister, SAVE_REGISTER, GateFlags::NONE_FLAG, 0, 1, value) \
V(SaveRegister, SAVE_REGISTER, GateFlags::NONE_FLAG, 0, 1, value)
#define GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \
V(TypedCall, TYPED_CALL, GateFlags::NONE_FLAG, 1, 1, value) \
V(Construct, CONSTRUCT, GateFlags::NONE_FLAG, 1, 1, value) \
V(TypedAotCall, TYPEDAOTCALL, GateFlags::NONE_FLAG, 1, 1, value) \
V(TypedAotCall, TYPEDAOTCALL, GateFlags::NONE_FLAG, 1, 1, value)
#define GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(V) \
V(CallGetter, CALL_GETTER, GateFlags::NONE_FLAG, 1, 1, 2) \
V(CallSetter, CALL_SETTER, GateFlags::NONE_FLAG, 1, 1, 3)
#define GATE_META_DATA_LIST_WITH_SIZE(V) \
V(Merge, MERGE, GateFlags::CONTROL, value, 0, 0) \
@ -242,7 +246,7 @@ std::string MachineTypeToStr(MachineType machineType);
V(IndexCheck, INDEX_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(Int32OverflowCheck, INT32_OVERFLOW_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(TypedUnaryOp, TYPED_UNARY_OP, GateFlags::NO_WRITE, 1, 1, 1) \
V(TypedConvert, TYPE_CONVERT, GateFlags::NO_WRITE, 1, 1, 1) \
V(TypedConvert, TYPE_CONVERT, GateFlags::NO_WRITE, 1, 1, 1)
#define GATE_META_DATA_LIST_WITH_VALUE(V) \
V(Icmp, ICMP, GateFlags::NONE_FLAG, 0, 0, 2) \
@ -275,6 +279,7 @@ enum class OpCode : uint8_t {
GATE_META_DATA_LIST_WITH_SIZE(DECLARE_GATE_OPCODE)
GATE_META_DATA_LIST_WITH_ONE_PARAMETER(DECLARE_GATE_OPCODE)
GATE_META_DATA_LIST_WITH_PC_OFFSET(DECLARE_GATE_OPCODE)
GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(DECLARE_GATE_OPCODE)
#undef DECLARE_GATE_OPCODE
#define DECLARE_GATE_OPCODE(NAME) NAME,
GATE_OPCODE_LIST(DECLARE_GATE_OPCODE)

View File

@ -112,6 +112,11 @@ public:
GATE_META_DATA_LIST_WITH_PC_OFFSET(DECLARE_GATE_META)
#undef DECLARE_GATE_META
#define DECLARE_GATE_META(NAME, OP, R, S, D, V) \
const GateMetaData* NAME(uint64_t pcOffset) const;
GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(DECLARE_GATE_META)
#undef DECLARE_GATE_META
explicit GateMetaBuilder(Chunk* chunk);
const GateMetaData* JSBytecode(size_t valuesIn, EcmaOpcode opcode, uint32_t pcOffset, GateFlags flags)
{
@ -146,4 +151,4 @@ private:
Chunk* chunk_;
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_GATE_META_DATA_CACHE_H
#endif // ECMASCRIPT_COMPILER_GATE_META_DATA_CACHE_H

View File

@ -1683,7 +1683,7 @@ inline GateRef StubBuilder::GetDoubleOfTNumber(GateRef x)
inline GateRef StubBuilder::LoadObjectFromWeakRef(GateRef x)
{
return env_->GetBuilder()->PtrAdd(x, IntPtr(-JSTaggedValue::TAG_WEAK));
return env_->GetBuilder()->LoadObjectFromWeakRef(x);
}
inline GateRef StubBuilder::ExtFloat32ToDouble(GateRef x)

View File

@ -648,10 +648,14 @@ void TSTypeLowering::LowerTypedLdObjByName(GateRef gate)
acc_.DeleteStateSplitAndFrameState(gate);
return;
}
JSTaggedValue hclass = tsManager_->GetHClassFromCache(hclassIndex);
JSHClass *hclass = JSHClass::Cast(tsManager_->GetHClassFromCache(hclassIndex).GetTaggedObject());
if (!hclass->HasTSSubtyping()) { // slowpath
acc_.DeleteStateSplitAndFrameState(gate);
return;
}
auto propertyOffset = tsManager_->GetPropertyOffset(hclass, prop);
if (propertyOffset == -1) { // slowpath
PropertyLookupResult plr = JSHClass::LookupProperty(thread, hclass, prop);
if (!plr.IsFound()) { // slowpath
acc_.DeleteStateSplitAndFrameState(gate);
return;
}
@ -659,11 +663,16 @@ void TSTypeLowering::LowerTypedLdObjByName(GateRef gate)
AddProfiling(gate);
GateRef hclassIndexGate = builder_.IntPtr(hclassIndex);
GateRef propertyOffsetGate = builder_.IntPtr(propertyOffset);
builder_.ObjectTypeCheck(receiverType, receiver, hclassIndexGate);
ASSERT(acc_.GetOpCode(acc_.GetDep(gate)) == OpCode::STATE_SPLIT);
GateRef result = builder_.LoadProperty(receiver, propertyOffsetGate);
GateRef pfrGate = builder_.Int32(plr.GetData());
GateRef result = Circuit::NullGate();
if (LIKELY(!plr.IsAccessor())) {
result = builder_.LoadProperty(receiver, pfrGate);
} else {
result = builder_.CallGetter(gate, receiver, pfrGate);
}
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
}
@ -695,10 +704,14 @@ void TSTypeLowering::LowerTypedStObjByName(GateRef gate, bool isThis)
acc_.DeleteStateSplitAndFrameState(gate);
return;
}
JSTaggedValue hclass = tsManager_->GetHClassFromCache(hclassIndex);
JSHClass *hclass = JSHClass::Cast(tsManager_->GetHClassFromCache(hclassIndex).GetTaggedObject());
if (!hclass->HasTSSubtyping()) { // slowpath
acc_.DeleteStateSplitAndFrameState(gate);
return;
}
auto propertyOffset = tsManager_->GetPropertyOffset(hclass, prop);
if (propertyOffset == -1) { // slowpath
PropertyLookupResult plr = JSHClass::LookupProperty(thread, hclass, prop);
if (!plr.IsFound() || plr.IsFunction()) { // slowpath
acc_.DeleteStateSplitAndFrameState(gate);
return;
}
@ -706,11 +719,15 @@ void TSTypeLowering::LowerTypedStObjByName(GateRef gate, bool isThis)
AddProfiling(gate);
GateRef hclassIndexGate = builder_.IntPtr(hclassIndex);
GateRef propertyOffsetGate = builder_.IntPtr(propertyOffset);
builder_.ObjectTypeCheck(receiverType, receiver, hclassIndexGate);
ASSERT(acc_.GetOpCode(acc_.GetDep(gate)) == OpCode::STATE_SPLIT);
builder_.StoreProperty(receiver, propertyOffsetGate, value);
GateRef pfrGate = builder_.Int32(plr.GetData());
if (LIKELY(plr.IsLocal())) {
builder_.StoreProperty(receiver, pfrGate, value);
} else {
builder_.CallSetter(gate, receiver, pfrGate, value);
}
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
}
@ -1076,7 +1093,7 @@ void TSTypeLowering::LowerTypedCallrange(GateRef gate)
const size_t callTargetIndex = 1; // acc
size_t argc = numArgs - callTargetIndex;
GateRef func = acc_.GetValueIn(gate, argc);
GateType funcType = acc_.GetGateType(func);
if (!tsManager_->IsFunctionTypeKind(funcType)) {
acc_.DeleteStateSplitAndFrameState(gate);

View File

@ -19,6 +19,7 @@
#include "ecmascript/deoptimizer/deoptimizer.h"
#include "ecmascript/js_arraybuffer.h"
#include "ecmascript/js_native_pointer.h"
#include "ecmascript/vtable.h"
namespace panda::ecmascript::kungfu {
void TypeLowering::RunTypeLowering()
@ -82,11 +83,17 @@ void TypeLowering::LowerType(GateRef gate)
LowerTypedUnaryOp(gate);
break;
case OpCode::LOAD_PROPERTY:
LowerLoadProperty(gate, glue);
LowerLoadProperty(gate);
break;
case OpCode::CALL_GETTER:
LowerCallGetter(gate, glue);
break;
case OpCode::STORE_PROPERTY:
LowerStoreProperty(gate, glue);
break;
case OpCode::CALL_SETTER:
LowerCallSetter(gate, glue);
break;
case OpCode::LOAD_ARRAY_LENGTH:
LowerLoadArrayLength(gate);
break;
@ -258,25 +265,53 @@ void TypeLowering::LowerObjectTypeCheck(GateRef gate)
Environment env(gate, circuit_, &builder_);
auto type = acc_.GetParamGateType(gate);
if (tsManager_->IsClassInstanceTypeKind(type)) {
LowerClassInstanceCheck(gate);
LowerTSSubtypingCheck(gate);
} else {
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
void TypeLowering::LowerClassInstanceCheck(GateRef gate)
void TypeLowering::LowerTSSubtypingCheck(GateRef gate)
{
GateRef frameState = GetFrameState(gate);
ArgumentAccessor argAcc(circuit_);
GateRef jsFunc = argAcc.GetCommonArgGate(CommonArgIdx::FUNC);
auto receiver = acc_.GetValueIn(gate, 0);
auto receiverHClass = builder_.LoadHClass(receiver);
auto hclassOffset = acc_.GetValueIn(gate, 1);
GateRef hclass = GetObjectFromConstPool(jsFunc, hclassOffset);
GateRef check = builder_.Equal(receiverHClass, hclass);
builder_.DeoptCheck(check, frameState, DeoptType::WRONGHCLASS);
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef aotHCIndex = acc_.GetValueIn(gate, 1);
Label receiverIsHeapObject(&builder_);
Label exit(&builder_);
DEFVAlUE(check, (&builder_), VariableType::BOOL(), builder_.False());
builder_.Branch(builder_.TaggedIsHeapObject(receiver), &receiverIsHeapObject, &exit);
builder_.Bind(&receiverIsHeapObject);
{
JSTaggedValue aotHC = tsManager_->GetHClassFromCache(acc_.TryGetValue(aotHCIndex));
ASSERT(aotHC.IsJSHClass());
int32_t level = JSHClass::Cast(aotHC.GetTaggedObject())->GetLevel();
ASSERT(level >= 0);
GateRef levelGate = builder_.Int32(level);
GateRef receiverHC = builder_.LoadHClass(receiver);
GateRef supers = LoadSupers(receiverHC);
GateRef length = GetLengthFromSupers(supers);
// Nextly, consider remove level check by guaranteeing not read illegal addresses.
Label levelValid(&builder_);
builder_.Branch(builder_.Int32LessThan(levelGate, length), &levelValid, &exit);
builder_.Bind(&levelValid);
{
GateRef aotHCGate = GetObjectFromConstPool(jsFunc, aotHCIndex);
check = builder_.Equal(aotHCGate, GetValueFromSupers(supers, levelGate));
builder_.Jump(&exit);
}
}
builder_.Bind(&exit);
builder_.DeoptCheck(*check, frameState, DeoptType::INCONSISTENTHCLASS);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
@ -466,36 +501,111 @@ GateRef TypeLowering::GetObjectFromConstPool(GateRef jsFunc, GateRef index)
return builder_.GetValueFromTaggedArray(constPool, index);
}
void TypeLowering::LowerLoadProperty(GateRef gate, [[maybe_unused]] GateRef glue)
void TypeLowering::LowerLoadProperty(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
Label hole(&builder_);
Label exit(&builder_);
ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: receiver, plr
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef offset = acc_.GetValueIn(gate, 1);
result = builder_.Load(VariableType::JS_ANY(), receiver, offset);
// simplify the process, need to query the vtable to complete the whole process later
builder_.Branch(builder_.IsSpecial(*result, JSTaggedValue::VALUE_HOLE), &hole, &exit);
builder_.Bind(&hole);
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
ASSERT(plr.IsLocal() || plr.IsFunction());
GateRef offset = builder_.IntPtr(plr.GetOffset());
if (plr.IsLocal()) {
Label returnUndefined(&builder_);
Label exit(&builder_);
result = builder_.Load(VariableType::JS_ANY(), receiver, offset);
builder_.Branch(builder_.IsSpecial(*result, JSTaggedValue::VALUE_HOLE), &returnUndefined, &exit);
builder_.Bind(&returnUndefined);
{
result = builder_.UndefineConstant();
builder_.Jump(&exit);
}
builder_.Bind(&exit);
} else {
GateRef vtable = LoadVTable(receiver);
GateRef itemOwner = GetOwnerFromVTable(vtable, offset);
GateRef itemOffset = GetOffsetFromVTable(vtable, offset);
result = builder_.Load(VariableType::JS_ANY(), itemOwner, itemOffset);
}
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
}
void TypeLowering::LowerCallGetter(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: receiver, plr
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
ASSERT(plr.IsAccessor());
GateRef offset = builder_.IntPtr(plr.GetOffset());
GateRef vtable = LoadVTable(receiver);
GateRef itemOwner = GetOwnerFromVTable(vtable, offset);
GateRef itemOffset = GetOffsetFromVTable(vtable, offset);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
Label callGetter(&builder_);
Label exit(&builder_);
GateRef accessor = builder_.Load(VariableType::JS_ANY(), itemOwner, itemOffset);
GateRef getter = builder_.Load(VariableType::JS_ANY(), accessor,
builder_.IntPtr(AccessorData::GETTER_OFFSET));
builder_.Branch(builder_.IsSpecial(getter, JSTaggedValue::VALUE_UNDEFINED), &exit, &callGetter);
builder_.Bind(&callGetter);
{
result = builder_.UndefineConstant();
result = CallAccessor(glue, gate, getter, receiver, AccessorMode::GETTER);
builder_.Jump(&exit);
}
builder_.Bind(&exit);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
ReplaceHirWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), *result);
}
void TypeLowering::LowerStoreProperty(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
ASSERT(acc_.GetNumValueIn(gate) == 3); // 3: receiver, plr, value
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef offset = acc_.GetValueIn(gate, 1);
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
GateRef value = acc_.GetValueIn(gate, 2);
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
ASSERT(plr.IsLocal());
GateRef offset = builder_.IntPtr(plr.GetOffset());
builder_.Store(VariableType::JS_ANY(), glue, receiver, offset, value);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void TypeLowering::LowerCallSetter(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
ASSERT(acc_.GetNumValueIn(gate) == 3); // 3: receiver, plr, value
GateRef receiver = acc_.GetValueIn(gate, 0);
GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
GateRef value = acc_.GetValueIn(gate, 2);
PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
ASSERT(plr.IsAccessor());
GateRef offset = builder_.IntPtr(plr.GetOffset());
GateRef vtable = LoadVTable(receiver);
GateRef itemOwner = GetOwnerFromVTable(vtable, offset);
GateRef itemOffset = GetOffsetFromVTable(vtable, offset);
Label callSetter(&builder_);
Label exit(&builder_);
GateRef accessor = builder_.Load(VariableType::JS_ANY(), itemOwner, itemOffset);
GateRef setter = builder_.Load(VariableType::JS_ANY(), accessor, builder_.IntPtr(AccessorData::SETTER_OFFSET));
builder_.Branch(builder_.IsSpecial(setter, JSTaggedValue::VALUE_UNDEFINED), &exit, &callSetter);
builder_.Bind(&callSetter);
{
CallAccessor(glue, gate, setter, receiver, AccessorMode::SETTER, value);
builder_.Jump(&exit);
}
builder_.Bind(&exit);
ReplaceHirWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void TypeLowering::LowerLoadArrayLength(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
@ -2972,4 +3082,71 @@ void TypeLowering::LowerGetSuperConstructor(GateRef gate)
GateRef superCtor = builder_.Load(VariableType::JS_ANY(), hclass, protoOffset);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), superCtor);
}
GateRef TypeLowering::LoadVTable(GateRef object)
{
GateRef hclass = builder_.LoadHClass(object);
return builder_.Load(VariableType::JS_ANY(), hclass, builder_.IntPtr(JSHClass::VTABLE_OFFSET));
}
GateRef TypeLowering::GetOwnerFromVTable(GateRef vtable, GateRef offset)
{
GateRef dataOffset = builder_.PtrAdd(offset, builder_.IntPtr(VTable::TupleItem::OWNER));
return builder_.GetValueFromTaggedArray(vtable, dataOffset);
}
GateRef TypeLowering::GetOffsetFromVTable(GateRef vtable, GateRef offset)
{
GateRef dataOffset = builder_.PtrAdd(offset, builder_.IntPtr(VTable::TupleItem::OFFSET));
return builder_.TaggedGetInt(builder_.GetValueFromTaggedArray(vtable, dataOffset));
}
GateRef TypeLowering::LoadSupers(GateRef hclass)
{
return builder_.Load(VariableType::JS_ANY(), hclass, builder_.IntPtr(JSHClass::SUPERS_OFFSET));
}
GateRef TypeLowering::GetLengthFromSupers(GateRef supers)
{
GateRef length = builder_.GetValueFromTaggedArray(supers, builder_.Int32(WeakVector::END_INDEX));
return builder_.TaggedGetInt(length);
}
GateRef TypeLowering::GetValueFromSupers(GateRef supers, GateRef index)
{
GateRef val = builder_.GetValueFromTaggedArray(supers,
builder_.Int32Add(index, builder_.Int32(WeakVector::ELEMENTS_START_INDEX)));
return builder_.LoadObjectFromWeakRef(val);
}
GateRef TypeLowering::CallAccessor(GateRef glue, GateRef gate, GateRef function, GateRef receiver, AccessorMode mode,
GateRef value)
{
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCall));
GateRef target = builder_.IntPtr(RTSTUB_ID(JSCall));
GateRef envArg = builder_.Undefined();
GateRef newTarget = builder_.Undefined();
GateRef argc = builder_.Int64(NUM_MANDATORY_JSFUNC_ARGS + (mode == AccessorMode::SETTER ? 1 : 0)); // 1: value
std::vector<GateRef> args { glue, envArg, argc, function, newTarget, receiver };
if (mode == AccessorMode::SETTER) {
args.emplace_back(value);
}
return builder_.Call(cs, glue, target, builder_.GetDepend(), args, gate);
}
void TypeLowering::ReplaceHirWithPendingException(GateRef hirGate, GateRef glue, GateRef state, GateRef depend,
GateRef value)
{
auto condition = builder_.HasPendingException(glue);
GateRef ifBranch = builder_.Branch(state, condition);
GateRef ifTrue = builder_.IfTrue(ifBranch);
GateRef ifFalse = builder_.IfFalse(ifBranch);
GateRef eDepend = builder_.DependRelay(ifTrue, depend);
GateRef sDepend = builder_.DependRelay(ifFalse, depend);
StateDepend success(ifFalse, sDepend);
StateDepend exception(ifTrue, eDepend);
acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
}
} // namespace panda::ecmascript

View File

@ -179,15 +179,17 @@ private:
void LowerTypedDecOverflowCheck(GateRef gate);
void LowerTypedNegOverflowCheck(GateRef gate);
void LowerObjectTypeCheck(GateRef gate);
void LowerClassInstanceCheck(GateRef gate);
void LowerTSSubtypingCheck(GateRef gate);
void LowerFloat32ArrayCheck(GateRef gate, GateRef glue);
void LowerArrayCheck(GateRef gate, GateRef glue);
void LowerStableArrayCheck(GateRef gate, GateRef glue);
void LowerTypedArrayCheck(GateRef gate, GateRef glue);
void LowerFloat32ArrayIndexCheck(GateRef gate);
void LowerArrayIndexCheck(GateRef gate);
void LowerLoadProperty(GateRef gate, GateRef glue);
void LowerLoadProperty(GateRef gate);
void LowerCallGetter(GateRef gate, GateRef glue);
void LowerStoreProperty(GateRef gate, GateRef glue);
void LowerCallSetter(GateRef gate, GateRef glue);
void LowerLoadArrayLength(GateRef gate);
void LowerStoreElement(GateRef gate, GateRef glue);
void LowerLoadElement(GateRef gate);
@ -208,6 +210,15 @@ private:
GateRef LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
bool useLabel = false);
enum AccessorMode {
GETTER,
SETTER,
};
GateRef CallAccessor(GateRef glue, GateRef gate, GateRef function, GateRef receiver, AccessorMode mode,
GateRef value = Circuit::NullGate());
void ReplaceHirWithPendingException(GateRef hirGate, GateRef glue, GateRef state, GateRef depend, GateRef value);
template<OpCode Op>
GateRef CalculateNumbers(GateRef left, GateRef right, GateType leftType, GateType rightType);
template<OpCode Op>
@ -247,6 +258,13 @@ private:
return acc_.GetFrameState(gate);
}
GateRef LoadVTable(GateRef object);
GateRef GetOwnerFromVTable(GateRef vtable, GateRef offset);
GateRef GetOffsetFromVTable(GateRef vtable, GateRef offset);
GateRef LoadSupers(GateRef hclass);
GateRef GetLengthFromSupers(GateRef supers);
GateRef GetValueFromSupers(GateRef supers, GateRef index);
Circuit *circuit_;
GateAccessor acc_;
CircuitBuilder builder_;

View File

@ -262,8 +262,8 @@ std::string Deoptimizier::DisplayItems(kungfu::DeoptType type)
return "NOT SARRAY";
case kungfu::DeoptType::NOTF32ARRAY:
return "NOT F32ARRAY";
case kungfu::DeoptType::WRONGHCLASS:
return "WRONG HCLASS";
case kungfu::DeoptType::INCONSISTENTHCLASS:
return "INCONSISTENT HCLASS";
case kungfu::DeoptType::NOTNEWOBJ:
return "NOT NEWOBJ TYPE";
case kungfu::DeoptType::NOTARRAYIDX:
@ -335,4 +335,4 @@ JSTaggedType Deoptimizier::ConstructAsmInterpretFrame(kungfu::DeoptType type)
frameWriter.PushRawValue(outputCount);
return reinterpret_cast<JSTaggedType>(frameWriter.GetTop());
}
} // namespace panda::ecmascript
} // namespace panda::ecmascript

View File

@ -224,6 +224,15 @@ inline void JSHClass::Copy(const JSThread *thread, const JSHClass *jshclass)
SetBitField(jshclass->GetBitField());
SetNumberOfProps(jshclass->NumberOfProps());
}
inline int JSHClass::FindPropertyEntry(const JSThread *thread, JSHClass *hclass, JSTaggedValue key)
{
DISALLOW_GARBAGE_COLLECTION;
LayoutInfo *layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
uint32_t propsNumber = hclass->NumberOfProps();
int entry = layout->FindElementWithCache(thread, hclass, key, propsNumber);
return entry;
}
} // namespace panda::ecmascript
#endif // ECMASCRIPT_JS_HCLASS_INL_H

View File

@ -24,6 +24,7 @@
#include "ecmascript/js_object-inl.h"
#include "ecmascript/js_symbol.h"
#include "ecmascript/mem/c_containers.h"
#include "ecmascript/subtyping_operator.h"
#include "ecmascript/tagged_array-inl.h"
#include "ecmascript/weak_vector.h"
@ -273,6 +274,11 @@ void JSHClass::AddProperty(const JSThread *thread, const JSHandle<JSObject> &obj
JSHClass::NotifyHclassChanged(thread, jshclass, newJsHClass);
#endif
obj->SetClass(*newJsHClass);
// Maintaining subtyping is no longer required when transition succeeds.
if (jshclass->HasTSSubtyping()) {
SubtypingOperator::TryMaintainTSSubtyping(thread, jshclass, newJsHClass, key);
}
}
JSHandle<JSHClass> JSHClass::TransitionExtension(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
@ -522,14 +528,18 @@ JSHandle<ProtoChangeDetails> JSHClass::GetProtoChangeDetails(const JSThread *thr
return GetProtoChangeDetails(thread, jshclass);
}
void JSHClass::MarkProtoChanged([[maybe_unused]] const JSThread *thread, const JSHandle<JSHClass> &jshclass)
void JSHClass::MarkProtoChanged(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
{
ASSERT(jshclass->IsPrototype() || jshclass->HasTSInheritInfo());
ASSERT(jshclass->IsPrototype() || jshclass->HasTSSubtyping());
JSTaggedValue markerValue = jshclass->GetProtoChangeMarker();
if (markerValue.IsProtoChangeMarker()) {
ProtoChangeMarker *protoChangeMarker = ProtoChangeMarker::Cast(markerValue.GetTaggedObject());
protoChangeMarker->SetHasChanged(true);
}
if (jshclass->HasTSSubtyping()) {
jshclass->InitTSInheritInfo(thread);
}
}
void JSHClass::NoticeThroughChain(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
@ -570,7 +580,7 @@ void JSHClass::RefreshUsers(const JSThread *thread, const JSHandle<JSHClass> &ol
}
}
bool JSHClass::HasTSInheritInfo() const
bool JSHClass::HasTSSubtyping() const
{
// if fill TS inherit info, supers must not be empty
WeakVector *supers = WeakVector::Cast(GetSupers().GetTaggedObject());
@ -579,6 +589,56 @@ bool JSHClass::HasTSInheritInfo() const
bool JSHClass::IsTSIHCWithInheritInfo() const
{
return IsTS() && !IsPrototype() && HasTSInheritInfo();
return IsTS() && !IsPrototype() && HasTSSubtyping();
}
PropertyLookupResult JSHClass::LookupProperty(const JSThread *thread, JSHClass *hclass, JSTaggedValue key)
{
DISALLOW_GARBAGE_COLLECTION;
ASSERT(hclass->IsTS());
PropertyLookupResult result;
int entry = JSHClass::FindPropertyEntry(thread, hclass, key);
// found in local
if (entry != -1) {
result.SetIsFound(true);
result.SetIsLocal(true);
uint32_t offset = hclass->GetInlinedPropertiesOffset(entry);
result.SetOffset(offset);
return result;
}
// found in vtable
JSHandle<VTable> vtable(thread, hclass->GetVTable());
entry = vtable->GetTupleIndexByName(key);
if (entry != -1) {
result.SetIsVtable();
uint32_t offset = entry * VTable::TUPLE_SIZE;
result.SetOffset(offset);
if (vtable->IsAccessor(entry)) {
result.SetIsAccessor(true);
}
return result;
}
// not fuond
result.SetIsFound(false);
return result;
}
void JSHClass::CopyTSInheritInfo(const JSThread *thread, const JSHandle<JSHClass> &oldHClass,
JSHandle<JSHClass> &newHClass)
{
JSHandle<WeakVector> supers(thread, oldHClass->GetSupers());
JSHandle<WeakVector> copySupers = WeakVector::Copy(thread, supers);
newHClass->SetSupers(thread, copySupers);
uint8_t level = oldHClass->GetLevel();
newHClass->SetLevel(level);
JSHandle<VTable> vtable(thread, oldHClass->GetVTable());
JSHandle<VTable> copyVtable = VTable::Copy(thread, vtable);
newHClass->SetVTable(thread, copyVtable);
}
} // namespace panda::ecmascript

View File

@ -60,6 +60,7 @@
*/
namespace panda::ecmascript {
class ProtoChangeDetails;
class PropertyLookupResult;
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define JSTYPE_DECL /* //////////////////////////////////////////////////////////////////////////////-PADDING */ \
@ -369,10 +370,13 @@ public:
void InitTSInheritInfo(const JSThread *thread);
bool HasTSInheritInfo() const;
bool HasTSSubtyping() const;
bool IsTSIHCWithInheritInfo() const;
static void CopyTSInheritInfo(const JSThread *thread, const JSHandle<JSHClass> &oldHClass,
JSHandle<JSHClass> &newHClass);
inline void ClearBitField()
{
SetBitField(0UL);
@ -1577,6 +1581,11 @@ public:
uint32_t bits = GetBitField1();
return HasDeletePropertyBit::Decode(bits);
}
inline static int FindPropertyEntry(const JSThread *thread, JSHClass *hclass, JSTaggedValue key);
static PropertyLookupResult LookupProperty(const JSThread *thread, JSHClass *hclass, JSTaggedValue key);
static constexpr size_t PROTOTYPE_OFFSET = TaggedObjectSize();
ACCESSORS(Proto, PROTOTYPE_OFFSET, LAYOUT_OFFSET);
ACCESSORS(Layout, LAYOUT_OFFSET, TRANSTIONS_OFFSET);
@ -1630,6 +1639,84 @@ private:
friend class RuntimeStubs;
};
static_assert(JSHClass::BIT_FIELD_OFFSET % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT) == 0);
// record property look up info in local and vtable
class PropertyLookupResult {
public:
using IsFoundBit = BitField<bool, 0, 1>;
using IsLocalBit = IsFoundBit::NextFlag;
using IsAccessorBit = IsLocalBit::NextFlag;
using OffsetBits = IsAccessorBit::NextField<uint32_t, PropertyAttributes::OFFSET_BITFIELD_NUM>;
explicit PropertyLookupResult(uint32_t data = 0) : data_(data) {}
~PropertyLookupResult() = default;
DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PropertyLookupResult);
DEFAULT_COPY_SEMANTIC(PropertyLookupResult);
inline bool IsFound() const
{
return IsFoundBit::Get(data_);
}
inline void SetIsFound(bool flag)
{
IsFoundBit::Set(flag, &data_);
}
inline bool IsLocal() const
{
return IsLocalBit::Get(data_);
}
inline void SetIsLocal(bool flag)
{
IsLocalBit::Set(flag, &data_);
}
inline bool IsVtable() const
{
return IsFound() && !IsLocal();
}
inline void SetIsVtable()
{
SetIsFound(true);
SetIsLocal(false);
}
inline bool IsAccessor() const
{
return IsAccessorBit::Get(data_);
}
inline void SetIsAccessor(bool flag)
{
IsAccessorBit::Set(flag, &data_);
}
inline bool IsFunction() const
{
return IsVtable() && !IsAccessor();
}
inline uint32_t GetOffset() const
{
return OffsetBits::Get(data_);
}
inline void SetOffset(uint32_t offset)
{
OffsetBits::Set<uint32_t>(offset, &data_);
}
inline uint32_t GetData() const
{
return data_;
}
private:
uint32_t data_ {0};
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_JS_HCLASS_H

View File

@ -162,6 +162,11 @@ JSHandle<NameDictionary> JSObject::TransitionToDictionary(const JSThread *thread
if (i < numberInlinedProps) {
value = receiver->GetPropertyInlinedProps(i);
// If delete a property in hclass which has subtyping info and not prototype, only set value as hole and
// not remove. When transition to dictionary, exclude it.
if (value.IsHole()) {
continue;
}
} else {
value = array->Get(i - numberInlinedProps);
}
@ -282,7 +287,9 @@ void JSObject::DeletePropertyInternal(JSThread *thread, const JSHandle<JSObject>
}
if (!array->IsDictionaryMode()) {
if (obj->GetJSHClass()->IsTS()) {
JSHClass *hclass = obj->GetJSHClass();
// To maintain TS inherit info, not change hclass, just set hole.
if (hclass->HasTSSubtyping() && !hclass->IsPrototype()) {
obj->SetPropertyInlinedProps(thread, index, JSTaggedValue::Hole());
return;
}

View File

@ -161,7 +161,7 @@ JSHandle<JSTaggedValue> SourceTextModule::ResolveCjsExport(JSThread *thread, con
// Get layoutInfo and compare the input and output names of files
JSHandle<LayoutInfo> layoutInfo(thread, jsHclass->GetLayout());
if (layoutInfo->NumberOfElements() != 0) {
JSHandle<JSTaggedValue> resolution = ResolveCjsLocalExport(thread, layoutInfo, exportName, module);
JSHandle<JSTaggedValue> resolution = ResolveCjsLocalExport(thread, jsHclass, exportName, module);
if (!resolution->IsUndefined()) {
return resolution;
}
@ -393,7 +393,7 @@ int SourceTextModule::InnerModuleInstantiation(JSThread *thread, const JSHandle<
ASSERT(moduleRecordName.IsString());
JSHandle<JSTaggedValue> requiredVal =
SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, required);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, SourceTextModule::UNDEFINED_INDEX);
requiredModule.Update(JSHandle<SourceTextModule>::Cast(requiredVal));
requestedModules->Set(thread, idx, requiredModule->GetEcmaModuleRecordName());
}
@ -1215,13 +1215,12 @@ void SourceTextModule::AddExportName(JSThread *thread, const JSTaggedValue &expo
}
JSHandle<JSTaggedValue> SourceTextModule::ResolveCjsLocalExport(JSThread *thread,
JSHandle<LayoutInfo> layoutInfo,
const JSHandle<JSHClass> &hclass,
const JSHandle<JSTaggedValue> &exportName,
const JSHandle<SourceTextModule> &module)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
int propertiesNumber = layoutInfo->NumberOfElements();
int idx = layoutInfo->FindElementWithCache(thread, nullptr, exportName.GetTaggedValue(), propertiesNumber);
int idx = JSHClass::FindPropertyEntry(thread, *hclass, exportName.GetTaggedValue());
if (idx != -1) {
return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, idx));
}

View File

@ -156,7 +156,7 @@ private:
const JSHandle<JSTaggedValue> &exportName,
const JSHandle<SourceTextModule> &module);
static JSHandle<JSTaggedValue> ResolveCjsLocalExport(JSThread *thread,
JSHandle<LayoutInfo> layoutInfo,
const JSHandle<JSHClass> &hclass,
const JSHandle<JSTaggedValue> &exportName,
const JSHandle<SourceTextModule> &module);
static bool CheckCircularImport(const JSHandle<SourceTextModule> &module,

View File

@ -67,10 +67,9 @@ JSTaggedValue ObjectFastOperator::GetPropertyByName(JSThread *thread, JSTaggedVa
if (LIKELY(!hclass->IsDictionaryMode())) {
ASSERT(!TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject())->IsDictionaryMode());
LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
uint32_t propsNumber = hclass->NumberOfProps();
int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber);
int entry = JSHClass::FindPropertyEntry(thread, hclass, key);
if (entry != -1) {
LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
PropertyAttributes attr(layoutInfo->GetAttr(entry));
ASSERT(static_cast<int>(attr.GetOffset()) == entry);
auto value = JSObject::Cast(holder)->GetProperty(hclass, attr);
@ -138,11 +137,10 @@ JSTaggedValue ObjectFastOperator::SetPropertyByName(JSThread *thread, JSTaggedVa
if (LIKELY(!hclass->IsDictionaryMode())) {
ASSERT(!TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject())->IsDictionaryMode());
LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
uint32_t propsNumber = hclass->NumberOfProps();
int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber);
int entry = JSHClass::FindPropertyEntry(thread, hclass, key);
if (entry != -1) {
LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
PropertyAttributes attr(layoutInfo->GetAttr(entry));
ASSERT(static_cast<int>(attr.GetOffset()) == entry);
if (UNLIKELY(attr.IsAccessor())) {
@ -798,4 +796,4 @@ bool ObjectFastOperator::GetNumFromString(const char *str, int len, int *index,
return true;
}
}
#endif // ECMASCRIPT_OBJECT_FAST_OPERATOR_INL_H
#endif // ECMASCRIPT_OBJECT_FAST_OPERATOR_INL_H

View File

@ -335,13 +335,12 @@ void ObjectOperator::LookupPropertyInlinedProps(const JSHandle<JSObject> &obj)
TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetTaggedObject());
if (!array->IsDictionaryMode()) {
JSHClass *jshclass = obj->GetJSHClass();
JSTaggedValue attrs = jshclass->GetLayout();
LayoutInfo *layoutInfo = LayoutInfo::Cast(attrs.GetTaggedObject());
uint32_t propsNumber = jshclass->NumberOfProps();
int entry = layoutInfo->FindElementWithCache(thread_, jshclass, key_.GetTaggedValue(), propsNumber);
int entry = JSHClass::FindPropertyEntry(thread_, jshclass, key_.GetTaggedValue());
if (entry == -1) {
return;
}
JSTaggedValue attrs = jshclass->GetLayout();
LayoutInfo *layoutInfo = LayoutInfo::Cast(attrs.GetTaggedObject());
PropertyAttributes attr(layoutInfo->GetAttr(entry));
ASSERT(entry == static_cast<int>(attr.GetOffset()));
JSTaggedValue value;

View File

@ -47,6 +47,7 @@
#include "ecmascript/message_string.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/pgo_profiler/pgo_profiler.h"
#include "ecmascript/subtyping_operator.h"
#include "ecmascript/tagged_dictionary.h"
#include "ecmascript/tagged_node.h"
#include "ecmascript/ts_types/ts_manager.h"
@ -345,6 +346,10 @@ DEF_RUNTIME_STUBS(UpdateLayOutAndAddTransition)
// 5. Add newClass to old hclass's transitions.
JSHClass::AddTransitions(thread, oldHClassHandle, newHClassHandle, keyHandle, attrValue);
if (oldHClassHandle->HasTSSubtyping()) {
SubtypingOperator::TryMaintainTSSubtyping(thread, oldHClassHandle, newHClassHandle, keyHandle);
}
return JSTaggedValue::Hole().GetRawData();
}

View File

@ -14,6 +14,7 @@
*/
#include "ecmascript/global_env.h"
#include "ecmascript/ic/proto_change_details.h"
#include "ecmascript/subtyping_operator-inl.h"
#include "ecmascript/vtable.h"
@ -196,4 +197,41 @@ void SubtypingOperator::AddSuper(const JSThread *thread, const JSHandle<JSHClass
iHClassVal, WeakVector::ElementType::WEAK);
iHClass->SetSupers(thread, newSupers);
}
} // namespace panda::ecmascript
// when add property in local, try maintain.
void SubtypingOperator::TryMaintainTSSubtyping(const JSThread *thread, const JSHandle<JSHClass> &oldHClass,
JSHandle<JSHClass> &newHClass, const JSHandle<JSTaggedValue> &key)
{
if (!key->IsString()) { // symbol
return;
}
ASSERT(!oldHClass->IsPrototype()); // normal object hclass
JSHandle<VTable> vtable(thread, oldHClass->GetVTable());
ASSERT(vtable->GetNumberOfTuples() > 0); // there have default key 'constructor' at least
if (vtable->Find(key.GetTaggedValue())) { // new key shadows vtable property
LOG_ECMA(DEBUG) << "TryMaintainTSSubtyping failed, key: "
<< ConvertToString(EcmaString::Cast(key->GetTaggedObject()));
return;
}
// Add newHClass to phc's listeners
JSHandle<JSTaggedValue> prototype(thread, oldHClass->GetPrototype());
ASSERT(prototype->IsClassPrototype());
JSHandle<JSHClass> phc(thread, prototype->GetTaggedObject()->GetClass());
// If hclass has inherit info, it had been registered on proto chain, details and listeners must not be Undefined.
JSHandle<ProtoChangeDetails> details(thread, phc->GetProtoChangeDetails());
JSHandle<ChangeListener> listeners(thread, details->GetChangeListener());
uint32_t registerIndex = 0;
JSHandle<ChangeListener> newListeners = ChangeListener::Add(thread, listeners, newHClass, &registerIndex);
if (UNLIKELY(registerIndex == TaggedArray::MAX_ARRAY_INDEX)) {
return;
}
// maintaining succeeds
details->SetChangeListener(thread, newListeners);
JSHClass::CopyTSInheritInfo(thread, oldHClass, newHClass);
}
} // namespace panda::ecmascript

View File

@ -32,6 +32,9 @@ public:
static void GenVTable(const JSThread *thread, const JSHandle<JSHClass> &ihcHandle,
const JSHandle<JSHClass> &phcHandle, const JSHandle<JSHClass> &eIhcHandle);
static void TryMaintainTSSubtyping(const JSThread *thread, const JSHandle<JSHClass> &oldHClass,
JSHandle<JSHClass> &newHClass, const JSHandle<JSTaggedValue> &key);
private:
static constexpr uint8_t MAX_LEVEL = 1 << JSHClass::LEVEL_BTTFIELD_NUM;
@ -80,4 +83,4 @@ private:
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_SUBTYPING_OPERATOR_H
#endif // ECMASCRIPT_SUBTYPING_OPERATOR_H

View File

@ -142,21 +142,6 @@ JSTaggedValue TSManager::GetHClassFromCache(uint32_t index)
return JSTaggedValue(hcVec[index - constantPool->GetCacheLength()]);
}
int TSManager::GetPropertyOffset(JSTaggedValue hclass, JSTaggedValue key)
{
JSHClass *hc = JSHClass::Cast(hclass.GetTaggedObject());
LayoutInfo *layoutInfo = LayoutInfo::Cast(hc->GetLayout().GetTaggedObject());
uint32_t propsNumber = hc->NumberOfProps();
int entry = layoutInfo->FindElementWithCache(thread_, hc, key, propsNumber);
if (entry == -1) {
return entry;
}
int offset = hc->GetInlinedPropertiesOffset(entry);
return offset;
}
JSHandle<TSClassType> TSManager::GetExtendedClassType(JSHandle<TSClassType> classType) const
{
ASSERT(classType.GetTaggedValue().IsTSClassType());

View File

@ -522,9 +522,6 @@ public:
(l == static_cast<uint32_t>(TSRuntimeType::ITERATOR_RESULT));
}
// not consider [[prototype]] properties and accessor, -1: not find
int PUBLIC_API GetPropertyOffset(JSTaggedValue hclass, JSTaggedValue key);
void PUBLIC_API SetCurConstantPool(const JSPandaFile *jsPandaFile, uint32_t methodOffset);
JSHandle<JSTaggedValue> PUBLIC_API GetConstantPool() const

View File

@ -35,6 +35,8 @@ public:
static constexpr uint32_t DEFAULT_CAPACITY = 4;
static constexpr uint32_t DEFAULT_GROW_SIZE = 5;
static constexpr uint32_t END_INDEX = 0;
static constexpr uint32_t ELEMENTS_START_INDEX = 1;
static JSHandle<WeakVector> Create(const JSThread *thread, uint32_t capacity = DEFAULT_CAPACITY);
static JSHandle<WeakVector> Grow(const JSThread *thread, const JSHandle<WeakVector> &old, uint32_t newCapacity);
static JSHandle<WeakVector> Append(const JSThread *thread, const JSHandle<WeakVector> &vec,
@ -89,8 +91,6 @@ public:
private:
static const uint32_t MIN_CAPACITY = 2;
static const uint32_t END_INDEX = 0;
static const uint32_t ELEMENTS_START_INDEX = 1;
static const uint32_t MAX_VECTOR_INDEX = TaggedArray::MAX_ARRAY_INDEX - ELEMENTS_START_INDEX;
inline static constexpr uint32_t VectorToArrayIndex(uint32_t index)

View File

@ -16,11 +16,10 @@ group("aot_compatibility_test") {
test_list = [
"base_verification",
"builtins_api",
"property_operation",
"prototype_accessor",
"prototype_base_verification",
#"builtins_api",
#"property_operation",
]
deps = []

View File

@ -26,4 +26,4 @@ true
true
true
xxxx
TypeError: CallObj is NonCallable
true

View File

@ -77,6 +77,6 @@ declare function print(arg:any):string;
try {
b5.foo();
} catch(e) {
print(e);
print(e instanceof TypeError);
}
}