SR Feature

1. Load and store module variable HIR.
2. New Array constructor inline.

Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8FEHQ
Signed-off-by: ginxu <xujie101@huawei.com>
Change-Id: I63dafdffde9c1c3b1c9f5e8be809ffe675a3635c
This commit is contained in:
ginxu 2023-11-09 17:08:59 +08:00
parent eb701ea45e
commit b429c4d90d
30 changed files with 593 additions and 35 deletions

View File

@ -131,7 +131,8 @@ int Main(const int argc, const char **argv)
cOptions.isEnableCollectLiteralInfo_,
cOptions.isEnableOptConstantFolding_,
cOptions.isEnableLexenvSpecialization_,
cOptions.isEnableNativeInline_);
cOptions.isEnableNativeInline_,
cOptions.isEnableFastModule_);
PassManager passManager(vm,
cOptions.triple_,

View File

@ -59,6 +59,7 @@ CompilationOptions::CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOpti
isEnableCollectLiteralInfo_ = false;
isEnableLexenvSpecialization_ = runtimeOptions.IsEnableLexenvSpecialization();
isEnableNativeInline_ = runtimeOptions.IsEnableNativeInline();
isEnableFastModule_ = runtimeOptions.IsEnableFastModule();
}
bool AotCompilerPreprocessor::HandleTargetCompilerMode(CompilationOptions &cOptions)

View File

@ -64,6 +64,7 @@ struct CompilationOptions {
bool isEnableLexenvSpecialization_;
bool isEnableNativeInline_;
bool isEnablePGOHCRLowering_;
bool isEnableFastModule_;
};
class AotCompilerPreprocessor {

View File

@ -327,6 +327,9 @@ public:
GateRef TypedCallNative(GateRef hirGate, GateRef thisObj, GateRef funcId);
GateRef IsBase(GateRef ctor);
GateRef ToLength(GateRef receiver);
GateRef StoreModuleVar(GateRef jsFunc, GateRef index, GateRef value);
GateRef LdLocalModuleVar(GateRef jsFunc, GateRef index);
GateRef BuiltinConstructor(BuiltinTypeId id, GateRef gate);
inline GateRef GetMethodId(GateRef func);
inline GateRef IsAOTLiteralInfo(GateRef x);
@ -397,6 +400,7 @@ public:
inline void StoreHClass(GateRef glue, GateRef object, GateRef hClass);
GateRef IsStabelArray(GateRef glue, GateRef obj);
inline void StorePrototype(GateRef glue, GateRef hclass, GateRef prototype);
void SetExtensibleToBitfield(GateRef glue, GateRef obj, bool isExtensible);
// WeakRef
inline GateRef CreateWeakRef(GateRef x);
@ -456,6 +460,7 @@ public:
GateRef InsertStableArrayCheck(GateRef array);
GateRef InsertLoadArrayLength(GateRef array, bool isTypedArray);
GateRef InsertTypedArrayCheck(GateType type, GateRef array);
GateRef ArrayConstructorCheck(GateRef gate);
GateRef InsertTypedBinaryop(GateRef left, GateRef right, GateType leftType, GateType rightType,
GateType gateType, PGOTypeRef pgoType, TypedBinOp op);
GateRef InsertRangeCheckPredicate(GateRef left, TypedBinOp cond, GateRef right);

View File

@ -87,6 +87,7 @@ GateRef EarlyElimination::VisitGate(GateRef gate)
case OpCode::ECMA_STRING_CHECK:
case OpCode::BUILTIN_PROTOTYPE_HCLASS_CHECK:
case OpCode::TYPE_OF_CHECK:
case OpCode::ARRAY_CONSTRUCTOR_CHECK:
return TryEliminateGate(gate);
case OpCode::STATE_SPLIT:
return TryEliminateFrameState(gate);
@ -364,6 +365,10 @@ bool EarlyElimination::CheckReplacement(GateRef lhs, GateRef rhs)
}
break;
}
case OpCode::ARRAY_CONSTRUCTOR_CHECK:
if (acc_.GetValueIn(lhs) != acc_.GetValueIn(rhs)) {
return false;
}
default:
break;
}

View File

@ -457,4 +457,70 @@ GateRef CircuitBuilder::IsStabelArray(GateRef glue, GateRef obj)
env_->SubCfgExit();
return res;
}
GateRef CircuitBuilder::StoreModuleVar(GateRef jsFunc, GateRef index, GateRef value)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
GateRef newGate = GetCircuit()->NewGate(circuit_->StoreModuleVar(), MachineType::I64,
{ currentControl, currentDepend, jsFunc, index, value }, GateType::TaggedValue());
currentLabel->SetControl(newGate);
currentLabel->SetDepend(newGate);
return newGate;
}
GateRef CircuitBuilder::LdLocalModuleVar(GateRef jsFunc, GateRef index)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
GateRef newGate = GetCircuit()->NewGate(circuit_->LdLocalModuleVar(), MachineType::I64,
{ currentControl, currentDepend, jsFunc, index}, GateType::TaggedValue());
currentLabel->SetControl(newGate);
currentLabel->SetDepend(newGate);
return newGate;
}
GateRef CircuitBuilder::BuiltinConstructor(BuiltinTypeId id, GateRef gate)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
GateRef newGate = Circuit::NullGate();
switch (id) {
case BuiltinTypeId::ARRAY: {
if (acc_.GetNumValueIn(gate) == 1) {
newGate = GetCircuit()->NewGate(circuit_->ArrayConstructor(1), MachineType::I64,
{ currentControl, currentDepend, acc_.GetValueIn(gate, 0)},
GateType::TaggedValue());
} else {
ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: num value in
newGate = GetCircuit()->NewGate(circuit_->ArrayConstructor(2), MachineType::I64,
{ currentControl, currentDepend, acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)},
GateType::TaggedValue());
}
break;
}
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
break;
}
currentLabel->SetControl(newGate);
currentLabel->SetDepend(newGate);
return newGate;
}
void CircuitBuilder::SetExtensibleToBitfield(GateRef glue, GateRef obj, bool isExtensible)
{
GateRef jsHclass = LoadHClass(obj);
GateRef bitfield = Load(VariableType::INT32(), jsHclass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
GateRef boolVal = Boolean(isExtensible);
GateRef boolToInt32 = ZExtInt1ToInt32(boolVal);
GateRef encodeValue = Int32LSL(boolToInt32, Int32(JSHClass::ExtensibleBit::START_BIT));
GateRef mask = Int32(((1LU << JSHClass::ExtensibleBit::SIZE) - 1) << JSHClass::ExtensibleBit::START_BIT);
bitfield = Int32Or(Int32And(bitfield, Int32Not(mask)), encodeValue);
Store(VariableType::INT32(), glue, jsHclass, IntPtr(JSHClass::BIT_FIELD_OFFSET), bitfield);
}
}

