mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-23 10:09:54 +00:00
Support loop invariant hoist for mir
Issues: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I7F1N4 Signed-off-by: sunzhe23 <sunzhe23@huawei.com>
This commit is contained in:
parent
0db98de96a
commit
333bdd63ba
@ -18,6 +18,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "ecmascript/mem/chunk.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
class BitSet {
|
||||
@ -29,22 +30,34 @@ public:
|
||||
static constexpr uint32_t BIT_PER_WORD_LOG2 = 6;
|
||||
static constexpr uint32_t BIT_PER_WORD_MASK = BIT_PER_WORD - 1;
|
||||
|
||||
explicit BitSet(size_t bitSize)
|
||||
explicit BitSet(Chunk* chunk, size_t bitSize)
|
||||
{
|
||||
wordCount_ = SizeOf(bitSize);
|
||||
if (UseWords()) {
|
||||
data_.words_ = new uint64_t[wordCount_];
|
||||
data_.words_ = chunk->NewArray<uint64_t>(wordCount_);
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
~BitSet()
|
||||
{
|
||||
if (UseWords()) {
|
||||
delete[] data_.words_;
|
||||
// no need delete chunk memory
|
||||
data_.words_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
if (!UseWords()) {
|
||||
data_.inlineWord_ = 0;
|
||||
} else {
|
||||
for (size_t i = 0; i < wordCount_; i++) {
|
||||
data_.words_[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TestBit(size_t offset) const
|
||||
{
|
||||
if (!UseWords()) {
|
||||
@ -127,7 +140,7 @@ private:
|
||||
|
||||
uint64_t Mask(size_t index) const
|
||||
{
|
||||
return 1 << index;
|
||||
return uint64_t{1} << index;
|
||||
}
|
||||
|
||||
size_t IndexInWord(size_t offset) const
|
||||
|
@ -41,6 +41,7 @@ public:
|
||||
{
|
||||
head_ = other->head_;
|
||||
size_ = other->size_;
|
||||
frameState_ = other->frameState_;
|
||||
}
|
||||
private:
|
||||
struct Node {
|
||||
|
@ -32,19 +32,6 @@ FrameStateBuilder::FrameStateBuilder(BytecodeCircuitBuilder *builder,
|
||||
|
||||
FrameStateBuilder::~FrameStateBuilder()
|
||||
{
|
||||
for (auto state : bcEndStateInfos_) {
|
||||
if (state != nullptr) {
|
||||
delete state;
|
||||
}
|
||||
}
|
||||
for (auto state : bbBeginStateInfos_) {
|
||||
if (state != nullptr) {
|
||||
delete state;
|
||||
}
|
||||
}
|
||||
if (liveOutResult_ != nullptr) {
|
||||
delete liveOutResult_;
|
||||
}
|
||||
liveOutResult_ = nullptr;
|
||||
bcEndStateInfos_.clear();
|
||||
bbBeginStateInfos_.clear();
|
||||
@ -109,7 +96,8 @@ void FrameStateBuilder::BindStateSplit(GateRef gate, GateRef frameState)
|
||||
|
||||
FrameStateInfo *FrameStateBuilder::CreateEmptyStateInfo()
|
||||
{
|
||||
auto frameInfo = new FrameStateInfo(numVregs_);
|
||||
auto chunk = circuit_->chunk();
|
||||
auto frameInfo = chunk->New<FrameStateInfo>(chunk, numVregs_);
|
||||
for (size_t i = 0; i < numVregs_; i++) {
|
||||
frameInfo->SetValuesAt(i, Circuit::NullGate());
|
||||
}
|
||||
@ -460,9 +448,6 @@ bool FrameStateBuilder::ShouldInsertFrameStateBefore(BytecodeRegion& bb,
|
||||
if (gateAcc_.GetOpCode(bb.dependCurrent) == OpCode::GET_EXCEPTION) {
|
||||
return true;
|
||||
}
|
||||
if (gateAcc_.GetOpCode(bb.stateCurrent) == OpCode::IF_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (gate == Circuit::NullGate() || gateAcc_.GetStateCount(gate) != 1) {
|
||||
return false;
|
||||
|
@ -29,7 +29,8 @@ struct BytecodeRegion;
|
||||
|
||||
class FrameStateInfo {
|
||||
public:
|
||||
explicit FrameStateInfo(size_t numVregs) : values_(numVregs), liveout_(numVregs) {}
|
||||
explicit FrameStateInfo(Chunk* chunk, size_t numVregs)
|
||||
: values_(numVregs, chunk), liveout_(chunk, numVregs) {}
|
||||
|
||||
void SetValuesAt(size_t index, GateRef gate)
|
||||
{
|
||||
@ -65,7 +66,7 @@ public:
|
||||
}
|
||||
private:
|
||||
// [numVRegs_] [extra args] [numArgs_] [accumulator]
|
||||
std::vector<GateRef> values_ {};
|
||||
ChunkVector<GateRef> values_;
|
||||
BitSet liveout_;
|
||||
};
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "ecmascript/compiler/graph_linearizer.h"
|
||||
#include "ecmascript/compiler/base/bit_set.h"
|
||||
#include "ecmascript/compiler/scheduler.h"
|
||||
|
||||
namespace panda::ecmascript::kungfu {
|
||||
@ -306,6 +307,249 @@ private:
|
||||
ChunkVector<ChunkDeque<size_t>> semiDomTree_;
|
||||
};
|
||||
|
||||
struct LoopInfo {
|
||||
GateRegion* loopHead {nullptr};
|
||||
BitSet* loopBodys {nullptr};
|
||||
ChunkVector<GateRegion*>* loopExits {nullptr};
|
||||
LoopInfo* outer_ {nullptr};
|
||||
};
|
||||
|
||||
class LoopInfoBuilder {
|
||||
public:
|
||||
explicit LoopInfoBuilder(GraphLinearizer *linearizer, Chunk* chunk)
|
||||
: linearizer_(linearizer), pendingList_(chunk),
|
||||
loops_(chunk), loopbacks_(chunk), chunk_(chunk),
|
||||
dfsStack_(chunk), acc_(linearizer->circuit_) {}
|
||||
|
||||
void Run()
|
||||
{
|
||||
ComputeLoopNumber();
|
||||
ComputeLoopInfo();
|
||||
ComputeLoopExit();
|
||||
ComputeLoopHeader();
|
||||
if (linearizer_->IsLogEnabled()) {
|
||||
for (size_t i = 0; i < numLoops_; i++) {
|
||||
auto& loopInfo = loops_[i];
|
||||
PrintLoop(loopInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrintLoop(LoopInfo& loopInfo)
|
||||
{
|
||||
auto size = linearizer_->regionList_.size();
|
||||
LOG_COMPILER(INFO) << "--------------------------------- LoopInfo Start ---------------------------------";
|
||||
LOG_COMPILER(INFO) << "Head: " << acc_.GetId(loopInfo.loopHead->state_);
|
||||
LOG_COMPILER(INFO) << "loopNumber: " << loopInfo.loopHead->loopNumber_;
|
||||
LOG_COMPILER(INFO) << "Body: [";
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (loopInfo.loopBodys->TestBit(i)) {
|
||||
auto current = linearizer_->regionList_.at(i)->state_;
|
||||
LOG_COMPILER(INFO) << acc_.GetId(current) << ", ";
|
||||
}
|
||||
}
|
||||
LOG_COMPILER(INFO) << "]";
|
||||
LOG_COMPILER(INFO) << "Exit: [";
|
||||
if (loopInfo.loopExits != nullptr) {
|
||||
for (auto region : *loopInfo.loopExits) {
|
||||
auto current = region->state_;
|
||||
LOG_COMPILER(INFO) << acc_.GetId(current) << ", ";
|
||||
}
|
||||
}
|
||||
LOG_COMPILER(INFO) << "]";
|
||||
LOG_COMPILER(INFO) << "--------------------------------- LoopInfo End ---------------------------------";
|
||||
}
|
||||
|
||||
void ComputeLoopInfo()
|
||||
{
|
||||
auto size = linearizer_->regionList_.size();
|
||||
loops_.resize(numLoops_, LoopInfo());
|
||||
|
||||
for (auto curState : loopbacks_) {
|
||||
GateRegion* curRegion = curState.region;
|
||||
GateRegion* loopHead = curRegion->succs_[curState.index];
|
||||
auto loopNumber = loopHead->GetLoopNumber();
|
||||
auto& loopInfo = loops_[loopNumber];
|
||||
|
||||
if (loopInfo.loopHead == nullptr) {
|
||||
loopInfo.loopHead = loopHead;
|
||||
loopInfo.loopBodys = chunk_->New<BitSet>(chunk_, size);
|
||||
}
|
||||
if (curRegion != loopHead) {
|
||||
loopInfo.loopBodys->SetBit(curRegion->GetId());
|
||||
pendingList_.emplace_back(curRegion);
|
||||
}
|
||||
PropagateLoopBody(loopInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void PropagateLoopBody(LoopInfo& loopInfo)
|
||||
{
|
||||
while (!pendingList_.empty()) {
|
||||
auto curRegion = pendingList_.back();
|
||||
pendingList_.pop_back();
|
||||
for (auto pred : curRegion->preds_) {
|
||||
if (pred != loopInfo.loopHead) {
|
||||
if (!loopInfo.loopBodys->TestBit(pred->GetId())) {
|
||||
loopInfo.loopBodys->SetBit(pred->GetId());
|
||||
pendingList_.emplace_back(pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ComputeLoopNumber()
|
||||
{
|
||||
auto size = linearizer_->regionList_.size();
|
||||
dfsStack_.resize(size, DFSState(nullptr, 0));
|
||||
linearizer_->circuit_->AdvanceTime();
|
||||
|
||||
auto entry = linearizer_->regionList_.front();
|
||||
auto currentDepth = Push(entry, 0);
|
||||
while (currentDepth > 0) {
|
||||
auto& curState = dfsStack_[currentDepth - 1]; // -1: for current
|
||||
auto curRegion = curState.region;
|
||||
auto index = curState.index;
|
||||
|
||||
if (index == curRegion->succs_.size()) {
|
||||
currentDepth--;
|
||||
curRegion->SetFinished(acc_);
|
||||
} else {
|
||||
GateRegion* succ = curRegion->succs_[index];
|
||||
curState.index = ++index;
|
||||
if (succ->IsFinished(acc_)) {
|
||||
continue;
|
||||
}
|
||||
if (succ->IsUnvisited(acc_)) {
|
||||
currentDepth = Push(succ, currentDepth);
|
||||
} else {
|
||||
ASSERT(succ->IsVisited(acc_));
|
||||
loopbacks_.emplace_back(DFSState(curRegion, index - 1)); // -1: for prev
|
||||
if (!succ->HasLoopNumber()) {
|
||||
succ->SetLoopNumber(numLoops_++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ComputeLoopExit()
|
||||
{
|
||||
linearizer_->circuit_->AdvanceTime();
|
||||
auto entry = linearizer_->regionList_.front();
|
||||
LoopInfo *loopInfo = nullptr;
|
||||
auto currentDepth = Push(entry, 0);
|
||||
while (currentDepth > 0) {
|
||||
auto &curState = dfsStack_[currentDepth - 1]; // -1: for current
|
||||
auto curRegion = curState.region;
|
||||
auto index = curState.index;
|
||||
GateRegion* succ = nullptr;
|
||||
if (index >= curRegion->succs_.size()) {
|
||||
if (curRegion->HasLoopNumber()) {
|
||||
if (curRegion->IsVisited(acc_)) {
|
||||
ASSERT(loopInfo != nullptr && loopInfo->loopHead == curRegion);
|
||||
loopInfo = loopInfo->outer_;
|
||||
}
|
||||
}
|
||||
curRegion->SetFinished(acc_);
|
||||
currentDepth--;
|
||||
} else {
|
||||
succ = curRegion->succs_[index];
|
||||
curState.index = ++index;
|
||||
if (!succ->IsUnvisited(acc_)) {
|
||||
continue;
|
||||
}
|
||||
if (loopInfo != nullptr) {
|
||||
if (!loopInfo->loopBodys->TestBit(succ->GetId())) {
|
||||
AddLoopExit(succ, loopInfo);
|
||||
} else {
|
||||
succ->loopHead_ = loopInfo->loopHead;
|
||||
}
|
||||
}
|
||||
currentDepth = Push(succ, currentDepth);
|
||||
loopInfo = EnterInnerLoop(succ, loopInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddLoopExit(GateRegion* succ, LoopInfo *loopInfo)
|
||||
{
|
||||
if (loopInfo->loopExits == nullptr) {
|
||||
loopInfo->loopExits = chunk_->New<ChunkVector<GateRegion*>>(chunk_);
|
||||
}
|
||||
loopInfo->loopExits->emplace_back(succ);
|
||||
}
|
||||
|
||||
LoopInfo *EnterInnerLoop(GateRegion* succ, LoopInfo *loopInfo)
|
||||
{
|
||||
// enter inner loop
|
||||
if (succ->HasLoopNumber()) {
|
||||
auto& innerLoop = loops_[succ->GetLoopNumber()];
|
||||
innerLoop.outer_ = loopInfo;
|
||||
loopInfo = &innerLoop;
|
||||
}
|
||||
return loopInfo;
|
||||
}
|
||||
|
||||
void ComputeLoopHeader()
|
||||
{
|
||||
auto size = linearizer_->regionList_.size();
|
||||
for (size_t i = 0; i < numLoops_; i++) {
|
||||
auto& loopInfo = loops_[i];
|
||||
for (size_t j = 0; j < size; j++) {
|
||||
if (loopInfo.loopBodys->TestBit(j)) {
|
||||
auto current = linearizer_->regionList_.at(j);
|
||||
if (!CheckRegionDomLoopExist(current, loopInfo)) {
|
||||
current->loopHead_ = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckRegionDomLoopExist(GateRegion* region, LoopInfo& loopInfo)
|
||||
{
|
||||
if (loopInfo.loopExits == nullptr) {
|
||||
return true;
|
||||
}
|
||||
for (auto exitRegion : *loopInfo.loopExits) {
|
||||
if (linearizer_->GetCommonDominator(region, exitRegion) != region) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Push(GateRegion *region, size_t depth)
|
||||
{
|
||||
if (region->IsUnvisited(acc_)) {
|
||||
dfsStack_[depth].region = region;
|
||||
dfsStack_[depth].index = 0;
|
||||
region->SetVisited(acc_);
|
||||
return depth + 1;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
private:
|
||||
struct DFSState {
|
||||
DFSState(GateRegion *region, size_t index)
|
||||
: region(region), index(index) {}
|
||||
|
||||
GateRegion *region;
|
||||
size_t index;
|
||||
};
|
||||
GraphLinearizer* linearizer_ {nullptr};
|
||||
ChunkDeque<GateRegion*> pendingList_;
|
||||
ChunkVector<LoopInfo> loops_;
|
||||
ChunkVector<DFSState> loopbacks_;
|
||||
Chunk* chunk_ {nullptr};
|
||||
ChunkVector<DFSState> dfsStack_;
|
||||
GateAccessor acc_;
|
||||
size_t numLoops_{0};
|
||||
};
|
||||
|
||||
class GateScheduler {
|
||||
public:
|
||||
explicit GateScheduler(GraphLinearizer *linearizer)
|
||||
@ -435,12 +679,28 @@ public:
|
||||
auto region = GetCommonDominatorOfAllUses(curGate);
|
||||
if (scheduleUpperBound_) {
|
||||
ASSERT(curInfo.upperBound != nullptr);
|
||||
ASSERT(GetCommonDominator(region, curInfo.upperBound) == curInfo.upperBound);
|
||||
region = curInfo.upperBound;
|
||||
ASSERT(linearizer_->GetCommonDominator(region, curInfo.upperBound) == curInfo.upperBound);
|
||||
auto uppermost = curInfo.upperBound->depth_;
|
||||
auto upperRegion = GetUpperBoundRegion(region);
|
||||
while (upperRegion != nullptr && upperRegion->depth_ >= uppermost) {
|
||||
region = upperRegion;
|
||||
upperRegion = GetUpperBoundRegion(region);
|
||||
}
|
||||
}
|
||||
ScheduleGate(curGate, region);
|
||||
}
|
||||
|
||||
GateRegion* GetUpperBoundRegion(GateRegion* region)
|
||||
{
|
||||
if (region->IsLoopHead()) {
|
||||
return region->iDominator_;
|
||||
}
|
||||
if (region->loopHead_ != nullptr) {
|
||||
return region->loopHead_->iDominator_;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ScheduleGate(GateRef gate, GateRegion* region)
|
||||
{
|
||||
auto ins = acc_.Ins(gate);
|
||||
@ -484,27 +744,15 @@ public:
|
||||
region = useRegion;
|
||||
} else {
|
||||
ASSERT(useRegion != nullptr);
|
||||
region = GetCommonDominator(region, useRegion);
|
||||
region = linearizer_->GetCommonDominator(region, useRegion);
|
||||
}
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
GateRegion* GetCommonDominator(GateRegion* left, GateRegion* right) const
|
||||
{
|
||||
while (left != right) {
|
||||
if (left->depth_ < right->depth_) {
|
||||
right = right->iDominator_;
|
||||
} else {
|
||||
left = left->iDominator_;
|
||||
}
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
bool IsInSameDominatorChain(GateRegion* left, GateRegion* right) const
|
||||
{
|
||||
auto dom = GetCommonDominator(left, right);
|
||||
auto dom = linearizer_->GetCommonDominator(left, right);
|
||||
return left == dom || right == dom;
|
||||
}
|
||||
|
||||
@ -547,6 +795,11 @@ void GraphLinearizer::LinearizeGraph()
|
||||
builder.Run();
|
||||
ImmediateDominatorsGenerator generator(this, chunk_, regionList_.size());
|
||||
generator.Run();
|
||||
if (!IsSchedueLIR() && loopNumber_ > 0) {
|
||||
scheduleUpperBound_ = true;
|
||||
LoopInfoBuilder loopInfoBuilder(this, chunk_);
|
||||
loopInfoBuilder.Run();
|
||||
}
|
||||
GateScheduler scheduler(this);
|
||||
scheduler.Prepare();
|
||||
scheduler.ScheduleUpperBound();
|
||||
@ -595,6 +848,18 @@ GateRegion* GraphLinearizer::FindPredRegion(GateRef input)
|
||||
return predRegion;
|
||||
}
|
||||
|
||||
GateRegion* GraphLinearizer::GetCommonDominator(GateRegion* left, GateRegion* right) const
|
||||
{
|
||||
while (left != right) {
|
||||
if (left->depth_ < right->depth_) {
|
||||
right = right->iDominator_;
|
||||
} else {
|
||||
left = left->iDominator_;
|
||||
}
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
void GraphLinearizer::PrintGraph(const char* title)
|
||||
{
|
||||
LOG_COMPILER(INFO) << "======================== " << title << " ========================";
|
||||
@ -602,9 +867,10 @@ void GraphLinearizer::PrintGraph(const char* title)
|
||||
auto bb = regionList_[i];
|
||||
auto front = bb->gateList_.front();
|
||||
auto opcode = acc_.GetOpCode(front);
|
||||
auto loopHeadId = bb->loopHead_ != nullptr ? bb->loopHead_->id_ : 0;
|
||||
LOG_COMPILER(INFO) << "B" << bb->id_ << ": " << "depth: [" << bb->depth_ << "] "
|
||||
<< opcode << "(" << acc_.GetId(front) << ") "
|
||||
<< "IDom B" << bb->iDominator_->id_;
|
||||
<< "IDom B" << bb->iDominator_->id_ << " loop Header: " << loopHeadId;
|
||||
std::string log("\tPreds: ");
|
||||
for (size_t k = 0; k < bb->preds_.size(); ++k) {
|
||||
log += std::to_string(bb->preds_[k]->id_) + ", ";
|
||||
|
@ -45,11 +45,26 @@ public:
|
||||
acc.SetMark(state_, MarkCode::VISITED);
|
||||
}
|
||||
|
||||
void SetFinished(GateAccessor& acc)
|
||||
{
|
||||
acc.SetMark(state_, MarkCode::FINISHED);
|
||||
}
|
||||
|
||||
bool IsUnvisited(GateAccessor& acc) const
|
||||
{
|
||||
return acc.GetMark(state_) == MarkCode::NO_MARK;
|
||||
}
|
||||
|
||||
bool IsVisited(GateAccessor& acc) const
|
||||
{
|
||||
return acc.GetMark(state_) == MarkCode::VISITED;
|
||||
}
|
||||
|
||||
bool IsFinished(GateAccessor& acc) const
|
||||
{
|
||||
return acc.GetMark(state_) == MarkCode::FINISHED;
|
||||
}
|
||||
|
||||
bool IsLoopHead() const
|
||||
{
|
||||
return stateKind_ == StateKind::LOOP_HEAD;
|
||||
@ -65,6 +80,21 @@ public:
|
||||
return id_;
|
||||
}
|
||||
|
||||
void SetLoopNumber(size_t loopNumber)
|
||||
{
|
||||
loopNumber_ = static_cast<int32_t>(loopNumber);
|
||||
}
|
||||
|
||||
size_t GetLoopNumber() const
|
||||
{
|
||||
return static_cast<size_t>(loopNumber_);
|
||||
}
|
||||
|
||||
bool HasLoopNumber() const
|
||||
{
|
||||
return loopNumber_ >= 0;
|
||||
}
|
||||
|
||||
private:
|
||||
enum StateKind {
|
||||
BRANCH,
|
||||
@ -76,15 +106,18 @@ private:
|
||||
size_t id_ {0};
|
||||
int32_t depth_ {INVALID_DEPTH};
|
||||
GateRegion* iDominator_ {nullptr};
|
||||
GateRegion* loopHead_ {nullptr};
|
||||
ChunkVector<GateRef> gateList_;
|
||||
ChunkVector<GateRegion*> preds_;
|
||||
ChunkVector<GateRegion*> succs_;
|
||||
ChunkVector<GateRegion*> dominatedRegions_;
|
||||
GateRef state_ {Circuit::NullGate()};
|
||||
StateKind stateKind_ {StateKind::OTHER};
|
||||
int32_t loopNumber_ {INVALID_DEPTH};
|
||||
friend class CFGBuilder;
|
||||
friend class GateScheduler;
|
||||
friend class ImmediateDominatorsGenerator;
|
||||
friend class LoopInfoBuilder;
|
||||
friend class GraphLinearizer;
|
||||
friend class StateDependBuilder;
|
||||
};
|
||||
@ -144,6 +177,7 @@ private:
|
||||
void LinearizeRegions(ControlFlowGraph &result);
|
||||
void CreateGateRegion(GateRef gate);
|
||||
GateRegion* FindPredRegion(GateRef input);
|
||||
GateRegion* GetCommonDominator(GateRegion* left, GateRegion* right) const;
|
||||
|
||||
GateInfo& GetGateInfo(GateRef gate)
|
||||
{
|
||||
@ -231,6 +265,7 @@ private:
|
||||
regionRootList_.clear();
|
||||
scheduleUpperBound_ = false;
|
||||
model_ = ScheduleModel::LIR;
|
||||
loopNumber_ = 0;
|
||||
}
|
||||
|
||||
void EnableScheduleUpperBound()
|
||||
@ -251,7 +286,7 @@ private:
|
||||
void PrintGraph(const char* title);
|
||||
|
||||
bool enableLog_ {false};
|
||||
bool scheduleUpperBound_ { false};
|
||||
bool scheduleUpperBound_ {false};
|
||||
ScheduleModel model_ {ScheduleModel::LIR};
|
||||
std::string methodName_;
|
||||
Chunk* chunk_ {nullptr};
|
||||
@ -266,6 +301,7 @@ private:
|
||||
friend class CFGBuilder;
|
||||
friend class GateScheduler;
|
||||
friend class ImmediateDominatorsGenerator;
|
||||
friend class LoopInfoBuilder;
|
||||
friend class StateSplitLinearizer;
|
||||
};
|
||||
}; // namespace panda::ecmascript::kungfu
|
||||
|
@ -453,7 +453,7 @@ void LCRLowering::LowerGetGlobalEnv(GateRef gate)
|
||||
{
|
||||
Environment env(gate, circuit_, &builder_);
|
||||
GateRef glueGlobalEnvOffset = builder_.IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(false));
|
||||
GateRef glueGlobalEnv = builder_.Load(VariableType::NATIVE_POINTER(), glue_, glueGlobalEnvOffset);
|
||||
GateRef glueGlobalEnv = builder_.Load(VariableType::JS_POINTER(), glue_, glueGlobalEnvOffset);
|
||||
acc_.ReplaceGate(gate, Circuit::NullGate(), builder_.GetDepend(), glueGlobalEnv);
|
||||
}
|
||||
|
||||
|
@ -18,4 +18,17 @@ var someArray = [1, 5, 7];
|
||||
for (var tmp of someArray) {
|
||||
var tmpNumber = tmp;
|
||||
print(tmpNumber);
|
||||
}
|
||||
}
|
||||
|
||||
class A {
|
||||
x: number;
|
||||
}
|
||||
|
||||
function foo(arr: A[]) {
|
||||
for (var tmp of arr) {
|
||||
tmp.x = 1;
|
||||
}
|
||||
}
|
||||
|
||||
let arr = [new A()]
|
||||
foo(arr);
|
||||
|
Loading…
Reference in New Issue
Block a user