Inline TypedArray.entries/key/values builtins

Signed-off-by: Mikhail Ivanov <ivanov.mikhail2@huawei.com>
Change-Id: I8b1ffa6a93a9d7f11a1393189c196f7d34cbcc37
This commit is contained in:
Mikhail Ivanov 2024-04-04 20:04:07 +08:00 committed by Ishin Pavel
parent d348db11c4
commit 93ef8a285c
30 changed files with 865 additions and 7 deletions

View File

@ -76,7 +76,7 @@
/* %TypedArray%.prototype.copyWithin ( target, start [ , end ] ) */ \
V("copyWithin", CopyWithin, 2, TypedArrayCopyWithin) \
/* %TypedArray%.prototype.entries ( ) */ \
V("entries", Entries, 0, INVALID) \
V("entries", Entries, 0, TypedArrayEntries) \
/* %TypedArray%.prototype.every ( callbackfn [ , thisArg ] ) */ \
V("every", Every, 1, TypedArrayEvery) \
/* %TypedArray%.prototype.fill ( value [ , start [ , end ] ] ) */ \
@ -100,7 +100,7 @@
/* %TypedArray%.prototype.join ( separator ) */ \
V("join", Join, 1, INVALID) \
/* %TypedArray%.prototype.keys ( ) */ \
V("keys", Keys, 0, INVALID) \
V("keys", Keys, 0, TypedArrayKeys) \
/* %TypedArray%.prototype.lastIndexOf ( searchElement [ , fromIndex ] ) */ \
V("lastIndexOf", LastIndexOf, 1, TypedArrayLastIndexOf) \
/* %TypedArray%.prototype.map ( callbackfn [ , thisArg ] ) */ \
@ -128,7 +128,7 @@
/* %TypedArray%.prototype.toSorted ( comparefn ) */ \
V("toSorted", ToSorted, 1, INVALID) \
/* %TypedArray%.prototype.values ( ) */ \
V("values", Values, 0, INVALID) \
V("values", Values, 0, TypedArrayValues) \
/* %TypedArray%.prototype.with ( index, value ) */ \
V("with", With, 2, TypedArrayWith)

View File