View File

@ -19,7 +19,10 @@
namespace panda::ecmascript::kungfu {
#define HCR_IMMUTABLE_META_DATA_CACHE_LIST(V) \
V(ToLength, TO_LENGTH, GateFlags::NONE_FLAG, 1, 1, 1)
V(ToLength, TO_LENGTH, GateFlags::NONE_FLAG, 1, 1, 1) \
V(StoreModuleVar, STORE_MODULE_VAR, GateFlags::NONE_FLAG, 1, 1, 3) \
V(LdLocalModuleVar, LD_LOCAL_MODULE_VAR, GateFlags::NONE_FLAG, 1, 1, 2)
#define HCR_GATE_META_DATA_LIST_WITH_VALUE_IN(V) \
V(Call, CALL, GateFlags::NONE_FLAG, 0, 1, value) \
@ -30,7 +33,8 @@ namespace panda::ecmascript::kungfu {
V(BuiltinsCall, BUILTINS_CALL, GateFlags::NONE_FLAG, 0, 1, value) \
V(RuntimeCall, RUNTIME_CALL, GateFlags::NONE_FLAG, 0, 1, value) \
V(RuntimeCallWithArgv, RUNTIME_CALL_WITH_ARGV, GateFlags::NONE_FLAG, 0, 1, value) \
V(SaveRegister, SAVE_REGISTER, GateFlags::NONE_FLAG, 0, 1, value)
V(SaveRegister, SAVE_REGISTER, GateFlags::NONE_FLAG, 0, 1, value) \
V(ArrayConstructor, ARRAY_CONSTRUCTOR, GateFlags::NONE_FLAG, 1, 1, value)
#define HCR_GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \
V(Construct, CONSTRUCT, GateFlags::HAS_FRAME_STATE, 1, 1, value)

View File

@ -1198,4 +1198,17 @@ GateRef CircuitBuilder::NeedCheckProperty(GateRef receiver)
SubCfgExit();
return ret;
}
GateRef CircuitBuilder::ArrayConstructorCheck(GateRef gate)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto frameState = acc_.FindNearestFrameState(currentDepend);
GateRef ret = GetCircuit()->NewGate(circuit_->ArrayConstructorCheck(),
MachineType::I64, {currentControl, currentDepend, gate, frameState}, GateType::IntType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);
return ret;
}
}

View File

