arkcompiler_ets_runtime/ecmascript/compiler/lexical_env_specialization_pass.cpp
@han_177 9ea7521009 修改告警
Signed-off-by: @han_177 <hanjing35@huawei.com>
issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I9KXRO
2024-05-04 18:22:49 +08:00

341 lines
10 KiB
C++

/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/compiler/lexical_env_specialization_pass.h"
#include "ecmascript/compiler/bytecodes.h"
#include "ecmascript/compiler/scheduler.h"
namespace panda::ecmascript::kungfu {
void LexicalEnvSpecializationPass::Initialize()
{
dependChains_.resize(circuit_->GetMaxGateId() + 1, nullptr); // 1: +1 for size
GateRef entry = acc_.GetDependRoot();
VisitDependEntry(entry);
}
GateRef LexicalEnvSpecializationPass::VisitDependEntry(GateRef gate)
{
auto empty = new (chunk_) DependChains(chunk_);
return UpdateDependChain(gate, empty);
}
GateRef LexicalEnvSpecializationPass::VisitGate(GateRef gate)
{
auto opcode = acc_.GetOpCode(gate);
switch (opcode) {
case OpCode::JS_BYTECODE: {
EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
if (Bytecodes::IsLdLexVarOp(ecmaOpcode)) {
return TrySpecializeLdLexVar(gate);
}
return VisitOther(gate);
}
case OpCode::DEPEND_SELECTOR:
return VisitDependSelector(gate);
default:
if (acc_.GetDependCount(gate) == 1) { // 1: depend in is 1
return VisitOther(gate);
}
}
return Circuit::NullGate();
}
GateRef LexicalEnvSpecializationPass::VisitOther(GateRef gate)
{
ASSERT(acc_.GetDependCount(gate) >= 1);
auto depIn = acc_.GetDep(gate);
auto dependChain = GetDependChain(depIn);
if (dependChain == nullptr) {
return Circuit::NullGate();
}
dependChain = dependChain->UpdateNode(gate);
return UpdateDependChain(gate, dependChain);
}
GateRef LexicalEnvSpecializationPass::VisitDependSelector(GateRef gate)
{
auto state = acc_.GetState(gate);
if (acc_.IsLoopHead(state)) {
// use loop head as depend chain
return VisitOther(gate);
}
auto dependCount = acc_.GetDependCount(gate);
for (size_t i = 0; i < dependCount; ++i) {
auto depend = acc_.GetDep(gate, i);
auto dependChain = GetDependChain(depend);
if (dependChain == nullptr) {
return Circuit::NullGate();
}
}
// all depend done.
auto depend = acc_.GetDep(gate);
auto dependChain = GetDependChain(depend);
DependChains* copy = new (chunk_) DependChains(chunk_);
copy->CopyFrom(dependChain);
for (size_t i = 1; i < dependCount; ++i) { // 1: second in
auto dependIn = acc_.GetDep(gate, i);
auto tempChain = GetDependChain(dependIn);
copy->Merge(tempChain);
}
HasNotdomStLexVarOrCall(gate, copy->GetHeadGate());
return UpdateDependChain(gate, copy);
}
GateRef LexicalEnvSpecializationPass::UpdateDependChain(GateRef gate, DependChains* dependChain)
{
ASSERT(dependChain != nullptr);
auto oldDependChain = GetDependChain(gate);
if (dependChain->Equals(oldDependChain)) {
return Circuit::NullGate();
}
dependChains_[acc_.GetId(gate)] = dependChain;
return gate;
}
GateRef LexicalEnvSpecializationPass::TrySpecializeLdLexVar(GateRef gate)
{
ASSERT(acc_.GetDependCount(gate) == 1);
auto depIn = acc_.GetDep(gate);
auto dependChain = GetDependChain(depIn);
// dependChain is null
if (dependChain == nullptr) {
return Circuit::NullGate();
}
auto stlexvarGate = LookupStLexvarNode(dependChain, gate);
if (stlexvarGate != Circuit::NullGate()) {
return acc_.GetValueIn(stlexvarGate, 3); // 3: stlexvar value in
}
// update gate, for others elimination
dependChain = dependChain->UpdateNode(gate);
return UpdateDependChain(gate, dependChain);
}
bool LexicalEnvSpecializationPass::SearchStLexVar(GateRef gate, GateRef ldLexVar, GateRef &result)
{
if (HasNotDomIllegalOp(gate)) {
result = ldLexVar;
return false;
}
if (acc_.GetOpCode(gate) != OpCode::JS_BYTECODE) {
return false;
}
EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
if (Bytecodes::IsStLexVarOp(ecmaOpcode)) {
if (CheckStLexVar(gate, ldLexVar)) {
result = gate;
specializeId_.emplace_back(acc_.GetId(ldLexVar));
return true;
}
return false;
}
if (Bytecodes::IsCallOrAccessorOp(ecmaOpcode)) {
result = ldLexVar;
return false;
}
return false;
}
bool LexicalEnvSpecializationPass::CheckStLexVar(GateRef gate, GateRef ldldLexVar)
{
int32_t ldLevel = static_cast<int32_t>(acc_.TryGetValue(acc_.GetValueIn(ldldLexVar, 0)));
int32_t ldSlot = static_cast<int32_t>(acc_.TryGetValue(acc_.GetValueIn(ldldLexVar, 1))); // 1: slot
int32_t stLevel = static_cast<int32_t>(acc_.TryGetValue(acc_.GetValueIn(gate, 0)));
int32_t stSlot = static_cast<int32_t>(acc_.TryGetValue(acc_.GetValueIn(gate, 1))); // 1: slot
if (stSlot != ldSlot) {
return false;
}
int32_t depth = 0;
GateRef ldEnv = acc_.GetValueIn(ldldLexVar, 2);
GateRef stEnv = acc_.GetValueIn(gate, 2);
if (caclulateDistanceToTarget(ldEnv, stEnv, depth)) {
return (ldLevel == stLevel + depth);
}
depth = 0;
if (caclulateDistanceToTarget(stEnv, ldEnv, depth)) {
return (ldLevel + depth == stLevel);
}
return false;
}
bool LexicalEnvSpecializationPass::caclulateDistanceToTarget(GateRef startEnv, GateRef targetEnv, int32_t &dis)
{
GateRef curEnv = startEnv;
while (true) {
if (curEnv == targetEnv) {
return true;
}
if (acc_.GetOpCode(curEnv) == OpCode::GET_ENV) {
return false;
}
if (acc_.GetOpCode(curEnv) != OpCode::JS_BYTECODE) {
return false;
}
EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(curEnv);
if (ecmaOpcode != EcmaOpcode::POPLEXENV) {
++dis;
} else {
--dis;
}
curEnv = acc_.GetValueIn(curEnv, acc_.GetNumValueIn(curEnv) - 1); // 1: env value in
}
return false;
}
void LexicalEnvSpecializationPass::HasNotdomStLexVarOrCall(GateRef gate, GateRef next)
{
ASSERT(acc_.GetOpCode(gate) == OpCode::DEPEND_SELECTOR);
ChunkVector<GateRef> vec(chunk_);
ChunkVector<GateRef> visited(chunk_);
vec.emplace_back(gate);
while (!vec.empty()) {
GateRef current = vec.back();
visited.emplace_back(current);
vec.pop_back();
if (current != next) {
if (acc_.GetOpCode(current) == OpCode::JS_BYTECODE) {
LookUpNotDomStLexVarOrCall(current, next);
}
for (size_t i = 0; i < acc_.GetDependCount(current); i++) {
GateRef dependIn = acc_.GetDep(current, i);
if (!std::count(visited.begin(), visited.end(), dependIn)) {
vec.emplace_back(dependIn);
}
}
}
}
}
void LexicalEnvSpecializationPass::LookUpNotDomStLexVarOrCall(GateRef current, GateRef next)
{
EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(current);
if (Bytecodes::IsStLexVarOp(ecmaOpcode)) {
if (current != next) {
auto iter = notdomStlexvar_.find(next);
if (iter == notdomStlexvar_.end()) {
notdomStlexvar_[next] = current;
}
}
}
if (Bytecodes::IsCallOrAccessorOp(ecmaOpcode)) {
if (current != next) {
auto iter = notDomCall_.find(next);
if (iter == notDomCall_.end()) {
notDomCall_[next] = current;
}
}
}
}
bool LexicalEnvSpecializationPass::HasNotDomIllegalOp(GateRef gate)
{
if (HasNotDomStLexvar(gate)) {
return true;
}
if (HasNotDomCall(gate)) {
return true;
}
return false;
}
bool LexicalEnvSpecializationPass::HasNotDomStLexvar(GateRef gate)
{
auto iter = notdomStlexvar_.find(gate);
if (iter != notdomStlexvar_.end()) {
return true;
}
return false;
}
bool LexicalEnvSpecializationPass::HasNotDomCall(GateRef gate)
{
auto iter = notDomCall_.find(gate);
if (iter != notDomCall_.end()) {
return true;
}
return false;
}
GateRef LexicalEnvSpecializationPass::LookupStLexvarNode(DependChains* dependChain, GateRef gate)
{
GateRef result = Circuit::NullGate();
for (auto iter = dependChain->begin(); iter != dependChain->end(); ++iter) {
GateRef curGate = iter.GetCurrentGate();
if (SearchStLexVar(curGate, gate, result)) {
return curGate;
} else {
if (result == gate) {
return Circuit::NullGate();
}
}
}
return Circuit::NullGate();
}
void LexicalEnvSpecializationPass::PrintSpecializeId()
{
if (enableLog_) {
LOG_COMPILER(INFO) << "\033[34m" << "================="
<< " specialize ldlexvar gate id "
<< "=================" << "\033[0m";
for (auto id : specializeId_) {
LOG_COMPILER(INFO) << "ldlexvar id: " << id;
}
LOG_COMPILER(INFO) << "\033[34m" << "===========================================================" << "\033[0m";
}
}
GateRef GetEnvSpecializationPass::VisitGate(GateRef gate)
{
auto opcode = acc_.GetOpCode(gate);
if (opcode == OpCode::GET_ENV && acc_.GetOpCode(acc_.GetValueIn(gate, 0)) != OpCode::ARG) {
GateRef func = acc_.GetValueIn(gate, 0);
if (acc_.GetOpCode(func) == OpCode::JS_BYTECODE) {
return TryGetReplaceEnv(func);
}
}
return Circuit::NullGate();
}
GateRef GetEnvSpecializationPass::TryGetReplaceEnv(GateRef func)
{
ASSERT(acc_.GetNumValueIn(func) >= 1);
EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(func);
switch (ecmaOpcode) {
case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8:
case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8:
case EcmaOpcode::DEFINEMETHOD_IMM8_ID16_IMM8:
case EcmaOpcode::DEFINEMETHOD_IMM16_ID16_IMM8: {
GateRef replacement = acc_.GetValueIn(func, acc_.GetNumValueIn(func) - 1); // 1: last value in
return replacement;
}
default:
return Circuit::NullGate();
}
return Circuit::NullGate();
}
}