mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-06 23:54:03 +00:00
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:
parent
717b6fa322
commit
68acce4ba9
@ -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",
|
||||
|
198
ecmascript/compiler/async_function_lowering.cpp
Normal file
198
ecmascript/compiler/async_function_lowering.cpp
Normal 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
|
||||
|
62
ecmascript/compiler/async_function_lowering.h
Normal file
62
ecmascript/compiler/async_function_lowering.h
Normal 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_
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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};
|
||||
|
@ -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
|
||||
|
@ -157,6 +157,8 @@ public:
|
||||
FLOAT_TO_SIGNED_INT,
|
||||
UNSIGNED_FLOAT_TO_INT,
|
||||
BITCAST,
|
||||
RESTORE_REGISTER,
|
||||
SAVE_REGISTER,
|
||||
};
|
||||
|
||||
OpCode() = default;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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_;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -13,6 +13,6 @@
|
||||
|
||||
import("//ark/js_runtime/test/test_helper.gni")
|
||||
|
||||
host_aot_test_action("suspendgenerator_branch") {
|
||||
host_aot_test_action("suspendgeneratorbranch") {
|
||||
deps = []
|
||||
}
|
@ -13,6 +13,6 @@
|
||||
|
||||
import("//ark/js_runtime/test/test_helper.gni")
|
||||
|
||||
host_aot_test_action("suspendgenerator_phi") {
|
||||
host_aot_test_action("suspendgeneratorfor") {
|
||||
deps = []
|
||||
}
|
26
test/aottest/suspendgeneratorfor/expect_output.txt
Normal file
26
test/aottest/suspendgeneratorfor/expect_output.txt
Normal 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
|
45
test/aottest/suspendgeneratorfor/suspendgeneratorfor.ts
Normal file
45
test/aottest/suspendgeneratorfor/suspendgeneratorfor.ts
Normal 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);
|
18
test/aottest/suspendgeneratorphi/BUILD.gn
Normal file
18
test/aottest/suspendgeneratorphi/BUILD.gn
Normal 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 = []
|
||||
}
|
18
test/aottest/suspendgeneratorreturn/BUILD.gn
Normal file
18
test/aottest/suspendgeneratorreturn/BUILD.gn
Normal 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 = []
|
||||
}
|
16
test/aottest/suspendgeneratorreturn/expect_output.txt
Normal file
16
test/aottest/suspendgeneratorreturn/expect_output.txt
Normal 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
|
@ -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);
|
18
test/aottest/suspendgeneratorthrow/BUILD.gn
Normal file
18
test/aottest/suspendgeneratorthrow/BUILD.gn
Normal 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 = []
|
||||
}
|
15
test/aottest/suspendgeneratorthrow/expect_output.txt
Normal file
15
test/aottest/suspendgeneratorthrow/expect_output.txt
Normal 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!
|
29
test/aottest/suspendgeneratorthrow/suspendgeneratorthrow.ts
Normal file
29
test/aottest/suspendgeneratorthrow/suspendgeneratorthrow.ts
Normal 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"));
|
Loading…
Reference in New Issue
Block a user