Add two HIRs RESTORE_REGISTER, SAVE_REGISTER to support generator command

Context is not saved when processing SUSPENDGENERATOR and RESUMEGENERASTOR
instructions, and contextual execution cannot be restored.
1、Add SAVE_REGISTER HIR for saving context
2、RESTORE_REGISTER HIR for restoring context

issue:https://gitee.com/openharmony/ark_js_runtime/issues/I5B2QO

Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I16b73390c6f7ae7c295f0aa1a9c9df538c2a4fec
This commit is contained in:
wanyanglan 2022-06-06 17:41:17 +08:00
parent 717b6fa322
commit 68acce4ba9
34 changed files with 816 additions and 34 deletions

View File

@ -47,6 +47,7 @@ source_set("libark_jsoptimizer_set") {
"assembler/x64/assembler_x64.cpp",
"assembler/x64/extended_assembler_x64.cpp",
"assembler_module.cpp",
"async_function_lowering.cpp",
"bc_call_signature.cpp",
"bytecode_circuit_builder.cpp",
"call_signature.cpp",

View File

@ -0,0 +1,198 @@
/*
* Copyright (c) 2022 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.
*/
#include "ecmascript/compiler/async_function_lowering.h"
namespace panda::ecmascript::kungfu {
void AsyncFunctionLowering::ProcessAll()
{
ProcessJumpTable();
}
void AsyncFunctionLowering::ProcessJumpTable()
{
GateRef newTarget = argAccessor_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
GateRef isEqual = builder_.Equal(newTarget, builder_.Undefined());
GateRef stateEntryState = *accessor_.ConstUses(stateEntry_).begin();
GateRef ifBranchCondition = builder_.Branch(stateEntry_, isEqual);
GateRef ifTrueCondition = builder_.IfTrue(ifBranchCondition);
GateRef ifFalseCondition = builder_.IfFalse(ifBranchCondition);
accessor_.ReplaceStateIn(stateEntryState, ifTrueCondition);
GateRef contextOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET);
GateRef val = builder_.PtrAdd(newTarget, contextOffset);
GateRef contextGate = circuit_->NewGate(OpCode(OpCode::LOAD), MachineType::I64, 0, {dependEntry_, val},
GateType::TaggedPointer());
GateRef bcOffset = builder_.IntPtr(GeneratorContext::GENERATOR_BC_OFFSET_OFFSET);
val = builder_.PtrAdd(contextGate, bcOffset);
GateRef restoreOffsetGate = circuit_->NewGate(OpCode(OpCode::LOAD), MachineType::I32, 0, {contextGate, val},
GateType::NJSValue());
GateRef firstState = Circuit::NullGate();
const auto &suspendAndResumeGates = bcBuilder_->GetAsyncRelatedGates();
for (const auto &gate : suspendAndResumeGates) {
auto curInfo = bcBuilder_->GetByteCodeInfo(gate);
if (curInfo.IsBc(EcmaOpcode::RESUMEGENERATOR_PREF_V8)) {
RebuildGeneratorCfg(gate, restoreOffsetGate, ifFalseCondition, newTarget, firstState);
}
}
}
void AsyncFunctionLowering::RebuildGeneratorCfg(GateRef resumeGate, GateRef restoreOffsetGate, GateRef ifFalseCondition,
GateRef newTarget, GateRef &firstState)
{
GateRef ifSuccess = accessor_.GetState(resumeGate);
GateRef suspendGate = accessor_.GetState(ifSuccess);
GateRef firstRestoreRegGate = GetFirstRestoreRegister(resumeGate);
GateRef offsetConstantGate = accessor_.GetValueIn(suspendGate);
offsetConstantGate = builder_.TruncInt64ToInt32(offsetConstantGate);
auto stateInGate = accessor_.GetState(resumeGate);
bool flag = true;
GateRef prevLoopBeginGate = Circuit::NullGate();
GateRef loopBeginStateIn = Circuit::NullGate();
GateRef prevBcOffsetPhiGate = Circuit::NullGate();
while (true) {
auto opcode = accessor_.GetOpCode(stateInGate);
if (opcode == OpCode::STATE_ENTRY) {
GateRef condition = circuit_->NewGate(OpCode(OpCode::EQ), 0, {offsetConstantGate, restoreOffsetGate},
GateType::NJSValue());
GateRef ifBranch = circuit_->NewGate(OpCode(OpCode::IF_BRANCH), 0, { ifFalseCondition, condition },
GateType::Empty());
GateRef ifTrue = circuit_->NewGate(OpCode(OpCode::IF_TRUE), 0, {ifBranch}, GateType::Empty());
GateRef ifFalse = circuit_->NewGate(OpCode(OpCode::IF_FALSE), 0, {ifBranch}, GateType::Empty());
if (flag) {
accessor_.ReplaceStateIn(resumeGate, ifTrue);
accessor_.ReplaceValueIn(resumeGate, newTarget);
accessor_.ReplaceDependIn(firstRestoreRegGate, restoreOffsetGate);
circuit_->NewGate(OpCode(OpCode::RETURN), 0,
{ifSuccess, suspendGate, suspendGate,
Circuit::GetCircuitRoot(OpCode(OpCode::RETURN_LIST))},
GateType::AnyType());
} else {
loopBeginStateIn = ifTrue;
}
accessor_.ReplaceStateIn(ifBranch, ifFalseCondition);
if (firstState != Circuit::NullGate()) {
accessor_.ReplaceStateIn(firstState, ifFalse);
} else {
auto constant = builder_.UndefineConstant();
circuit_->NewGate(OpCode(OpCode::RETURN), 0,
{ifFalse, restoreOffsetGate, constant,
Circuit::GetCircuitRoot(OpCode(OpCode::RETURN_LIST))},
GateType::AnyType());
}
firstState = ifBranch;
}
if (opcode == OpCode::LOOP_BEGIN) {
// This constant gate must be created by the NewGate method to distinguish whether the while
// loop needs to modify the phi node or not.
GateRef emptyOffsetGate = circuit_->NewGate(OpCode(OpCode::CONSTANT), MachineType::I32,
static_cast<BitField>(-1),
{Circuit::GetCircuitRoot(OpCode(OpCode::CIRCUIT_ROOT))},
GateType::NJSValue());
GateRef bcOffsetPhiGate = circuit_->NewGate(OpCode(OpCode::VALUE_SELECTOR), MachineType::I32, 2,
{stateInGate, restoreOffsetGate, emptyOffsetGate},
GateType::NJSValue());
GateRef condition = circuit_->NewGate(OpCode(OpCode::EQ), 0, {offsetConstantGate, bcOffsetPhiGate},
GateType::NJSValue());
GateRef ifBranch = circuit_->NewGate(OpCode(OpCode::IF_BRANCH), 0, {stateInGate, condition},
GateType::Empty());
GateRef ifTrue = circuit_->NewGate(OpCode(OpCode::IF_TRUE), 0, {ifBranch}, GateType::Empty());
GateRef ifFalse = circuit_->NewGate(OpCode(OpCode::IF_FALSE), 0, {ifBranch}, GateType::Empty());
GateRef resumeStateGate = accessor_.GetState(resumeGate);
if (accessor_.GetOpCode(resumeStateGate) != OpCode::IF_TRUE) {
accessor_.ReplaceStateIn(resumeGate, ifTrue);
accessor_.ReplaceValueIn(resumeGate, newTarget);
accessor_.ReplaceDependIn(firstRestoreRegGate, bcOffsetPhiGate);
circuit_->NewGate(OpCode(OpCode::RETURN), 0,
{ifSuccess, suspendGate, suspendGate,
Circuit::GetCircuitRoot(OpCode(OpCode::RETURN_LIST))},
GateType::AnyType());
} else {
// Handling multi-layer for loops
UpdateValueSelector(prevLoopBeginGate, ifTrue, prevBcOffsetPhiGate);
accessor_.ReplaceValueIn(prevBcOffsetPhiGate, bcOffsetPhiGate);
}
accessor_.ReplaceStateIn(ifBranch, stateInGate);
// Find the node with LOOP_BEGIN as State input and modify its
// state input to the newly created IF_FALSE node.
auto uses = accessor_.Uses(stateInGate);
for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
if (accessor_.GetOpCode(*useIt).IsState() && *useIt != ifBranch) {
accessor_.ReplaceIn(useIt, ifFalse);
}
}
prevLoopBeginGate = stateInGate;
prevBcOffsetPhiGate = bcOffsetPhiGate;
stateInGate = accessor_.GetState(stateInGate);
flag = false;
continue;
}
if (loopBeginStateIn != Circuit::NullGate()) {
UpdateValueSelector(prevLoopBeginGate, loopBeginStateIn, prevBcOffsetPhiGate);
break;
}
if (accessor_.GetOpCode(stateInGate) == OpCode::STATE_ENTRY) {
break;
}
stateInGate = accessor_.GetState(stateInGate);
}
}
void AsyncFunctionLowering::UpdateValueSelector(GateRef prevLoopBeginGate,
GateRef controlStateGate,
GateRef prevBcOffsetPhiGate)
{
GateRef loopBeginFirstState = accessor_.GetState(prevLoopBeginGate);
GateRef newGate = circuit_->NewGate(OpCode(OpCode::MERGE), 2,
{controlStateGate, loopBeginFirstState}, GateType::Empty());
accessor_.ReplaceStateIn(prevLoopBeginGate, newGate);
auto loopBeginUses = accessor_.Uses(prevLoopBeginGate);
for (auto use : loopBeginUses) {
if (accessor_.GetOpCode(use) == OpCode::VALUE_SELECTOR && use != prevBcOffsetPhiGate) {
auto machineType = accessor_.GetMachineType(use);
auto gateType = accessor_.GetGateType(use);
auto undefinedGate =
accessor_.GetConstantGate(machineType, JSTaggedValue::VALUE_UNDEFINED, gateType);
auto firstValueGate = accessor_.GetValueIn(use, 0);
auto newValueSelector = circuit_->NewGate(OpCode(OpCode::VALUE_SELECTOR), machineType,
2, {newGate, undefinedGate, firstValueGate},
gateType);
accessor_.ReplaceValueIn(use, newValueSelector);
}
}
}
bool AsyncFunctionLowering::IsAsyncRelated() const
{
return bcBuilder_->GetAsyncRelatedGates().size() > 0;
}
GateRef AsyncFunctionLowering::GetFirstRestoreRegister(GateRef gate) const
{
GateRef firstRestoreGate = 0;
GateRef curRestoreGate = accessor_.GetDep(gate);
while (accessor_.GetOpCode(curRestoreGate) == OpCode::RESTORE_REGISTER) {
firstRestoreGate = curRestoreGate;
curRestoreGate = accessor_.GetDep(curRestoreGate);
}
return firstRestoreGate;
}
} // panda::ecmascript::kungfu

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_COMPILER_ASYNC_FUNCTION_LOWRING_H_
#define ECMASCRIPT_COMPILER_ASYNC_FUNCTION_LOWRING_H_
#include "ecmascript/compiler/bytecode_circuit_builder.h"
#include "ecmascript/compiler/circuit.h"
#include "ecmascript/compiler/circuit_builder-inl.h"
#include "ecmascript/compiler/circuit_builder.h"
namespace panda::ecmascript::kungfu {
class AsyncFunctionLowering {
public:
AsyncFunctionLowering(BytecodeCircuitBuilder *bcBuilder, Circuit *circuit, CompilationConfig *cmpCfg,
bool enableLog)
: bcBuilder_(bcBuilder), circuit_(circuit), builder_(circuit, cmpCfg), enableLog_(enableLog),
stateEntry_(Circuit::GetCircuitRoot(OpCode(OpCode::STATE_ENTRY))),
dependEntry_(Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY))),
accessor_(circuit), argAccessor_(circuit)
{
}
~AsyncFunctionLowering() = default;
void ProcessAll();
bool IsAsyncRelated() const;
private:
void ProcessJumpTable();
void RebuildGeneratorCfg(GateRef resumeGate, GateRef restoreOffsetGate, GateRef ifFalseCondition, GateRef newTarget,
GateRef &firstState);
void UpdateValueSelector(GateRef prevLoopBeginGate, GateRef controlStateGate, GateRef prevBcOffsetPhiGate);
GateRef GetFirstRestoreRegister(GateRef gate) const;
BytecodeCircuitBuilder *bcBuilder_;
Circuit *circuit_;
CircuitBuilder builder_;
[[maybe_unused]] bool enableLog_ {false};
GateRef stateEntry_ {Circuit::NullGate()};
GateRef dependEntry_ {Circuit::NullGate()};
GateAccessor accessor_;
ArgumentAccessor argAccessor_;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_ASYNC_FUNCTION_LOWRING_H_