@ -139,6 +139,9 @@ namespace panda::ecmascript::kungfu {
V(Some, TypedArray, Undefined()) \
V(Filter, TypedArray, Undefined()) \
V(With, TypedArray, Undefined()) \
V(Entries, TypedArray, Undefined()) \
V(Keys, TypedArray, Undefined()) \
V(Values, TypedArray, Undefined()) \
V(Slice, TypedArray, Undefined()) \
V(SubArray, TypedArray, Undefined()) \
V(Sort, TypedArray, Undefined()) \
@ -332,6 +335,9 @@ public:
case BuiltinsStubCSigns::ID::MapGet:
case BuiltinsStubCSigns::ID::MapHas:
case BuiltinsStubCSigns::ID::SetHas:
case BuiltinsStubCSigns::ID::TypedArrayEntries:
case BuiltinsStubCSigns::ID::TypedArrayKeys:
case BuiltinsStubCSigns::ID::TypedArrayValues:
return true;
default:
return false;
@ -476,6 +482,12 @@ public:
return ConstantIndex::DATE_GET_TIME_INDEX;
case BuiltinsStubCSigns::ID::DateNow:
return ConstantIndex::DATE_NOW_INDEX;
case BuiltinsStubCSigns::ID::TypedArrayEntries:
return ConstantIndex::TYPED_ARRAY_ENTRIES_INDEX;
case BuiltinsStubCSigns::ID::TypedArrayKeys:
return ConstantIndex::TYPED_ARRAY_KEYS_INDEX;
case BuiltinsStubCSigns::ID::TypedArrayValues:
return ConstantIndex::TYPED_ARRAY_VALUES_INDEX;
case BuiltinsStubCSigns::ID::GlobalIsFinite:
return ConstantIndex::GLOBAL_IS_FINITE_INDEX;
case BuiltinsStubCSigns::ID::GlobalIsNan:
@ -572,6 +584,9 @@ public:
{MathMin, "Math.min"},
{DateGetTime, "Date.prototype.getTime"},
{DateNow, "Date.now"},
{TypedArrayEntries, "TypedArray.entries"},
{TypedArrayKeys, "TypedArray.keys"},
{TypedArrayValues, "TypedArray.values"},
{GlobalIsFinite, "isFinite"},
{GlobalIsNan, "isNan"},
{BigIntAsIntN, "BigInt.asIntN"},

View File

@ -19,6 +19,7 @@
#include "ecmascript/byte_array.h"
#include "ecmascript/compiler/builtins/builtins_array_stub_builder.h"
#include "ecmascript/compiler/new_object_stub_builder.h"
#include "ecmascript/js_iterator.h"
namespace panda::ecmascript::kungfu {
GateRef BuiltinsTypedArrayStubBuilder::GetDataPointFromBuffer(GateRef arrBuf)
@ -2289,4 +2290,44 @@ void BuiltinsTypedArrayStubBuilder::FindIndex(GateRef glue, GateRef thisValue, G
Bind(&loopExit);
Jump(exit);
}
void BuiltinsTypedArrayStubBuilder::Entries(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath)
{
BuildArrayIterator(glue, thisValue, numArgs, result, exit, slowPath, IterationKind::KEY_AND_VALUE);
}
void BuiltinsTypedArrayStubBuilder::Keys(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath)
{
BuildArrayIterator(glue, thisValue, numArgs, result, exit, slowPath, IterationKind::KEY);
}
void BuiltinsTypedArrayStubBuilder::Values(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath)
{
BuildArrayIterator(glue, thisValue, numArgs, result, exit, slowPath, IterationKind::VALUE);
}
void BuiltinsTypedArrayStubBuilder::BuildArrayIterator(GateRef glue, GateRef thisValue,
[[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath, IterationKind iteratorKind)
{
auto env = GetEnvironment();
Label thisExists(env);
Label isEcmaObject(env);
Label isTypedArray(env);
BRANCH(BoolOr(TaggedIsHole(thisValue), TaggedIsUndefinedOrNull(thisValue)), slowPath, &thisExists);
Bind(&thisExists);
BRANCH(IsEcmaObject(thisValue), &isEcmaObject, slowPath);
Bind(&isEcmaObject);
BRANCH(IsTypedArray(thisValue), &isTypedArray, slowPath);
Bind(&isTypedArray);
NewObjectStubBuilder newBuilder(this);
newBuilder.SetGlue(glue);
GateRef kind = Int32(static_cast<int32_t>(iteratorKind));
newBuilder.CreateJSTypedArrayIterator(result, exit, thisValue, kind);
}
} // namespace panda::ecmascript::kungfu

View File

@ -78,6 +78,9 @@ private:
{
return GetEnvironment()->GetBuilder()->ChangeTaggedPointerToInt64(x);
}
private:
void BuildArrayIterator(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath, IterationKind iteratorKind);
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_BUILTINS_TYPEDARRAY_STUB_BUILDER_H

View File

@ -286,6 +286,9 @@ GateRef BuiltinLowering::CheckPara(GateRef gate, GateRef funcCheck)
case BuiltinsStubCSigns::ID::ArrayIteratorProtoNext:
case BuiltinsStubCSigns::ID::IteratorProtoReturn:
case BuiltinsStubCSigns::ID::NumberConstructor:
case BuiltinsStubCSigns::ID::TypedArrayEntries:
case BuiltinsStubCSigns::ID::TypedArrayKeys:
case BuiltinsStubCSigns::ID::TypedArrayValues:
// Don't need check para
return funcCheck;
default: {

View File

@ -2517,4 +2517,48 @@ DEF_CALL_SIGNATURE(CopyTypedArrayBuffer)
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
}
DEF_CALL_SIGNATURE(CreateJSTypedArrayEntries)
{
// 2 : 2 input parameters
CallSignature signature("CreateJSTypedArrayEntries", 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(CreateJSTypedArrayKeys)
{
// 2 : 2 input parameters
CallSignature signature("CreateJSTypedArrayKeys", 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(CreateJSTypedArrayValues)
{
// 2 : 2 input parameters
CallSignature signature("CreateJSTypedArrayValues", 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);
}
} // namespace panda::ecmascript::kungfu

View File

@ -517,6 +517,9 @@ private:
V(JSMapGet) \
V(JSMapHas) \
V(JSSetHas) \
V(CreateJSTypedArrayEntries) \
V(CreateJSTypedArrayKeys) \
V(CreateJSTypedArrayValues) \
V(JSHClassFindProtoTransitions) \
V(NumberHelperStringToDouble) \
V(GetStringToListCacheArray) \

View File

@ -210,6 +210,14 @@ GateRef CircuitBuilder::GetLengthOfJSTypedArray(GateRef array)
return Load(VariableType::INT32(), array, IntPtr(JSTypedArray::ARRAY_LENGTH_OFFSET));
}
GateRef CircuitBuilder::IsTypedArray(GateRef array)
{
GateRef hclass = LoadHClass(array);
GateRef type = GetObjectType(hclass);
return BoolAnd(Int32GreaterThan(type, Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY_FIRST))),
Int32GreaterThanOrEqual(Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY_LAST)), type));
}
void CircuitBuilder::Jump(Label *label)
{
ASSERT(label);

View File

@ -202,6 +202,7 @@ public:
GateRef GetElementsArray(GateRef object);
GateRef GetLengthOfTaggedArray(GateRef array);
GateRef GetLengthOfJSTypedArray(GateRef array);
GateRef IsTypedArray(GateRef array);
GateRef GetSuperConstructor(GateRef ctor);
GateRef Merge(const std::vector<GateRef> &inList);
GateRef Selector(OpCode opcode, MachineType machineType, GateRef control, const std::vector<GateRef> &values,
@ -840,6 +841,8 @@ public:
template<OpCode Op, MachineType Type>
inline GateRef BinaryOpWithOverflow(GateRef x, GateRef y);
GateRef BuildTypedArrayIterator(GateRef gate, const GateMetaData* op);
#define ARITHMETIC_BINARY_OP_WITH_BITWIDTH(NAME, OPCODEID, MACHINETYPEID) \
inline GateRef NAME(GateRef x, GateRef y, GateType type = GateType::Empty(), const char* comment = nullptr) \
{ \

View File

@ -1175,6 +1175,57 @@ void JSSetHasStubBuilder::GenerateCircuit()
Return(builder.Has(linkedTable, key));
}
void CreateJSTypedArrayEntriesStubBuilder::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.CreateJSTypedArrayIterator(&result, &exit, obj, kind);
Bind(&exit);
Return(*result);
}
void CreateJSTypedArrayKeysStubBuilder::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));
newBuilder.CreateJSTypedArrayIterator(&result, &exit, obj, kind);
Bind(&exit);
Return(*result);
}
void CreateJSTypedArrayValuesStubBuilder::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.CreateJSTypedArrayIterator(&result, &exit, obj, kind);
Bind(&exit);
Return(*result);
}
CallSignature CommonStubCSigns::callSigns_[CommonStubCSigns::NUM_OF_STUBS];
void CommonStubCSigns::Initialize()

