Impl for-of and for-in HIR lowering

1.Inline getnextpropname HIR of for-in
2.profile iterator type of for-of
3.Inline getiterator and next(call) of for-of
4.Update detector when set prototype

Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I89SMQ?from=project-issue
Signed-off-by: zhangyukun8 <zhangyukun8@huawei.com>
Change-Id: Ib18d8b9529c41ec435d5d2d97839d82c389267b6
This commit is contained in:
zhangyukun8 2023-10-21 16:42:54 +08:00
parent ed291cce5c
commit cba971f0e7
109 changed files with 3029 additions and 245 deletions

View File

@ -93,6 +93,7 @@
#include "ecmascript/require/js_cjs_require.h"
#include "ecmascript/require/js_cjs_exports.h"
#include "ecmascript/symbol_table.h"
#include "ecmascript/marker_cell.h"
#include "ecmascript/napi/include/jsnapi.h"
#include "ecmascript/object_factory.h"
#ifdef ARK_SUPPORT_INTL
@ -358,7 +359,7 @@ void Builtins::Initialize(const JSHandle<GlobalEnv> &env, JSThread *thread, bool
InitializeCjsRequire(env);
InitializeDefaultExportOfScript(env);
InitializeFunctionHclassForOptimized(env);
InitializePropertyDetector(env);
InitializePropertyDetector(env, lazyInit);
JSHandle<JSHClass> generatorFuncClass =
factory_->CreateFunctionClass(FunctionKind::GENERATOR_FUNCTION, JSFunction::SIZE, JSType::JS_GENERATOR_FUNCTION,
env->GetGeneratorFunctionPrototype());
@ -399,10 +400,13 @@ void Builtins::InitializeFunctionHclassForOptimized(const JSHandle<GlobalEnv> &e
#undef JSFUNCTION_JCLASS_LIST
}
void Builtins::InitializePropertyDetector(const JSHandle<GlobalEnv> &env) const
void Builtins::InitializePropertyDetector(const JSHandle<GlobalEnv> &env, bool lazyInit) const
{
#define INITIALIZE_PROPERTY_DETECTOR(type, name, index) \
JSHandle<MarkerCell> name##detector = factory_->NewMarkerCell(); \
if (lazyInit) { \
name##detector->InvalidatePropertyDetector(); \
} \
env->Set##name(thread_, name##detector);
GLOBAL_ENV_DETECTOR_FIELDS(INITIALIZE_PROPERTY_DETECTOR)
#undef INITIALIZE_PROPERTY_DETECTOR
@ -596,8 +600,6 @@ void Builtins::InitializeSymbol(const JSHandle<GlobalEnv> &env, const JSHandle<J
SetNoneAttributeProperty(symbolFunction, "isConcatSpreadable", isConcatSpreadableSymbol);
JSHandle<JSTaggedValue> toStringTagSymbol(factory_->NewWellKnownSymbolWithChar("Symbol.toStringTag"));
SetNoneAttributeProperty(symbolFunction, "toStringTag", toStringTagSymbol);
JSHandle<JSTaggedValue> iteratorSymbol(factory_->NewPublicSymbolWithChar("Symbol.iterator"));
SetNoneAttributeProperty(symbolFunction, "iterator", iteratorSymbol);
JSHandle<JSTaggedValue> asyncIteratorSymbol(factory_->NewPublicSymbolWithChar("Symbol.asyncIterator"));
SetNoneAttributeProperty(symbolFunction, "asyncIterator", asyncIteratorSymbol);
JSHandle<JSTaggedValue> matchSymbol(factory_->NewPublicSymbolWithChar("Symbol.match"));
@ -662,7 +664,6 @@ DETECTOR_SYMBOL_LIST(REGISTER_SYMBOL)
env->SetHasInstanceSymbol(thread_, hasInstanceSymbol);
env->SetIsConcatSpreadableSymbol(thread_, isConcatSpreadableSymbol);
env->SetToStringTagSymbol(thread_, toStringTagSymbol);
env->SetIteratorSymbol(thread_, iteratorSymbol);
env->SetAsyncIteratorSymbol(thread_, asyncIteratorSymbol);
env->SetMatchSymbol(thread_, matchSymbol);
env->SetMatchAllSymbol(thread_, matchAllSymbol);
@ -1261,6 +1262,7 @@ void Builtins::InitializeSet(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedVa
env->SetBuiltinsSetFunction(thread_, setFunction);
env->SetSetPrototype(thread_, setFuncPrototype);
env->SetSetProtoValuesFunction(thread_, valuesFunc);
thread_->SetInitialBuiltinHClass(BuiltinTypeId::SET,
setFunction->GetTaggedObject()->GetClass(),
setFuncPrototype->GetJSHClass());
@ -1329,6 +1331,7 @@ void Builtins::InitializeMap(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedVa
env->SetBuiltinsMapFunction(thread_, mapFunction);
env->SetMapPrototype(thread_, mapFuncPrototype);
env->SetMapProtoEntriesFunction(thread_, entriesFunc);
thread_->SetInitialBuiltinHClass(BuiltinTypeId::MAP,
mapFunction->GetTaggedObject()->GetClass(),
mapFuncPrototype->GetJSHClass());
@ -1607,8 +1610,8 @@ void Builtins::InitializeString(const JSHandle<GlobalEnv> &env, JSHandle<JSTagge
SetFunction(env, stringFuncPrototype, entry.GetName(), entry.GetEntrypoint(),
entry.GetLength(), entry.GetBuiltinStubId());
}
SetFunctionAtSymbol(env, stringFuncPrototype, env->GetIteratorSymbol(), "[Symbol.iterator]",
BuiltinsString::GetStringIterator, FunctionLength::ZERO);
JSHandle<JSTaggedValue> stringIter = SetAndReturnFunctionAtSymbol(env, stringFuncPrototype,
env->GetIteratorSymbol(), "[Symbol.iterator]", BuiltinsString::GetStringIterator, FunctionLength::ZERO);
// String method
for (const base::BuiltinFunctionEntry &entry: BuiltinsString::GetStringFunctions()) {
@ -1623,6 +1626,7 @@ void Builtins::InitializeString(const JSHandle<GlobalEnv> &env, JSHandle<JSTagge
env->SetStringFunction(thread_, stringFunction);
env->SetStringPrototype(thread_, stringFuncPrototype);
env->SetStringProtoIterFunction(thread_, stringIter);
thread_->SetInitialBuiltinHClass(BuiltinTypeId::STRING,
stringFunction->GetJSHClass(),
stringFuncPrototype->GetJSHClass());
@ -1642,11 +1646,13 @@ void Builtins::InitializeStringIterator(const JSHandle<GlobalEnv> &env,
factory_->NewJSFunction(env, static_cast<void *>(nullptr), FunctionKind::BASE_CONSTRUCTOR));
strIterFunction->SetFunctionPrototype(thread_, strIterFuncInstanceHClass.GetTaggedValue());
SetFunction(env, strIterPrototype, "next", StringIterator::Next, FunctionLength::ZERO);
JSHandle<JSFunction> nextFunc = SetAndReturnFunction(
env, strIterPrototype, "next", StringIterator::Next, FunctionLength::ZERO);
SetStringTagSymbol(env, strIterPrototype, "String Iterator");
env->SetStringIterator(thread_, strIterFunction);
env->SetStringIteratorPrototype(thread_, strIterPrototype);
env->SetStringIteratorProtoNext(thread_, nextFunc);
}
void Builtins::InitializeAsyncFromSyncIterator(const JSHandle<GlobalEnv> &env,
@ -1762,9 +1768,11 @@ void Builtins::InitializeSetIterator(const JSHandle<GlobalEnv> &env,
// SetIterator.prototype
JSHandle<JSObject> setIteratorPrototype(factory_->NewJSObjectWithInit(iteratorFuncClass));
// Iterator.prototype.next()
SetFunction(env, setIteratorPrototype, "next", JSSetIterator::Next, FunctionLength::ZERO);
JSHandle<JSFunction> nextFunc = SetAndReturnFunction(
env, setIteratorPrototype, "next", JSSetIterator::Next, FunctionLength::ZERO);
SetStringTagSymbol(env, setIteratorPrototype, "Set Iterator");
env->SetSetIteratorPrototype(thread_, setIteratorPrototype);
env->SetSetIteratorProtoNext(thread_, nextFunc);
JSHandle<JSTaggedValue> protoValue = env->GetSetIteratorPrototype();
const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
JSHandle<JSHClass> hclassHandle(globalConst->GetHandledJSSetIteratorClass());
@ -1778,9 +1786,11 @@ void Builtins::InitializeMapIterator(const JSHandle<GlobalEnv> &env,
// MapIterator.prototype
JSHandle<JSObject> mapIteratorPrototype(factory_->NewJSObjectWithInit(iteratorFuncClass));
// Iterator.prototype.next()
SetFunction(env, mapIteratorPrototype, "next", JSMapIterator::Next, FunctionLength::ZERO);
JSHandle<JSFunction> nextFunc = SetAndReturnFunction(
env, mapIteratorPrototype, "next", JSMapIterator::Next, FunctionLength::ZERO);
SetStringTagSymbol(env, mapIteratorPrototype, "Map Iterator");
env->SetMapIteratorPrototype(thread_, mapIteratorPrototype);
env->SetMapIteratorProtoNext(thread_, nextFunc);
JSHandle<JSTaggedValue> protoValue = env->GetMapIteratorPrototype();
const GlobalEnvConstants *globalConst = thread_->GlobalConstants();
JSHandle<JSHClass> hclassHandle(globalConst->GetHandledJSMapIteratorClass());
@ -1794,9 +1804,11 @@ void Builtins::InitializeArrayIterator(const JSHandle<GlobalEnv> &env,
// ArrayIterator.prototype
JSHandle<JSObject> arrayIteratorPrototype(factory_->NewJSObjectWithInit(iteratorFuncClass));
// Iterator.prototype.next()
SetFunction(env, arrayIteratorPrototype, "next", JSArrayIterator::Next, FunctionLength::ZERO);
JSHandle<JSFunction> nextFunc = SetAndReturnFunction(
env, arrayIteratorPrototype, "next", JSArrayIterator::Next, FunctionLength::ZERO);
SetStringTagSymbol(env, arrayIteratorPrototype, "Array Iterator");
env->SetArrayIteratorPrototype(thread_, arrayIteratorPrototype);
env->SetArrayIteratorProtoNext(thread_, nextFunc);
}
void Builtins::InitializeRegexpIterator(const JSHandle<GlobalEnv> &env,
@ -2063,6 +2075,7 @@ void Builtins::InitializeTypedArray(const JSHandle<GlobalEnv> &env, JSHandle<JST
env->SetTypedArrayFunction(thread_, typedArrayFunction.GetTaggedValue());
env->SetTypedArrayPrototype(thread_, typedArrFuncPrototype);
env->SetTypedArrayProtoValuesFunction(thread_, valuesFunc);
thread_->SetInitialBuiltinHClass(BuiltinTypeId::TYPED_ARRAY,
typedArrayFunction->GetJSHClass(),
typedArrFuncPrototype->GetJSHClass());
@ -2115,6 +2128,7 @@ void Builtins::Initialize##Type(const JSHandle<GlobalEnv> &env, const JSHandle<J
SetConstant(arrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement)); \
SetConstant(JSHandle<JSObject>(arrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement)); \
env->Set##Type##Function(thread_, arrayFunction); \
env->Set##Type##FunctionPrototype(thread_, arrFuncPrototypeValue); \
/* Initializes HClass record of %TypedArray% */ \
thread_->SetInitialBuiltinHClass(BuiltinTypeId::TYPE, \
arrayFunction->GetJSHClass(), \
@ -2552,6 +2566,38 @@ void Builtins::SetFunctionAtSymbol(const JSHandle<GlobalEnv> &env, const JSHandl
JSObject::DefineOwnProperty(thread_, obj, symbol, descriptor);
}
template<int flag>
JSHandle<JSTaggedValue> Builtins::SetAndReturnFunctionAtSymbol(const JSHandle<GlobalEnv> &env,
const JSHandle<JSObject> &obj,
const JSHandle<JSTaggedValue> &symbol,
std::string_view name,
EcmaEntrypoint func,
int length) const
{
JSHandle<JSFunction> function = factory_->NewJSFunction(env, reinterpret_cast<void *>(func));
JSFunction::SetFunctionLength(thread_, function, JSTaggedValue(length));
JSHandle<JSTaggedValue> nameString(factory_->NewFromUtf8(name));
JSHandle<JSFunctionBase> baseFunction(function);
JSHandle<JSTaggedValue> handleUndefine(thread_, JSTaggedValue::Undefined());
JSFunction::SetFunctionName(thread_, baseFunction, nameString, handleUndefine);
// NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
if constexpr (flag == JSSymbol::SYMBOL_TO_PRIMITIVE_TYPE) {
PropertyDescriptor descriptor(thread_, JSHandle<JSTaggedValue>::Cast(function), false, false, true);
JSObject::DefineOwnProperty(thread_, obj, symbol, descriptor);
return JSHandle<JSTaggedValue>(function);
} else if constexpr (flag == JSSymbol::SYMBOL_HAS_INSTANCE_TYPE) { // NOLINTE(readability-braces-around-statements)
// ecma 19.2.3.6 Function.prototype[@@hasInstance] has the attributes
// { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.
PropertyDescriptor descriptor(thread_, JSHandle<JSTaggedValue>::Cast(function), false, false, false);
JSObject::DefineOwnProperty(thread_, obj, symbol, descriptor);
env->SetHasInstanceFunction(thread_, function);
return JSHandle<JSTaggedValue>(function);
}
PropertyDescriptor descriptor(thread_, JSHandle<JSTaggedValue>::Cast(function), true, false, true);
JSObject::DefineOwnProperty(thread_, obj, symbol, descriptor);
return JSHandle<JSTaggedValue>(function);
}
void Builtins::SetStringTagSymbol(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &obj,
std::string_view key) const
{

View File

@ -65,7 +65,7 @@ private:
kungfu::BuiltinsStubCSigns::ID builtinId =
kungfu::BuiltinsStubCSigns::INVALID) const;
void InitializePropertyDetector(const JSHandle<GlobalEnv> &env) const;
void InitializePropertyDetector(const JSHandle<GlobalEnv> &env, bool lazyInit) const;
void SetLazyAccessor(const JSHandle<JSObject> &object, const JSHandle<JSTaggedValue> &key,
const JSHandle<AccessorData> &accessor) const;
@ -289,6 +289,14 @@ private:
const JSHandle<JSTaggedValue> &symbol, std::string_view name, EcmaEntrypoint func,
int length) const;
template<int type = JSSymbol::SYMBOL_DEFAULT_TYPE>
JSHandle<JSTaggedValue> SetAndReturnFunctionAtSymbol(const JSHandle<GlobalEnv> &env,
const JSHandle<JSObject> &obj,
const JSHandle<JSTaggedValue> &symbol,
std::string_view name,
EcmaEntrypoint func,
int length) const;
void SetStringTagSymbol(const JSHandle<GlobalEnv> &env, const JSHandle<JSObject> &obj,
std::string_view key) const;
JSHandle<JSTaggedValue> CreateGetter(const JSHandle<GlobalEnv> &env, EcmaEntrypoint func,

View File

@ -327,6 +327,41 @@ JSTaggedValue BuiltinsArkTools::IsRegExpReplaceDetectorValid(EcmaRuntimeCallInfo
return JSTaggedValue(PropertyDetector::IsRegExpReplaceDetectorValid(env));
}
JSTaggedValue BuiltinsArkTools::IsSymbolIteratorDetectorValid(EcmaRuntimeCallInfo *info)
{
ASSERT(info);
JSThread *thread = info->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> kind = GetCallArg(info, 0);
if (!kind->IsString()) {
return JSTaggedValue::Undefined();
}
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<EcmaString> mapString = factory->NewFromUtf8("Map");
if (JSTaggedValue::Equal(thread, kind, JSHandle<JSTaggedValue>(mapString))) {
return JSTaggedValue(PropertyDetector::IsMapIteratorDetectorValid(env));
}
JSHandle<EcmaString> setString = factory->NewFromUtf8("Set");
if (JSTaggedValue::Equal(thread, kind, JSHandle<JSTaggedValue>(setString))) {
return JSTaggedValue(PropertyDetector::IsSetIteratorDetectorValid(env));
}
JSHandle<EcmaString> stringString = factory->NewFromUtf8("String");
if (JSTaggedValue::Equal(thread, kind, JSHandle<JSTaggedValue>(stringString))) {
return JSTaggedValue(PropertyDetector::IsStringIteratorDetectorValid(env));
}
JSHandle<EcmaString> arrayString = factory->NewFromUtf8("Array");
if (JSTaggedValue::Equal(thread, kind, JSHandle<JSTaggedValue>(arrayString))) {
return JSTaggedValue(PropertyDetector::IsArrayIteratorDetectorValid(env));
}
JSHandle<EcmaString> typedarrayString = factory->NewFromUtf8("TypedArray");
if (JSTaggedValue::Equal(thread, kind, JSHandle<JSTaggedValue>(typedarrayString))) {
return JSTaggedValue(PropertyDetector::IsTypedArrayIteratorDetectorValid(env));
}
return JSTaggedValue::Undefined();
}
JSTaggedValue BuiltinsArkTools::TimeInUs([[maybe_unused]] EcmaRuntimeCallInfo *info)
{
ClockScope scope;

View File

@ -35,6 +35,7 @@
V("isNotHoleProperty", IsNotHoleProperty, 2, INVALID) \
V("isPrototype", IsPrototype, 1, INVALID) \
V("isRegExpReplaceDetectorValid", IsRegExpReplaceDetectorValid, 0, INVALID) \
V("isSymbolIteratorDetectorValid", IsSymbolIteratorDetectorValid, 1, INVALID) \
V("isTSHClass", IsTSHClass, 1, INVALID) \
V("print", ObjectDump, 0, INVALID) \
V("removeAOTFlag", RemoveAOTFlag, 1, INVALID) \
@ -96,6 +97,8 @@ public:
static JSTaggedValue IsRegExpReplaceDetectorValid(EcmaRuntimeCallInfo *info);
static JSTaggedValue IsSymbolIteratorDetectorValid(EcmaRuntimeCallInfo *info);
static JSTaggedValue TimeInUs(EcmaRuntimeCallInfo *info);
static Span<const base::BuiltinFunctionEntry> GetArkToolsFunctions()

View File

@ -32,6 +32,11 @@ JSTaggedValue BuiltinsStringIterator::Next(EcmaRuntimeCallInfo *argv)
[[maybe_unused]] EcmaHandleScope handleScope(thread);
// 1. Let O be the this value.
JSHandle<JSTaggedValue> thisValue = GetThis(argv);
return NextInternal(thread, thisValue);
}
JSTaggedValue BuiltinsStringIterator::NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisValue)
{
// 2. If Type(O) is not Object, throw a TypeError exception.
// 3. If O does not have all of the internal slots of an String Iterator Instance (21.1.5.3),
// throw a TypeError exception.

View File

@ -23,6 +23,7 @@ class BuiltinsStringIterator : public base::BuiltinsBase {
public:
// 21.1.5.2.1
static JSTaggedValue Next(EcmaRuntimeCallInfo *argv);
static JSTaggedValue NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisValue);
};
} // namespace panda::ecmascript::builtins
#endif // ECMASCRIPT_BUILTINS_BUILTINS_STRING_ITERATOR_H

View File

@ -451,6 +451,8 @@ namespace panda::ecmascript::kungfu {
APPEND_SUFFIX_IMM16(HandleNewobjrangeImm16Imm8V8, V) \
APPEND_SUFFIX_IMM16(HandleWideNewobjrangePrefImm16V8, V) \
APPEND_SUFFIX(HandleInstanceofImm8V8, V) \
APPEND_SUFFIX(HandleGetiteratorImm8, V) \
APPEND_SUFFIX_IMM16(HandleGetiteratorImm16, V) \
APPEND_SUFFIX(HandleTryldglobalbynameImm8Id16, V) \
APPEND_SUFFIX_IMM16(HandleTryldglobalbynameImm16Id16, V) \
APPEND_SUFFIX(HandleTrystglobalbynameImm8Id16, V) \

View File

@ -1302,7 +1302,7 @@ GateRef BytecodeCircuitBuilder::ResolveDef(const size_t bbId, int32_t bcId,
ans = byteCodeToJSGates_.at(iterator.Index()).at(0);
auto oldType = gateAcc_.GetGateType(ans);
if (!type.IsAnyType() && oldType.IsAnyType()) {
typeRecorder_.GetOrUpdatePGOType(gateAcc_.TryGetPcOffset(ans));
typeRecorder_.GetPGOHclassLayoutInfo(gateAcc_.TryGetPcOffset(ans));
gateAcc_.SetGateType(ans, type);
}
break;
@ -1429,14 +1429,16 @@ void BytecodeCircuitBuilder::BuildCircuit()
auto type = typeRecorder_.GetType(bcIndex);
gateAcc_.SetGateType(gate, type);
auto pgoType = typeRecorder_.GetOrUpdatePGOType(gateAcc_.TryGetPcOffset(gate));
gateAcc_.TrySetPGOType(gate, pgoType);
uint32_t pcOffset = gateAcc_.TryGetPcOffset(gate);
EcmaOpcode opcode = bytecodeInfo.GetOpcode();
auto pgoTypeInfo = typeRecorder_.GetPGOTypeInfo(pcOffset, opcode);
gateAcc_.TrySetPGOType(gate, pgoTypeInfo);
auto valueCount = gateAcc_.GetInValueCount(gate);
[[maybe_unused]] size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
[[maybe_unused]] size_t numValueOutputs = bytecodeInfo.ComputeOutCount();
// RETURNUNDEFINED has value input, but not from acc
ASSERT(numValueInputs == valueCount || bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED);
ASSERT(numValueInputs == valueCount || opcode == EcmaOpcode::RETURNUNDEFINED);
ASSERT(numValueOutputs <= 1 + (bytecodeInfo.EnvOut() ? 1 : 0));
auto valueStarts = gateAcc_.GetInValueStarts(gate);
for (size_t valueIdx = 0; valueIdx < valueCount; valueIdx++) {
@ -1455,7 +1457,7 @@ void BytecodeCircuitBuilder::BuildCircuit()
gateAcc_.NewIn(gate, inIdx, defVreg);
} else {
GateRef defAcc = ResolveDef(bb, bcIndex, 0, true);
if (!Bytecodes::IsCallOp(bytecodeInfo.GetOpcode())) {
if (!Bytecodes::IsCallOp(opcode)) {
gateAcc_.NewIn(gate, inIdx, defAcc);
continue;
}

View File

@ -440,7 +440,7 @@ public:
ElementsKind GetArrayElementsKind(GateRef gate) const
{
auto pgoType = typeRecorder_.GetOrUpdatePGOType(gateAcc_.TryGetPcOffset(gate));
auto pgoType = typeRecorder_.GetPGOHclassLayoutInfo(gateAcc_.TryGetPcOffset(gate));
return typeRecorder_.GetElementsKind(pgoType);
}

View File

@ -2079,6 +2079,36 @@ DEF_CALL_SIGNATURE(Getnextpropname)
callSign->SetCallConv(CallSignature::CallConv::CCallConv);
}
DEF_CALL_SIGNATURE(CreateJSSetIterator)
{
// 2 : 2 input parameters
CallSignature signature("CreateJSSetIterator", 0, 2,
ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY());
*callSign = signature;
// 2 : 2 input parameters
std::array<VariableType, 2> params = {
VariableType::NATIVE_POINTER(), // glue
VariableType::JS_ANY(), // obj
};
callSign->SetParameters(params.data());
callSign->SetCallConv(CallSignature::CallConv::CCallConv);
}
DEF_CALL_SIGNATURE(CreateJSMapIterator)
{
// 2 : 2 input parameters
CallSignature signature("CreateJSMapIterator", 0, 2,
ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY());
*callSign = signature;
// 2 : 2 input parameters
std::array<VariableType, 2> params = {
VariableType::NATIVE_POINTER(), // glue
VariableType::JS_ANY(), // obj
};
callSign->SetParameters(params.data());
callSign->SetCallConv(CallSignature::CallConv::CCallConv);
}
DEF_CALL_SIGNATURE(FastStringEqual)
{
// 3 : 3 input parameters

View File

@ -466,6 +466,8 @@ private:
V(FastStringEqual) \
V(Getpropiterator) \
V(Getnextpropname) \
V(CreateJSSetIterator) \
V(CreateJSMapIterator) \
V(JSHClassFindProtoTransitions)
#define DECL_CALL_SIGNATURE(name) \

View File

@ -24,6 +24,8 @@
#include "ecmascript/compiler/rt_call_signature.h"
#include "ecmascript/deoptimizer/deoptimizer.h"
#include "ecmascript/global_env.h"
#include "ecmascript/ic/proto_change_details.h"
#include "ecmascript/js_for_in_iterator.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/js_function.h"
#include "ecmascript/jspandafile/program_object.h"
@ -513,6 +515,134 @@ GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, Ga
return GetObjectFromConstPool(glue, hirGate, constPool, module, index, type);
}
GateRef CircuitBuilder::GetEmptyArray(GateRef glue)
{
GateRef gConstAddr = Load(VariableType::JS_ANY(), glue,
IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit())));
GateRef offset = GetGlobalConstantOffset(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
return Load(VariableType::JS_ANY(), gConstAddr, offset);
}
GateRef CircuitBuilder::GetPrototypeFromHClass(GateRef hClass)
{
GateRef protoOffset = IntPtr(JSHClass::PROTOTYPE_OFFSET);
return Load(VariableType::JS_ANY(), hClass, protoOffset);
}
GateRef CircuitBuilder::GetEnumCacheFromHClass(GateRef hClass)
{
GateRef offset = IntPtr(JSHClass::ENUM_CACHE_OFFSET);
return Load(VariableType::JS_ANY(), hClass, offset);
}
GateRef CircuitBuilder::GetProtoChangeMarkerFromHClass(GateRef hClass)
{
GateRef offset = IntPtr(JSHClass::PROTO_CHANGE_MARKER_OFFSET);
return Load(VariableType::JS_ANY(), hClass, offset);
}
GateRef CircuitBuilder::GetLengthFromForInIterator(GateRef iter)
{
GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET);
return Load(VariableType::INT32(), iter, offset);
}
GateRef CircuitBuilder::GetIndexFromForInIterator(GateRef iter)
{
GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
return Load(VariableType::INT32(), iter, offset);
}
GateRef CircuitBuilder::GetKeysFromForInIterator(GateRef iter)
{
GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET);
return Load(VariableType::JS_ANY(), iter, offset);
}
GateRef CircuitBuilder::GetObjectFromForInIterator(GateRef iter)
{
GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET);
return Load(VariableType::JS_ANY(), iter, offset);
}
GateRef CircuitBuilder::GetCachedHclassFromForInIterator(GateRef iter)
{
GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET);
return Load(VariableType::JS_ANY(), iter, offset);
}
void CircuitBuilder::SetLengthOfForInIterator(GateRef glue, GateRef iter, GateRef length)
{
GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET);
Store(VariableType::INT32(), glue, iter, offset, length);
}
void CircuitBuilder::SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index)
{
GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
Store(VariableType::INT32(), glue, iter, offset, index);
}
void CircuitBuilder::SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys)
{
GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET);
Store(VariableType::JS_ANY(), glue, iter, offset, keys);
}
void CircuitBuilder::SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object)
{
GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET);
Store(VariableType::JS_ANY(), glue, iter, offset, object);
}
void CircuitBuilder::SetCachedHclassOfForInIterator(GateRef glue, GateRef iter, GateRef hclass)
{
GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET);
Store(VariableType::JS_ANY(), glue, iter, offset, hclass);
}
void CircuitBuilder::IncreaseInteratorIndex(GateRef glue, GateRef iter, GateRef index)
{
GateRef newIndex = Int32Add(index, Int32(1));
GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
Store(VariableType::INT32(), glue, iter, offset, newIndex);
}
GateRef CircuitBuilder::GetHasChanged(GateRef object)
{
GateRef bitfieldOffset = IntPtr(ProtoChangeMarker::BIT_FIELD_OFFSET);
GateRef bitfield = Load(VariableType::INT32(), object, bitfieldOffset);
GateRef mask = Int32(1LLU << (ProtoChangeMarker::HAS_CHANGED_BITS - 1));
return Int32NotEqual(Int32And(bitfield, mask), Int32(0));
}
GateRef CircuitBuilder::HasDeleteProperty(GateRef hClass)
{
GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD1_OFFSET));
return Int32NotEqual(
Int32And(Int32LSR(bitfield, Int32(JSHClass::HasDeletePropertyBit::START_BIT)),
Int32((1LLU << JSHClass::HasDeletePropertyBit::SIZE) - 1)),
Int32(0));
}
GateRef CircuitBuilder::IsEcmaObject(GateRef obj)
{
Label entryPass(env_);
SubCfgEntry(&entryPass);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
Label heapObj(env_);
Label exit(env_);
GateRef isHeapObject = TaggedIsHeapObject(obj);
Branch(isHeapObject, &heapObj, &exit);
Bind(&heapObj);
result = LogicAnd(isHeapObject, TaggedObjectIsEcmaObject(obj));
Jump(&exit);
Bind(&exit);
auto ret = *result;
SubCfgExit();
return ret;
}
GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool, GateRef module,
GateRef index, ConstPoolType type)
{

View File

@ -236,6 +236,24 @@ public:
GateRef GetHomeObjectFromFunction(GateRef function);
inline GateRef GetExpectedNumOfArgs(GateRef method);
inline GateRef GetGlobalConstantOffset(ConstantIndex index); // shareir
GateRef GetEmptyArray(GateRef glue);
GateRef GetPrototypeFromHClass(GateRef hClass);
GateRef GetEnumCacheFromHClass(GateRef hClass);
GateRef GetProtoChangeMarkerFromHClass(GateRef hClass);
GateRef GetLengthFromForInIterator(GateRef iter);
GateRef GetIndexFromForInIterator(GateRef iter);
GateRef GetKeysFromForInIterator(GateRef iter);
GateRef GetObjectFromForInIterator(GateRef iter);
GateRef GetCachedHclassFromForInIterator(GateRef iter);
void SetLengthOfForInIterator(GateRef glue, GateRef iter, GateRef length);
void SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index);
void SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys);
void SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object);
void SetCachedHclassOfForInIterator(GateRef glue, GateRef iter, GateRef hclass);
void IncreaseInteratorIndex(GateRef glue, GateRef iter, GateRef index);
GateRef GetHasChanged(GateRef object);
GateRef HasDeleteProperty(GateRef hClass);
GateRef IsEcmaObject(GateRef obj);
// Set
void SetLexicalEnvToFunction(GateRef glue, GateRef function, GateRef value);
@ -299,6 +317,7 @@ public:
GateRef CreateArrayWithBuffer(ElementsKind kind, ArrayMetaDataAccessor::Mode mode,
GateRef constPoolIndex, GateRef elementIndex);
GateRef Construct(GateRef hirGate, std::vector<GateRef> args);
GateRef TypedCallNative(GateRef hirGate, GateRef thisObj, GateRef funcId);
GateRef IsBase(GateRef ctor);
GateRef ToLength(GateRef receiver);
@ -412,6 +431,9 @@ public:
inline GateRef JSNoGCCallThisTargetTypeCheck(GateType type, GateRef func, GateRef methodId, GateRef gate);
GateRef TypeOfCheck(GateRef gate, GateType type);
GateRef TypedTypeOf(GateType type);
GateRef IteratorFunctionCheck(GateRef obj, GateRef kind);
GateRef GetFixedIterator(GateRef obj, GateRef kind);
GateRef NativeCallTargetCheck(GateRef func, GateRef funcId);
GateRef TypedCallOperator(GateRef hirGate, MachineType type, const std::vector<GateRef>& inList);
inline GateRef TypedCallBuiltin(GateRef hirGate, const std::vector<GateRef> &args, BuiltinsStubCSigns::ID id);
GateRef TypeConvert(MachineType type, GateType typeFrom, GateType typeTo, const std::vector<GateRef>& inList);
@ -502,6 +524,13 @@ public:
GateRef IsOptimizedWithBitField(GateRef bitfield);
GateRef ComputeTaggedArraySize(GateRef length);
GateRef HeapAlloc(GateRef size, GateType type, RegionSpaceFlag flag);
GateRef IsRegExpReplaceDetectorValid(GateRef glue);
GateRef IsRegExpSplitDetectorValid(GateRef glue);
GateRef IsMapIteratorDetectorValid(GateRef glue);
GateRef IsSetIteratorDetectorValid(GateRef glue);
GateRef IsStringIteratorDetectorValid(GateRef glue);
GateRef IsArrayIteratorDetectorValid(GateRef glue);
GateRef IsTypedArrayIteratorDetectorValid(GateRef glue);
// bit operation
inline GateRef TaggedIsInt(GateRef x);
@ -519,7 +548,7 @@ public:
inline GateRef TaggedIsAsyncGeneratorObject(GateRef x);
inline GateRef TaggedIsJSGlobalObject(GateRef x);
inline GateRef TaggedIsGeneratorObject(GateRef x);
inline GateRef TaggedIsJSArray(GateRef x);
inline GateRef TaggedIsJSArray(GateRef obj);
inline GateRef TaggedIsPropertyBox(GateRef x);
inline GateRef TaggedIsWeak(GateRef x);
inline GateRef TaggedIsPrototypeHandler(GateRef x);
@ -536,6 +565,9 @@ public:
inline GateRef TaggedIsStringOrSymbol(GateRef obj);
inline GateRef TaggedIsSymbol(GateRef obj);
inline GateRef TaggedIsProtoChangeMarker(GateRef obj);
inline GateRef TaggedIsJSMap(GateRef obj);
inline GateRef TaggedIsJSSet(GateRef obj);
inline GateRef TaggedIsTypedArray(GateRef obj);
inline GateRef TaggedGetInt(GateRef x);
inline GateRef TaggedObjectIsString(GateRef obj);
inline GateRef TaggedObjectBothAreString(GateRef x, GateRef y);
@ -554,6 +586,11 @@ public:
GateRef GetHashcodeFromString(GateRef glue, GateRef value);
GateRef TryGetHashcodeFromString(GateRef string);
// for in
GateRef GetEnumCacheKind(GateRef glue, GateRef enumCache);
GateRef IsEnumCacheValid(GateRef receiver, GateRef cachedHclass, GateRef kind);
GateRef NeedCheckProperty(GateRef receiver);
// ************************************************************* Low IR **********************************************************************************
inline GateRef Equal(GateRef x, GateRef y, const char* comment = nullptr);
inline GateRef NotEqual(GateRef x, GateRef y, const char* comment = nullptr);