@ -50,6 +50,7 @@ namespace panda::ecmascript::kungfu {
V(TypedNewAllocateThis, TYPED_NEW_ALLOCATE_THIS, GateFlags::CHECKABLE, 1, 1, 2) \
V(TypedSuperAllocateThis, TYPED_SUPER_ALLOCATE_THIS, GateFlags::CHECKABLE, 1, 1, 2) \
V(InlineAccessorCheck, INLINE_ACCESSOR_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(ArrayConstructorCheck, ARRAY_CONSTRUCTOR_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
MCR_BINARY_GATE_META_DATA_CACHE_LIST(V)
#define MCR_GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \

View File

@ -75,6 +75,14 @@ void NTypeBytecodeLowering::Lower(GateRef gate)
case EcmaOpcode::WIDE_STLEXVAR_PREF_IMM16_IMM16:
LowerStLexVar(gate);
break;
case EcmaOpcode::LDLOCALMODULEVAR_IMM8:
case EcmaOpcode::WIDE_LDLOCALMODULEVAR_PREF_IMM16:
LowerLdLocalMoudleVar(gate);
break;
case EcmaOpcode::STMODULEVAR_IMM8:
case EcmaOpcode::WIDE_STMODULEVAR_PREF_IMM16:
LowerStModuleVar(gate);
break;
default:
break;
}
@ -82,6 +90,7 @@ void NTypeBytecodeLowering::Lower(GateRef gate)
void NTypeBytecodeLowering::LowerThrowUndefinedIfHoleWithName(GateRef gate)
{
AddProfiling(gate);
GateRef value = acc_.GetValueIn(gate, 1); // 1: the second parameter
builder_.LexVarIsHoleCheck(value);
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
@ -233,4 +242,29 @@ void NTypeBytecodeLowering::AddProfiling(GateRef gate)
builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: profiling or STATE_SPLIT
}
}
void NTypeBytecodeLowering::LowerLdLocalMoudleVar(GateRef gate)
{
if (!IsFastModule()) {
return;
}
AddProfiling(gate);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef index = acc_.GetValueIn(gate, 0);
GateRef result = builder_.LdLocalModuleVar(jsFunc, index);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
void NTypeBytecodeLowering::LowerStModuleVar(GateRef gate)
{
if (!IsFastModule()) {
return;
}
AddProfiling(gate);
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef index = acc_.GetValueIn(gate, 0);
GateRef value = acc_.GetValueIn(gate, 1);
builder_.StoreModuleVar(jsFunc, index, value);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
}

View File

@ -26,7 +26,7 @@ namespace panda::ecmascript::kungfu {
class NTypeBytecodeLowering {
public:
NTypeBytecodeLowering(Circuit *circuit, PassContext *ctx, TSManager *tsManager,
bool enableLog, const std::string& name)
bool enableLog, const std::string& name, bool fastModule)
: circuit_(circuit),
acc_(circuit),
builder_(circuit, ctx->GetCompilerConfig()),
@ -37,7 +37,9 @@ public:
profiling_(ctx->GetCompilerConfig()->IsProfiling()),
traceBc_(ctx->GetCompilerConfig()->IsTraceBC()),
methodName_(name),
glue_(acc_.GetGlueFromArgList()) {}
glue_(acc_.GetGlueFromArgList()),
argAcc_(circuit),
fastModule_(fastModule) {}
~NTypeBytecodeLowering() = default;
@ -50,6 +52,8 @@ private:
void LowerLdLexVar(GateRef gate);
void LowerStLexVar(GateRef gate);
void LowerThrowUndefinedIfHoleWithName(GateRef gate);
void LowerLdLocalMoudleVar(GateRef gate);
void LowerStModuleVar(GateRef gate);
bool IsLogEnabled() const
{
@ -66,6 +70,11 @@ private:
return traceBc_;
}
bool IsFastModule() const
{
return fastModule_;
}
const std::string& GetMethodName() const
{
return methodName_;
@ -83,6 +92,8 @@ private:
bool traceBc_ {false};
std::string methodName_;
GateRef glue_ {Circuit::NullGate()};
ArgumentAccessor argAcc_;
bool fastModule_;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_NTYPE_BYTECODE_LOWERING_H

View File

@ -30,6 +30,12 @@ GateRef NTypeHCRLowering::VisitGate(GateRef gate)
case OpCode::CREATE_ARRAY_WITH_BUFFER:
LowerCreateArrayWithBuffer(gate, glue);
break;
case OpCode::STORE_MODULE_VAR:
LowerStoreModuleVar(gate, glue);
break;
case OpCode::LD_LOCAL_MODULE_VAR:
LowerLdLocalModuleVar(gate);
break;
default:
break;
}
@ -199,4 +205,126 @@ GateRef NTypeHCRLowering::LowerCallRuntime(GateRef glue, GateRef hirGate, int in
return result;
}
}
void NTypeHCRLowering::LowerStoreModuleVar(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef jsFunc = acc_.GetValueIn(gate, 0);
GateRef index = acc_.GetValueIn(gate, 1);
GateRef value = acc_.GetValueIn(gate, 2);
GateRef method = builder_.GetMethodFromFunction(jsFunc);
GateRef moduleOffset = builder_.IntPtr(Method::ECMA_MODULE_OFFSET);
GateRef module = builder_.Load(VariableType::JS_ANY(), method, moduleOffset);
GateRef localExportEntriesOffset = builder_.IntPtr(SourceTextModule::LOCAL_EXPORT_ENTTRIES_OFFSET);
GateRef localExportEntries = builder_.Load(VariableType::JS_ANY(), module, localExportEntriesOffset);
GateRef nameDictionaryOffset = builder_.IntPtr(SourceTextModule::NAME_DICTIONARY_OFFSET);
GateRef data = builder_.Load(VariableType::JS_ANY(), module, nameDictionaryOffset);
DEFVALUE(array, (&builder_), VariableType::JS_ANY(), data);
Label dataIsUndefined(&builder_);
Label exit(&builder_);
builder_.Branch(builder_.TaggedIsUndefined(data), &dataIsUndefined, &exit);
builder_.Bind(&dataIsUndefined);
{
GateRef size = builder_.GetLengthOfTaggedArray(localExportEntries);
Label fastpath(&builder_);
Label slowPath(&builder_);
Label finishNew(&builder_);
builder_.Branch(builder_.Int32LessThan(size, builder_.Int32(MAX_TAGGED_ARRAY_LENGTH)), &fastpath, &slowPath);
builder_.Bind(&fastpath);
{
array = NewTaggedArray(size);
builder_.Jump(&finishNew);
}
builder_.Bind(&slowPath);
{
array = LowerCallRuntime(glue, gate, RTSTUB_ID(NewTaggedArray), { builder_.Int32ToTaggedInt(size) }, true);
builder_.Jump(&finishNew);
}
builder_.Bind(&finishNew);
{
builder_.StoreConstOffset(VariableType::JS_ANY(), module, SourceTextModule::NAME_DICTIONARY_OFFSET, *array);
builder_.Jump(&exit);
}
}
builder_.Bind(&exit);
GateRef dataOffset = builder_.Int32(TaggedArray::DATA_OFFSET);
GateRef indexOffset = builder_.Int32Mul(index, builder_.Int32(JSTaggedValue::TaggedTypeSize()));
GateRef offset = builder_.Int32Add(indexOffset, dataOffset);
builder_.Store(VariableType::JS_ANY(), glue_, *array, offset, value);
ReplaceGateWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
GateRef NTypeHCRLowering::NewTaggedArray(GateRef length)
{
Label subentry(&builder_);
builder_.SubCfgEntry(&subentry);
Label exit(&builder_);
DEFVALUE(array, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
GateRef hclass = builder_.GetGlobalConstantValue(ConstantIndex::ARRAY_CLASS_INDEX);
GateRef size = builder_.ComputeTaggedArraySize(builder_.ZExtInt32ToPtr(length));
builder_.StartAllocate();
array = builder_.HeapAlloc(size, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
builder_.StoreConstOffset(VariableType::JS_POINTER(), *array, 0, hclass);
builder_.StoreConstOffset(VariableType::JS_ANY(), *array, TaggedArray::LENGTH_OFFSET,
builder_.Int32ToTaggedInt(length));
GateRef dataOffset = builder_.Int32(TaggedArray::DATA_OFFSET);
GateRef offset = builder_.Int32Mul(length, builder_.Int32(JSTaggedValue::TaggedTypeSize()));
GateRef endOffset = builder_.Int32Add(offset, builder_.Int32(TaggedArray::DATA_OFFSET));
Label loopHead(&builder_);
Label loopEnd(&builder_);
DEFVALUE(startOffset, (&builder_), VariableType::INT32(), dataOffset);
builder_.Branch(builder_.Int32UnsignedLessThan(*startOffset, endOffset), &loopHead, &exit);
builder_.LoopBegin(&loopHead);
builder_.Store(VariableType::INT64(), glue_, *array, *startOffset, builder_.Hole());
startOffset = builder_.Int32Add(*startOffset, builder_.Int32(JSTaggedValue::TaggedTypeSize()));
builder_.Branch(builder_.Int32UnsignedLessThan(*startOffset, endOffset), &loopEnd, &exit);
builder_.Bind(&loopEnd);
builder_.LoopEnd(&loopHead);
builder_.Bind(&exit);
builder_.FinishAllocate();
auto ret = *array;
builder_.SubCfgExit();
return ret;
}
void NTypeHCRLowering::LowerLdLocalModuleVar(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
GateRef jsFunc = acc_.GetValueIn(gate, 0);
GateRef index = acc_.GetValueIn(gate, 1);
GateRef method = builder_.GetMethodFromFunction(jsFunc);
GateRef moduleOffset = builder_.IntPtr(Method::ECMA_MODULE_OFFSET);
GateRef module = builder_.Load(VariableType::JS_ANY(), method, moduleOffset);
GateRef nameDictionaryOffset = builder_.IntPtr(SourceTextModule::NAME_DICTIONARY_OFFSET);
GateRef dictionary = builder_.Load(VariableType::JS_ANY(), module, nameDictionaryOffset);
DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
Label dataIsNotUndefined(&builder_);
Label exit(&builder_);
builder_.Branch(builder_.TaggedIsUndefined(dictionary), &exit, &dataIsNotUndefined);
builder_.Bind(&dataIsNotUndefined);
{
GateRef dataOffset = builder_.Int32(TaggedArray::DATA_OFFSET);
GateRef indexOffset = builder_.Int32Mul(index, builder_.Int32(JSTaggedValue::TaggedTypeSize()));
GateRef offset = builder_.Int32Add(indexOffset, dataOffset);
result = builder_.Load(VariableType::JS_ANY(), dictionary, offset);
builder_.Jump(&exit);
}
builder_.Bind(&exit);
ReplaceGateWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), *result);
}
void NTypeHCRLowering::ReplaceGateWithPendingException(GateRef gate, GateRef state, GateRef depend, GateRef value)
{
auto condition = builder_.HasPendingException(glue_);
GateRef ifBranch = builder_.Branch(state, condition);
GateRef ifTrue = builder_.IfTrue(ifBranch);
GateRef ifFalse = builder_.IfFalse(ifBranch);
GateRef eDepend = builder_.DependRelay(ifTrue, depend);
GateRef sDepend = builder_.DependRelay(ifFalse, depend);
StateDepend success(ifFalse, sDepend);
StateDepend exception(ifTrue, eDepend);
acc_.ReplaceHirWithIfBranch(gate, success, exception, value);
}
}

View File

@ -46,15 +46,17 @@ private:
void LowerCreateArrayWithBuffer(GateRef gate, GateRef glue);
void LowerCreateEmptyArray(GateRef gate);
void LowerCreateArrayWithOwn(GateRef gate, GateRef glue);
void LowerStLexVar(GateRef gate);
void LowerLdLexVar(GateRef gate);
void LowerStoreModuleVar(GateRef gate, GateRef glue);
void LowerLdLocalModuleVar(GateRef gate);
GateRef LoadFromConstPool(GateRef jsFunc, size_t index, size_t valVecType);
GateRef NewJSArrayLiteral(GateRef gate, GateRef elements, GateRef length);
GateRef NewTaggedArray(size_t length);
GateRef NewTaggedArray(GateRef length);
GateRef CreateElementsWithLength(GateRef gate, GateRef glue, size_t arrayLength);
GateRef LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
bool useLabel = false);
void ReplaceGateWithPendingException(GateRef gate, GateRef state, GateRef depend, GateRef value);
GateRef GetFrameState(GateRef gate) const
{

View File

@ -143,6 +143,8 @@ GateRef NumberSpeculativeRetype::VisitGate(GateRef gate)
case OpCode::STORE_CONST_OFFSET:
case OpCode::LEX_VAR_IS_HOLE_CHECK:
case OpCode::TYPE_OF_CHECK:
// case OpCode::ARRAY_CONSTRUCTOR:
case OpCode::LD_LOCAL_MODULE_VAR:
return VisitOthers(gate);
default:
return Circuit::NullGate();

View File

@ -299,7 +299,7 @@ public:
bool enableLog = data->GetLog()->EnableMethodCIRLog();
bool enableTypeLog = data->GetLog()->GetEnableMethodLog() && data->GetLog()->OutputType();
TypeBytecodeLowering lowering(data->GetCircuit(), data->GetPassContext(),
enableLog, enableTypeLog, data->GetMethodName());
enableLog, enableTypeLog, data->GetMethodName(), passOptions->EnableFastModule());
bool success = lowering.RunTypeBytecodeLowering();
if (!success) {
data->MarkAsTypeAbort();
@ -329,7 +329,7 @@ public:
TimeScope timescope("NTypeBytecodeLoweringPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
bool enableLog = data->GetLog()->EnableMethodCIRLog();
NTypeBytecodeLowering lowering(data->GetCircuit(), data->GetPassContext(), data->GetTSManager(),
enableLog, data->GetMethodName());
enableLog, data->GetMethodName(), passOptions->EnableFastModule());
lowering.RunNTypeBytecodeLowering();
Chunk chunk(data->GetNativeAreaAllocator());
CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk);

View File

@ -135,7 +135,8 @@ public:
bool enableLaterElimination, bool enableValueNumbering, bool enableTypeInfer,
bool enableOptInlining, bool enableOptPGOType, bool enableOptTrackField, bool enableOptLoopPeeling,
bool enableOptOnHeapCheck, bool enableOptLoopInvariantCodeMotion, bool enableCollectLiteralInfo,
bool enableOptConstantFolding, bool enableLexenvSpecialization, bool enableInlineNative)
bool enableOptConstantFolding, bool enableLexenvSpecialization, bool enableInlineNative,
bool enableFastModule)
: enableArrayBoundsCheckElimination_(enableArrayBoundsCheckElimination),
enableTypeLowering_(enableTypeLowering),
enableEarlyElimination_(enableEarlyElimination),
@ -151,7 +152,8 @@ public:
enableCollectLiteralInfo_(enableCollectLiteralInfo),
enableOptConstantFolding_(enableOptConstantFolding),
enableLexenvSpecialization_(enableLexenvSpecialization),
enableInlineNative_(enableInlineNative)
enableInlineNative_(enableInlineNative),
enableFastModule_(enableFastModule)
{
}
@ -173,7 +175,8 @@ public:
V(CollectLiteralInfo, false) \
V(OptConstantFolding, true) \
V(LexenvSpecialization, false) \
V(InlineNative, false)
V(InlineNative, false) \
V(FastModule, false)
#define DECL_OPTION(NAME, DEFAULT) \
public: \