View File

@ -94,6 +94,9 @@ namespace panda::ecmascript::kungfu {
V(JSMapGet) \
V(JSMapHas) \
V(JSSetHas) \
V(CreateJSTypedArrayEntries) \
V(CreateJSTypedArrayKeys) \
V(CreateJSTypedArrayValues) \
V(GetSingleCharCodeByIndex) \
V(FastStringEqual) \
V(FastStringAdd) \

View File

@ -1818,6 +1818,19 @@ GateRef CircuitBuilder::BuildBigIntAsIntN(const GateMetaData* op, std::vector<Ga
return ret;
}
GateRef CircuitBuilder::BuildTypedArrayIterator(GateRef gate, const GateMetaData* op)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
GateRef ret =
GetCircuit()->NewGate(op, MachineType::I64,
{ currentControl, currentDepend, gate }, GateType::AnyType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
GateRef CircuitBuilder::IsASCIICharacter(GateRef gate)
{
return Int32UnsignedLessThan(Int32Sub(gate, Int32(1)), Int32(base::utf_helper::UTF8_1B_MAX));

View File

@ -62,6 +62,9 @@ namespace panda::ecmascript::kungfu {
V(IndexCheck, INDEX_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(MonoLoadPropertyOnProto, MONO_LOAD_PROPERTY_ON_PROTO, GateFlags::CHECKABLE, 1, 1, 4) \
V(StringFromSingleCharCode, STRING_FROM_SINGLE_CHAR_CODE, GateFlags::NO_WRITE, 1, 1, 1) \
V(TypedArrayEntries, TYPED_ARRAY_ENTRIES, GateFlags::NO_WRITE, 1, 1, 1) \
V(TypedArrayKeys, TYPED_ARRAY_KEYS, GateFlags::NO_WRITE, 1, 1, 1) \
V(TypedArrayValues, TYPED_ARRAY_VALUES, GateFlags::NO_WRITE, 1, 1, 1) \
V(MigrateFromRawValueToHeapValues, MIGRATE_FROM_RAWVALUE_TO_HEAPVALUES, GateFlags::NONE_FLAG, 1, 1, 3) \
V(MigrateFromHeapValueToRawValue, MIGRATE_FROM_HEAPVALUE_TO_RAWVALUE, GateFlags::NONE_FLAG, 1, 1, 3) \
V(MigrateFromHoleIntToHoleNumber, MIGRATE_FROM_HOLEINT_TO_HOLENUMBER, GateFlags::NONE_FLAG, 1, 1, 1) \

View File

@ -20,6 +20,10 @@
#include "ecmascript/compiler/circuit_builder_helper.h"
#include "ecmascript/compiler/share_gate_meta_data.h"
#include "ecmascript/js_dataview.h"
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/compiler/new_object_stub_builder.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_iterator.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/message_string.h"
@ -90,6 +94,15 @@ void NativeInlineLowering::RunNativeInlineLowering()
case BuiltinsStubCSigns::ID::NumberIsSafeInteger:
TryInlineNumberIsSafeInteger(gate, argc, skipThis);
break;
case BuiltinsStubCSigns::ID::TypedArrayEntries:
TryInlineTypedArrayIteratorBuiltin(gate, id, circuit_->TypedArrayEntries(), skipThis);
break;
case BuiltinsStubCSigns::ID::TypedArrayKeys:
TryInlineTypedArrayIteratorBuiltin(gate, id, circuit_->TypedArrayKeys(), skipThis);
break;
case BuiltinsStubCSigns::ID::TypedArrayValues:
TryInlineTypedArrayIteratorBuiltin(gate, id, circuit_->TypedArrayValues(), skipThis);
break;
case BuiltinsStubCSigns::ID::MathAcos:
TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAcos(), skipThis);
break;
@ -385,6 +398,29 @@ void NativeInlineLowering::TryInlineBigIntAsIntN(GateRef gate, size_t argc, Buil
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret);
}
void NativeInlineLowering::TryInlineTypedArrayIteratorBuiltin(GateRef gate,
BuiltinsStubCSigns::ID id,
const GateMetaData* op, bool skipThis)
{
if (!skipThis) {
return;
}
CallThis0TypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
Environment env(gate, circuit_, &builder_);
if (!Uncheck()) {
builder_.CallTargetCheck(gate, tacc.GetFunc(), builder_.IntPtr(static_cast<int64_t>(id)), {tacc.GetThisObj()});
}
if (EnableTrace()) {
AddTraceLogs(gate, id);
}
GateRef ret = builder_.BuildTypedArrayIterator(acc_.GetValueIn(gate, 0), op);
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret);
}
void NativeInlineLowering::TryInlineMathUnaryBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id,
const GateMetaData* op, bool skipThis)
{

View File

@ -29,9 +29,10 @@
namespace panda::ecmascript::kungfu {
class NativeInlineLowering {
public:
explicit NativeInlineLowering(Circuit *circuit, PassContext *ctx, bool enableLog, const std::string& name)
explicit NativeInlineLowering(Circuit *circuit, CompilationConfig* cmpCfg, PassContext *ctx, bool enableLog,
const std::string& name)
: circuit_(circuit),
builder_(circuit),
builder_(circuit, cmpCfg),
acc_(circuit),
glue_(acc_.GetGlueFromArgList()),
tsManager_(ctx->GetTSManager()),
@ -50,6 +51,8 @@ private:
void TryInlineNumberIsInteger(GateRef gate, size_t argc, bool skipThis);
void TryInlineNumberIsNaN(GateRef gate, size_t argc, bool skipThis);
void TryInlineNumberIsSafeInteger(GateRef gate, size_t argc, bool skipThis);
void TryInlineTypedArrayIteratorBuiltin(GateRef gate, BuiltinsStubCSigns::ID id,
const GateMetaData* op, bool skipThis);
void TryInlineMathUnaryBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, const GateMetaData* op,
bool skipThis);
void TryInlineMathBinaryBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, const GateMetaData* op,

View File

@ -26,6 +26,7 @@
#include "ecmascript/js_thread.h"
#include "ecmascript/lexical_env.h"
#include "ecmascript/mem/mem.h"
#include "ecmascript/js_array_iterator.h"
#include "ecmascript/js_map_iterator.h"
#include "ecmascript/js_set_iterator.h"
#include "ecmascript/js_set.h"
@ -1555,6 +1556,61 @@ template void NewObjectStubBuilder::CreateJSCollectionIterator<JSSetIterator, JS
template void NewObjectStubBuilder::CreateJSCollectionIterator<JSMapIterator, JSMap>(
Variable *result, Label *exit, GateRef set, GateRef kind);
void NewObjectStubBuilder::CreateJSTypedArrayIterator(Variable *result, Label *exit, GateRef thisValue, GateRef kind)
{
auto env = GetEnvironment();
size_ = IntPtr(JSArrayIterator::SIZE);
ConstantIndex iterClassIdx = ConstantIndex::JS_ARRAY_ITERATOR_CLASS_INDEX;
GateRef iteratorHClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, iterClassIdx);
Label thisExists(env);
Label isEcmaObject(env);
Label isTypedArray(env);
Label throwTypeError(env);
BRANCH(BoolOr(TaggedIsHole(thisValue), TaggedIsUndefinedOrNull(thisValue)), &throwTypeError, &thisExists);
Bind(&thisExists);
BRANCH(IsEcmaObject(thisValue), &isEcmaObject, &throwTypeError);
Bind(&isEcmaObject);
BRANCH(IsTypedArray(thisValue), &isTypedArray, &throwTypeError);
Bind(&isTypedArray);
Label noException(env);
// Be careful. NO GC is allowed when initization is not complete.
AllocateInYoung(result, exit, &noException, iteratorHClass);
Bind(&noException);
{
StoreBuiltinHClass(glue_, result->ReadVariable(), iteratorHClass);
SetHash(glue_, result->ReadVariable(), Int64(JSTaggedValue(0).GetRawData()));
auto emptyArray = GetGlobalConstantValue(
VariableType::JS_POINTER(), glue_, ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
SetPropertiesArray(VariableType::INT64(), glue_, result->ReadVariable(), emptyArray);
SetElementsArray(VariableType::INT64(), glue_, result->ReadVariable(), emptyArray);
GateRef iteratorOffset = IntPtr(JSArrayIterator::ITERATED_ARRAY_OFFSET);
Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), iteratorOffset, thisValue,
MemoryOrder::NeedBarrier());
// SetIteratorNextIndex
GateRef nextIndexOffset = IntPtr(JSArrayIterator::NEXT_INDEX_OFFSET);
Store(VariableType::INT32(), glue_, result->ReadVariable(), nextIndexOffset, Int32(0));
// SetIterationKind
GateRef kindBitfieldOffset = IntPtr(JSArrayIterator::BIT_FIELD_OFFSET);
Store(VariableType::INT32(), glue_, result->ReadVariable(), kindBitfieldOffset, kind);
Jump(exit);
}
Bind(&throwTypeError);
{
GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(LenGreaterThanMax));
CallRuntime(glue_, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
result->WriteVariable(Exception());
Jump(exit);
}
}
GateRef NewObjectStubBuilder::NewTaggedSubArray(GateRef glue, GateRef srcTypedArray,
GateRef elementSize, GateRef newLength, GateRef beginIndex, GateRef arrayCls, GateRef buffer)
{

View File

@ -85,6 +85,7 @@ public:
void NewMutantTaggedArrayChecked(Variable *result, GateRef len, Label *exit);
template <typename IteratorType, typename CollectionType>
void CreateJSCollectionIterator(Variable *result, Label *exit, GateRef set, GateRef kind);
void CreateJSTypedArrayIterator(Variable *result, Label *exit, GateRef set, GateRef kind);
GateRef NewTaggedSubArray(GateRef glue, GateRef srcTypedArray, GateRef elementSize, GateRef newLength,
GateRef beginIndex, GateRef arrayCls, GateRef buffer);
GateRef NewTypedArray(GateRef glue, GateRef srcTypedArray, GateRef srcType, GateRef length);

View File

@ -285,6 +285,9 @@ GateRef NumberSpeculativeRetype::VisitGate(GateRef gate)
case OpCode::TYPED_CALL_BUILTIN_SIDE_EFFECT:
case OpCode::MAP_GET:
case OpCode::NEW_NUMBER:
case OpCode::TYPED_ARRAY_ENTRIES:
case OpCode::TYPED_ARRAY_KEYS:
case OpCode::TYPED_ARRAY_VALUES:
return VisitOthers(gate);
default:
return Circuit::NullGate();

View File

@ -551,8 +551,8 @@ public:
}
if (passOptions->EnableInlineNative()) {
NativeInlineLowering nativeInline(data->GetCircuit(), data->GetPassContext(), enableLog,
data->GetMethodName());
NativeInlineLowering nativeInline(data->GetCircuit(), data->GetCompilerConfig(), data->GetPassContext(),
enableLog, data->GetMethodName());
nativeInline.RunNativeInlineLowering();
}
return true;

View File

@ -38,6 +38,10 @@
#include "ecmascript/js_primitive_ref.h"
#include "ecmascript/message_string.h"
#include "macros.h"
#include "ecmascript/compiler/new_object_stub_builder.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_array_iterator.h"
#include "ecmascript/js_iterator.h"
namespace panda::ecmascript::kungfu {
GateRef TypedNativeInlineLowering::VisitGate(GateRef gate)
@ -219,6 +223,18 @@ GateRef TypedNativeInlineLowering::VisitGate(GateRef gate)
case OpCode::DATE_NOW:
LowerGeneralWithoutArgs(gate, RTSTUB_ID(CallDateNow));
break;
case OpCode::TYPED_ARRAY_ENTRIES:
LowerTypedArrayIterator(gate, CommonStubCSigns::CreateJSTypedArrayEntries,
IterationKind::KEY_AND_VALUE);
break;
case OpCode::TYPED_ARRAY_KEYS:
LowerTypedArrayIterator(gate, CommonStubCSigns::CreateJSTypedArrayKeys,
IterationKind::KEY);
break;
case OpCode::TYPED_ARRAY_VALUES:
LowerTypedArrayIterator(gate, CommonStubCSigns::CreateJSTypedArrayValues,
IterationKind::VALUE);
break;
default:
break;
}
@ -265,6 +281,91 @@ void TypedNativeInlineLowering::LowerMathCeilFloorWithRuntimeCall(GateRef gate)
}
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
}
GateRef TypedNativeInlineLowering::AllocateTypedArrayIterator(GateRef glue, GateRef self,
GateRef iteratorHClass,
IterationKind iterationKind)
{
GateRef emptyArray = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
GateRef kind = builder_.Int32(static_cast<int32_t>(iterationKind));
builder_.StartAllocate();
GateRef iterator = builder_.HeapAlloc(glue, builder_.IntPtr(JSArrayIterator::SIZE),
GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
builder_.StoreConstOffset(VariableType::JS_POINTER(), iterator, TaggedObject::HCLASS_OFFSET,
iteratorHClass, MemoryOrder::NeedBarrierAndAtomic());
builder_.StoreConstOffset(VariableType::INT64(), iterator, JSObject::HASH_OFFSET,
builder_.Int64(JSTaggedValue(0).GetRawData()));
builder_.StoreConstOffset(VariableType::INT64(), iterator, JSObject::PROPERTIES_OFFSET, emptyArray);
builder_.StoreConstOffset(VariableType::INT64(), iterator, JSObject::ELEMENTS_OFFSET, emptyArray);
builder_.StoreConstOffset(VariableType::JS_ANY(), iterator, JSArrayIterator::ITERATED_ARRAY_OFFSET, self);
builder_.StoreConstOffset(VariableType::INT32(), iterator, JSArrayIterator::NEXT_INDEX_OFFSET, builder_.Int32(0));
builder_.StoreConstOffset(VariableType::INT32(), iterator, JSArrayIterator::BIT_FIELD_OFFSET, kind);
GateRef result = builder_.FinishAllocate(iterator);
builder_.SubCfgExit();
return result;
}
void TypedNativeInlineLowering::LowerTypedArrayIterator(GateRef gate, CommonStubCSigns::ID index,
IterationKind iterationKind)
{
Environment env(gate, circuit_, &builder_);
GateRef glue = acc_.GetGlueFromArgList();
GateRef self = acc_.GetValueIn(gate, 0);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
Label selfExistsLabel(&env);
Label isHeapObjectLabel(&env);
Label isTypedArrayLabel(&env);
Label selfValidLabel(&env);
Label selfInvalidLabel(&env);
Label exit(&env);
GateRef selfExists = builder_.TaggedIsNotUndefinedAndNullAndHole(self);
BRANCH_CIR(selfExists, &selfExistsLabel, &selfInvalidLabel);
builder_.Bind(&selfExistsLabel);
GateRef isHeapObject = builder_.TaggedIsHeapObject(self);
BRANCH_CIR(isHeapObject, &isHeapObjectLabel, &selfInvalidLabel);
builder_.Bind(&isHeapObjectLabel);
GateRef isTypedArray = builder_.IsTypedArray(self);
BRANCH_CIR(isTypedArray, &isTypedArrayLabel, &selfInvalidLabel);
builder_.Bind(&isTypedArrayLabel);
GateRef hasNoConstructor = builder_.BoolNot(builder_.HasConstructor(self));
BRANCH_CIR(hasNoConstructor, &selfValidLabel, &selfInvalidLabel);
builder_.Bind(&selfValidLabel);
{
GateRef glueGlobalEnvOffset = builder_.IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env.Is32Bit()));
GateRef glueGlobalEnv = builder_.Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
GateRef prototype = builder_.GetGlobalEnvValue(VariableType::JS_POINTER(), glueGlobalEnv,
GlobalEnv::ARRAY_ITERATOR_PROTOTYPE_INDEX);
GateRef iteratorHClass = builder_.GetGlobalConstantValue(ConstantIndex::JS_ARRAY_ITERATOR_CLASS_INDEX);
GateRef offset = builder_.IntPtr(JSHClass::PROTOTYPE_OFFSET);
builder_.Store(VariableType::JS_POINTER(), glue, iteratorHClass, offset, prototype);
result = AllocateTypedArrayIterator(glue, self, iteratorHClass, iterationKind);
builder_.Jump(&exit);
}
builder_.Bind(&selfInvalidLabel);
{
result = builder_.CallStub(glue, gate, index, { glue, self });
builder_.Jump(&exit);
}
builder_.Bind(&exit);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
}
GateRef TypedNativeInlineLowering::LowerGlobalDoubleIsFinite(GateRef value)
{
// set the sign bit to 0 by shift left then right.

View File

@ -110,6 +110,9 @@ private:
void LowerGlobalIsFinite(GateRef gate);
void LowerGlobalIsNan(GateRef gate);
void LowerGeneralWithoutArgs(GateRef gate, RuntimeStubCSigns::ID stubId);
GateRef AllocateTypedArrayIterator(GateRef glue, GateRef self,
GateRef iteratorHClass, IterationKind iterationKind);
void LowerTypedArrayIterator(GateRef gate, CommonStubCSigns::ID index, IterationKind iterationKind);
GateRef LowerGlobalDoubleIsFinite(GateRef value);
GateRef LowerGlobalTNumberIsFinite(GateRef value);

View File

@ -209,6 +209,9 @@ class ObjectFactory;
V(JSTaggedValue, ArrayIteratorProtoNext, ARRAY_ITERATOR_PROTO_NEXT_INDEX, ecma_roots_builtins) \
V(JSTaggedValue, IteratorProtoReturn, ITERATOR_PROTO_RETURN_INDEX, ecma_roots_builtins) \
V(JSTaggedValue, StringFromCharCode, STRING_FROM_CHAR_CODE_INDEX, ecma_roots_builtins) \
V(JSTaggedValue, TypedArrayEntries, TYPED_ARRAY_ENTRIES_INDEX, ecma_roots_special) \
V(JSTaggedValue, TypedArrayKeys, TYPED_ARRAY_KEYS_INDEX, ecma_roots_special) \
V(JSTaggedValue, TypedArrayValues, TYPED_ARRAY_VALUES_INDEX, ecma_roots_special) \
V(JSTaggedValue, ArrayBufferIsView, ARRAY_BUFFER_IS_VIEW_INDEX, ecma_roots_builtins) \
V(JSTaggedValue, DataViewGetFloat32, DATA_VIEW_GET_FLOAT32_INDEX, ecma_roots_builtins) \
V(JSTaggedValue, DataViewGetFloat64, DATA_VIEW_GET_FLOAT64_INDEX, ecma_roots_builtins) \

View File

@ -21,5 +21,6 @@ group("ark_aot_builtin_inlining_test") {
"math:ark_aot_builtin_inlining_math_test",
"number:ark_aot_builtin_inlining_number_test",
"set:ark_aot_builtin_inlining_set_test",
"typedarray:ark_aot_builtin_inlining_typedarray_test",
]
}