View File

@ -25,6 +25,10 @@
#include "ecmascript/compiler/stub_builder-inl.h"
#include "ecmascript/compiler/variable_type.h"
#include "ecmascript/js_array.h"
#include "ecmascript/js_map.h"
#include "ecmascript/js_map_iterator.h"
#include "ecmascript/js_set.h"
#include "ecmascript/js_set_iterator.h"
#include "ecmascript/message_string.h"
#include "ecmascript/tagged_hash_table.h"
@ -936,6 +940,40 @@ void GetnextpropnameStubBuilder::GenerateCircuit()
Return(result);
}
void CreateJSSetIteratorStubBuilder::GenerateCircuit()
{
auto env = GetEnvironment();
Label exit(env);
GateRef glue = PtrArgument(0);
GateRef obj = TaggedArgument(1);
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
NewObjectStubBuilder newBuilder(this);
newBuilder.SetGlue(glue);
GateRef kind = Int32(static_cast<int32_t>(IterationKind::VALUE));
newBuilder.CreateJSCollectionIterator<JSSetIterator, JSSet>(&result, &exit, obj, kind);
Bind(&exit);
Return(*result);
}
void CreateJSMapIteratorStubBuilder::GenerateCircuit()
{
auto env = GetEnvironment();
Label exit(env);
GateRef glue = PtrArgument(0);
GateRef obj = TaggedArgument(1);
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
NewObjectStubBuilder newBuilder(this);
newBuilder.SetGlue(glue);
GateRef kind = Int32(static_cast<int32_t>(IterationKind::KEY_AND_VALUE));
newBuilder.CreateJSCollectionIterator<JSMapIterator, JSMap>(&result, &exit, obj, kind);
Bind(&exit);
Return(*result);
}
CallSignature CommonStubCSigns::callSigns_[CommonStubCSigns::NUM_OF_STUBS];
void CommonStubCSigns::Initialize()