View File

@ -129,7 +129,7 @@ void BytecodeCircuitBuilder::CollectBytecodeBlockInfo(uint8_t *pc, std::vector<C
case EcmaOpcode::JNEZ_IMM16: {
std::vector<uint8_t *> temp;
temp.emplace_back(pc + BytecodeOffset::THREE); // first successor
int8_t offset = static_cast<int8_t>(READ_INST_16_0());
int16_t offset = static_cast<int16_t>(READ_INST_16_0());
temp.emplace_back(pc + offset); // second successor
bytecodeBlockInfos.emplace_back(pc, SplitKind::END, temp);
bytecodeBlockInfos.emplace_back(pc + BytecodeOffset::THREE, SplitKind::START,
@ -1255,8 +1255,11 @@ BytecodeInfo BytecodeCircuitBuilder::GetBytecodeInfo(const uint8_t *pc)
case EcmaOpcode::SUSPENDGENERATOR_PREF_V8_V8: {
uint16_t v0 = READ_INST_8_1();
uint16_t v1 = READ_INST_8_2();
info.accIn = true;
info.accOut = true;
info.offset = BytecodeOffset::FOUR;
uint32_t offset = pc - method_->GetBytecodeArray();
info.inputs.emplace_back(Immediate(offset)); // Save the pc offset when suspend
info.inputs.emplace_back(VirtualRegister(v0));
info.inputs.emplace_back(VirtualRegister(v1));
break;
@ -1766,6 +1769,12 @@ void BytecodeCircuitBuilder::InsertPhi()
auto pc = bb.start;
while (pc <= bb.end) {
auto bytecodeInfo = GetBytecodeInfo(pc);
if (bytecodeInfo.IsBc(EcmaOpcode::RESUMEGENERATOR_PREF_V8)) {
auto numVRegs = method_->GetNumVregs();
for (size_t i = 0; i < numVRegs; i++) {
bytecodeInfo.vregOut.emplace_back(i);
}
}
pc = pc + bytecodeInfo.offset; // next inst start pc
for (const auto &vreg: bytecodeInfo.vregOut) {
defsitesInfo[vreg].insert(bb.id);
@ -2109,6 +2118,9 @@ void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, const uint8_t *pc, Ga
GateType::AnyType());
}
jsgateToBytecode_[gate] = {bb.id, pc};
if (bytecodeInfo.IsGeneratorRelative()) {
suspendAndResumeGates_.emplace_back(gate);
}
if (bytecodeInfo.IsThrow()) {
auto constant = circuit_.NewGate(OpCode(OpCode::CONSTANT), MachineType::I64,
JSTaggedValue::VALUE_HOLE,
@ -2337,8 +2349,8 @@ GateRef BytecodeCircuitBuilder::RenameVariable(const size_t bbId,
}
std::reverse(instList.begin(), instList.end());
auto tmpAcc = acc;
for (auto pcIter: instList) { // upper bound
auto curInfo = GetBytecodeInfo(pcIter);
for (auto pcIter = instList.begin(); pcIter != instList.end(); pcIter++) { // upper bound
auto curInfo = GetBytecodeInfo(*pcIter);
// original bc use acc as input && current bc use acc as output
bool isTransByAcc = tmpAcc && curInfo.accOut;
// 0 : the index in vreg-out list
@ -2353,10 +2365,31 @@ GateRef BytecodeCircuitBuilder::RenameVariable(const size_t bbId,
tsType = GetRealGateType(tmpReg, tsType);
}
} else {
ans = byteCodeToJSGate_.at(pcIter);
ans = byteCodeToJSGate_.at(*pcIter);
break;
}
}
if (static_cast<EcmaOpcode>(curInfo.opcode) != EcmaOpcode::RESUMEGENERATOR_PREF_V8) {
continue;
}
// New RESTORE_REGISTER HIR, used to restore the register content when processing resume instruction.
// New SAVE_REGISTER HIR, used to save register content when processing suspend instruction.
GateAccessor accessor(&circuit_);
auto resumeGate = byteCodeToJSGate_.at(*pcIter);
GateRef resumeDependGate = accessor.GetDep(resumeGate);
ans = circuit_.NewGate(OpCode(OpCode::RESTORE_REGISTER), MachineType::I64, tmpReg,
{resumeDependGate}, GateType::NJSValue());
accessor.SetDep(resumeGate, ans);
auto saveRegGate = RenameVariable(bbId, *pcIter - 1, tmpReg, tmpAcc, tsType);
auto nextPcIter = pcIter;
nextPcIter++;
ASSERT(GetBytecodeInfo(*nextPcIter).opcode == EcmaOpcode::SUSPENDGENERATOR_PREF_V8_V8);
GateRef suspendGate = byteCodeToJSGate_.at(*nextPcIter);
auto dependGate = accessor.GetDep(suspendGate);
auto newDependGate = circuit_.NewGate(OpCode(OpCode::SAVE_REGISTER), tmpReg, {dependGate, saveRegGate},
GateType::Empty());
accessor.SetDep(suspendGate, newDependGate);
break;
}
// find GET_EXCEPTION gate if this is a catch block
if (ans == Circuit::NullGate() && tmpAcc) {
@ -2430,9 +2463,10 @@ void BytecodeCircuitBuilder::BuildCircuit()
for (const auto &[key, value]: jsgateToBytecode_) {
byteCodeToJSGate_[value.second] = key;
}
GateAccessor accessor = GateAccessor(&circuit_);
// resolve def-site of virtual regs and set all value inputs
for (auto gate: circuit_.GetAllGates()) {
auto valueCount = circuit_.GetOpCode(gate).GetInValueCount(circuit_.GetBitField(gate));
auto valueCount = accessor.GetInValueCount(gate);
auto it = jsgateToBytecode_.find(gate);
if (it == jsgateToBytecode_.cend()) {
continue;
@ -2446,8 +2480,8 @@ void BytecodeCircuitBuilder::BuildCircuit()
[[maybe_unused]] size_t numValueOutputs = bytecodeInfo.ComputeOutCount() + bytecodeInfo.vregOut.size();
ASSERT(numValueInputs == valueCount);
ASSERT(numValueOutputs <= 1);
auto stateCount = circuit_.GetOpCode(gate).GetStateCount(circuit_.GetBitField(gate));
auto dependCount = circuit_.GetOpCode(gate).GetDependCount(circuit_.GetBitField(gate));
auto stateCount = accessor.GetStateCount(gate);
auto dependCount = accessor.GetDependCount(gate);
for (size_t valueIdx = 0; valueIdx < valueCount; valueIdx++) {
auto inIdx = valueIdx + stateCount + dependCount;
if (!circuit_.IsInGateNull(gate, inIdx)) {

View File

@ -360,6 +360,23 @@ struct BytecodeInfo {
{
return ComputeValueInputCount() + ComputeBCOffsetInputCount();
}
bool IsGeneratorRelative() const
{
auto ecmaOpcode = static_cast<EcmaOpcode>(opcode);
switch (ecmaOpcode) {
case EcmaOpcode::SUSPENDGENERATOR_PREF_V8_V8:
case EcmaOpcode::RESUMEGENERATOR_PREF_V8:
return true;
default:
return false;
}
}
bool IsBc(EcmaOpcode ecmaOpcode) const
{
return opcode == ecmaOpcode;
}
};
enum BytecodeOffset {
@ -437,6 +454,11 @@ public:
return enableLog_;
}
[[nodiscard]] const std::vector<kungfu::GateRef>& GetAsyncRelatedGates() const
{
return suspendAndResumeGates_;
}
private:
void PUBLIC_API CollectBytecodeBlockInfo(uint8_t* pc, std::vector<CfgInfo> &bytecodeBlockInfos);
@ -474,7 +496,6 @@ private:
GateRef RenameVariable(const size_t bbId, const uint8_t *end,
const uint16_t reg, const bool acc, GateType gateType = GateType::AnyType());
void BuildCircuit();
void PrintCollectBlockInfo(std::vector<CfgInfo> &bytecodeBlockInfos);
void PrintGraph();
void PrintBytecodeInfo();
@ -499,6 +520,7 @@ private:
ArgumentAccessor argAcc_;
bool enableLog_ {false};
std::map<uint8_t *, int32_t> pcToBCOffset_;
std::vector<kungfu::GateRef> suspendAndResumeGates_ {};
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H

View File

@ -502,6 +502,11 @@ GateRef CircuitBuilder::GetDepend() const
return GetCurrentLabel()->GetDepend();
}
void CircuitBuilder::SetDepend(GateRef depend)
{
GetCurrentLabel()->SetDepend(depend);
}
void Label::Seal()
{
return impl_->Seal();

View File

@ -396,6 +396,7 @@ public:
inline Label *GetCurrentLabel() const;
inline GateRef GetState() const;
inline GateRef GetDepend() const;
inline void SetDepend(GateRef depend);
private:
Circuit *circuit_ {nullptr};

View File

@ -184,6 +184,11 @@ Properties OpCode::GetProperties() const
return {FLEX, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
case BITCAST:
return {FLEX, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
// suspend relate HIR
case RESTORE_REGISTER:
return {FLEX, NO_STATE, ONE_DEPEND, NO_VALUE, NO_ROOT};
case SAVE_REGISTER:
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT};
default:
LOG_COMPILER(ERROR) << "Please complete OpCode properties (OpCode=" << op_ << ")";
UNREACHABLE();
@ -293,6 +298,8 @@ std::string OpCode::Str() const
{FLOAT_TO_SIGNED_INT, "FLOAT_TO_SIGNED_INT"},
{UNSIGNED_FLOAT_TO_INT, "UNSIGNED_FLOAT_TO_INT"},
{BITCAST, "BITCAST"},
{RESTORE_REGISTER, "RESTORE_REGISTER"},
{SAVE_REGISTER, "SAVE_REGISTER"},
};
if (strMap.count(op_) > 0) {
return strMap.at(op_);
@ -309,10 +316,9 @@ size_t OpCode::GetStateCount(BitField bitfield) const
size_t OpCode::GetDependCount(BitField bitfield) const
{
const size_t manyDepend = 2;
auto properties = GetProperties();
auto dependProp = properties.dependsIn;
return (dependProp == manyDepend) ? bitfield : dependProp;
return (dependProp == MANY_DEPEND) ? bitfield : dependProp;
}
size_t OpCode::GetInValueCount(BitField bitfield) const

View File

@ -157,6 +157,8 @@ public:
FLOAT_TO_SIGNED_INT,
UNSIGNED_FLOAT_TO_INT,
BITCAST,
RESTORE_REGISTER,
SAVE_REGISTER,
};
OpCode() = default;

View File

@ -180,4 +180,70 @@ void GateAccessor::NewIn(GateRef gate, size_t idx, GateRef in)
{
circuit_->NewIn(gate, idx, in);
}
size_t GateAccessor::GetStateCount(GateRef gate) const
{
return circuit_->LoadGatePtr(gate)->GetStateCount();
}
size_t GateAccessor::GetDependCount(GateRef gate) const
{
return circuit_->LoadGatePtr(gate)->GetDependCount();
}
size_t GateAccessor::GetInValueCount(GateRef gate) const
{
return circuit_->LoadGatePtr(gate)->GetInValueCount();
}
void GateAccessor::ReplaceAllDepends(GateRef gate, GateRef replaceDependIn)
{
auto uses = Uses(gate);
for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
size_t dependStartIndex = circuit_->LoadGatePtr(*useIt)->GetStateCount();
size_t dependEndIndex = circuit_->LoadGatePtr(*useIt)->GetDependCount() + dependStartIndex;
if (useIt.GetIndex() >= dependStartIndex && useIt.GetIndex() < dependEndIndex) {
circuit_->ModifyIn(*useIt, useIt.GetIndex(), replaceDependIn);
}
}
}
void GateAccessor::ReplaceIn(GateRef gate, size_t index, GateRef in)
{
circuit_->ModifyIn(gate, index, in);
}
void GateAccessor::ReplaceStateIn(GateRef gate, GateRef in, size_t index)
{
ASSERT(index < GetStateCount(gate));
circuit_->ModifyIn(gate, index, in);
}
void GateAccessor::ReplaceDependIn(GateRef gate, GateRef in, size_t index)
{
ASSERT(index < GetDependCount(gate));
size_t stateCount = GetStateCount(gate);
circuit_->ModifyIn(gate, stateCount + index, in);
}
void GateAccessor::ReplaceValueIn(GateRef gate, GateRef in, size_t index)
{
ASSERT(index < GetInValueCount(gate));
size_t valueStartIndex = GetStateCount(gate) + GetDependCount(gate);
circuit_->ModifyIn(gate, valueStartIndex + index, in);
}
void GateAccessor::DeleteGate(GateRef gate)
{
circuit_->DeleteGate(gate);
}
MachineType GateAccessor::GetMachineType(GateRef gate) const
{
return circuit_->GetMachineType(gate);
}
GateRef GateAccessor::GetConstantGate(MachineType bitValue, BitField bitfield, GateType type) const
{
return circuit_->GetConstantGate(bitValue, bitfield, type);
}
} // namespace panda::ecmascript::kungfu

View File

@ -320,7 +320,7 @@ public:
void SetBitField(GateRef gate, BitField bitField);
void Print(GateRef gate) const;
[[nodiscard]] GateId GetId(GateRef gate) const;
[[nodiscard]] GateRef GetValueIn(GateRef gate, size_t idx) const;
[[nodiscard]] GateRef GetValueIn(GateRef gate, size_t idx = 0) const;
[[nodiscard]] size_t GetNumValueIn(GateRef gate) const;
[[nodiscard]] GateRef GetIn(GateRef gate, size_t idx) const;
[[nodiscard]] GateRef GetState(GateRef gate, size_t idx = 0) const;
@ -337,6 +337,17 @@ public:
void DeleteGate(UsesIterator &useIt);
void DecreaseIn(UsesIterator &useIt);
void NewIn(GateRef gate, size_t idx, GateRef in);
[[nodiscard]] size_t GetStateCount(GateRef gate) const;
[[nodiscard]] size_t GetDependCount(GateRef gate) const;
[[nodiscard]] size_t GetInValueCount(GateRef gate) const;
void ReplaceAllDepends(GateRef gate, GateRef replaceDependIn);
void ReplaceIn(GateRef gate, size_t index, GateRef in);
void ReplaceStateIn(GateRef gate, GateRef in, size_t index = 0);
void ReplaceDependIn(GateRef gate, GateRef in, size_t index = 0);
void ReplaceValueIn(GateRef gate, GateRef in, size_t index = 0);
void DeleteGate(GateRef gate);
MachineType GetMachineType(GateRef gate) const;
GateRef GetConstantGate(MachineType bitValue, BitField bitfield, GateType type) const;
private:
[[nodiscard]] ConstUsesIterator ConstUseBegin(GateRef gate) const

View File

@ -16,14 +16,15 @@
#ifndef ECMASCRIPT_COMPILER_PASS_H
#define ECMASCRIPT_COMPILER_PASS_H
#include "bytecode_circuit_builder.h"
#include "common_stubs.h"
#include "type_lowering.h"
#include "llvm_codegen.h"
#include "scheduler.h"
#include "slowpath_lowering.h"
#include "type_inference/type_infer.h"
#include "verifier.h"
#include "ecmascript/compiler/async_function_lowering.h"
#include "ecmascript/compiler/bytecode_circuit_builder.h"
#include "ecmascript/compiler/common_stubs.h"
#include "ecmascript/compiler/llvm_codegen.h"
#include "ecmascript/compiler/scheduler.h"
#include "ecmascript/compiler/slowpath_lowering.h"
#include "ecmascript/compiler/type_inference/type_infer.h"
#include "ecmascript/compiler/type_lowering.h"
#include "ecmascript/compiler/verifier.h"
namespace panda::ecmascript::kungfu {
class PassData {
@ -133,5 +134,17 @@ public:
private:
std::unique_ptr<CodeGeneratorImpl> llvmImpl_ {nullptr};
};
class AsyncFunctionLoweringPass {
public:
bool Run(PassData* data, bool enableLog, BytecodeCircuitBuilder *builder, CompilationConfig *cmpCfg)
{
AsyncFunctionLowering lowering(builder, data->GetCircuit(), cmpCfg, enableLog);
if (lowering.IsAsyncRelated()) {
lowering.ProcessAll();
}
return true;
}
};
} // namespace panda::ecmascript::kungfu
#endif

View File

@ -56,6 +56,7 @@ bool PassManager::Compile(const std::string &fileName, AOTFileGenerator &generat
builder.BytecodeToCircuit();
PassData data(builder.GetCircuit());
PassRunner<PassData> pipeline(&data, enableLog);
pipeline.RunPass<AsyncFunctionLoweringPass>(&builder, &cmpCfg);
pipeline.RunPass<TypeInferPass>(&builder, tsLoader);
pipeline.RunPass<TypeLoweringPass>(&builder, &cmpCfg, tsLoader);
pipeline.RunPass<SlowPathLoweringPass>(&builder, &cmpCfg);

View File

@ -332,7 +332,7 @@ void SlowPathLowering::Lower(GateRef gate)
LowerCreateIterResultObj(gate, glue);
break;
case SUSPENDGENERATOR_PREF_V8_V8:
LowerSuspendGenerator(gate, glue);
LowerSuspendGenerator(gate, glue, jsFunc);
break;
case ASYNCFUNCTIONAWAITUNCAUGHT_PREF_V8_V8:
LowerAsyncFunctionAwaitUncaught(gate, glue);
@ -656,12 +656,85 @@ void SlowPathLowering::LowerCreateIterResultObj(GateRef gate, GateRef glue)
ReplaceHirToCall(gate, newGate);
}
void SlowPathLowering::LowerSuspendGenerator(GateRef gate, GateRef glue)
// When executing to SUSPENDGENERATOR instruction, save contextual information to GeneratorContext,
// including registers, acc, etc.
void SlowPathLowering::SaveFrameToContext(GateRef gate, GateRef glue, GateRef jsFunc)
{
GateRef genObj = acc_.GetValueIn(gate, 1);
GateRef saveRegister = acc_.GetDep(gate);
ASSERT(acc_.GetOpCode(saveRegister) == OpCode::SAVE_REGISTER);
std::vector<GateRef> saveRegisterGates {};
while (acc_.GetOpCode(saveRegister) == OpCode::SAVE_REGISTER) {
saveRegisterGates.emplace_back(saveRegister);
saveRegister = acc_.GetDep(saveRegister);
}
acc_.SetDep(gate, saveRegister);
builder_.SetDepend(saveRegister);
GateRef context =
builder_.Load(VariableType::JS_POINTER(), genObj, builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET));
// new tagged array
const size_t arrLength = 65536; // 65536: Maximum number of virtual registers
GateRef length = builder_.Int32((arrLength));
GateRef taggedLength = builder_.TaggedTypeNGC(builder_.ZExtInt32ToInt64(length));
const int arrayId = RTSTUB_ID(NewTaggedArray);
GateRef taggedArray = LowerCallRuntime(glue, arrayId, {taggedLength});
// setRegsArrays
for (auto item : saveRegisterGates) {
auto index = acc_.GetBitField(item);
auto valueGate = acc_.GetValueIn(item);
builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue, taggedArray, builder_.Int32(index), valueGate);
acc_.DeleteGate(item);
}
// setRegsArrays
GateRef regsArrayOffset = builder_.IntPtr(GeneratorContext::GENERATOR_REGS_ARRAY_OFFSET);
builder_.Store(VariableType::JS_POINTER(), glue, context, regsArrayOffset, taggedArray);
// set method
GateRef methodOffset = builder_.IntPtr(GeneratorContext::GENERATOR_METHOD_OFFSET);
builder_.Store(VariableType::JS_ANY(), glue, context, methodOffset, jsFunc);
// set acc
GateRef accOffset = builder_.IntPtr(GeneratorContext::GENERATOR_ACC_OFFSET);
GateRef curAccGate = acc_.GetValueIn(gate, 3); // get current acc
builder_.Store(VariableType::JS_ANY(), glue, context, accOffset, curAccGate);
// set generator object
GateRef generatorObjectOffset = builder_.IntPtr(GeneratorContext::GENERATOR_GENERATOR_OBJECT_OFFSET);
builder_.Store(VariableType::JS_ANY(), glue, context, generatorObjectOffset, genObj);
// set lexical env
const int id = RTSTUB_ID(GetAotLexicalEnv);
GateRef lexicalEnvGate = LowerCallRuntime(glue, id, {jsFunc});
GateRef lexicalEnvOffset = builder_.IntPtr(GeneratorContext::GENERATOR_LEXICALENV_OFFSET);
builder_.Store(VariableType::JS_ANY(), glue, context, lexicalEnvOffset, lexicalEnvGate);
// set nregs
GateRef nregsOffset = builder_.IntPtr(GeneratorContext::GENERATOR_NREGS_OFFSET);
builder_.Store(VariableType::INT32(), glue, context, nregsOffset, length);
// set bc size
GateRef bcSizeOffset = builder_.IntPtr(GeneratorContext::GENERATOR_BC_OFFSET_OFFSET);
GateRef bcSizeGate = acc_.GetValueIn(gate, 0); // saved bc_offset
bcSizeGate = builder_.TruncInt64ToInt32(bcSizeGate);
builder_.Store(VariableType::INT32(), glue, context, bcSizeOffset, bcSizeGate);
// set context to generator object
GateRef contextOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET);
builder_.Store(VariableType::JS_POINTER(), glue, genObj, contextOffset, context);
// set generator object to context
builder_.Store(VariableType::JS_POINTER(), glue, context, generatorObjectOffset, genObj);
}
void SlowPathLowering::LowerSuspendGenerator(GateRef gate, GateRef glue, [[maybe_unused]]GateRef jsFunc)
{
// 4: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 4);
SaveFrameToContext(gate, glue, jsFunc);
acc_.SetDep(gate, builder_.GetDepend());
const int id = RTSTUB_ID(SuspendAotGenerator);
// 2: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 2);
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 0), acc_.GetValueIn(gate, 1)});
GateRef newGate = LowerCallRuntime(glue, id, {acc_.GetValueIn(gate, 1), acc_.GetValueIn(gate, 2)});
ReplaceHirToCall(gate, newGate);
}
@ -790,7 +863,6 @@ void SlowPathLowering::LowerGetIterator(GateRef gate, GateRef glue)
ReplaceHirToSubCfg(gate, value, successControl, failControl);
}
void SlowPathLowering::LowerToJSCall(GateRef gate, GateRef glue, const std::vector<GateRef> &args)
{
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCall));
@ -2858,13 +2930,52 @@ void SlowPathLowering::LowerTypeOfDyn(GateRef gate, GateRef glue)
ReplaceHirToSubCfg(gate, *result, successControl, failControl, true);
}
GateRef SlowPathLowering::GetValueFromTaggedArray(GateRef arrayGate, GateRef indexOffset)
{
GateRef offset = builder_.PtrMul(builder_.ChangeInt32ToIntPtr(indexOffset),
builder_.IntPtr(JSTaggedValue::TaggedTypeSize()));
GateRef dataOffset = builder_.PtrAdd(offset, builder_.IntPtr(TaggedArray::DATA_OFFSET));
GateRef value = builder_.Load(VariableType::JS_ANY(), arrayGate, dataOffset);
return value;
}
void SlowPathLowering::LowerResumeGenerator(GateRef gate)
{
GateRef obj = acc_.GetValueIn(gate, 0);
GateRef restoreGate = acc_.GetDep(gate);
std::vector<GateRef> registerGates {};
while (acc_.GetOpCode(restoreGate) == OpCode::RESTORE_REGISTER) {
registerGates.emplace_back(restoreGate);
restoreGate = acc_.GetDep(restoreGate);
}
acc_.SetDep(gate, restoreGate);
builder_.SetDepend(restoreGate);
GateRef contextOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_CONTEXT_OFFSET);
GateRef contextGate = builder_.Load(VariableType::JS_POINTER(), obj, contextOffset);
GateRef arrayOffset = builder_.IntPtr(GeneratorContext::GENERATOR_REGS_ARRAY_OFFSET);
GateRef arrayGate = builder_.Load(VariableType::JS_POINTER(), contextGate, arrayOffset);
for (auto item : registerGates) {
auto index = acc_.GetBitField(item);
auto indexOffset = builder_.Int32(index);
GateRef value = GetValueFromTaggedArray(arrayGate, indexOffset);
auto uses = acc_.Uses(item);
for (auto use = uses.begin(); use != uses.end(); use++) {
size_t valueStartIndex = acc_.GetStateCount(*use) + acc_.GetDependCount(*use);
size_t valueEndIndex = valueStartIndex + acc_.GetInValueCount(*use);
if (use.GetIndex() >= valueStartIndex && use.GetIndex() < valueEndIndex) {
acc_.ReplaceIn(use, value);
}
}
acc_.DeleteGate(item);
}
// 1: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 1);
std::vector<GateRef> successControl;
std::vector<GateRef> failControl;
GateRef obj = acc_.GetValueIn(gate, 0);
GateRef resumeResultOffset = builder_.IntPtr(JSGeneratorObject::GENERATOR_RESUME_RESULT_OFFSET);
GateRef result = builder_.Load(VariableType::JS_ANY(), obj, resumeResultOffset);
successControl.emplace_back(builder_.GetState());