View File

@ -0,0 +1,29 @@
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
group("ark_aot_builtin_inlining_typedarray_test") {
testonly = true
test_list = [
"Entries",
"Keys",
"Values",
]
deps = []
foreach(test, test_list) {
deps += [ "${test}:builtinTypedArray${test}AotAction" ]
if (!is_debug) {
deps += [ "${test}:builtinTypedArray${test}AotContextAction" ]
}
}
}

View File

@ -0,0 +1,17 @@
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_builtin_inlining_test_action("builtinTypedArrayEntries") {
}

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
declare interface ArkTools {
isAOTCompiled(args: any): boolean;
}
declare function print(arg: any): string;
function replace(a: any)
{
return a;
}
function getItems(x: any) {
return myArray.entries(x);
}
function printItems(x: any) {
try {
print(getItems(x));
} finally {
}
}
let myArray = new Uint8Array([10, 20, 30]);
//aot: [trace] aot inline builtin: TypedArray.entries, caller function name:func_main_0@builtinTypedArrayEntries
let items0 = myArray.entries();
print(items0); //: [object Array Iterator]
//aot: [trace] aot inline builtin: TypedArray.entries, caller function name:func_main_0@builtinTypedArrayEntries
let items1 = myArray.entries();
print(items1.next().value); //: 0,10
//aot: [trace] aot inline builtin: TypedArray.entries, caller function name:func_main_0@builtinTypedArrayEntries
let items2 = myArray.entries();
items2.next();
print(items2.next().value); //: 1,20
//aot: [trace] aot inline builtin: TypedArray.entries, caller function name:func_main_0@builtinTypedArrayEntries
let items3 = myArray.entries();
items3.next();
items3.next();
print(items3.next().value); //: 2,30
//aot: [trace] aot inline builtin: TypedArray.entries, caller function name:func_main_0@builtinTypedArrayEntries
let items4 = myArray.entries();
items4.next();
items4.next();
items4.next();
print(items4.next().value); //: undefined
// Check own methods
//aot: [trace] aot inline builtin: TypedArray.entries, caller function name:func_main_0@builtinTypedArrayEntries
print(myArray.entries().throw); //: function throw() { [native code] }
//aot: [trace] aot inline builtin: TypedArray.entries, caller function name:func_main_0@builtinTypedArrayEntries
print(myArray.entries().return); //: function return() { [native code] }
// Check using in loop
//aot: [trace] aot inline builtin: TypedArray.entries, caller function name:func_main_0@builtinTypedArrayEntries
for (let item of myArray.entries()) {
print(item);
}
//: 0,10
//: 1,20
//: 2,30
// Replace standard builtin
let restore = myArray.entries
myArray.entries = replace
// no deopt
print(myArray.entries(2.5)); //: 2.5
myArray.entries = restore
if (ArkTools.isAOTCompiled(printItems)) {
// Replace standard builtin after call to standard builtin was profiled
myArray.entries = replace
}
//aot: [trace] Check Type: NotCallTarget1
printItems(2.5); //aot: 2.5
//pgo: [object Array Iterator]
//aot: [trace] Check Type: NotCallTarget1
printItems("abc"); //aot: abc
//pgo: [object Array Iterator]
myArray.entries = restore
// Check IR correctness inside try-block
try {
//aot: [trace] Check Type: NotCallTarget1
printItems(2.5); //: [object Array Iterator]
//aot: [trace] Check Type: NotCallTarget1
printItems("abc"); //: [object Array Iterator]
} catch (e) {
}
// Check using out of boundaries
//aot: [trace] aot inline builtin: TypedArray.entries, caller function name:func_main_0@builtinTypedArrayEntries
let items5 = myArray.entries();
for (let item of items5) {
print(item);
}
//: 0,10
//: 1,20
//: 2,30
// Check reusing possibility
for (let item of items5) {
print(item);
} // <nothing>
print(items5.next().value); //: undefined