View File

@ -80,6 +80,8 @@ namespace panda::ecmascript::kungfu {
V(CreateStringBySingleCharCode) \
V(Getpropiterator) \
V(Getnextpropname) \
V(CreateJSSetIterator) \
V(CreateJSMapIterator) \
V(GetSingleCharCodeByIndex) \
V(FastStringEqual)

View File

@ -86,6 +86,8 @@ GateRef EarlyElimination::VisitGate(GateRef gate)
case OpCode::ECMA_STRING_CHECK:
case OpCode::BUILTIN_PROTOTYPE_HCLASS_CHECK:
case OpCode::TYPE_OF_CHECK:
case OpCode::ITERATOR_FUNCTION_CHECK:
case OpCode::NATIVE_CALLTARGET_CHECK:
return TryEliminateGate(gate);
case OpCode::STATE_SPLIT:
return TryEliminateFrameState(gate);

View File

@ -455,6 +455,7 @@ uint32_t GateAccessor::TryGetPcOffset(GateRef gate) const
return gatePtr->GetJSBytecodeMetaData()->GetPcOffset();
case OpCode::TYPED_CALL_BUILTIN:
case OpCode::CONSTRUCT:
case OpCode::TYPED_CALL_NATIVE:
case OpCode::CALL_GETTER:
case OpCode::CALL_SETTER:
return static_cast<uint32_t>(gatePtr->GetOneParameterMetaData()->GetValue());

View File

@ -386,6 +386,25 @@ GateRef CircuitBuilder::Construct(GateRef hirGate, std::vector<GateRef> args)
return callGate;
}
GateRef CircuitBuilder::TypedCallNative(GateRef hirGate, GateRef thisObj, GateRef funcId)
{
ASSERT(acc_.GetOpCode(hirGate) == OpCode::JS_BYTECODE);
uint64_t pcOffset = acc_.TryGetPcOffset(hirGate);
ASSERT(pcOffset != 0);
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
std::vector<GateRef> args = { currentControl, currentDepend, thisObj, funcId };
uint64_t bitfield = args.size() - 2; // 2: skip control and depend
AppendFrameArgs(args, hirGate);
GateRef ret = GetCircuit()->NewGate(circuit_->TypedCallNative(bitfield, pcOffset),
MachineType::I64, args.size(), args.data(), GateType::AnyType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::CreateArray(ElementsKind kind, uint32_t arraySize)
{
auto currentLabel = env_->GetCurrentLabel();

View File

@ -33,7 +33,8 @@ namespace panda::ecmascript::kungfu {
V(SaveRegister, SAVE_REGISTER, GateFlags::NONE_FLAG, 0, 1, value)
#define HCR_GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \
V(Construct, CONSTRUCT, GateFlags::HAS_FRAME_STATE, 1, 1, value)
V(Construct, CONSTRUCT, GateFlags::HAS_FRAME_STATE, 1, 1, value) \
V(TypedCallNative, TYPED_CALL_NATIVE, GateFlags::HAS_FRAME_STATE, 1, 1, value)
#define HCR_GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(V) \
V(CallGetter, CALL_GETTER, GateFlags::HAS_FRAME_STATE, 1, 1, 2) \

View File

@ -497,14 +497,14 @@ DECLARE_ASM_HANDLER(HandleCreateemptyarrayImm16)
DECLARE_ASM_HANDLER(HandleGetiteratorImm8)
{
DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc);
GateRef res = CallRuntime(glue, RTSTUB_ID(GetIterator), { *varAcc });
GateRef res = GetIterator(glue, *varAcc, callback);
CHECK_PENDING_EXCEPTION(res, INT_PTR(GETITERATOR_IMM8));
}
DECLARE_ASM_HANDLER(HandleGetiteratorImm16)
{
DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc);
GateRef res = CallRuntime(glue, RTSTUB_ID(GetIterator), { *varAcc });
GateRef res = GetIterator(glue, *varAcc, callback);
CHECK_PENDING_EXCEPTION(res, INT_PTR(GETITERATOR_IMM16));
}

View File

@ -13,9 +13,13 @@
* limitations under the License.
*/
#include "ecmascript/compiler/circuit_builder-inl.h"
#include "ecmascript/compiler/mcr_circuit_builder.h"
#include "ecmascript/compiler/circuit_builder-inl.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_object.h"
#include "ecmascript/marker_cell.h"
namespace panda::ecmascript::kungfu {
GateRef CircuitBuilder::ObjectTypeCheck(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex)
@ -239,6 +243,60 @@ GateRef CircuitBuilder::TypedTypeOf(GateType type)
return ret;
}
GateRef CircuitBuilder::IteratorFunctionCheck(GateRef obj, GateRef kind)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto frameState = acc_.FindNearestFrameState(currentDepend);
GateRef ret = GetCircuit()->NewGate(circuit_->IteratorFunctionCheck(),
MachineType::I1, {currentControl, currentDepend, obj, kind, frameState}, GateType::NJSValue());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::GetFixedIterator(GateRef obj, GateRef kind)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
GateRef ret = GetCircuit()->NewGate(circuit_->GetFixedIterator(),
MachineType::I64, {currentControl, currentDepend, obj, kind}, GateType::AnyType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::NativeCallTargetCheck(GateRef func, GateRef funcId)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto frameState = acc_.FindNearestFrameState(currentDepend);
GateRef ret = GetCircuit()->NewGate(circuit_->NativeCallTargetCheck(),
MachineType::I1, {currentControl, currentDepend, func, funcId, frameState}, GateType::NJSValue());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
#define SYMBOL_DETECTOR_VALID_DEFINE(type, name, index) \
GateRef CircuitBuilder::Is##name##Valid(GateRef glue) \
{ \
GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env_->Is32Bit())); \
GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); \
GateRef cell = GetGlobalEnvValue( \
VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::index); \
GateRef bitfield = Load(VariableType::INT32(), cell, IntPtr(MarkerCell::BIT_FIELD_OFFSET)); \
return Int32Equal( \
Int32And(Int32LSR(bitfield, Int32(MarkerCell::IsDetectorInvalidBits::START_BIT)), \
Int32((1LU << MarkerCell::IsDetectorInvalidBits::SIZE) - 1)), \
Int32(0)); \
}
GLOBAL_ENV_DETECTOR_FIELDS(SYMBOL_DETECTOR_VALID_DEFINE)
#undef SYMBOL_DETECTOR_VALID_DEFINE
GateRef CircuitBuilder::CheckAndConvert(GateRef gate, ValueType src, ValueType dst, ConvertSupport support)
{
auto currentLabel = env_->GetCurrentLabel();
@ -963,4 +1021,119 @@ GateRef CircuitBuilder::ComputeTaggedArraySize(GateRef length)
return PtrAdd(IntPtr(TaggedArray::DATA_OFFSET),
PtrMul(IntPtr(JSTaggedValue::TaggedTypeSize()), length));
}
GateRef CircuitBuilder::GetEnumCacheKind(GateRef glue, GateRef enumCache)
{
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::INT32(), Int32(static_cast<int32_t>(EnumCacheKind::NONE)));
Label enumCacheIsArray(env_);
Label isEmptyArray(env_);
Label notEmptyArray(env_);
Branch(TaggedIsUndefinedOrNull(enumCache), &exit, &enumCacheIsArray);
Bind(&enumCacheIsArray);
GateRef emptyArray = GetEmptyArray(glue);
Branch(Int64Equal(enumCache, emptyArray), &isEmptyArray, &notEmptyArray);
Bind(&isEmptyArray);
{
result = Int32(static_cast<int32_t>(EnumCacheKind::SIMPLE));
Jump(&exit);
}
Bind(&notEmptyArray);
{
GateRef taggedKind = GetValueFromTaggedArray(enumCache, Int32(EnumCache::ENUM_CACHE_KIND_OFFSET));
result = TaggedGetInt(taggedKind);
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
SubCfgExit();
return ret;
}
GateRef CircuitBuilder::IsEnumCacheValid(GateRef receiver, GateRef cachedHclass, GateRef kind)
{
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
Label isSameHclass(env_);
Label isSimpleEnumCache(env_);
Label notSimpleEnumCache(env_);
Label prototypeIsEcmaObj(env_);
Label isProtoChangeMarker(env_);
Label protoNotChanged(env_);
GateRef hclass = LoadHClass(receiver);
Branch(Int64Equal(hclass, cachedHclass), &isSameHclass, &exit);
Bind(&isSameHclass);
Branch(Int32Equal(kind, Int32(static_cast<int32_t>(EnumCacheKind::SIMPLE))),
&isSimpleEnumCache, &notSimpleEnumCache);
Bind(&isSimpleEnumCache);
{
result = True();
Jump(&exit);
}
Bind(&notSimpleEnumCache);
GateRef prototype = GetPrototypeFromHClass(hclass);
Branch(IsEcmaObject(prototype), &prototypeIsEcmaObj, &exit);
Bind(&prototypeIsEcmaObj);
GateRef protoChangeMarker = GetProtoChangeMarkerFromHClass(hclass);
Branch(TaggedIsProtoChangeMarker(protoChangeMarker), &isProtoChangeMarker, &exit);
Bind(&isProtoChangeMarker);
Branch(GetHasChanged(protoChangeMarker), &exit, &protoNotChanged);
Bind(&protoNotChanged);
{
result = True();
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
SubCfgExit();
return ret;
}
GateRef CircuitBuilder::NeedCheckProperty(GateRef receiver)
{
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
Label loopHead(env_);
Label loopEnd(env_);
Label afterLoop(env_);
Label isJSObject(env_);
Label hasNoDeleteProperty(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), True());
DEFVAlUE(current, env_, VariableType::JS_ANY(), receiver);
Branch(TaggedIsHeapObject(*current), &loopHead, &afterLoop);
LoopBegin(&loopHead);
{
Branch(IsJSObject(*current), &isJSObject, &exit);
Bind(&isJSObject);
GateRef hclass = LoadHClass(*current);
Branch(HasDeleteProperty(hclass), &exit, &hasNoDeleteProperty);
Bind(&hasNoDeleteProperty);
current = GetPrototypeFromHClass(hclass);
Branch(TaggedIsHeapObject(*current), &loopEnd, &afterLoop);
}
Bind(&loopEnd);
LoopEnd(&loopHead);
Bind(&afterLoop);
{
result = False();
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
SubCfgExit();
return ret;
}
}

View File