View File

@ -143,7 +143,8 @@ private:
void Lower(GateRef gate);
void LowerAdd2Dyn(GateRef gate, GateRef glue);
void LowerCreateIterResultObj(GateRef gate, GateRef glue);
void LowerSuspendGenerator(GateRef gate, GateRef glue);
void SaveFrameToContext(GateRef gate, GateRef glue, GateRef jsFunc);
void LowerSuspendGenerator(GateRef gate, GateRef glue, [[maybe_unused]]GateRef jsFunc);
void LowerAsyncFunctionAwaitUncaught(GateRef gate, GateRef glue);
void LowerAsyncFunctionResolve(GateRef gate, GateRef glue);
void LowerAsyncFunctionReject(GateRef gate, GateRef glue);
@ -265,6 +266,7 @@ private:
void LowerCopyRestArgs(GateRef gate, GateRef glue, GateRef actualArgc);
GateRef LowerCallRuntime(GateRef glue, int index, const std::vector<GateRef> &args, bool useLabel = false);
int32_t ComputeCallArgc(GateRef gate, EcmaOpcode op);
GateRef GetValueFromTaggedArray(GateRef arrayGate, GateRef indexOffset);
BytecodeCircuitBuilder *bcBuilder_;
Circuit *circuit_;

View File

@ -559,11 +559,15 @@ JSTaggedValue EcmaInterpreter::Execute(EcmaRuntimeCallInfo *info)
JSTaggedValue EcmaInterpreter::GeneratorReEnterInterpreter(JSThread *thread, JSHandle<GeneratorContext> context)
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(JSHandle<JSTaggedValue>(thread, context->GetMethod()));
JSMethod *method = func->GetCallTarget();
if (method->IsAotWithCallField()) {
return GeneratorReEnterAot(thread, context);
}
if (thread->IsAsmInterpreter()) {
return InterpreterAssembly::GeneratorReEnterInterpreter(thread, context);
}
JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(JSHandle<JSTaggedValue>(thread, context->GetMethod()));
JSMethod *method = func->GetCallTarget();
JSTaggedType *currentSp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame());
@ -619,6 +623,27 @@ JSTaggedValue EcmaInterpreter::GeneratorReEnterInterpreter(JSThread *thread, JSH
return res;
}
JSTaggedValue EcmaInterpreter::GeneratorReEnterAot(JSThread *thread, JSHandle<GeneratorContext> context)
{
JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(JSHandle<JSTaggedValue>(thread, context->GetMethod()));
JSMethod *method = func->GetCallTarget();
JSTaggedValue genObject = context->GetGeneratorObject();
std::vector<JSTaggedType> args(method->GetNumArgs() + NUM_MANDATORY_JSFUNC_ARGS + 1,
JSTaggedValue::Undefined().GetRawData());
args[0] = func.GetTaggedValue().GetRawData();
args[1] = genObject.GetRawData();
JSTaggedValue env = func->GetLexicalEnv();
args[args.size() - 1] = env.GetRawData(); // last arg is env.
auto entry = thread->GetRTInterface(kungfu::RuntimeStubCSigns::ID_JSFunctionEntry);
auto res = reinterpret_cast<JSFunctionEntryType>(entry)(thread->GetGlueAddr(),
reinterpret_cast<uintptr_t>(thread->GetLastLeaveFrame()),
static_cast<uint32_t>(args.size()) - 1,
static_cast<uint32_t>(args.size()) - 1,
args.data(),
func->GetCodeEntry());
return JSTaggedValue(res);
}
void EcmaInterpreter::NotifyBytecodePcChanged(JSThread *thread)
{
FrameHandler frameHandler(thread);

View File

@ -40,6 +40,7 @@ public:
JSThread *thread, JSHandle<JSTaggedValue> func, JSHandle<JSTaggedValue> thisObj,
JSHandle<JSTaggedValue> newTarget, int32_t numArgs);
static inline JSTaggedValue GeneratorReEnterInterpreter(JSThread *thread, JSHandle<GeneratorContext> context);
static inline JSTaggedValue GeneratorReEnterAot(JSThread *thread, JSHandle<GeneratorContext> context);
static inline void RunInternal(JSThread *thread, ConstantPool *constpool, const uint8_t *pc, JSTaggedType *sp);
static inline void InitStackFrame(JSThread *thread);
static inline uint32_t FindCatchBlock(JSMethod *caller, uint32_t pc);

