1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/compiler/ts_hcr_opt_pass.h" 17#include "ecmascript/jit/jit.h" 18 19namespace panda::ecmascript::kungfu { 20 21GateRef TSHCROptPass::VisitGate(GateRef gate) 22{ 23 AddProfiling(gate); 24 auto opcode = acc_.GetOpCode(gate); 25 switch (opcode) { 26 case OpCode::TYPED_BINARY_OP: 27 return VisitTypedBinaryOp(gate); 28 default: 29 break; 30 } 31 return Circuit::NullGate(); 32} 33 34void TSHCROptPass::AddProfiling(GateRef gate) 35{ 36 if (IsTypedOpProfiling() && acc_.UseForTypeOpProfilerGate(gate)) { 37 Environment env(gate, circuit_, &builder_); 38 OpCode opcode = acc_.GetOpCode(gate); 39 auto opcodeGate = builder_.Int32(static_cast<uint32_t>(opcode)); 40 GateRef constOpcode = builder_.Int32ToTaggedInt(opcodeGate); 41 GateRef traceGate = builder_.CallRuntime(acc_.GetGlueFromArgList(), RTSTUB_ID(ProfileTypedOp), 42 acc_.GetDep(gate), { constOpcode }, gate); 43 acc_.SetDep(gate, traceGate); 44 builder_.SetDepend(acc_.GetDep(gate)); 45 } 46} 47 48GateRef TSHCROptPass::VisitTypedBinaryOp(GateRef gate) 49{ 50 if (acc_.HasStringType(gate)) { 51 return VisitStringBinOp(gate); 52 } 53 return Circuit::NullGate(); 54} 55 56GateRef TSHCROptPass::VisitStringBinOp(GateRef gate) 57{ 58 TypedBinOp op = acc_.GetTypedBinaryOp(gate); 59 switch (op) { 60 case TypedBinOp::TYPED_EQ: { 61 Jit::JitLockHolder lock(compilationEnv_, "VisitStringEqual"); 62 return VisitStringEqual(gate); 63 } 64 default: 65 return Circuit::NullGate(); 66 } 67} 68 69GateRef TSHCROptPass::VisitStringEqual(GateRef gate) 70{ 71 Environment env(gate, circuit_, &builder_); 72 GateRef left = acc_.GetValueIn(gate, 0); 73 GateRef right = acc_.GetValueIn(gate, 1); 74 if (acc_.IsConstString(left) && acc_.IsConstString(right)) { 75 return ConvertStringEqualToConst(left, right); 76 } 77 78 if (IsSingleCharString(left) && IsSingleCharString(right)) { 79 return ConvertToSingleCharComparison(left, right); 80 } 81 82 if (IsNotLoadStrOrStringLoadElement(left) || IsNotLoadStrOrStringLoadElement(right)) { 83 return Circuit::NullGate(); 84 } 85 86 if (IsSingleCharString(left) || IsSingleCharString(right)) { 87 return builder_.Boolean(false); 88 } 89 90 return Circuit::NullGate(); 91} 92 93GateRef TSHCROptPass::ConvertStringEqualToConst(GateRef left, GateRef right) 94{ 95 uint32_t leftId = acc_.GetStringIdFromLdaStrGate(left); 96 uint32_t rightId = acc_.GetStringIdFromLdaStrGate(right); 97 98 auto leftMethodOffset = acc_.TryGetMethodOffset(left); 99 auto rightMethodOffset = acc_.TryGetMethodOffset(right); 100 JSTaggedValue leftStr = GetStringFromConstantPool(leftMethodOffset, leftId); 101 // jit: disallow alloc jsstring, across gc point 102 JSTaggedValue rightStr = GetStringFromConstantPool(rightMethodOffset, rightId, false); 103 if (leftStr == JSTaggedValue::Undefined() || rightStr == JSTaggedValue::Undefined()) { 104 return Circuit::NullGate(); 105 } 106 if (leftStr == rightStr) { 107 return builder_.Boolean(true); 108 } 109 return builder_.Boolean(false); 110} 111 112bool TSHCROptPass::IsSingleCharString(GateRef gate) 113{ 114 if (acc_.IsConstString(gate)) { 115 uint32_t strId = acc_.GetStringIdFromLdaStrGate(gate); 116 auto methodOffset = acc_.TryGetMethodOffset(gate); 117 JSTaggedValue str = GetStringFromConstantPool(methodOffset, strId); 118 if (str.IsUndefined()) { 119 return false; 120 } 121 return EcmaStringAccessor(str).GetLength() == 1; 122 } 123 return acc_.IsSingleCharGate(gate); 124} 125 126bool TSHCROptPass::IsNotLoadStrOrStringLoadElement(GateRef gate) 127{ 128 OpCode op = acc_.GetOpCode(gate); 129 if (op == OpCode::JS_BYTECODE) { 130 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate); 131 return ecmaOpcode != EcmaOpcode::LDA_STR_ID16; 132 } 133 if (op == OpCode::LOAD_ELEMENT) { 134 return acc_.GetTypedLoadOp(gate) != TypedLoadOp::STRING_LOAD_ELEMENT; 135 } 136 return true; 137} 138 139GateRef TSHCROptPass::ConvertConstSingleCharToInt32(GateRef gate) 140{ 141 ASSERT(acc_.IsConstString(gate)); 142 uint32_t strId = acc_.GetStringIdFromLdaStrGate(gate); 143 auto methodOffset = acc_.TryGetMethodOffset(gate); 144 JSTaggedValue str = GetStringFromConstantPool(methodOffset, strId); 145 if (str == JSTaggedValue::Undefined()) { 146 return Circuit::NullGate(); 147 } 148 ASSERT(EcmaStringAccessor(str).GetLength() == 1); 149 uint16_t strToInt = EcmaStringAccessor(str).Get(0); 150 return builder_.Int32(strToInt); 151} 152 153GateRef TSHCROptPass::ConvertToSingleCharComparison(GateRef left, GateRef right) 154{ 155 ASSERT(!acc_.IsConstString(left) || !acc_.IsConstString(right)); 156 if (acc_.IsConstString(left)) { 157 left = ConvertConstSingleCharToInt32(left); 158 } else if (acc_.IsConstString(right)) { 159 right = ConvertConstSingleCharToInt32(right); 160 } 161 // change string binary operator to int binary operator 162 return builder_.TypedBinaryOp<TypedBinOp::TYPED_EQ>(left, right, ParamType::IntType()); 163} 164} // namespace panda::ecmascript::kungfu 165