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