View File

@ -129,6 +129,11 @@ struct PUBLIC_API JSMethod : public base::AlignedStruct<sizeof(uint64_t),
return IsNativeBit::Decode(callField_);
}
bool IsAotWithCallField() const
{
return IsAotCodeBit::Decode(callField_);
}
bool OnlyHaveThisWithCallField() const
{
return (callField_ & CALL_TYPE_MASK) == 1; // 1: the first bit of callFiled is HaveThisBit

View File

@ -121,9 +121,13 @@ group("ark_aot_test") {
#"supercall:supercallAotAction",
#"supercallspread:supercallspreadAotAction",
#"suspendgenerator:suspendgeneratorAotAction",
#"suspendgenerator_branch:suspendgenerator_branchAotAction",
#"suspendgenerator_phi:suspendgenerator_phiAotAction",
"suspendgenerator:suspendgeneratorAotAction",
"suspendgeneratorbranch:suspendgeneratorbranchAotAction",
#"suspendgeneratorfor:suspendgeneratorforAotAction",
"suspendgeneratorphi:suspendgeneratorphiAotAction",
"suspendgeneratorreturn:suspendgeneratorreturnAotAction",
"suspendgeneratorthrow:suspendgeneratorthrowAotAction",
"throw:throwAotAction",
"throwifsupernotcorrectcall:throwifsupernotcorrectcallAotAction",
"throwundefindeifhole:throwundefindeifholeAotAction",

View File

@ -13,6 +13,6 @@
import("//ark/js_runtime/test/test_helper.gni")
host_aot_test_action("suspendgenerator_branch") {
host_aot_test_action("suspendgeneratorbranch") {
deps = []
}

View File

@ -13,6 +13,6 @@
import("//ark/js_runtime/test/test_helper.gni")
host_aot_test_action("suspendgenerator_phi") {
host_aot_test_action("suspendgeneratorfor") {
deps = []
}

View File

@ -0,0 +1,26 @@
# Copyright (c) 2022 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.
10000
1
11
20000
102
112
30000
1003
1013
40000
1104
1114
undefined

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022 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(str: any): string;
function* genFun() {
let t = 0;
for (var i = 0; i < 2; i += 1) {
for (var j = 0; j < 2; j += 1) {
for (var k = 0; k < 1; k += 1) {
t++;
yield t * 10000;
}
for (var k = 0; k < 2; k += 1) {
try {
yield i * 1000 + j * 100 + k * 10 + t;
} catch (e) {
print(e);
}
}
}
}
}
var func = genFun();
print(func.next().value);
print(func.next().value);
print(func.next().value);
print(func.next().value);
print(func.next().value);
print(func.next().value);
print(func.next().value);
print(func.next().value);
print(func.next().value);

View File

@ -0,0 +1,18 @@
# Copyright (c) 2022 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("//ark/js_runtime/test/test_helper.gni")
host_aot_test_action("suspendgeneratorphi") {
deps = []
}

View File

@ -0,0 +1,18 @@
# Copyright (c) 2022 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("//ark/js_runtime/test/test_helper.gni")
host_aot_test_action("suspendgeneratorreturn") {
deps = []
}

View File

@ -0,0 +1,16 @@
# Copyright (c) 2022 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
undefined
undefined

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2022 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(str:any):string;
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
print(g.next().value);
print(g.return().value);
print(g.next().value);

View File

@ -0,0 +1,18 @@
# Copyright (c) 2022 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("//ark/js_runtime/test/test_helper.gni")
host_aot_test_action("suspendgeneratorthrow") {
deps = []
}

View File

@ -0,0 +1,15 @@
# Copyright (c) 2022 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.
42
Error caught!

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2022 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(str:any): string;
function* gen() {
while (true) {
try {
yield 42;
} catch (e) {
print("Error caught!");
}
}
}
var g = gen();
print(g.next().value);
g.throw(new Error("Something went wrong"));