View File

@ -0,0 +1,17 @@
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_builtin_inlining_test_action("builtinTypedArrayKeys") {
}

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
declare interface ArkTools {
isAOTCompiled(args: any): boolean;
}
declare function print(arg: any): string;
function replace(a: any)
{
return a;
}
function getItems(x: any) {
return myArray.keys(x);
}
function printItems(x: any) {
try {
print(getItems(x));
} finally {
}
}
let myArray = new Uint8Array([10, 20, 30]);
//aot: [trace] aot inline builtin: TypedArray.keys, caller function name:func_main_0@builtinTypedArrayKeys
let items0 = myArray.keys();
print(items0); //: [object Array Iterator]
//aot: [trace] aot inline builtin: TypedArray.keys, caller function name:func_main_0@builtinTypedArrayKeys
let items1 = myArray.keys();
print(items1.next().value); //: 0
//aot: [trace] aot inline builtin: TypedArray.keys, caller function name:func_main_0@builtinTypedArrayKeys
let items2 = myArray.keys();
items2.next();
print(items2.next().value); //: 1
//aot: [trace] aot inline builtin: TypedArray.keys, caller function name:func_main_0@builtinTypedArrayKeys
let items3 = myArray.keys();
items3.next();
items3.next();
print(items3.next().value); //: 2
//aot: [trace] aot inline builtin: TypedArray.keys, caller function name:func_main_0@builtinTypedArrayKeys
let items4 = myArray.keys();
items4.next();
items4.next();
items4.next();
print(items4.next().value); //: undefined
// Check own methods
//aot: [trace] aot inline builtin: TypedArray.keys, caller function name:func_main_0@builtinTypedArrayKeys
print(myArray.keys().throw); //: function throw() { [native code] }
//aot: [trace] aot inline builtin: TypedArray.keys, caller function name:func_main_0@builtinTypedArrayKeys
print(myArray.keys().return); //: function return() { [native code] }
// Check using in loop
//aot: [trace] aot inline builtin: TypedArray.keys, caller function name:func_main_0@builtinTypedArrayKeys
for (let item of myArray.keys()) {
print(item);
}
//: 0
//: 1
//: 2
// Replace standard builtin
let restore = myArray.keys
myArray.keys = replace
// no deopt
print(myArray.keys(2.5)); //: 2.5
myArray.keys = restore
if (ArkTools.isAOTCompiled(printItems)) {
// Replace standard builtin after call to standard builtin was profiled
myArray.keys = replace
}
//aot: [trace] Check Type: NotCallTarget1
printItems(2.5); //aot: 2.5
//pgo: [object Array Iterator]
//aot: [trace] Check Type: NotCallTarget1
printItems("abc"); //aot: abc
//pgo: [object Array Iterator]
myArray.keys = restore
// Check IR correctness inside try-block
try {
//aot: [trace] Check Type: NotCallTarget1
printItems(2.5); //: [object Array Iterator]
//aot: [trace] Check Type: NotCallTarget1
printItems("abc"); //: [object Array Iterator]
} catch (e) {
}
// Check using out of boundaries
//aot: [trace] aot inline builtin: TypedArray.keys, caller function name:func_main_0@builtinTypedArrayKeys
let items5 = myArray.keys();
for (let item of items5) {
print(item);
}
//: 0
//: 1
//: 2
// Check reusing possibility
for (let item of items5) {
print(item);
} // <nothing>
print(items5.next().value); //: undefined

