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
19 namespace panda::ecmascript::kungfu {
20
VisitGate(GateRef gate)21 GateRef 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
AddProfiling(GateRef gate)34 void 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
VisitTypedBinaryOp(GateRef gate)48 GateRef TSHCROptPass::VisitTypedBinaryOp(GateRef gate)
49 {
50 if (acc_.HasStringType(gate)) {
51 return VisitStringBinOp(gate);
52 }
53 return Circuit::NullGate();
54 }
55
VisitStringBinOp(GateRef gate)56 GateRef 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
VisitStringEqual(GateRef gate)69 GateRef 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
ConvertStringEqualToConst(GateRef left, GateRef right)93 GateRef 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
IsSingleCharString(GateRef gate)112 bool 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
IsNotLoadStrOrStringLoadElement(GateRef gate)126 bool 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
ConvertConstSingleCharToInt32(GateRef gate)139 GateRef 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
ConvertToSingleCharComparison(GateRef left, GateRef right)153 GateRef 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