@ -17,6 +17,7 @@
#define ECMASCRIPT_COMPILER_MCR_CIRCUIT_BUILDER_H
#include "ecmascript/compiler/circuit_builder.h"
#include "ecmascript/compiler/circuit_builder_helper.h"
#include "ecmascript/mem/region.h"
#include "ecmascript/method.h"
@ -184,6 +185,67 @@ GateRef CircuitBuilder::TaggedIsProtoChangeMarker(GateRef obj)
return ret;
}
GateRef CircuitBuilder::TaggedIsJSMap(GateRef obj)
{
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
Label isHeapObject(env_);
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
Bind(&isHeapObject);
{
GateRef objType = GetObjectType(LoadHClass(obj));
result = Equal(objType, Int32(static_cast<int32_t>(JSType::JS_MAP)));
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
SubCfgExit();
return ret;
}
GateRef CircuitBuilder::TaggedIsJSSet(GateRef obj)
{
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
Label isHeapObject(env_);
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
Bind(&isHeapObject);
{
GateRef objType = GetObjectType(LoadHClass(obj));
result = Equal(objType, Int32(static_cast<int32_t>(JSType::JS_SET)));
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
SubCfgExit();
return ret;
}
GateRef CircuitBuilder::TaggedIsTypedArray(GateRef obj)
{
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
Label isHeapObject(env_);
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
Bind(&isHeapObject);
{
GateRef jsType = GetObjectType(LoadHClass(obj));
result = BoolAnd(Int32GreaterThan(jsType, Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY_FIRST))),
Int32GreaterThanOrEqual(Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY_LAST)), jsType));
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
SubCfgExit();
return ret;
}
inline GateRef CircuitBuilder::IsOptimizedAndNotFastCall(GateRef obj)
{
GateRef hClass = LoadHClass(obj);
@ -297,11 +359,24 @@ GateRef CircuitBuilder::TaggedIsGeneratorObject(GateRef x)
return LogicAnd(isHeapObj, isAsyncGeneratorObj);
}
GateRef CircuitBuilder::TaggedIsJSArray(GateRef x)
GateRef CircuitBuilder::TaggedIsJSArray(GateRef obj)
{
GateRef objType = GetObjectType(LoadHClass(x));
GateRef isJSArray = Equal(objType, Int32(static_cast<int32_t>(JSType::JS_ARRAY)));
return isJSArray;
Label entry(env_);
SubCfgEntry(&entry);
Label exit(env_);
DEFVAlUE(result, env_, VariableType::BOOL(), False());
Label isHeapObject(env_);
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
Bind(&isHeapObject);
{
GateRef objType = GetObjectType(LoadHClass(obj));
result = Equal(objType, Int32(static_cast<int32_t>(JSType::JS_ARRAY)));
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
SubCfgExit();
return ret;
}
GateRef CircuitBuilder::TaggedIsPropertyBox(GateRef x)

View File

@ -26,6 +26,9 @@ namespace panda::ecmascript::kungfu {
V(Int32UnsignedUpperBoundCheck, INT32_UNSIGNED_UPPER_BOUND_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(Int32DivWithCheck, INT32_DIV_WITH_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(LexVarIsHoleCheck, LEX_VAR_IS_HOLE_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(IteratorFunctionCheck, ITERATOR_FUNCTION_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(GetFixedIterator, GET_FIXED_ITERATOR, GateFlags::NONE_FLAG, 1, 1, 2) \
V(NativeCallTargetCheck, NATIVE_CALLTARGET_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(StringEqual, STRING_EQUAL, GateFlags::NO_WRITE, 1, 1, 2)
#define MCR_IMMUTABLE_META_DATA_CACHE_LIST(V) \

View File

@ -216,7 +216,7 @@ GateRef NewObjectStubBuilder::NewJSForinIterator(GateRef glue, GateRef receiver,
GateRef iter = NewJSObject(glue, hclass);
// init JSForinIterator
SetObjectOfForInIterator(glue, iter, receiver);
SetCachedHclassOFForInIterator(glue, iter, cachedHclass);
SetCachedHclassOfForInIterator(glue, iter, cachedHclass);
SetKeysOfForInIterator(glue, iter, keys);
SetIndexOfForInIterator(glue, iter, Int32(EnumCache::ENUM_CACHE_HEADER_SIZE));
GateRef length = GetLengthOfTaggedArray(keys);

View File

@ -24,6 +24,7 @@
namespace panda::ecmascript::kungfu {
enum class OperationType : uint8_t {
CALL,
NATIVE_CALL,
OPERATION_TYPE,
DEFINE_CLASS,
CREATE_OBJECT,
@ -31,6 +32,7 @@ enum class OperationType : uint8_t {
FALSE_BRANCH,
TRY_DUMP,
TRY_PREDUMP,
ITERATOR_FUNC_KIND
};
using SlotIDFormat = BytecodeInstruction::Format;
@ -57,6 +59,13 @@ public:
}
}
inline void ProfileNativeCall(GateRef func) const
{
if (callback_) {
callback_({ func }, OperationType::NATIVE_CALL);
}
}
inline void ProfileOpType(GateRef type) const
{
if (callback_) {
@ -108,6 +117,13 @@ public:
}
}
inline void ProfileGetIterator(GateRef iterator) const
{
if (callback_) {
callback_({ iterator }, OperationType::ITERATOR_FUNC_KIND);
}
}
private:
Callback callback_;
};

View File

@ -21,6 +21,7 @@
#include "ecmascript/ic/profile_type_info.h"
namespace panda::ecmascript::kungfu {
using PGONativeFunctionId = panda::ecmascript::pgo::DumpUtils::PGONativeFunctionId;
void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo,
const std::vector<GateRef> &values, SlotIDFormat format, OperationType type)
{
@ -28,6 +29,9 @@ void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef pc, GateRef func, Ga
case OperationType::CALL:
ProfileCall(glue, pc, func, values[0], profileTypeInfo, format);
break;
case OperationType::NATIVE_CALL:
ProfileNativeCall(glue, pc, func, values[0], profileTypeInfo, format);
break;
case OperationType::OPERATION_TYPE:
ProfileOpType(glue, pc, func, profileTypeInfo, values[0], format);
break;
@ -49,6 +53,9 @@ void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef pc, GateRef func, Ga
case OperationType::FALSE_BRANCH:
ProfileBranch(glue, pc, func, profileTypeInfo, false);
break;
case OperationType::ITERATOR_FUNC_KIND:
ProfileGetIterator(glue, pc, func, values[0], profileTypeInfo, format);
break;
default:
break;
}
@ -282,6 +289,107 @@ void ProfilerStubBuilder::ProfileCall(
env->SubCfgExit();
}
GateRef ProfilerStubBuilder::TryGetPGONativeFunctionID(GateRef glue, GateRef target)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
Label exit(env);
DEFVARIABLE(functionKind, VariableType::INT32(), Int32(static_cast<int32_t>(PGONativeFunctionId::INVALID)));
DEFVARIABLE(maybeFunc, VariableType::JS_ANY(), Undefined());
Label isArrayIterProtoNext(env);
Label notArrayIterProtoNext(env);
Label isMapIterProtoNext(env);
Label notMapIterProtoNext(env);
Label isSetIterProtoNext(env);
Label notSetIterProtoNext(env);
Label isStringIterProtoNext(env);
GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_ITERATOR_PROTO_NEXT_INDEX);
Branch(Int64Equal(target, *maybeFunc), &isArrayIterProtoNext, &notArrayIterProtoNext);
Bind(&isArrayIterProtoNext);
{
functionKind = Int32(static_cast<int32_t>(PGONativeFunctionId::ARRAY_ITERATOR_PROTO_NEXT));
Jump(&exit);
}
Bind(&notArrayIterProtoNext);
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::MAP_ITERATOR_PROTO_NEXT_INDEX);
Branch(Int64Equal(target, *maybeFunc), &isMapIterProtoNext, &notMapIterProtoNext);
Bind(&isMapIterProtoNext);
{
functionKind = Int32(static_cast<int32_t>(PGONativeFunctionId::MAP_ITERATOR_PROTO_NEXT));
Jump(&exit);
}
Bind(&notMapIterProtoNext);
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::SET_ITERATOR_PROTO_NEXT_INDEX);
Branch(Int64Equal(target, *maybeFunc), &isSetIterProtoNext, &notSetIterProtoNext);
Bind(&isSetIterProtoNext);
{
functionKind = Int32(static_cast<int32_t>(PGONativeFunctionId::SET_ITERATOR_PROTO_NEXT));
Jump(&exit);
}
Bind(&notSetIterProtoNext);
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::STRING_ITERATOR_PROTO_NEXT_INDEX);
Branch(Int64Equal(target, *maybeFunc), &isStringIterProtoNext, &exit);
Bind(&isStringIterProtoNext);
{
functionKind = Int32(static_cast<int32_t>(PGONativeFunctionId::STRING_ITERATOR_PROTO_NEXT));
Jump(&exit);
}
Bind(&exit);
auto ret = *functionKind;
env->SubCfgExit();
return ret;
}
void ProfilerStubBuilder::ProfileNativeCall(
GateRef glue, GateRef pc, GateRef func, GateRef target, GateRef profileTypeInfo, SlotIDFormat format)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
Label exit(env);
Label currentIsHot(env);
Branch(TaggedIsUndefined(profileTypeInfo), &exit, &currentIsHot);
Bind(&currentIsHot);
{
Label updateSlot(env);
Label initSlot(env);
Label sameValueCheck(env);
Label invalidate(env);
GateRef slotId = GetSlotID(pc, format);
GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
GateRef newId = TryGetPGONativeFunctionID(glue, target);
Branch(TaggedIsInt(slotValue), &updateSlot, &initSlot);
Bind(&updateSlot);
GateRef oldId = TaggedGetInt(slotValue);
Branch(Int32Equal(oldId, Int32(static_cast<int32_t>(PGONativeFunctionId::INVALID))), &exit, &sameValueCheck);
Bind(&sameValueCheck);
Branch(Int32Equal(oldId, newId), &exit, &invalidate);
Bind(&invalidate);
{
GateRef invalidId = Int32(static_cast<int32_t>(PGONativeFunctionId::INVALID));
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(invalidId));
TryPreDumpInner(glue, func, profileTypeInfo);
Jump(&exit);
}
Bind(&initSlot);
{
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newId));
TryPreDumpInner(glue, func, profileTypeInfo);
Jump(&exit);
}
}
Bind(&exit);
env->SubCfgExit();
}
GateRef ProfilerStubBuilder::IsProfileTypeInfoDumped(GateRef profileTypeInfo, ProfileOperation callback)
{
if (callback.IsEmpty()) {
@ -521,6 +629,118 @@ void ProfilerStubBuilder::TryPreDumpInner(GateRef glue, GateRef func, GateRef pr
env->SubCfgExit();
}
GateRef ProfilerStubBuilder::GetIterationFunctionKind(GateRef glue, GateRef iterator)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
Label exit(env);
DEFVARIABLE(functionKind, VariableType::INT32(), Int32(static_cast<int32_t>(PGONativeFunctionId::INVALID)));
DEFVARIABLE(maybeFunc, VariableType::JS_ANY(), Undefined());
Label isArrayProtoValues(env);
Label notArrayProtoValues(env);
Label isSetProtoValues(env);
Label notSetProtoValues(env);
Label isMapProtoEntries(env);
Label notMapProtoEntries(env);
Label isStringProtoIter(env);
Label notStringProtoIter(env);
Label isTypedArrayProtoValues(env);
GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_PROTO_VALUES_FUNCTION_INDEX);
Branch(Int64Equal(iterator, *maybeFunc), &isArrayProtoValues, &notArrayProtoValues);
Bind(&isArrayProtoValues);
{
functionKind = Int32(static_cast<int32_t>(PGONativeFunctionId::ARRAY_PROTO_ITERATOR));
Jump(&exit);
}
Bind(&notArrayProtoValues);
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::SET_PROTO_VALUES_FUNCTION_INDEX);
Branch(Int64Equal(iterator, *maybeFunc), &isSetProtoValues, &notSetProtoValues);
Bind(&isSetProtoValues);
{
functionKind = Int32(static_cast<int32_t>(PGONativeFunctionId::SET_PROTO_ITERATOR));
Jump(&exit);
}
Bind(&notSetProtoValues);
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::MAP_PROTO_ENTRIES_FUNCTION_INDEX);
Branch(Int64Equal(iterator, *maybeFunc), &isMapProtoEntries, &notMapProtoEntries);
Bind(&isMapProtoEntries);
{
functionKind = Int32(static_cast<int32_t>(PGONativeFunctionId::MAP_PROTO_ITERATOR));
Jump(&exit);
}
Bind(&notMapProtoEntries);
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::STRING_PROTO_ITER_FUNCTION_INDEX);
Branch(Int64Equal(iterator, *maybeFunc), &isStringProtoIter, &notStringProtoIter);
Bind(&isStringProtoIter);
{
functionKind = Int32(static_cast<int32_t>(PGONativeFunctionId::STRING_PROTO_ITERATOR));
Jump(&exit);
}
Bind(&notStringProtoIter);
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
GlobalEnv::TYPED_ARRAY_PROTO_VALUES_FUNCTION_INDEX);
Branch(Int64Equal(iterator, *maybeFunc), &isTypedArrayProtoValues, &exit);
Bind(&isTypedArrayProtoValues);
{
functionKind = Int32(static_cast<int32_t>(PGONativeFunctionId::TYPED_ARRAY_PROTO_ITERATOR));
Jump(&exit);
}
Bind(&exit);
auto ret = *functionKind;
env->SubCfgExit();
return ret;
}
void ProfilerStubBuilder::ProfileGetIterator(
GateRef glue, GateRef pc, GateRef func, GateRef iterator, GateRef profileTypeInfo, SlotIDFormat format)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
Label exit(env);
Label profiler(env);
Branch(TaggedIsUndefined(profileTypeInfo), &exit, &profiler);
Bind(&profiler);
{
Label updateSlot(env);
Label initSlot(env);
Label sameValueCheck(env);
Label invalidate(env);
GateRef slotId = GetSlotID(pc, format);
GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
GateRef newIterKind = GetIterationFunctionKind(glue, iterator);
Branch(TaggedIsInt(slotValue), &updateSlot, &initSlot);
Bind(&updateSlot);
GateRef oldIterKind = TaggedGetInt(slotValue);
Branch(Int32Equal(oldIterKind, Int32(static_cast<int32_t>(PGONativeFunctionId::INVALID))),
&exit, &sameValueCheck);
Bind(&sameValueCheck);
Branch(Int32Equal(oldIterKind, newIterKind), &exit, &invalidate);
Bind(&invalidate);
{
GateRef invalidKind = Int32(static_cast<int32_t>(PGONativeFunctionId::INVALID));
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(invalidKind));
TryPreDumpInner(glue, func, profileTypeInfo);
Jump(&exit);
}
Bind(&initSlot);
{
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newIterKind));
TryPreDumpInner(glue, func, profileTypeInfo);
Jump(&exit);
}
}
Bind(&exit);
env->SubCfgExit();
}
GateRef ProfilerStubBuilder::GetSlotID(GateRef pc, SlotIDFormat format)
{
if (format == SlotIDFormat::IMM16) {

View File

@ -37,6 +37,8 @@ public:
void ProfileCall(
GateRef glue, GateRef pc, GateRef func, GateRef target, GateRef profileTypeInfo, SlotIDFormat format);
void ProfileNativeCall(
GateRef glue, GateRef pc, GateRef func, GateRef target, GateRef profileTypeInfo, SlotIDFormat format);
void ProfileOpType(
GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo, GateRef type, SlotIDFormat format);
void ProfileDefineClass(
@ -44,6 +46,8 @@ public:
void ProfileCreateObject(
GateRef glue, GateRef pc, GateRef func, GateRef newObj, GateRef profileTypeInfo, SlotIDFormat format);
void ProfileBranch(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo, bool isTrue);
void ProfileGetIterator(
GateRef glue, GateRef pc, GateRef func, GateRef iterator, GateRef profileTypeInfo, SlotIDFormat format);
GateRef UpdateTrackTypeInPropAttr(GateRef attr, GateRef value, ProfileOperation callback);
void UpdatePropAttrIC(GateRef glue, GateRef receiver, GateRef value, GateRef handler, ProfileOperation callback);
@ -68,6 +72,8 @@ private:
void SetDumpPeriodIndex(GateRef glue, GateRef profileTypeInfo);
void SetPreDumpPeriodIndex(GateRef glue, GateRef profileTypeInfo);
GateRef TaggedToTrackType(GateRef value);
GateRef GetIterationFunctionKind(GateRef glue, GateRef iterator);
GateRef TryGetPGONativeFunctionID(GateRef glue, GateRef target);
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_PROFILER_STUB_BUILDER_H

View File

@ -66,7 +66,9 @@ enum class TypedCallTargetCheckOp : uint8_t;
V(NotString, NOTSTRING) \
V(InconsistentType, INCONSISTENTTYPE) \
V(NotNull, NOTNULL) \
V(BuiltinPrototypeHClassMismatch, BUILTINPROTOHCLASSMISMATCH)
V(BuiltinPrototypeHClassMismatch, BUILTINPROTOHCLASSMISMATCH) \
V(IteratorFunctionDisMactch, ITERATORFUNCTIONDISMATCH) \
V(NativeCallTargetDisMatch, NATIVECALLTARGETDISMATCH)
enum class DeoptType : uint8_t {
NOTCHECK = 0,

View File

@ -1807,8 +1807,40 @@ void SlowPathLowering::LowerGetNextPropName(GateRef gate)
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef iter = acc_.GetValueIn(gate, 0);
GateRef newGate = builder_.CallStub(glue_, gate, CommonStubCSigns::Getnextpropname, {glue_, iter});
ReplaceHirWithValue(gate, newGate);
DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
Label notFinish(&builder_);
Label notEnumCacheValid(&builder_);
Label fastGetKey(&builder_);
Label slowpath(&builder_);
Label exit(&builder_);
GateRef index = builder_.GetIndexFromForInIterator(iter);
GateRef length = builder_.GetLengthFromForInIterator(iter);
builder_.Branch(builder_.Int32GreaterThanOrEqual(index, length), &exit, &notFinish);
builder_.Bind(&notFinish);
GateRef keys = builder_.GetKeysFromForInIterator(iter);
GateRef receiver = builder_.GetObjectFromForInIterator(iter);
GateRef cachedHclass = builder_.GetCachedHclassFromForInIterator(iter);
GateRef kind = builder_.GetEnumCacheKind(glue_, keys);
builder_.Branch(builder_.IsEnumCacheValid(receiver, cachedHclass, kind), &fastGetKey, &notEnumCacheValid);
builder_.Bind(&notEnumCacheValid);
builder_.Branch(builder_.NeedCheckProperty(receiver), &slowpath, &fastGetKey);
builder_.Bind(&fastGetKey);
{
result = builder_.GetValueFromTaggedArray(keys, index);
builder_.IncreaseInteratorIndex(glue_, iter, index);
builder_.Jump(&exit);
}
builder_.Bind(&slowpath);
{
result = LowerCallRuntime(gate, RTSTUB_ID(GetNextPropNameSlowpath), { iter }, true);
builder_.Jump(&exit);
}
builder_.Bind(&exit);
ReplaceHirWithValue(gate, *result);
}
void SlowPathLowering::LowerCopyDataProperties(GateRef gate)

View File

@ -1100,21 +1100,7 @@ inline GateRef StubBuilder::TaggedObjectIsEcmaObject(GateRef obj)
inline GateRef StubBuilder::IsEcmaObject(GateRef obj)
{
auto env = GetEnvironment();
Label entryPass(env);
env->SubCfgEntry(&entryPass);
DEFVARIABLE(result, VariableType::BOOL(), False());
Label heapObj(env);
Label exit(env);
GateRef isHeapObject = TaggedIsHeapObject(obj);
Branch(isHeapObject, &heapObj, &exit);
Bind(&heapObj);
result = env_->GetBuilder()->LogicAnd(isHeapObject, TaggedObjectIsEcmaObject(obj));
Jump(&exit);
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
return env_->GetBuilder()->IsEcmaObject(obj);
}
inline GateRef StubBuilder::IsJSObject(GateRef obj)
@ -1424,10 +1410,7 @@ inline GateRef StubBuilder::GetStoreTSHandlerHandlerInfo(GateRef object)
inline GateRef StubBuilder::GetHasChanged(GateRef object)
{
GateRef bitfieldOffset = IntPtr(ProtoChangeMarker::BIT_FIELD_OFFSET);
GateRef bitfield = Load(VariableType::INT32(), object, bitfieldOffset);
GateRef mask = Int32(1LLU << (ProtoChangeMarker::HAS_CHANGED_BITS - 1));
return Int32NotEqual(Int32And(bitfield, mask), Int32(0));
return env_->GetBuilder()->GetHasChanged(object);
}
inline GateRef StubBuilder::HclassIsPrototypeHandler(GateRef hClass)
@ -1455,77 +1438,62 @@ inline GateRef StubBuilder::TaggedIsProtoChangeMarker(GateRef obj)
inline GateRef StubBuilder::GetEmptyArray(GateRef glue)
{
GateRef gConstAddr = Load(VariableType::JS_ANY(), glue,
IntPtr(JSThread::GlueData::GetGlobalConstOffset(env_->Is32Bit())));
GateRef offset = GetGlobalConstantOffset(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
return Load(VariableType::JS_ANY(), gConstAddr, offset);
return env_->GetBuilder()->GetEmptyArray(glue);
}
inline GateRef StubBuilder::GetLengthFromForInIterator(GateRef iter)
{
GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET);
return Load(VariableType::INT32(), iter, offset);
return env_->GetBuilder()->GetLengthFromForInIterator(iter);
}
inline GateRef StubBuilder::GetIndexFromForInIterator(GateRef iter)
{
GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
return Load(VariableType::INT32(), iter, offset);
return env_->GetBuilder()->GetIndexFromForInIterator(iter);
}
inline GateRef StubBuilder::GetKeysFromForInIterator(GateRef iter)
{
GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET);
return Load(VariableType::JS_ANY(), iter, offset);
return env_->GetBuilder()->GetKeysFromForInIterator(iter);
}
inline GateRef StubBuilder::GetObjectFromForInIterator(GateRef iter)
{
GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET);
return Load(VariableType::JS_ANY(), iter, offset);
return env_->GetBuilder()->GetObjectFromForInIterator(iter);
}
inline GateRef StubBuilder::GetCachedHclassFromForInIterator(GateRef iter)
{
GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET);
return Load(VariableType::JS_ANY(), iter, offset);
return env_->GetBuilder()->GetCachedHclassFromForInIterator(iter);
}
inline void StubBuilder::SetLengthOfForInIterator(GateRef glue, GateRef iter, GateRef length)
{
GateRef offset = IntPtr(JSForInIterator::LENGTH_OFFSET);
Store(VariableType::INT32(), glue, iter, offset, length);
env_->GetBuilder()->SetLengthOfForInIterator(glue, iter, length);
}
inline void StubBuilder::SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index)
{
GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
Store(VariableType::INT32(), glue, iter, offset, index);
env_->GetBuilder()->SetIndexOfForInIterator(glue, iter, index);
}
inline void StubBuilder::SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys)
{
GateRef offset = IntPtr(JSForInIterator::KEYS_OFFSET);
Store(VariableType::JS_ANY(), glue, iter, offset, keys);
env_->GetBuilder()->SetKeysOfForInIterator(glue, iter, keys);
}
inline void StubBuilder::SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object)
{
GateRef offset = IntPtr(JSForInIterator::OBJECT_OFFSET);
Store(VariableType::JS_ANY(), glue, iter, offset, object);
env_->GetBuilder()->SetObjectOfForInIterator(glue, iter, object);
}
inline void StubBuilder::SetCachedHclassOFForInIterator(GateRef glue, GateRef iter, GateRef hclass)
inline void StubBuilder::SetCachedHclassOfForInIterator(GateRef glue, GateRef iter, GateRef hclass)
{
GateRef offset = IntPtr(JSForInIterator::CACHED_HCLASS_OFFSET);
Store(VariableType::JS_ANY(), glue, iter, offset, hclass);
env_->GetBuilder()->SetCachedHclassOfForInIterator(glue, iter, hclass);
}
inline void StubBuilder::IncreaseInteratorIndex(GateRef glue, GateRef iter, GateRef index)
{
GateRef newIndex = Int32Add(index, Int32(1));
GateRef offset = IntPtr(JSForInIterator::INDEX_OFFSET);
Store(VariableType::INT32(), glue, iter, offset, newIndex);
env_->GetBuilder()->IncreaseInteratorIndex(glue, iter, index);
}
inline GateRef StubBuilder::IsField(GateRef attr)
@ -1702,20 +1670,17 @@ inline GateRef StubBuilder::SetDictionaryOrderFieldInPropAttr(GateRef attr, Gate
inline GateRef StubBuilder::GetPrototypeFromHClass(GateRef hClass)
{
GateRef protoOffset = IntPtr(JSHClass::PROTOTYPE_OFFSET);
return Load(VariableType::JS_ANY(), hClass, protoOffset);
return env_->GetBuilder()->GetPrototypeFromHClass(hClass);
}
inline GateRef StubBuilder::GetEnumCacheFromHClass(GateRef hClass)
{
GateRef offset = IntPtr(JSHClass::ENUM_CACHE_OFFSET);
return Load(VariableType::JS_ANY(), hClass, offset);
return env_->GetBuilder()->GetEnumCacheFromHClass(hClass);
}
inline GateRef StubBuilder::GetProtoChangeMarkerFromHClass(GateRef hClass)
{
GateRef offset = IntPtr(JSHClass::PROTO_CHANGE_MARKER_OFFSET);
return Load(VariableType::JS_ANY(), hClass, offset);
return env_->GetBuilder()->GetProtoChangeMarkerFromHClass(hClass);
}
inline GateRef StubBuilder::GetLayoutFromHClass(GateRef hClass)
@ -1877,11 +1842,7 @@ inline GateRef StubBuilder::GetNumberOfPropsFromHClass(GateRef hClass)
inline GateRef StubBuilder::HasDeleteProperty(GateRef hClass)
{
GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD1_OFFSET));
return Int32NotEqual(
Int32And(Int32LSR(bitfield, Int32(JSHClass::HasDeletePropertyBit::START_BIT)),
Int32((1LLU << JSHClass::HasDeletePropertyBit::SIZE) - 1)),
Int32(0));
return env_->GetBuilder()->HasDeleteProperty(hClass);
}
inline GateRef StubBuilder::IsTSHClass(GateRef hClass)