View File

@ -72,6 +72,7 @@ enum class TypedCallTargetCheckOp : uint8_t;
V(IteratorFunctionDisMactch, ITERATORFUNCTIONDISMATCH) \
V(NativeCallTargetDisMatch, NATIVECALLTARGETDISMATCH) \
V(ProtoTypeChanged, PROTOTYPECHANGED) \
V(NewBuiltinCtorFail, NEWBUILTINCTORFAIL) \
enum class DeoptType : uint8_t {
NOTCHECK = 0,

View File

@ -200,7 +200,7 @@ inline GateRef StubBuilder::CallRuntime(GateRef glue, int index, const std::init
SavePcIfNeeded(glue);
const std::string name = RuntimeStubCSigns::GetRTName(index);
GateRef result = env_->GetBuilder()->CallRuntime(glue, index, Gate::InvalidGateRef, args,
Circuit::NullGate(), name.c_str());
glue, name.c_str());
return result;
}

View File

@ -283,6 +283,7 @@ void TypeBytecodeLowering::Lower(GateRef gate)
case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
LowerTypedNewObjRange(gate);
break;
case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
@ -1472,27 +1473,33 @@ void TypeBytecodeLowering::LowerTypedNewObjRange(GateRef gate)
{
GateRef ctor = acc_.GetValueIn(gate, 0);
GateType ctorType = acc_.GetGateType(ctor);
if (!tsManager_->IsClassTypeKind(ctorType)) {
return;
GlobalTSTypeRef ctorGT = ctorType.GetGTRef();
if (ctorGT.IsBuiltinModule()) {
if (TryLowerNewBuiltinConstructor(gate)) {
return;
}
}
}
AddProfiling(gate);
int hclassIndex = tsManager_->GetHClassIndexByClassGateType(ctorType);
GateRef stateSplit = acc_.GetDep(gate);
GateRef frameState = acc_.FindNearestFrameState(stateSplit);
GateRef thisObj = builder_.TypedNewAllocateThis(ctor, builder_.IntPtr(hclassIndex), frameState);
// call constructor
size_t range = acc_.GetNumValueIn(gate);
GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(range, EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
std::vector<GateRef> args { glue_, actualArgc, ctor, ctor, thisObj };
for (size_t i = 1; i < range; ++i) { // 1:skip ctor
args.emplace_back(acc_.GetValueIn(gate, i));
bool TypeBytecodeLowering::TryLowerNewBuiltinConstructor(GateRef gate)
{
GateRef ctor = acc_.GetValueIn(gate, 0);
GateType ctorType = acc_.GetGateType(ctor);
GlobalTSTypeRef ctorGT = ctorType.GetGTRef();
GateRef constructGate = Circuit::NullGate();
if (tsManager_->IsBuiltinConstructor(BuiltinTypeId::ARRAY, ctorGT) && enableNewArrayInline_) {
if (acc_.GetNumValueIn(gate) <= 2) { // 2: ctor and first arg
if (!Uncheck()) {
builder_.ArrayConstructorCheck(ctor);
}
constructGate = builder_.BuiltinConstructor(BuiltinTypeId::ARRAY, gate);
}
}
if (constructGate == Circuit::NullGate()) {
return false;
}
GateRef constructGate = builder_.Construct(gate, args);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
return true;
}
void TypeBytecodeLowering::LowerTypedSuperCall(GateRef gate)

View File

@ -29,7 +29,7 @@ class TypeBytecodeLowering {
public:
TypeBytecodeLowering(Circuit *circuit, PassContext *ctx,
bool enableLog, bool enableTypeLog,
const std::string& name)
const std::string& name, bool enableNewArrayInline)
: circuit_(circuit),
acc_(circuit),
builder_(circuit, ctx->GetCompilerConfig()),
@ -45,7 +45,8 @@ public:
argAcc_(circuit),
pgoTypeLog_(circuit),
noCheck_(ctx->GetEcmaVM()->GetJSOptions().IsCompilerNoCheck()),
thread_(ctx->GetEcmaVM()->GetJSThread()) {}
thread_(ctx->GetEcmaVM()->GetJSThread()),
enableNewArrayInline_(enableNewArrayInline) {}
~TypeBytecodeLowering() = default;
@ -172,6 +173,7 @@ private:
BuiltinsStubCSigns::ID GetBuiltinId(BuiltinTypeId id, GateRef func);
BuiltinsStubCSigns::ID GetPGOBuiltinId(GateRef gate);
void DeleteConstDataIfNoUser(GateRef gate);
bool TryLowerNewBuiltinConstructor(GateRef gate);
void AddProfiling(GateRef gate);
@ -202,6 +204,7 @@ private:
std::unordered_map<EcmaOpcode, uint32_t> bytecodeHitTimeMap_;
bool noCheck_ {false};
const JSThread *thread_ {nullptr};
bool enableNewArrayInline_ {false};
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_TYPE_BYTECODE_LOWERING_H

View File

@ -138,6 +138,12 @@ GateRef TypeHCRLowering::VisitGate(GateRef gate)
case OpCode::TYPE_OF:
LowerTypeOf(gate, glue);
break;
case OpCode::ARRAY_CONSTRUCTOR_CHECK:
LowerArrayConstructorCheck(gate, glue);
break;
case OpCode::ARRAY_CONSTRUCTOR:
LowerArrayConstructor(gate, glue);
break;
default:
break;
}
@ -1801,4 +1807,164 @@ void TypeHCRLowering::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 TypeHCRLowering::LowerArrayConstructorCheck(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
GateRef frameState = GetFrameState(gate);
GateRef newTarget = acc_.GetValueIn(gate, 0);
Label isHeapObject(&builder_);
Label exit(&builder_);
DEFVALUE(check, (&builder_), VariableType::BOOL(), builder_.True());
check = builder_.TaggedIsHeapObject(newTarget);
builder_.Branch(*check, &isHeapObject, &exit);
builder_.Bind(&isHeapObject);
{
Label isJSFunction(&builder_);
check = builder_.IsJSFunction(newTarget);
builder_.Branch(*check, &isJSFunction, &exit);
builder_.Bind(&isJSFunction);
{
Label getHclass(&builder_);
GateRef glueGlobalEnvOffset = builder_.IntPtr(
JSThread::GlueData::GetGlueGlobalEnvOffset(builder_.GetCurrentEnvironment()->Is32Bit()));
GateRef glueGlobalEnv = builder_.Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
GateRef arrayFunc =
builder_.GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
check = builder_.Equal(arrayFunc, newTarget);
builder_.Branch(*check, &getHclass, &exit);
builder_.Bind(&getHclass);
{
GateRef intialHClass = builder_.Load(VariableType::JS_ANY(), newTarget,
builder_.IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
check = builder_.IsJSHClass(intialHClass);
builder_.Jump(&exit);
}
}
}
builder_.Bind(&exit);
builder_.DeoptCheck(*check, frameState, DeoptType::NEWBUILTINCTORFAIL);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
void TypeHCRLowering::LowerArrayConstructor(GateRef gate, GateRef glue)
{
Environment env(gate, circuit_, &builder_);
if (acc_.GetNumValueIn(gate) == 1) {
NewArrayConstructorWithNoArgs(gate, glue);
return;
}
ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: new target and arg0
DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
Label slowPath(&builder_);
Label exit(&builder_);
GateRef newTarget = acc_.GetValueIn(gate, 0);
GateRef arg0 = acc_.GetValueIn(gate, 1);
GateRef intialHClass =
builder_.Load(VariableType::JS_ANY(), newTarget, builder_.IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
DEFVALUE(arrayLength, (&builder_), VariableType::INT64(), builder_.Int64(0));
Label argIsNumber(&builder_);
Label arrayCreate(&builder_);
builder_.Branch(builder_.TaggedIsNumber(arg0), &argIsNumber, &slowPath);
builder_.Bind(&argIsNumber);
{
Label argIsInt(&builder_);
Label argIsDouble(&builder_);
builder_.Branch(builder_.TaggedIsInt(arg0), &argIsInt, &argIsDouble);
builder_.Bind(&argIsInt);
{
Label validIntLength(&builder_);
GateRef intLen = builder_.GetInt64OfTInt(arg0);
GateRef isGEZero = builder_.Int64GreaterThanOrEqual(intLen, builder_.Int64(0));
GateRef isLEMaxLen = builder_.Int64LessThanOrEqual(intLen, builder_.Int64(JSArray::MAX_ARRAY_INDEX));
builder_.Branch(builder_.BoolAnd(isGEZero, isLEMaxLen), &validIntLength, &slowPath);
builder_.Bind(&validIntLength);
{
arrayLength = intLen;
builder_.Jump(&arrayCreate);
}
}
builder_.Bind(&argIsDouble);
{
Label validDoubleLength(&builder_);
Label GetDoubleToIntValue(&builder_);
GateRef doubleLength = builder_.GetDoubleOfTDouble(arg0);
GateRef doubleToInt = builder_.DoubleToInt(doubleLength, &GetDoubleToIntValue);
GateRef intToDouble = builder_.CastInt64ToFloat64(builder_.SExtInt32ToInt64(doubleToInt));
GateRef doubleEqual = builder_.DoubleEqual(doubleLength, intToDouble);
GateRef doubleLEMaxLen =
builder_.DoubleLessThanOrEqual(doubleLength, builder_.Double(JSArray::MAX_ARRAY_INDEX));
builder_.Branch(builder_.BoolAnd(doubleEqual, doubleLEMaxLen), &validDoubleLength, &slowPath);
builder_.Bind(&validDoubleLength);
{
arrayLength = builder_.SExtInt32ToInt64(doubleToInt);
builder_.Jump(&arrayCreate);
}
}
}
builder_.Bind(&arrayCreate);
{
Label lengthValid(&builder_);
builder_.Branch(
builder_.Int64GreaterThan(*arrayLength, builder_.Int64(JSObject::MAX_GAP)), &slowPath, &lengthValid);
builder_.Bind(&lengthValid);
{
NewObjectStubBuilder newBuilder(builder_.GetCurrentEnvironment());
newBuilder.SetParameters(glue, 0);
res = newBuilder.NewJSArrayWithSize(intialHClass, *arrayLength);
GateRef lengthOffset = builder_.IntPtr(JSArray::LENGTH_OFFSET);
builder_.Store(VariableType::INT32(), glue, *res, lengthOffset, builder_.TruncInt64ToInt32(*arrayLength));
GateRef accessor = builder_.GetGlobalConstantValue(ConstantIndex::ARRAY_LENGTH_ACCESSOR);
builder_.SetPropertyInlinedProps(glue, *res, intialHClass, accessor,
builder_.Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX), VariableType::JS_ANY());
builder_.SetExtensibleToBitfield(glue, *res, true);
builder_.Jump(&exit);
}
}
builder_.Bind(&slowPath);
{
size_t range = acc_.GetNumValueIn(gate);
std::vector<GateRef> args(range);
for (size_t i = 0; i < range; ++i) {
args[i] = acc_.GetValueIn(gate, i);
}
res = LowerCallRuntime(glue, gate, RTSTUB_ID(OptNewObjRange), args, true);
builder_.Jump(&exit);
}
builder_.Bind(&exit);
ReplaceGateWithPendingException(glue, gate, builder_.GetState(), builder_.GetDepend(), *res);
}
void TypeHCRLowering::NewArrayConstructorWithNoArgs(GateRef gate, GateRef glue)
{
GateRef newTarget = acc_.GetValueIn(gate, 0);
GateRef intialHClass =
builder_.Load(VariableType::JS_ANY(), newTarget, builder_.IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
GateRef arrayLength = builder_.Int64(0);
NewObjectStubBuilder newBuilder(builder_.GetCurrentEnvironment());
newBuilder.SetParameters(glue, 0);
GateRef res = newBuilder.NewJSArrayWithSize(intialHClass, arrayLength);
GateRef lengthOffset = builder_.IntPtr(JSArray::LENGTH_OFFSET);
builder_.Store(VariableType::INT32(), glue, res, lengthOffset, builder_.TruncInt64ToInt32(arrayLength));
GateRef accessor = builder_.GetGlobalConstantValue(ConstantIndex::ARRAY_LENGTH_ACCESSOR);
builder_.SetPropertyInlinedProps(glue, res, intialHClass, accessor,
builder_.Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX), VariableType::JS_ANY());
builder_.SetExtensibleToBitfield(glue, res, true);
ReplaceGateWithPendingException(glue, gate, builder_.GetState(), builder_.GetDepend(), res);
}
void TypeHCRLowering::ReplaceGateWithPendingException(GateRef glue, GateRef gate, GateRef state, GateRef depend,
GateRef value)
{
auto condition = builder_.HasPendingException(glue);
GateRef ifBranch = builder_.Branch(state, condition);
GateRef ifTrue = builder_.IfTrue(ifBranch);
GateRef ifFalse = builder_.IfFalse(ifBranch);
GateRef eDepend = builder_.DependRelay(ifTrue, depend);
GateRef sDepend = builder_.DependRelay(ifFalse, depend);
StateDepend success(ifFalse, sDepend);
StateDepend exception(ifTrue, eDepend);
acc_.ReplaceHirWithIfBranch(gate, success, exception, value);
}
} // namespace panda::ecmascript::kungfu

View File

@ -188,6 +188,10 @@ private:
void LowerStringAdd(GateRef gate, GateRef glue);
void LowerTypeOfCheck(GateRef gate);
void LowerTypeOf(GateRef gate, GateRef glue);
void LowerArrayConstructorCheck(GateRef gate, GateRef glue);
void NewArrayConstructorWithNoArgs(GateRef gate, GateRef glue);
void LowerArrayConstructor(GateRef gate, GateRef glue);
void ReplaceGateWithPendingException(GateRef glue, GateRef gate, GateRef state, GateRef depend, GateRef value);
GateRef LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
bool useLabel = false);

View File

@ -154,6 +154,7 @@ const std::string PUBLIC_API HELP_OPTION_MSG =
"--compiler-enable-external-pkg Enable compile with external package for ark aot compiler\n"
"--compiler-enable-lexenv-specialization: Enable replace ldlexvar with specific values: Default: 'true'\n"
"--compiler-enable-native-inline: Enable inline native function: Default: 'false'\n"
"--compiler-enable-fast-module: Enable fast module bytecode: Default: 'false'\n"
"--compiler-opt-array-onheap-check: Enable TypedArray on heap check for aot compiler: Default: 'false'\n\n";
bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
@ -246,7 +247,8 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
{"compiler-enable-external-pkg", required_argument, nullptr, OPTION_COMPILER_ENABLE_EXTERNAL_PKG},
{"compiler-enable-lexenv-specialization", required_argument, nullptr,
OPTION_COMPILER_ENABLE_LEXENV_SPECIALIZATION},
{"compiler-enable-native-inline", required_argument, nullptr, OPTION_COMPILER_ENBALE_NATIVE_INLINE},
{"compiler-enable-native-inline", required_argument, nullptr, OPTION_COMPILER_ENABLE_NATIVE_INLINE},
{"compiler-enable-fast-module", required_argument, nullptr, OPTION_COMPILER_ENABLE_FAST_MODULE},
{nullptr, 0, nullptr, 0},
};
@ -840,7 +842,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
return false;
}
break;
case OPTION_COMPILER_ENBALE_NATIVE_INLINE:
case OPTION_COMPILER_ENABLE_NATIVE_INLINE:
ret = ParseBoolParam(&argBool);
if (ret) {
SetEnableNativeInline(argBool);
@ -848,6 +850,15 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
return false;
}
break;
case OPTION_COMPILER_ENABLE_FAST_MODULE:
ret = ParseBoolParam(&argBool);
if (ret) {
SetEnableFastModule(argBool);
} else {
return false;
}
break;
default:
LOG_ECMA(ERROR) << "Invalid option\n";
return false;