View File

@ -0,0 +1,17 @@
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_builtin_inlining_test_action("builtinTypedArrayValues") {
}

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
declare interface ArkTools {
isAOTCompiled(args: any): boolean;
}
declare function print(arg: any): string;
function replace(a: any)
{
return a;
}
function getItems(x: any) {
return myArray.values(x);
}
function printItems(x: any) {
try {
print(getItems(x));
} finally {
}
}
let myArray = new Uint8Array([10, 20, 30]);
//aot: [trace] aot inline builtin: TypedArray.values, caller function name:func_main_0@builtinTypedArrayValues
let items0 = myArray.values();
print(items0); //: [object Array Iterator]
//aot: [trace] aot inline builtin: TypedArray.values, caller function name:func_main_0@builtinTypedArrayValues
let items1 = myArray.values();
print(items1.next().value); //: 10
//aot: [trace] aot inline builtin: TypedArray.values, caller function name:func_main_0@builtinTypedArrayValues
let items2 = myArray.values();
items2.next();
print(items2.next().value); //: 20
//aot: [trace] aot inline builtin: TypedArray.values, caller function name:func_main_0@builtinTypedArrayValues
let items3 = myArray.values();
items3.next();
items3.next();
print(items3.next().value); //: 30
//aot: [trace] aot inline builtin: TypedArray.values, caller function name:func_main_0@builtinTypedArrayValues
let items4 = myArray.values();
items4.next();
items4.next();
items4.next();
print(items4.next().value); //: undefined
// Check own methods
//aot: [trace] aot inline builtin: TypedArray.values, caller function name:func_main_0@builtinTypedArrayValues
print(myArray.values().throw); //: function throw() { [native code] }
//aot: [trace] aot inline builtin: TypedArray.values, caller function name:func_main_0@builtinTypedArrayValues
print(myArray.values().return); //: function return() { [native code] }
// Check using in loop
//aot: [trace] aot inline builtin: TypedArray.values, caller function name:func_main_0@builtinTypedArrayValues
for (let item of myArray.values()) {
print(item);
}
//: 10
//: 20
//: 30
// Replace standard builtin
let restore = myArray.values
myArray.values = replace
// no deopt
print(myArray.values(2.5)); //: 2.5
myArray.values = restore
if (ArkTools.isAOTCompiled(printItems)) {
// Replace standard builtin after call to standard builtin was profiled
myArray.values = replace
}
//aot: [trace] Check Type: NotCallTarget1
printItems(2.5); //aot: 2.5
//pgo: [object Array Iterator]
//aot: [trace] Check Type: NotCallTarget1
printItems("abc"); //aot: abc
//pgo: [object Array Iterator]
myArray.values = restore
// Check IR correctness inside try-block
try {
//aot: [trace] Check Type: NotCallTarget1
printItems(2.5); //: [object Array Iterator]
//aot: [trace] Check Type: NotCallTarget1
printItems("abc"); //: [object Array Iterator]
} catch (e) {
}
// Check using out of boundaries
//aot: [trace] aot inline builtin: TypedArray.values, caller function name:func_main_0@builtinTypedArrayValues
let items5 = myArray.values();
for (let item of items5) {
print(item);
}
//: 10
//: 20
//: 30
// Check reusing possibility
for (let item of items5) {
print(item);
} // <nothing>
print(items5.next().value); //: undefined