View File

@ -3715,8 +3715,7 @@ GateRef StubBuilder::FastGetPropertyByName(GateRef glue, GateRef obj, GateRef ke
}
Bind(&slowpath);
{
result = CallRuntime(glue, RTSTUB_ID(LoadICByName),
{ Undefined(), obj, key, Int64ToTaggedPtr(Int32(0)) });
result = CallRuntime(glue, RTSTUB_ID(LoadICByName), { Undefined(), obj, key, IntToTaggedInt(Int32(0)) });
Jump(&exit);
}
Bind(&exit);
@ -3792,7 +3791,7 @@ void StubBuilder::FastSetPropertyByName(GateRef glue, GateRef obj, GateRef key,
}
Bind(&slowPath);
{
result = CallRuntime(glue, RTSTUB_ID(StoreICByValue), { obj, *keyVar, value, Int64ToTaggedPtr(Int32(0)) });
result = CallRuntime(glue, RTSTUB_ID(StoreICByValue), { obj, *keyVar, value, IntToTaggedInt(Int32(0)) });
Jump(&exit);
}
Bind(&exit);
@ -5260,120 +5259,17 @@ GateRef StubBuilder::JSAPIContainerGet(GateRef glue, GateRef receiver, GateRef i
GateRef StubBuilder::GetEnumCacheKind(GateRef glue, GateRef enumCache)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
DEFVARIABLE(result, VariableType::INT32(), Int32(static_cast<int32_t>(EnumCacheKind::NONE)));
Label enumCacheIsArray(env);
Label isEmptyArray(env);
Label notEmptyArray(env);
Branch(TaggedIsUndefinedOrNull(enumCache), &exit, &enumCacheIsArray);
Bind(&enumCacheIsArray);
GateRef emptyArray = GetEmptyArray(glue);
Branch(Int64Equal(enumCache, emptyArray), &isEmptyArray, &notEmptyArray);
Bind(&isEmptyArray);
{
result = Int32(static_cast<int32_t>(EnumCacheKind::SIMPLE));
Jump(&exit);
}
Bind(&notEmptyArray);
{
GateRef taggedKind = GetValueFromTaggedArray(enumCache, Int32(EnumCache::ENUM_CACHE_KIND_OFFSET));
result = TaggedGetInt(taggedKind);
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
return env_->GetBuilder()->GetEnumCacheKind(glue, enumCache);
}
GateRef StubBuilder::IsEnumCacheValid(GateRef receiver, GateRef cachedHclass, GateRef kind)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
DEFVARIABLE(result, VariableType::BOOL(), False());
Label isSameHclass(env);
Label isSimpleEnumCache(env);
Label notSimpleEnumCache(env);
Label prototypeIsEcmaObj(env);
Label isProtoChangeMarker(env);
Label protoNotChanged(env);
GateRef hclass = LoadHClass(receiver);
Branch(Int64Equal(hclass, cachedHclass), &isSameHclass, &exit);
Bind(&isSameHclass);
Branch(Int32Equal(kind, Int32(static_cast<int32_t>(EnumCacheKind::SIMPLE))),
&isSimpleEnumCache, &notSimpleEnumCache);
Bind(&isSimpleEnumCache);
{
result = True();
Jump(&exit);
}
Bind(&notSimpleEnumCache);
GateRef prototype = GetPrototypeFromHClass(hclass);
Branch(IsEcmaObject(prototype), &prototypeIsEcmaObj, &exit);
Bind(&prototypeIsEcmaObj);
GateRef protoChangeMarker = GetProtoChangeMarkerFromHClass(hclass);
Branch(TaggedIsProtoChangeMarker(protoChangeMarker), &isProtoChangeMarker, &exit);
Bind(&isProtoChangeMarker);
Branch(GetHasChanged(protoChangeMarker), &exit, &protoNotChanged);
Bind(&protoNotChanged);
{
result = True();
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
return env_->GetBuilder()->IsEnumCacheValid(receiver, cachedHclass, kind);
}
GateRef StubBuilder::NeedCheckProperty(GateRef receiver)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label loopHead(env);
Label loopEnd(env);
Label afterLoop(env);
Label isJSObject(env);
Label hasNoDeleteProperty(env);
DEFVARIABLE(result, VariableType::BOOL(), True());
DEFVARIABLE(current, VariableType::JS_ANY(), receiver);
Branch(TaggedIsHeapObject(*current), &loopHead, &afterLoop);
LoopBegin(&loopHead);
{
Branch(IsJSObject(*current), &isJSObject, &exit);
Bind(&isJSObject);
GateRef hclass = LoadHClass(*current);
Branch(HasDeleteProperty(hclass), &exit, &hasNoDeleteProperty);
Bind(&hasNoDeleteProperty);
current = GetPrototypeFromHClass(hclass);
Branch(TaggedIsHeapObject(*current), &loopEnd, &afterLoop);
}
Bind(&loopEnd);
LoopEnd(&loopHead);
Bind(&afterLoop);
{
result = False();
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
return env_->GetBuilder()->NeedCheckProperty(receiver);
}
GateRef StubBuilder::NextInternal(GateRef glue, GateRef iter)
@ -5865,6 +5761,83 @@ GateRef StubBuilder::ConstructorCheck(GateRef glue, GateRef ctor, GateRef outPut
return ret;
}
GateRef StubBuilder::GetIterator(GateRef glue, GateRef obj, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entryPass(env);
Label exit(env);
env->SubCfgEntry(&entryPass);
DEFVARIABLE(result, VariableType::JS_ANY(), Exception());
Label isPendingException(env);
Label noPendingException(env);
Label isHeapObject(env);
Label objIsCallable(env);
GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
GateRef iteratorKey = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ITERATOR_SYMBOL_INDEX);
result = FastGetPropertyByName(glue, obj, iteratorKey, ProfileOperation());
Branch(HasPendingException(glue), &isPendingException, &noPendingException);
Bind(&isPendingException);
{
result = Exception();
Jump(&exit);
}
Bind(&noPendingException);
callback.ProfileGetIterator(*result);
Branch(TaggedIsHeapObject(*result), &isHeapObject, &exit);
Bind(&isHeapObject);
Branch(IsCallable(*result), &objIsCallable, &exit);
Bind(&objIsCallable);
{
result = JSCallDispatch(glue, *result, Int32(0), 0, Circuit::NullGate(),
JSCallMode::CALL_GETTER, { obj }, ProfileOperation());
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
bool StubBuilder::IsCallModeSupportPGO(JSCallMode mode)
{
switch (mode) {
case JSCallMode::CALL_ARG0:
case JSCallMode::CALL_ARG1:
case JSCallMode::CALL_ARG2:
case JSCallMode::CALL_ARG3:
case JSCallMode::CALL_WITH_ARGV:
case JSCallMode::CALL_THIS_ARG0:
case JSCallMode::CALL_THIS_ARG1:
case JSCallMode::CALL_THIS_ARG2:
case JSCallMode::CALL_THIS_ARG3:
case JSCallMode::CALL_THIS_WITH_ARGV:
case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
return true;
case JSCallMode::DEPRECATED_CALL_ARG0:
case JSCallMode::DEPRECATED_CALL_ARG1:
case JSCallMode::DEPRECATED_CALL_ARG2:
case JSCallMode::DEPRECATED_CALL_ARG3:
case JSCallMode::DEPRECATED_CALL_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_THIS_WITH_ARGV:
case JSCallMode::DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV:
case JSCallMode::CALL_ENTRY:
case JSCallMode::CALL_FROM_AOT:
case JSCallMode::CALL_GENERATOR:
case JSCallMode::CALL_GETTER:
case JSCallMode::CALL_SETTER:
case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
return false;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNumArgs, GateRef jumpSize,
GateRef hotnessCounter, JSCallMode mode, std::initializer_list<GateRef> args,
ProfileOperation callback)
@ -5912,6 +5885,9 @@ GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNu
// 3. call native
Bind(&methodIsNative);
{
if (IsCallModeSupportPGO(mode)) {
callback.ProfileNativeCall(func);
}
GateRef nativeCode = Load(VariableType::NATIVE_POINTER(), method,
IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
GateRef newTarget = Undefined();
@ -6017,7 +5993,7 @@ GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNu
// 4. call nonNative
Bind(&methodNotNative);
if (mode != JSCallMode::CALL_GETTER && mode != JSCallMode::CALL_SETTER) {
if (IsCallModeSupportPGO(mode)) {
callback.ProfileCall(func);
}
Label funcIsClassConstructor(env);

View File

@ -632,7 +632,7 @@ public:
void SetIndexOfForInIterator(GateRef glue, GateRef iter, GateRef index);
void SetKeysOfForInIterator(GateRef glue, GateRef iter, GateRef keys);
void SetObjectOfForInIterator(GateRef glue, GateRef iter, GateRef object);
void SetCachedHclassOFForInIterator(GateRef glue, GateRef iter, GateRef hclass);
void SetCachedHclassOfForInIterator(GateRef glue, GateRef iter, GateRef hclass);
void IncreaseInteratorIndex(GateRef glue, GateRef iter, GateRef index);
GateRef GetEnumCacheKind(GateRef glue, GateRef enumCache);
GateRef GetEmptyArray(GateRef glue);
@ -677,6 +677,7 @@ public:
GateRef CallGetterHelper(
GateRef glue, GateRef receiver, GateRef holder, GateRef accessor, ProfileOperation callback);
GateRef ConstructorCheck(GateRef glue, GateRef ctor, GateRef outPut, GateRef thisObj);
GateRef GetIterator(GateRef glue, GateRef obj, ProfileOperation callback);
GateRef JSCallDispatch(GateRef glue, GateRef func, GateRef actualNumArgs, GateRef jumpSize, GateRef hotnessCounter,
JSCallMode mode, std::initializer_list<GateRef> args,
ProfileOperation callback = ProfileOperation());
@ -719,6 +720,7 @@ private:
const BinaryOperation& intOp, const BinaryOperation& floatOp, ProfileOperation callback);
void InitializeArguments();
void CheckDetectorName(GateRef glue, GateRef key, Label *fallthrough, Label *slow);
bool IsCallModeSupportPGO(JSCallMode mode);
CallSignature *callSignature_ {nullptr};
Environment *env_;

View File

@ -17,11 +17,12 @@
#include "ecmascript/compiler/bytecodes.h"
#include "ecmascript/compiler/builtins_lowering.h"
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/enum_conversion.h"
#include "ecmascript/dfx/vmstat/opt_code_profiler.h"
#include "ecmascript/enum_conversion.h"
#include "ecmascript/stackmap/llvm_stackmap_parser.h"
namespace panda::ecmascript::kungfu {
using PGONativeFunctionId = pgo::DumpUtils::PGONativeFunctionId;
bool TSHCRLowering::RunTSHCRLowering()
{
std::vector<GateRef> gateList;
@ -319,6 +320,10 @@ void TSHCRLowering::Lower(GateRef gate)
case EcmaOpcode::TYPEOF_IMM16:
LowerTypedTypeOf(gate);
break;
case EcmaOpcode::GETITERATOR_IMM8:
case EcmaOpcode::GETITERATOR_IMM16:
LowerGetIterator(gate);
break;
default:
DeleteBytecodeCount(ecmaOpcode);
allNonTypedOpCount_++;
@ -1201,6 +1206,28 @@ void TSHCRLowering::SpeculateCallBuiltin(GateRef gate, GateRef func, const std::
}
}
bool TSHCRLowering::TrySpeculateCallThis0Native(GateRef gate, GateRef func, GateRef thisObj)
{
PGOSampleType sampleType = acc_.TryGetPGOType(gate);
if (sampleType.IsNone()) {
return false;
}
ASSERT(sampleType.GetProfileType().IsNativeFunctionId());
int funcIdValue = (-1) * sampleType.GetProfileType().GetId();
PGONativeFunctionId funcId = static_cast<PGONativeFunctionId>(funcIdValue);
if (funcId == PGONativeFunctionId::INVALID) {
return false;
}
AddProfiling(gate);
GateRef funcIdGate = builder_.Int32(funcIdValue);
if (!Uncheck()) {
builder_.NativeCallTargetCheck(func, funcIdGate);
}
GateRef result = builder_.TypedCallNative(gate, thisObj, funcIdGate);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
return true;
}
BuiltinsStubCSigns::ID TSHCRLowering::GetBuiltinId(BuiltinTypeId id, GateRef func)
{
GateType funcType = acc_.GetGateType(func);
@ -1449,14 +1476,17 @@ void TSHCRLowering::LowerTypedCallthis0(GateRef gate)
{
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateRef func = acc_.GetValueIn(gate, 1);
BuiltinsStubCSigns::ID id = GetBuiltinId(BuiltinTypeId::ARRAY, func);
if (id == BuiltinsStubCSigns::ID::SORT) {
AddProfiling(gate);
GateRef thisObj = acc_.GetValueIn(gate, 0);
SpeculateCallBuiltin(gate, func, { thisObj }, id, true);
return;
}
if (TrySpeculateCallThis0Native(gate, func, thisObj)) {
return;
}
if (!CanOptimizeAsFastCall(func)) {
return;
}
@ -1659,4 +1689,28 @@ void TSHCRLowering::LowerTypedTypeOf(GateRef gate)
GateRef result = builder_.TypedTypeOf(valueType);
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
}
void TSHCRLowering::LowerGetIterator(GateRef gate)
{
PGOSampleType sampleType = acc_.TryGetPGOType(gate);
if (sampleType.IsNone()) {
return;
}
ASSERT(sampleType.GetProfileType().IsNativeFunctionId());
int iterKindValue = (-1) * sampleType.GetProfileType().GetId();
PGONativeFunctionId iterKind = static_cast<PGONativeFunctionId>(iterKindValue);
if (iterKind == PGONativeFunctionId::INVALID) {
return;
}
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
GateRef obj = acc_.GetValueIn(gate, 0);
GateRef iterKindGate = builder_.Int32(iterKindValue);
AddProfiling(gate);
if (!Uncheck()) {
builder_.IteratorFunctionCheck(obj, iterKindGate);
}
GateRef result = builder_.GetFixedIterator(obj, iterKindGate);
acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
}
} // namespace panda::ecmascript

View File

@ -139,6 +139,7 @@ private:
void LowerFastCall(GateRef gate, GateRef func, const std::vector<GateRef> &argsFastCall, bool isNoGC);
void LowerCall(GateRef gate, GateRef func, const std::vector<GateRef> &args, bool isNoGC);
void LowerTypedTypeOf(GateRef gate);
void LowerGetIterator(GateRef gate);
GateRef LoadStringByIndex(GateRef receiver, GateRef propKey);
GateRef LoadJSArrayByIndex(GateRef receiver, GateRef propKey, ElementsKind kind);
GateRef LoadTypedArrayByIndex(GateRef receiver, GateRef propKey);
@ -168,6 +169,7 @@ private:
void SpeculateCallBuiltin(GateRef gate, GateRef func, const std::vector<GateRef> &args,
BuiltinsStubCSigns::ID id, bool isThrow);
BuiltinsStubCSigns::ID GetBuiltinId(BuiltinTypeId id, GateRef func);
bool TrySpeculateCallThis0Native(GateRef gate, GateRef func, GateRef thisObj);
void DeleteConstDataIfNoUser(GateRef gate);
void AddProfiling(GateRef gate);

View File

@ -24,7 +24,7 @@
#include "ecmascript/vtable.h"
#include "ecmascript/message_string.h"
namespace panda::ecmascript::kungfu {
using PGONativeFunctionId = panda::ecmascript::pgo::DumpUtils::PGONativeFunctionId;
GateRef TypeMCRLowering::VisitGate(GateRef gate)
{
GateRef glue = acc_.GetGlueFromArgList();
@ -133,6 +133,18 @@ GateRef TypeMCRLowering::VisitGate(GateRef gate)
case OpCode::TYPE_OF:
LowerTypeOf(gate, glue);
break;
case OpCode::ITERATOR_FUNCTION_CHECK:
LowerIteratorFunctionCheck(gate, glue);
break;
case OpCode::GET_FIXED_ITERATOR:
LowerGetFixedIterator(gate, glue);
break;
case OpCode::NATIVE_CALLTARGET_CHECK:
LowerNativeCallTargetCheck(gate);
break;
case OpCode::TYPED_CALL_NATIVE:
LowerTypedCallNative(gate, glue);
break;
default:
break;
}
@ -1680,4 +1692,140 @@ void TypeMCRLowering::LowerTypeOf(GateRef gate, GateRef glue)
GateRef result = builder_.Load(VariableType::JS_POINTER(), gConstAddr, builder_.GetGlobalConstantOffset(index));
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
void TypeMCRLowering::LowerIteratorFunctionCheck(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef frameState = GetFrameState(gate);
GateRef obj = acc_.GetValueIn(gate, 0);
GateRef iterKind = acc_.GetValueIn(gate, 1);
PGONativeFunctionId iterKindValue = static_cast<PGONativeFunctionId>(acc_.GetConstantValue(iterKind));
GateRef check = Circuit::NullGate();
switch (iterKindValue) {
case PGONativeFunctionId::MAP_PROTO_ITERATOR: {
check = builder_.BoolAnd(builder_.TaggedIsJSMap(obj), builder_.IsMapIteratorDetectorValid(glue));
break;
}
case PGONativeFunctionId::SET_PROTO_ITERATOR: {
check = builder_.BoolAnd(builder_.TaggedIsJSSet(obj), builder_.IsSetIteratorDetectorValid(glue));
break;
}
case PGONativeFunctionId::STRING_PROTO_ITERATOR: {
check = builder_.BoolAnd(builder_.TaggedIsString(obj), builder_.IsStringIteratorDetectorValid(glue));
break;
}
case PGONativeFunctionId::ARRAY_PROTO_ITERATOR: {
check = builder_.BoolAnd(builder_.TaggedIsJSArray(obj), builder_.IsArrayIteratorDetectorValid(glue));
break;
}
case PGONativeFunctionId::TYPED_ARRAY_PROTO_ITERATOR: {
check =
builder_.BoolAnd(builder_.TaggedIsTypedArray(obj), builder_.IsTypedArrayIteratorDetectorValid(glue));
break;
}
default:
UNREACHABLE();
}
builder_.DeoptCheck(check, frameState, DeoptType::ITERATORFUNCTIONDISMATCH);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void TypeMCRLowering::LowerGetFixedIterator(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef obj = acc_.GetValueIn(gate, 0);
GateRef iterKind = acc_.GetValueIn(gate, 1);
PGONativeFunctionId iterKindValue = static_cast<PGONativeFunctionId>(acc_.GetConstantValue(iterKind));
GateRef result = Circuit::NullGate();
switch (iterKindValue) {
case PGONativeFunctionId::MAP_PROTO_ITERATOR: {
result = builder_.CallStub(glue, gate, CommonStubCSigns::CreateJSMapIterator, { glue, obj });
break;
}
case PGONativeFunctionId::SET_PROTO_ITERATOR: {
result = builder_.CallStub(glue, gate, CommonStubCSigns::CreateJSSetIterator, { glue, obj });
break;
}
case PGONativeFunctionId::STRING_PROTO_ITERATOR: {
result = LowerCallRuntime(glue, gate, RTSTUB_ID(CreateStringIterator), { obj }, true);
break;
}
case PGONativeFunctionId::ARRAY_PROTO_ITERATOR: {
result = LowerCallRuntime(glue, gate, RTSTUB_ID(NewJSArrayIterator), { obj }, true);
break;
}
case PGONativeFunctionId::TYPED_ARRAY_PROTO_ITERATOR: {
result = LowerCallRuntime(glue, gate, RTSTUB_ID(NewJSTypedArrayIterator), { obj }, true);
break;
}
default:
UNREACHABLE();
}
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
void TypeMCRLowering::LowerNativeCallTargetCheck(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
GateRef frameState = GetFrameState(gate);
GateRef func = acc_.GetValueIn(gate, 0);
GateRef funcId = acc_.GetValueIn(gate, 1);
PGONativeFunctionId funcIdValue = static_cast<PGONativeFunctionId>(acc_.GetConstantValue(funcId));
size_t index = 0;
switch (funcIdValue) {
case PGONativeFunctionId::MAP_ITERATOR_PROTO_NEXT: {
index = GlobalEnv::MAP_ITERATOR_PROTO_NEXT_INDEX;
break;
}
case PGONativeFunctionId::SET_ITERATOR_PROTO_NEXT: {
index = GlobalEnv::SET_ITERATOR_PROTO_NEXT_INDEX;
break;
}
case PGONativeFunctionId::STRING_ITERATOR_PROTO_NEXT: {
index = GlobalEnv::STRING_ITERATOR_PROTO_NEXT_INDEX;
break;
}
case PGONativeFunctionId::ARRAY_ITERATOR_PROTO_NEXT: {
index = GlobalEnv::ARRAY_ITERATOR_PROTO_NEXT_INDEX;
break;
}
default:
UNREACHABLE();
}
GateRef globalEnv = builder_.GetGlobalEnv();
GateRef expectFunc = builder_.GetGlobalEnvObj(globalEnv, index);
GateRef check = builder_.Equal(func, expectFunc, "check calltarget");
builder_.DeoptCheck(check, frameState, DeoptType::NATIVECALLTARGETDISMATCH);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void TypeMCRLowering::LowerTypedCallNative(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateRef funcId = acc_.GetValueIn(gate, 1);
PGONativeFunctionId funcIdValue = static_cast<PGONativeFunctionId>(acc_.GetConstantValue(funcId));
GateRef result = Circuit::NullGate();
switch (funcIdValue) {
case PGONativeFunctionId::MAP_ITERATOR_PROTO_NEXT: {
result = LowerCallRuntime(glue, gate, RTSTUB_ID(MapIteratorNext), { thisObj }, true);
break;
}
case PGONativeFunctionId::SET_ITERATOR_PROTO_NEXT: {
result = LowerCallRuntime(glue, gate, RTSTUB_ID(SetIteratorNext), { thisObj }, true);
break;
}
case PGONativeFunctionId::STRING_ITERATOR_PROTO_NEXT: {
result = LowerCallRuntime(glue, gate, RTSTUB_ID(StringIteratorNext), { thisObj }, true);
break;
}
case PGONativeFunctionId::ARRAY_ITERATOR_PROTO_NEXT: {
result = LowerCallRuntime(glue, gate, RTSTUB_ID(ArrayIteratorNext), { thisObj }, true);
break;
}
default:
UNREACHABLE();
}
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
} // namespace panda::ecmascript::kungfu

View File

@ -187,6 +187,10 @@ private:
void LowerStringEqual(GateRef gate, GateRef glue);
void LowerTypeOfCheck(GateRef gate);
void LowerTypeOf(GateRef gate, GateRef glue);
void LowerIteratorFunctionCheck(GateRef gate, GateRef glue);
void LowerGetFixedIterator(GateRef gate, GateRef glue);
void LowerNativeCallTargetCheck(GateRef gate);
void LowerTypedCallNative(GateRef gate, GateRef glue);
GateRef LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
bool useLabel = false);

View File

@ -162,7 +162,11 @@ void TypeRecorder::CreateTypesForPGO(const JSPandaFile *jsPandaFile, const Metho
EcmaOpcode ecmaOpcode = bytecodes_->GetOpcode(pcOffsets_[bcIdx]);
if (jsPandaFile->HasTSTypes(recordName) && Bytecodes::IsCallOp(ecmaOpcode)) {
uint32_t callTargetMethodOffset = it->second.GetProfileType().GetId();
auto profile = it->second.GetProfileType();
if (!profile.IsMethodId()) {
return;
}
uint32_t callTargetMethodOffset = profile.GetId();
if (callTargetMethodOffset == 0) {
return;
}
@ -312,7 +316,7 @@ ElementsKind TypeRecorder::GetElementsKind(PGOSampleType type) const
return ElementsKind::GENERIC;
}
PGOSampleType TypeRecorder::GetOrUpdatePGOType(int32_t offset) const
PGOSampleType TypeRecorder::GetPGOHclassLayoutInfo(int32_t offset) const
{
if (bcOffsetPGOOpTypeMap_.find(offset) != bcOffsetPGOOpTypeMap_.end()) {
const auto iter = bcOffsetPGOOpTypeMap_.at(offset);
@ -328,6 +332,39 @@ PGOSampleType TypeRecorder::GetOrUpdatePGOType(int32_t offset) const
return PGOSampleType::NoneType();
}
PGOSampleType TypeRecorder::GetPGOTypeInfo(int32_t offset, EcmaOpcode opcode) const
{
if (bcOffsetPGOOpTypeMap_.find(offset) == bcOffsetPGOOpTypeMap_.end()) {
return PGOSampleType::NoneType();
}
switch (opcode) {
case EcmaOpcode::GETITERATOR_IMM8:
case EcmaOpcode::GETITERATOR_IMM16:
case EcmaOpcode::CALLARG0_IMM8:
case EcmaOpcode::CALLARG1_IMM8_V8:
case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
case EcmaOpcode::CALLTHIS0_IMM8_V8:
case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8: {
const auto sampleType = bcOffsetPGOOpTypeMap_.at(offset);
ASSERT(sampleType.IsProfileType());
if (!sampleType.GetProfileType().IsNativeFunctionId()) {
return PGOSampleType::NoneType();
}
return sampleType;
}
default:
break;
}
return GetPGOHclassLayoutInfo(offset);
}
GateType TypeRecorder::GetCallTargetType(int32_t offset) const
{
if (bcOffsetCallTargetGtMap_.find(offset) != bcOffsetCallTargetGtMap_.end()) {

View File

@ -39,12 +39,13 @@ public:
GateType GetType(const int32_t offset) const;
ElementsKind GetElementsKind(PGOSampleType type) const;
PGOSampleType GetOrUpdatePGOType(int32_t offset) const;
PGOSampleType GetPGOHclassLayoutInfo(int32_t offset) const;
PGORWOpType GetRwOpType(int32_t offset) const;
std::vector<ElementsKind> LoadElementsKinds(int32_t offset) const;
GateType GetArgType(const uint32_t argIndex) const;
GateType UpdateType(const int32_t offset, const GateType &type) const;
GateType GetCallTargetType(int32_t offset) const;
PGOSampleType GetPGOTypeInfo(int32_t offset, EcmaOpcode opcode) const;
void BindPgoTypeToGateType(const JSPandaFile *jsPandaFile, TSManager *tsManager,
const MethodLiteral *methodLiteral) const;

View File

@ -98,6 +98,7 @@ bool EcmaContext::Initialize()
globalEnv_ = globalEnv.GetTaggedValue();
Builtins builtins;
bool builtinsLazyEnabled = vm_->GetJSOptions().IsWorker() && vm_->GetJSOptions().GetEnableBuiltinsLazy();
thread_->SetEnableLazyBuiltins(builtinsLazyEnabled);
builtins.Initialize(globalEnv, thread_, builtinsLazyEnabled);
SetupRegExpResultCache();

View File

@ -34,7 +34,7 @@ public:
GLOBAL_ENV_FIELDS(GLOBAL_ENV_SLOT)
static constexpr uint8_t FIRST_DETECTOR_SYMBOL_INDEX = static_cast<uint8_t>(Field::REPLACE_SYMBOL_INDEX);
static constexpr uint8_t LAST_DETECTOR_SYMBOL_INDEX = static_cast<uint8_t>(Field::SPLIT_SYMBOL_INDEX);
static constexpr uint8_t LAST_DETECTOR_SYMBOL_INDEX = static_cast<uint8_t>(Field::ITERATOR_SYMBOL_INDEX);
static constexpr uint8_t FINAL_INDEX = static_cast<uint8_t>(GlobalEnvField::FINAL_INDEX);
#undef GLOBAL_ENV_SLOT

View File

@ -49,9 +49,24 @@
V(JSTaggedValue, Float64ArrayFunction, FLOAT64_ARRAY_FUNCTION_INDEX) \
V(JSTaggedValue, BigInt64ArrayFunction, BIGINT64_ARRAY_FUNCTION_INDEX) \
V(JSTaggedValue, BigUint64ArrayFunction, BIGUINT64_ARRAY_FUNCTION_INDEX) \
V(JSTaggedValue, Int8ArrayFunctionPrototype, INT8_ARRAY_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, Uint8ArrayFunctionPrototype, UINT8_ARRAY_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, Uint8ClampedArrayFunctionPrototype, UINT8_CLAMPED_ARRAY_FUNCTION_PROTO_INDEX) \
V(JSTaggedValue, Int16ArrayFunctionPrototype, INT16_ARRAY_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, Uint16ArrayFunctionPrototype, UINT16_ARRAY_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, Int32ArrayFunctionPrototype, INT32_ARRAY_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, Uint32ArrayFunctionPrototype, UINT32_ARRAY_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, Float32ArrayFunctionPrototype, FLOAT32_ARRAY_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, Float64ArrayFunctionPrototype, FLOAT64_ARRAY_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, BigInt64ArrayFunctionPrototype, BIGINT64_ARRAY_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, BigUint64ArrayFunctionPrototype, BIGUINT64_ARRAY_FUNCTION_PROTOTYPE_INDEX) \
V(JSTaggedValue, ArrayBufferFunction, ARRAY_BUFFER_FUNCTION_INDEX) \
V(JSTaggedValue, SharedArrayBufferFunction, SHAREDARRAY_BUFFER_FUNCTION_INDEX) \
V(JSTaggedValue, ArrayProtoValuesFunction, ARRAY_PROTO_VALUES_FUNCTION_INDEX) \
V(JSTaggedValue, SetProtoValuesFunction, SET_PROTO_VALUES_FUNCTION_INDEX) \
V(JSTaggedValue, MapProtoEntriesFunction, MAP_PROTO_ENTRIES_FUNCTION_INDEX) \
V(JSTaggedValue, StringProtoIterFunction, STRING_PROTO_ITER_FUNCTION_INDEX) \
V(JSTaggedValue, TypedArrayProtoValuesFunction, TYPED_ARRAY_PROTO_VALUES_FUNCTION_INDEX) \
V(JSTaggedValue, DataViewFunction, DATA_VIEW_FUNCTION_INDEX) \
V(JSTaggedValue, DataViewPrototype, DATA_VIEW_PROTOTYPE_INDEX) \
V(JSTaggedValue, SymbolFunction, SYMBOL_FUNCTION_INDEX) \
@ -107,7 +122,6 @@
V(JSTaggedValue, HasInstanceFunction, HASINSTANCE_FUNCTION_INDEX) \
V(JSTaggedValue, IsConcatSpreadableSymbol, ISCONCAT_SYMBOL_INDEX) \
V(JSTaggedValue, ToStringTagSymbol, TOSTRINGTAG_SYMBOL_INDEX) \
V(JSTaggedValue, IteratorSymbol, ITERATOR_SYMBOL_INDEX) \
V(JSTaggedValue, AsyncIteratorSymbol, ASYNC_ITERATOR_SYMBOL_INDEX) \
V(JSTaggedValue, MatchSymbol, MATCH_SYMBOL_INDEX) \
V(JSTaggedValue, MatchAllSymbol, MATCH_All_SYMBOL_INDEX) \
@ -129,6 +143,10 @@
V(JSTaggedValue, ArrayIteratorPrototype, ARRAY_ITERATOR_PROTOTYPE_INDEX) \
V(JSTaggedValue, StringIteratorPrototype, STRING_ITERATOR_PROTOTYPE_INDEX) \
V(JSTaggedValue, AsyncFromSyncIteratorPrototype, ASYNC_FROM_SYNC_ITERATOR_PROTOTYPE_INDEX) \
V(JSTaggedValue, MapIteratorProtoNext, MAP_ITERATOR_PROTO_NEXT_INDEX) \
V(JSTaggedValue, SetIteratorProtoNext, SET_ITERATOR_PROTO_NEXT_INDEX) \
V(JSTaggedValue, StringIteratorProtoNext, STRING_ITERATOR_PROTO_NEXT_INDEX) \
V(JSTaggedValue, ArrayIteratorProtoNext, ARRAY_ITERATOR_PROTO_NEXT_INDEX) \
/* SymbolTable *RegisterSymbols */ \
V(JSTaggedValue, RegisterSymbols, SYMBOLS_INDEX) \
V(JSTaggedValue, ThrowTypeError, THROW_TYPE_ERROR_INDEX) \
@ -201,6 +219,7 @@
#define GLOBAL_ENV_DETECTOR_SYMBOL_FIELDS(V) \
V(JSTaggedValue, ReplaceSymbol, REPLACE_SYMBOL_INDEX) \
V(JSTaggedValue, SplitSymbol, SPLIT_SYMBOL_INDEX) \
V(JSTaggedValue, IteratorSymbol, ITERATOR_SYMBOL_INDEX)
#define GLOBAL_ENV_FIELDS(V) \
GLOBAL_ENV_COMMON_FIELDS(V) \

View File

@ -30,15 +30,19 @@ JSTaggedValue JSArrayIterator::Next(EcmaRuntimeCallInfo *argv)
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
// 1.Let O be the this value.
JSHandle<JSTaggedValue> input(BuiltinsBase::GetThis(argv));
JSHandle<JSTaggedValue> thisObj(BuiltinsBase::GetThis(argv));
return NextInternal(thread, thisObj);
}
JSTaggedValue JSArrayIterator::NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisObj)
{
// 2.If Type(O) is not Object, throw a TypeError exception.
// 3.If O does not have all of the internal slots of an TaggedArray Iterator Instance (22.1.5.3), throw a TypeError
// exception.
if (!input->IsJSArrayIterator()) {
if (!thisObj->IsJSArrayIterator()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not an array iterator", JSTaggedValue::Exception());
}
JSHandle<JSArrayIterator> iter(input);
JSHandle<JSArrayIterator> iter(thisObj);
// 4.Let a be O.[[IteratedArrayLike]].
JSHandle<JSTaggedValue> array(thread, iter->GetIteratedArray());
JSHandle<JSTaggedValue> undefinedHandle(thread, JSTaggedValue::Undefined());

View File

@ -25,6 +25,7 @@ public:
CAST_CHECK(JSArrayIterator, IsJSArrayIterator);
static JSTaggedValue Next(EcmaRuntimeCallInfo *argv);
static JSTaggedValue NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisObj);
static constexpr size_t ITERATED_ARRAY_OFFSET = JSObject::SIZE;
ACCESSORS(IteratedArray, ITERATED_ARRAY_OFFSET, NEXT_INDEX_OFFSET)

View File

@ -29,14 +29,18 @@ JSTaggedValue JSMapIterator::Next(EcmaRuntimeCallInfo *argv)
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
// 1.Let O be the this value
JSHandle<JSTaggedValue> input(BuiltinsBase::GetThis(argv));
JSHandle<JSTaggedValue> thisObj(BuiltinsBase::GetThis(argv));
return NextInternal(thread, thisObj);
}
JSTaggedValue JSMapIterator::NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisObj)
{
// 3.If O does not have all of the internal slots of a Map Iterator Instance (23.1.5.3), throw a TypeError
// exception.
if (!input->IsJSMapIterator()) {
if (!thisObj->IsJSMapIterator()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not a map iterator", JSTaggedValue::Exception());
}
JSHandle<JSMapIterator> iter(input);
JSHandle<JSMapIterator> iter(thisObj);
iter->Update(thread);
JSHandle<JSTaggedValue> undefinedHandle(thread, JSTaggedValue::Undefined());
// 4.Let m be O.[[IteratedMap]].

View File

@ -31,6 +31,7 @@ public:
IterationKind kind);
static JSTaggedValue Next(EcmaRuntimeCallInfo *argv);
static JSTaggedValue NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisObj);
void Update(const JSThread *thread);
static JSTaggedValue MapIteratorToList(JSThread *thread, JSHandle<JSTaggedValue> &items,
JSHandle<JSTaggedValue> &method);

View File

@ -1249,6 +1249,7 @@ bool JSObject::SetPrototype(JSThread *thread, const JSHandle<JSObject> &obj, con
JSHClass::NotifyHclassChanged(thread, hclass, newClass);
obj->SynchronizedSetClass(*newClass);
thread->NotifyStableArrayElementsGuardians(obj, StableArrayChangeKind::PROTO);
ObjectOperator::UpdateDetectorOnSetPrototype(thread, obj.GetTaggedValue());
return true;
}

View File

@ -30,14 +30,18 @@ JSTaggedValue JSSetIterator::Next(EcmaRuntimeCallInfo *argv)
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
// 1.If Type(O) is not Object, throw a TypeError exception.
JSHandle<JSTaggedValue> input(BuiltinsBase::GetThis(argv));
JSHandle<JSTaggedValue> thisObj(BuiltinsBase::GetThis(argv));
return NextInternal(thread, thisObj);
}
JSTaggedValue JSSetIterator::NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisObj)
{
// 3.If O does not have all of the internal slots of a Set Iterator Instance (23.2.5.3), throw a TypeError
// exception.
if (!input->IsJSSetIterator()) {
if (!thisObj->IsJSSetIterator()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not a set iterator", JSTaggedValue::Exception());
}
JSHandle<JSSetIterator> iter(input);
JSHandle<JSSetIterator> iter(thisObj);
iter->Update(thread);
JSHandle<JSTaggedValue> undefinedHandle(thread, JSTaggedValue::Undefined());
// 4.Let s be O.[[IteratedSet]].

View File

@ -28,6 +28,7 @@ public:
IterationKind kind);
static JSTaggedValue Next(EcmaRuntimeCallInfo *argv);
static JSTaggedValue NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisObj);
void Update(const JSThread *thread);

View File

@ -704,6 +704,11 @@ bool JSThread::IsAllContextsInitialized() const
return contexts_.back()->IsInitialized();
}
bool JSThread::IsReadyToUpdateDetector() const
{
return !GetEnableLazyBuiltins() && IsAllContextsInitialized();
}
Area *JSThread::GetOrCreateRegExpCache()
{
if (regExpCache_ == nullptr) {

View File

@ -427,6 +427,16 @@ public:
return enableStackSourceFile_;
}
void SetEnableLazyBuiltins(bool value)
{
enableLazyBuiltins_ = value;
}
bool GetEnableLazyBuiltins() const
{
return enableLazyBuiltins_;
}
static constexpr size_t GetGlueDataOffset()
{
return MEMBER_OFFSET(JSThread, glueData_);
@ -877,6 +887,7 @@ public:
const GlobalEnvConstants *GetFirstGlobalConst() const;
bool IsAllContextsInitialized() const;
bool IsReadyToUpdateDetector() const;
Area *GetOrCreateRegExpCache();
private:
@ -933,6 +944,7 @@ private:
bool isAsmInterpreter_ {false};
VmThreadControl *vmThreadControl_ {nullptr};
bool enableStackSourceFile_ {true};
bool enableLazyBuiltins_ {false};
// CpuProfiler
bool isProfiling_ {false};

View File

@ -214,6 +214,63 @@ void ObjectOperator::FastAdd(JSThread *thread, const JSTaggedValue &receiver, co
op.AddPropertyInternal(value);
}
// static
void ObjectOperator::UpdateDetectorOnSetPrototype(const JSThread *thread, JSTaggedValue receiver)
{
// skip env prepare
if (!thread->IsReadyToUpdateDetector()) {
return;
}
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
if (receiver.IsJSRegExp()) {
if (PropertyDetector::IsRegExpReplaceDetectorValid(env)) {
PropertyDetector::InvalidateRegExpReplaceDetector(env);
}
if (PropertyDetector::IsRegExpSplitDetectorValid(env)) {
PropertyDetector::InvalidateRegExpSplitDetector(env);
}
return;
}
if (receiver.IsJSMap() && PropertyDetector::IsMapIteratorDetectorValid(env)) {
PropertyDetector::InvalidateMapIteratorDetector(env);
return;
}
if (receiver.IsJSSet() && PropertyDetector::IsSetIteratorDetectorValid(env)) {
PropertyDetector::InvalidateSetIteratorDetector(env);
return;
}
if (receiver.IsJSPrimitiveRef() &&
JSPrimitiveRef::Cast(receiver.GetTaggedObject())->IsString() &&
PropertyDetector::IsStringIteratorDetectorValid(env)) {
PropertyDetector::InvalidateStringIteratorDetector(env);
return;
}
if (receiver.IsJSArray() && PropertyDetector::IsArrayIteratorDetectorValid(env)) {
PropertyDetector::InvalidateArrayIteratorDetector(env);
return;
}
if (receiver.IsTypedArray() && PropertyDetector::IsTypedArrayIteratorDetectorValid(env)) {
PropertyDetector::InvalidateTypedArrayIteratorDetector(env);
return;
}
if (receiver.GetTaggedObject()->GetClass()->IsPrototype() &&
(receiver == env->GetTaggedInt8ArrayFunctionPrototype() ||
receiver == env->GetTaggedUint8ArrayFunctionPrototype() ||
receiver == env->GetTaggedUint8ClampedArrayFunctionPrototype() ||
receiver == env->GetTaggedInt16ArrayFunctionPrototype() ||
receiver == env->GetTaggedUint16ArrayFunctionPrototype() ||
receiver == env->GetTaggedInt32ArrayFunctionPrototype() ||
receiver == env->GetTaggedUint32ArrayFunctionPrototype() ||
receiver == env->GetTaggedFloat32ArrayFunctionPrototype() ||
receiver == env->GetTaggedFloat64ArrayFunctionPrototype() ||
receiver == env->GetTaggedBigInt64ArrayFunctionPrototype() ||
receiver == env->GetTaggedBigUint64ArrayFunctionPrototype()) &&
PropertyDetector::IsTypedArrayIteratorDetectorValid(env)) {
PropertyDetector::InvalidateTypedArrayIteratorDetector(env);
return;
}
}
void ObjectOperator::UpdateDetector()
{
if (IsElement()) {
@ -226,7 +283,7 @@ void ObjectOperator::UpdateDetector()
void ObjectOperator::UpdateDetector(const JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
{
// skip env prepare
if (!thread->IsAllContextsInitialized()) {
if (!thread->IsReadyToUpdateDetector()) {
return;
}
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
@ -250,6 +307,46 @@ void ObjectOperator::UpdateDetector(const JSThread *thread, JSTaggedValue receiv
}
PropertyDetector::InvalidateRegExpSplitDetector(env);
}
} else if (key == env->GetTaggedIteratorSymbol()) {
if (receiver.IsJSMap() || receiver == env->GetTaggedMapPrototype()) {
if (!PropertyDetector::IsMapIteratorDetectorValid(env)) {
return;
}
PropertyDetector::InvalidateMapIteratorDetector(env);
} else if (receiver.IsJSSet() || receiver == env->GetTaggedSetPrototype()) {
if (!PropertyDetector::IsSetIteratorDetectorValid(env)) {
return;
}
PropertyDetector::InvalidateSetIteratorDetector(env);
} else if ((receiver.IsJSPrimitiveRef() && JSPrimitiveRef::Cast(receiver.GetTaggedObject())->IsString()) ||
receiver == env->GetTaggedStringPrototype()) {
if (!PropertyDetector::IsStringIteratorDetectorValid(env)) {
return;
}
PropertyDetector::InvalidateStringIteratorDetector(env);
} else if (receiver.IsJSArray() || receiver == env->GetTaggedArrayPrototype()) {
if (!PropertyDetector::IsArrayIteratorDetectorValid(env)) {
return;
}
PropertyDetector::InvalidateArrayIteratorDetector(env);
} else if (receiver.IsTypedArray() ||
receiver == env->GetTaggedArrayPrototype() ||
receiver == env->GetTaggedInt8ArrayFunctionPrototype() ||
receiver == env->GetTaggedUint8ArrayFunctionPrototype() ||
receiver == env->GetTaggedUint8ClampedArrayFunctionPrototype() ||
receiver == env->GetTaggedInt16ArrayFunctionPrototype() ||
receiver == env->GetTaggedUint16ArrayFunctionPrototype() ||
receiver == env->GetTaggedInt32ArrayFunctionPrototype() ||
receiver == env->GetTaggedUint32ArrayFunctionPrototype() ||
receiver == env->GetTaggedFloat32ArrayFunctionPrototype() ||
receiver == env->GetTaggedFloat64ArrayFunctionPrototype() ||
receiver == env->GetTaggedBigInt64ArrayFunctionPrototype() ||
receiver == env->GetTaggedBigUint64ArrayFunctionPrototype()) {
if (!PropertyDetector::IsTypedArrayIteratorDetectorValid(env)) {
return;
}
PropertyDetector::InvalidateTypedArrayIteratorDetector(env);
}
}
}

View File

@ -62,6 +62,7 @@ public:
void UpdateDetector();
static void UpdateDetector(const JSThread *thread, JSTaggedValue receiver, JSTaggedValue key);
static void UpdateDetectorOnSetPrototype(const JSThread *thread, JSTaggedValue receiver);
static bool IsDetectorName(JSHandle<GlobalEnv> env, JSTaggedValue key);
NO_COPY_SEMANTIC(ObjectOperator);

View File

@ -480,6 +480,16 @@ void PGOProfiler::ProfileBytecode(ApEntityId abcId, const CString &recordName, J
DumpCreateObject(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo, traceId);
break;
}
case EcmaOpcode::GETITERATOR_IMM8: {
uint8_t slotId = READ_INST_8_0();
DumpGetIterator(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
break;
}
case EcmaOpcode::GETITERATOR_IMM16: {
uint16_t slotId = READ_INST_16_0();
DumpGetIterator(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
break;
}
case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8:
default:
break;
@ -835,9 +845,27 @@ void PGOProfiler::DumpCall(ApEntityId abcId, const CString &recordName, EntityId
if (!slotValue.IsInt()) {
return;
}
auto calleeMethodId = slotValue.GetInt();
int calleeMethodId = slotValue.GetInt();
ProfileType::Kind kind = (calleeMethodId < 0) ? ProfileType::Kind::NativeFunctionId : ProfileType::Kind::MethodId;
PGOSampleType type = PGOSampleType::CreateProfileType(abcId, std::abs(calleeMethodId), kind);
ProfileType recordType = GetRecordProfileType(abcId, recordName);
recordInfos_->AddCallTargetType(recordType, methodId, bcOffset, type);
}
PGOSampleType type = PGOSampleType::CreateProfileType(abcId, calleeMethodId);
void PGOProfiler::DumpGetIterator(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
uint32_t slotId, ProfileTypeInfo *profileTypeInfo)
{
if (vm_->GetJSThread()->GetEnableLazyBuiltins()) {
return;
}
JSTaggedValue value = profileTypeInfo->Get(slotId);
if (!value.IsInt()) {
return;
}
int iterKind = value.GetInt();
ASSERT(iterKind <= 0);
ProfileType::Kind pgoKind = ProfileType::Kind::NativeFunctionId;
PGOSampleType type = PGOSampleType::CreateProfileType(abcId, std::abs(iterKind), pgoKind);
ProfileType recordType = GetRecordProfileType(abcId, recordName);
recordInfos_->AddCallTargetType(recordType, methodId, bcOffset, type);
}

View File

@ -116,6 +116,9 @@ private:
void DumpCall(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
ProfileTypeInfo *profileTypeInfo);
void DumpGetIterator(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
uint32_t slotId, ProfileTypeInfo *profileTypeInfo);
void AddObjectInfo(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
JSHClass *hclass, PGOObjKind kind);
bool AddObjectInfoByTraceId(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,

View File

@ -40,6 +40,23 @@ public:
static const std::string VERSION_HEADER;
static const std::string PANDA_FILE_INFO_HEADER;
static const uint32_t HEX_FORMAT_WIDTH_FOR_32BITS;
enum class PGONativeFunctionId : int8_t {
// iterator function
MAP_PROTO_ITERATOR = -9, // 9: number of registered functions
SET_PROTO_ITERATOR,
STRING_PROTO_ITERATOR,
ARRAY_PROTO_ITERATOR,
TYPED_ARRAY_PROTO_ITERATOR,
// next function
MAP_ITERATOR_PROTO_NEXT,
SET_ITERATOR_PROTO_NEXT,
STRING_ITERATOR_PROTO_NEXT,
ARRAY_ITERATOR_PROTO_NEXT,
LAST,
INVALID = 0, // keep the same with method offset 0 to reuse calltarget offset field in pgo
};
static_assert(PGONativeFunctionId::LAST == PGONativeFunctionId::INVALID);
};
} // namespace panda::ecmascript::pgo
#endif // ECMASCRIPT_PGO_PROFILER_PGO_UTILS_H

View File

@ -41,6 +41,8 @@ public:
ElementId,
BuiltinsId,
LegacyKind = BuiltinsId,
MethodId, // method offset of js function
NativeFunctionId, // function index of registered function
LocalRecordId,
ModuleRecordId,
TotalKinds,
@ -97,6 +99,16 @@ public:
return GetKind() == Kind::ElementId;
}
bool IsMethodId() const
{
return GetKind() == Kind::MethodId;
}
bool IsNativeFunctionId() const
{
return GetKind() == Kind::NativeFunctionId;
}
uint32_t GetId() const
{
return IdBits::Decode(type_);

View File

@ -194,10 +194,13 @@ public:
PGOSampleTemplate CombineCallTargetType(PGOSampleTemplate type)
{
ASSERT(type_.index() == 1);
ProfileType::Kind oldKind = GetProfileType().GetKind();
ProfileType::Kind newKind = type.GetProfileType().GetKind();
uint32_t oldMethodId = GetProfileType().GetId();
uint32_t newMethodId = type.GetProfileType().GetId();
// If we have recorded a valid method if before, invalidate it.
if ((oldMethodId != newMethodId) && (oldMethodId != 0)) {
if ((oldMethodId != 0) &&
((oldKind != newKind) || (oldMethodId != newMethodId))) {
type_ = ProfileType::PROFILE_TYPE_NONE;
}
return *this;

View File

@ -27,7 +27,12 @@ class PropertyDetector {
public:
#define GLOBAL_ENV_DETECTOR_FIELDS(V) \
V(JSTaggedValue, RegExpReplaceDetector, REGEXP_REPLACE_DETECTOR_INDEX) \
V(JSTaggedValue, RegExpSplitDetector, REGEXP_SPLIT_DETECTOR_INDEX)
V(JSTaggedValue, RegExpSplitDetector, REGEXP_SPLIT_DETECTOR_INDEX) \
V(JSTaggedValue, MapIteratorDetector, MAP_ITERATOR_DETECTOR_INDEX) \
V(JSTaggedValue, SetIteratorDetector, SET_ITERATOR_DETECTOR_INDEX) \
V(JSTaggedValue, StringIteratorDetector, STRING_ITERATOR_DETECTOR_INDEX) \
V(JSTaggedValue, ArrayIteratorDetector, ARRAY_ITERATOR_DETECTOR_INDEX) \
V(JSTaggedValue, TypedArrayIteratorDetector, TYPED_ARRAY_ITERATOR_DETECTOR_INDEX)
#define DECLARE_DETECTOR(type, name, index) \
static inline bool Is##name##Valid(JSHandle<GlobalEnv> env); \
@ -36,8 +41,9 @@ public:
#undef DECLARE_DETECTOR
#define DETECTOR_SYMBOL_LIST(V) \
V(ReplaceSymbol, "Symbol.replace", replace) \
V(SplitSymbol, "Symbol.split", split )
V(ReplaceSymbol, "Symbol.replace", replace ) \
V(SplitSymbol, "Symbol.split", split ) \
V(IteratorSymbol, "Symbol.iterator", iterator)
};
} // namespace ecmascript

View File

@ -116,6 +116,13 @@ namespace panda::ecmascript {
V(Copyrestargs) \
V(Trystobjprop) \
V(GetTemplateObject) \
V(CreateStringIterator) \
V(NewJSArrayIterator) \
V(NewJSTypedArrayIterator) \
V(MapIteratorNext) \
V(SetIteratorNext) \
V(StringIteratorNext) \
V(ArrayIteratorNext) \
V(GetIterator) \
V(GetAsyncIterator) \
V(ThrowIfNotObject) \

View File

@ -22,6 +22,8 @@
#include "ecmascript/base/fast_json_stringifier.h"
#include "ecmascript/base/number_helper.h"
#include "ecmascript/base/string_helper.h"
#include "ecmascript/base/typed_array_helper.h"
#include "ecmascript/builtins/builtins_string_iterator.h"
#include "ecmascript/compiler/builtins/containers_stub_builder.h"
#include "ecmascript/compiler/call_signature.h"
#include "ecmascript/compiler/ecma_opcode_des.h"
@ -39,11 +41,15 @@
#include "ecmascript/interpreter/interpreter-inl.h"
#include "ecmascript/interpreter/interpreter_assembly.h"
#include "ecmascript/js_api/js_api_arraylist.h"
#include "ecmascript/js_array_iterator.h"
#include "ecmascript/js_date.h"
#include "ecmascript/js_function.h"
#include "ecmascript/js_map_iterator.h"
#include "ecmascript/js_object.h"
#include "ecmascript/js_primitive_ref.h"
#include "ecmascript/js_proxy.h"
#include "ecmascript/js_set_iterator.h"
#include "ecmascript/js_string_iterator.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/js_typed_array.h"
#include "ecmascript/jspandafile/program_object.h"
@ -628,6 +634,60 @@ DEF_RUNTIME_STUBS(GetTemplateObject)
return RuntimeGetTemplateObject(thread, literal).GetRawData();
}
DEF_RUNTIME_STUBS(CreateStringIterator)
{
RUNTIME_STUBS_HEADER(CreateStringIterator);
JSHandle<JSTaggedValue> obj = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
return JSStringIterator::CreateStringIterator(thread, JSHandle<EcmaString>(obj)).GetTaggedValue().GetRawData();
}
DEF_RUNTIME_STUBS(NewJSArrayIterator)
{
RUNTIME_STUBS_HEADER(NewJSArrayIterator);
JSHandle<JSObject> obj = GetHArg<JSObject>(argv, argc, 0); // 0: means the zeroth parameter
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
return factory->NewJSArrayIterator(obj, IterationKind::VALUE).GetTaggedValue().GetRawData();
}
DEF_RUNTIME_STUBS(NewJSTypedArrayIterator)
{
RUNTIME_STUBS_HEADER(NewJSArrayIterator);
JSHandle<JSTaggedValue> obj = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
base::TypedArrayHelper::ValidateTypedArray(thread, obj);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception().GetRawData());
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSArrayIterator> iter(factory->NewJSArrayIterator(JSHandle<JSObject>(obj), IterationKind::VALUE));
return iter.GetTaggedValue().GetRawData();
}
DEF_RUNTIME_STUBS(MapIteratorNext)
{
RUNTIME_STUBS_HEADER(MapIteratorNext);
JSHandle<JSTaggedValue> thisObj = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
return JSMapIterator::NextInternal(thread, thisObj).GetRawData();
}
DEF_RUNTIME_STUBS(SetIteratorNext)
{
RUNTIME_STUBS_HEADER(SetIteratorNext);
JSHandle<JSTaggedValue> thisObj = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
return JSSetIterator::NextInternal(thread, thisObj).GetRawData();
}
DEF_RUNTIME_STUBS(StringIteratorNext)
{
RUNTIME_STUBS_HEADER(StringIteratorNext);
JSHandle<JSTaggedValue> thisObj = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
return builtins::BuiltinsStringIterator::NextInternal(thread, thisObj).GetRawData();
}
DEF_RUNTIME_STUBS(ArrayIteratorNext)
{
RUNTIME_STUBS_HEADER(ArrayIteratorNext);
JSHandle<JSTaggedValue> thisObj = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
return JSArrayIterator::NextInternal(thread, thisObj).GetRawData();
}
DEF_RUNTIME_STUBS(GetNextPropName)
{
RUNTIME_STUBS_HEADER(GetNextPropName);

View File

@ -175,6 +175,13 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(CreateGeneratorObj) \
V(ThrowConstAssignment) \
V(GetTemplateObject) \
V(CreateStringIterator) \
V(NewJSArrayIterator) \
V(NewJSTypedArrayIterator) \
V(MapIteratorNext) \
V(SetIteratorNext) \
V(StringIteratorNext) \
V(ArrayIteratorNext) \
V(GetNextPropName) \
V(GetNextPropNameSlowpath) \
V(ThrowIfNotObject) \

View File

@ -107,6 +107,12 @@ group("ark_aot_ts_test") {
"exp",
"fast_call_builtins",
"frame_states",
"forin_delete_property",
"forin_dictionary_mode",
"forin_empty_prototype",
"forin_enum_cache",
"forin_non_empty_prototype",
"forin_special_object",
"forloop",
"framestatesasync",
"framestatesphi",
@ -165,6 +171,13 @@ group("ark_aot_ts_test") {
"or",
"pgo_call",
"pgo_class_operation",
"pgo_forof_array",
"pgo_forof_map",
"pgo_forof_modify_iterator",
"pgo_forof_set",
"pgo_forof_set_prototype",
"pgo_forof_string",
"pgo_forof_typed_array",
"pgo_objectliteral_operation",
"pgo_call_deopt",
"poplexenv",

View File

@ -0,0 +1,18 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("forin_delete_property") {
deps = []
}

View File

@ -0,0 +1,23 @@
# Copyright (c) 2023 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.
a
b
===============
a
b
1
===============
b
1
a

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2023 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.
*/
/*
* @tc.name:forin_delete_property
* @tc.desc:test forin_delete_property
* @tc.type: FUNC
* @tc.require: issueI89SMQ
*/
declare function print(str:any):string;
// fast path
let fast = {"a":1}
fast.b = "a"
for (let i in fast) {
print(i)
delete fast.a
}
print("===============")
// slow path
let parent = {
"c": undefined,
"a": 1,
"b": undefined,
1: 2
}
let own = {
"a": 1,
"b": 1,
}
own.__proto__ = parent
for (let i in own) {
delete own.a
print(i)
delete parent.c
}
print("===============")
for (let i in own) {
print(i)
}

View File

@ -0,0 +1,18 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("forin_dictionary_mode") {
deps = []
}

View File

@ -0,0 +1,21 @@
# Copyright (c) 2023 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.
1
c
b
=============
1
a
c
b

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2023 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.
*/
/*
* @tc.name:forin_dictionary_mode
* @tc.desc:test forin_dictionary_mode
* @tc.type: FUNC
* @tc.require: issueI89SMQ
*/
declare function print(str:any):string;
let parent = {
"c": undefined,
"a": 1,
"b": undefined,
1: 2
}
delete parent.a
let own = {
"a": 1,
"b": 1,
1: 2,
}
delete own.b
own.__proto__ = parent
for (let i in parent) {
print(i)
}
print("=============")
for (let i in own) {
print(i)
}

View File

@ -0,0 +1,18 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("forin_empty_prototype") {
deps = []
}

View File

@ -0,0 +1,23 @@
# Copyright (c) 2023 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.
a
b
a
b
a
b
c
2
4
s

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2023 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.
*/
/*
* @tc.name:forin_empty_prototype
* @tc.desc:test forin_empty_prototype
* @tc.type: FUNC
* @tc.require: issueI89SMQ
*/
declare function print(str:any):string;
// no elements
let fast = {"a":1}
fast.b = "a"
for (let i in fast) {
print(i)
}
// use enum cache
for (let i in fast) {
print(i)
}
fast.c = 1
// invalidate enum cache
for (let i in fast) {
print(i)
}
// has elements
let slow = {"s":222}
slow[2] = "aa"
slow[4] = 1
for (let i in slow) {
print(i)
}

View File

@ -0,0 +1,18 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("forin_enum_cache") {
deps = []
}

View File

@ -0,0 +1,34 @@
# Copyright (c) 2023 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.
===generate enum cache===
a
b
c
===use enum cache===
a
b
c
===re-generate enum cache===
a
b
c
e
===change attribute===
a
b
c
===delete property===
a
b
c

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2023 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.
*/
/*
* @tc.name:forin_enum_cache
* @tc.desc:test forin_enum_cache
* @tc.type: FUNC
* @tc.require: issueI89SMQ
*/
declare function print(str:any):string;
let grandparent = {}
let parent = {
"c": undefined,
"a": 1,
"b": undefined,
}
let own = {
"a": 1,
"b": 1,
}
own.__proto__ = parent
parent.__proto__ = grandparent
// generate enum cache
print("===generate enum cache===")
for (let i in own) {
print(i)
}
// use enum cache
print("===use enum cache===")
for (let i in own) {
print(i)
}
// invalid enum cache and re-generate enum cache
print("===re-generate enum cache===")
grandparent['e'] = 1
for (let i in own) {
print(i)
}
// change attribute
print("===change attribute===")
Object.defineProperty(grandparent, "e", {
configurable:true,
enumerable:false,
value:"ggg",
writable:true
})
for (let i in own) {
print(i)
}
// delete property
print("===delete property===")
grandparent['f'] = 1
for (let i in own) {
print(i)
delete grandparent['f']
}

View File

@ -0,0 +1,18 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("forin_non_empty_prototype") {
deps = []
}

View File

@ -0,0 +1,19 @@
# Copyright (c) 2023 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.
1
a
b
c
2
d

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2023 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.
*/
/*
* @tc.name:forin_non_empty_prototype
* @tc.desc:test forin_non_empty_prototype
* @tc.type: FUNC
* @tc.require: issueI89SMQ
*/
declare function print(str:any):string;
let grandparent = {
"a": 1,
"d": undefined,
1: 2,
2: 3
}
let parent = {
"c": undefined,
"a": 1,
"b": undefined,
1: 2
}
let own = {
"a": 1,
"b": 1,
1: 2,
}
own.__proto__ = parent
parent.__proto__ = grandparent
for (let i in own) {
print(i)
}

View File

@ -0,0 +1,18 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("forin_special_object") {
deps = []
}

View File

@ -0,0 +1,39 @@
# Copyright (c) 2023 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.
2
8
a
0
1
3
4
5
6
7
9
===============
0
1
2
3
4
5
6
7
8
9
===============
_secret
test
eyeCount

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2023 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.
*/
/*
* @tc.name:forin_specail_object
* @tc.desc:test forin_specail_object
* @tc.type: FUNC
* @tc.require: issueI89SMQ
*/
declare function print(str:any):string;
var arr = new Array(10)
for (let i = 0; i < 5; i++) {
arr[i] = i;
}
let parent = new Int8Array(arr);
let self = {
2: "b",
"a": {},
8: []
}
self.__proto__ = parent
for (let i in self) {
print(i)
}
print("===============")
for (let i in parent) {
print(i)
}
print("===============")
const targetObj = {
_secret: 'easily scared',
test: "ss",
eyeCount: 4
};
const proxy_has = new Proxy(targetObj, {
has: (target, key) => {
return key in target;
}
})
for (const key in proxy_has) {
print(key);
}

View File

@ -0,0 +1,22 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("pgo_forof_array") {
deps = []
is_only_typed_path = true
is_enable_pgo = true
is_enable_trace_deopt = true
log_option = " --log-info=trace"
}

View File

@ -0,0 +1,14 @@
# Copyright (c) 2023 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.
600

View File

@ -0,0 +1,14 @@
# Copyright (c) 2023 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.
600

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2023 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.
*/
// @ts-nocheck
declare function print(arg:any):string;
let r = 0;
function foo(obj) {
for (let value of obj) {
r += value
}
for (let value of obj) {
r += value
}
}
let obj1 = new Array(1, 2, 3)
for (let i = 0; i < 50; i++) {
foo(obj1)
}
print(r)

View File

@ -0,0 +1,22 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("pgo_forof_map") {
deps = []
is_only_typed_path = true
is_enable_pgo = true
is_enable_trace_deopt = true
log_option = " --log-info=trace"
}

View File

@ -0,0 +1,24 @@
# Copyright (c) 2023 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.
true
true
true
true
true
true
true
true
true
true
600

View File

@ -0,0 +1,24 @@
# Copyright (c) 2023 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.
true
true
true
true
true
true
true
true
true
true
600

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2023 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.
*/
// @ts-nocheck
declare function print(arg:any):string;
let r = 0
function foo(obj) {
for (let value of obj) {
if (typeof value[0] == "string"){
r += value[1]
}
}
}
let p1 = new Array("apples", 1)
let p2 = new Array("bananas", 2)
let p3 = new Array("oranges", 3)
let a = new Array(p1, p2, p3)
let obj1 = new Map(a)
for (let i = 0; i < 100; i++) {
foo(obj1)
}
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
Object.prototype[Symbol.iterator] = { "next": function () { return {"value":1, "done":true} } }
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
print(r)

View File

@ -0,0 +1,22 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("pgo_forof_modify_iterator") {
deps = []
is_only_typed_path = true
is_enable_pgo = true
is_enable_trace_deopt = true
log_option = " --log-info=trace"
}

View File

@ -0,0 +1,24 @@
# Copyright (c) 2023 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.
true
true
true
true
true
true
true
false
true
true
600

View File

@ -0,0 +1,24 @@
# Copyright (c) 2023 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.
true
true
true
true
true
true
true
false
true
true
600

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2023 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.
*/
// @ts-nocheck
declare function print(arg:any):string;
let r = 0;
function foo(obj) {
for (let value of obj) {
r += value
}
}
// let obj1 = [1,2,3]
let obj1 = new Array(1, 2, 3)
for (let i = 0; i < 100; i++) {
foo(obj1)
}
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
Array.prototype[Symbol.iterator] = { "next": function () { return {"value":1, "done":true} } }
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
foo(obj1)
print(r)

View File

@ -0,0 +1,22 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("pgo_forof_set") {
deps = []
is_only_typed_path = true
is_enable_pgo = true
is_enable_trace_deopt = true
log_option = " --log-info=trace"
}

View File

@ -0,0 +1,14 @@
# Copyright (c) 2023 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.
600

View File

@ -0,0 +1,14 @@
# Copyright (c) 2023 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.
600

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2023 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.
*/
// @ts-nocheck
declare function print(arg:any):string;
let r = 0;
function foo(obj) {
for (let value of obj) {
r += value
}
}
let a = new Array(1, 2, 3)
let obj1 = new Set(a)
for (let i = 0; i < 100; i++) {
foo(obj1)
}
print(r)

View File

@ -0,0 +1,22 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("pgo_forof_set_prototype") {
deps = []
is_only_typed_path = true
is_enable_pgo = true
is_enable_trace_deopt = true
log_option = " --log-info=trace"
}

View File

@ -0,0 +1,62 @@
# Copyright (c) 2023 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.
before change
true
true
true
true
true
after change raw string.__proto__
true
true
true
true
true
after change string.__proto__
true
true
true
false
true
after change array.__proto__
true
true
false
false
true
after change map.__proto__
false
true
false
false
true
after change set.__proto__
false
false
false
false
true
after change Uint8Array.prototype.__proto__
false
false
false
false
false
after change obj(typed array).__proto__
false
false
false
false
false
601

View File

@ -0,0 +1,62 @@
# Copyright (c) 2023 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.
before change
true
true
true
true
true
after change raw string.__proto__
true
true
true
true
true
after change string.__proto__
true
true
true
false
true
after change array.__proto__
true
true
false
false
true
after change map.__proto__
false
true
false
false
true
after change set.__proto__
false
false
false
false
true
after change Uint8Array.prototype.__proto__
false
false
false
false
false
after change obj(typed array).__proto__
false
false
false
false
false
601

View File

@ -0,0 +1,112 @@
/*
* Copyright (c) 2023 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.
*/
// @ts-nocheck
declare function print(arg:any):string;
let r = 0;
function foo(obj) {
for (let value of obj) {
r += value
}
}
let a = new Array(1, 2, 3)
let obj1 = new Uint8Array(a);
for (let i = 0; i < 100; i++) {
foo(obj1)
}
print("before change")
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
let obj2 = "123";
obj2.__proto__ = {}
print("after change raw string.__proto__")
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
let obj3 = new String("123")
obj3.__proto__ = {}
print("after change string.__proto__")
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
let obj4 = new Array(1, 2, 3)
obj4.__proto__ = {}
print("after change array.__proto__")
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
let temp = new Array()
let obj5 = new Map(temp)
obj5.__proto__ = {}
print("after change map.__proto__")
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
let obj6 = new Set(temp)
obj6.__proto__ = {}
print("after change set.__proto__")
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
let index = 0
Uint8Array.prototype.__proto__ = {[Symbol.iterator] : { "next": function () {
if (index == 1) {
return {"value":1, "done":true}
} else {
index++
return {"value":1, "done":false}
}
}}}
for (let i = 0; i < 100; i++) {
foo(obj1)
}
print("after change Uint8Array.prototype.__proto__")
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
obj1.__proto__ = {[Symbol.iterator] : { "next": function () { return {"value":1, "done":true} } }}
for (let i = 0; i < 100; i++) {
foo(obj1)
}
print("after change obj(typed array).__proto__")
print(ArkTools.isSymbolIteratorDetectorValid("Map"))
print(ArkTools.isSymbolIteratorDetectorValid("Set"))
print(ArkTools.isSymbolIteratorDetectorValid("Array"))
print(ArkTools.isSymbolIteratorDetectorValid("String"))
print(ArkTools.isSymbolIteratorDetectorValid("TypedArray"))
print(r)

Some files were not shown because too many files have changed in this diff Show More