View File

@ -150,7 +150,8 @@ enum CommandValues {
OPTION_COMPILER_TRACE_VALUE_NUMBERING,
OPTION_COMPILER_OPT_INSTRUCTIONE_COMBINE,
OPTION_COMPILER_OPT_NEW_VALUE_NUMBERING,
OPTION_COMPILER_ENBALE_NATIVE_INLINE,
OPTION_COMPILER_ENABLE_NATIVE_INLINE,
OPTION_COMPILER_ENABLE_FAST_MODULE
};
class PUBLIC_API JSRuntimeOptions {
@ -1323,6 +1324,16 @@ public:
enableNativeInline_ = value;
}
bool IsEnableFastModule() const
{
return enableFastModule_;
}
void SetEnableFastModule(bool value)
{
enableFastModule_ = value;
}
private:
static bool StartsWith(const std::string &haystack, const std::string &needle)
{
@ -1431,6 +1442,7 @@ private:
bool enableOptLoopInvariantCodeMotion_ {false};
bool enableLexenvSpecialization_ {true};
bool enableNativeInline_ {false};
bool enableFastModule_ {false};
};
} // namespace panda::ecmascript

View File

@ -1434,4 +1434,22 @@ int TSModuleTable::GetGlobalModuleID(JSThread *thread, JSHandle<EcmaString> amiP
}
return NOT_FOUND;
}
bool TSManager::IsBuiltinConstructor(BuiltinTypeId id, GlobalTSTypeRef ctorGT) const
{
ASSERT(ctorGT.IsBuiltinModule());
if (IsBuiltinsDTSEnabled()) {
uint32_t idx = static_cast<uint32_t>(id);
const JSPandaFile *builtinPandaFile = GetBuiltinPandaFile();
uint32_t builtinOffset = GetBuiltinOffset(idx);
GlobalTypeID gId(builtinPandaFile, builtinOffset);
bool hasCreatedGT = HasCreatedGT(gId);
if (hasCreatedGT) {
auto gt = GetGTByGlobalTypeID(gId);
return ctorGT == gt;
}
}
return false;
}
} // namespace panda::ecmascript

View File

@ -509,6 +509,7 @@ public:
}
bool PUBLIC_API IsBuiltinObjectMethod(BuiltinTypeId id, kungfu::GateType funcType) const;
bool PUBLIC_API IsBuiltinConstructor(BuiltinTypeId id, GlobalTSTypeRef ctorType) const;
inline const JSPandaFile *GetBuiltinPandaFile() const
{

View File

@ -158,6 +158,7 @@ group("ark_aot_ts_test") {
"lexenv_specialization",
"lexenv_specialization",
"lexenv_specialization_noopt",
"load_local_module_var",
"logic_op",
"loop_peeling",
"loop_phi",

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("load_local_module_var") {
deps = []
}

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.
2

View File

@ -0,0 +1,25 @@
/*
* 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.
*/
declare function print(arg:any) : string;
export function RunNormalCall():number {
let res : number = 1;
res++;
return res
}
let num = RunNormalCall()
print(num)