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/ntype_bytecode_lowering.h"
17 #include "ecmascript/compiler/circuit_builder-inl.h"
18 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
19 #include "ecmascript/compiler/type_info_accessors.h"
20
21 namespace panda::ecmascript::kungfu {
22
RunNTypeBytecodeLowering()23 void NTypeBytecodeLowering::RunNTypeBytecodeLowering()
24 {
25 std::vector<GateRef> gateList;
26 circuit_->GetAllGates(gateList);
27 for (const auto &gate : gateList) {
28 auto op = acc_.GetOpCode(gate);
29 if (op == OpCode::JS_BYTECODE) {
30 Lower(gate);
31 }
32 }
33
34 if (IsLogEnabled()) {
35 LOG_COMPILER(INFO) << "";
36 LOG_COMPILER(INFO) << "\033[34m"
37 << "===================="
38 << " After NTypeBytecodeLowering "
39 << "[" << GetMethodName() << "]"
40 << "===================="
41 << "\033[0m";
42 circuit_->PrintAllGatesWithBytecode();
43 LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
44 }
45 }
46
Lower(GateRef gate)47 void NTypeBytecodeLowering::Lower(GateRef gate)
48 {
49 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
50 // initialize label manager
51 Environment env(gate, circuit_, &builder_);
52 switch (ecmaOpcode) {
53 case EcmaOpcode::CREATEEMPTYARRAY_IMM8:
54 case EcmaOpcode::CREATEEMPTYARRAY_IMM16:
55 LowerNTypedCreateEmptyArray(gate);
56 break;
57 case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
58 case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
59 LowerNTypedCreateArrayWithBuffer(gate);
60 break;
61 case EcmaOpcode::STOWNBYINDEX_IMM8_V8_IMM16:
62 case EcmaOpcode::STOWNBYINDEX_IMM16_V8_IMM16:
63 case EcmaOpcode::WIDE_STOWNBYINDEX_PREF_V8_IMM32:
64 LowerNTypedStownByIndex(gate);
65 break;
66 case EcmaOpcode::THROW_UNDEFINEDIFHOLEWITHNAME_PREF_ID16:
67 LowerThrowUndefinedIfHoleWithName(gate);
68 break;
69 case EcmaOpcode::LDLEXVAR_IMM4_IMM4:
70 case EcmaOpcode::LDLEXVAR_IMM8_IMM8:
71 case EcmaOpcode::WIDE_LDLEXVAR_PREF_IMM16_IMM16:
72 LowerLdLexVar(gate);
73 break;
74 case EcmaOpcode::STLEXVAR_IMM4_IMM4:
75 case EcmaOpcode::STLEXVAR_IMM8_IMM8:
76 case EcmaOpcode::WIDE_STLEXVAR_PREF_IMM16_IMM16:
77 LowerStLexVar(gate);
78 break;
79 case EcmaOpcode::LDLOCALMODULEVAR_IMM8:
80 case EcmaOpcode::WIDE_LDLOCALMODULEVAR_PREF_IMM16:
81 LowerLdLocalMoudleVar(gate);
82 break;
83 case EcmaOpcode::STMODULEVAR_IMM8:
84 case EcmaOpcode::WIDE_STMODULEVAR_PREF_IMM16:
85 LowerStModuleVar(gate);
86 break;
87 case EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8:
88 case EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8:
89 LowerNTypedStOwnByName(gate);
90 break;
91 default:
92 break;
93 }
94 }
95
LowerThrowUndefinedIfHoleWithName(GateRef gate)96 void NTypeBytecodeLowering::LowerThrowUndefinedIfHoleWithName(GateRef gate)
97 {
98 AddProfiling(gate);
99 GateRef value = acc_.GetValueIn(gate, 1); // 1: the second parameter
100 builder_.LexVarIsHoleCheck(value);
101 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
102 }
103
LowerLdLexVar(GateRef gate)104 void NTypeBytecodeLowering::LowerLdLexVar(GateRef gate)
105 {
106 AddProfiling(gate);
107 GateRef level = acc_.GetValueIn(gate, 0); // 0: first parameter
108 GateRef index = acc_.GetValueIn(gate, 1); // 1: the second parameter
109 GateRef currentEnv = acc_.GetValueIn(gate, 2); // 2: the third parameter
110
111 uint32_t levelValue = static_cast<uint32_t>(acc_.GetConstantValue(level));
112 uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
113 indexValue += LexicalEnv::RESERVED_ENV_LENGTH;
114 GateRef result = Circuit::NullGate();
115 if (levelValue == 0) {
116 result = builder_.LoadFromTaggedArray(currentEnv, indexValue);
117 } else if (levelValue == 1) { // 1: level 1
118 auto parentEnv = builder_.LoadFromTaggedArray(currentEnv, LexicalEnv::PARENT_ENV_INDEX);
119 result = builder_.LoadFromTaggedArray(parentEnv, indexValue);
120 } else {
121 // level > 1, go slowpath
122 return;
123 }
124 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
125 }
126
LowerStLexVar(GateRef gate)127 void NTypeBytecodeLowering::LowerStLexVar(GateRef gate)
128 {
129 AddProfiling(gate);
130 GateRef level = acc_.GetValueIn(gate, 0); // 0: first parameter
131 GateRef index = acc_.GetValueIn(gate, 1); // 1: the second parameter
132 GateRef currentEnv = acc_.GetValueIn(gate, 2); // 2: the third parameter
133 GateRef value = acc_.GetValueIn(gate, 3); // 3: the fourth parameter
134
135 uint32_t levelValue = static_cast<uint32_t>(acc_.GetConstantValue(level));
136 uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
137 indexValue += LexicalEnv::RESERVED_ENV_LENGTH;
138 GateRef result = Circuit::NullGate();
139 if (levelValue == 0) {
140 result = builder_.StoreToTaggedArray(currentEnv, indexValue, value);
141 } else if (levelValue == 1) { // 1: level 1
142 auto parentEnv = builder_.LoadFromTaggedArray(currentEnv, LexicalEnv::PARENT_ENV_INDEX);
143 result = builder_.StoreToTaggedArray(parentEnv, indexValue, value);
144 } else {
145 // level > 1, go slowpath
146 return;
147 }
148 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
149 }
150
LowerNTypedCreateEmptyArray(GateRef gate)151 void NTypeBytecodeLowering::LowerNTypedCreateEmptyArray(GateRef gate)
152 {
153 // in the future, the type of the elements in the array will be obtained through pgo,
154 // and the type will be used to determine whether to create a typed-array.
155 AddProfiling(gate);
156 ElementsKind kind = acc_.TryGetElementsKind(gate);
157 uint32_t length = acc_.TryGetArrayElementsLength(gate);
158 GateRef array = builder_.CreateArray(kind, 0, builder_.Int64(length));
159 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
160 }
161
LowerNTypedCreateArrayWithBuffer(GateRef gate)162 void NTypeBytecodeLowering::LowerNTypedCreateArrayWithBuffer(GateRef gate)
163 {
164 // 1: number of value inputs
165 ASSERT(acc_.GetNumValueIn(gate) == 1);
166 GateRef index = acc_.GetValueIn(gate, 0);
167 uint32_t cpIdx = static_cast<uint32_t>(acc_.GetConstantValue(index));
168 auto methodOffset = acc_.TryGetMethodOffset(gate);
169 uint32_t cpId = tsManager_->GetConstantPoolId(methodOffset);
170 JSTaggedValue cp = tsManager_->GetConstantPool(methodOffset);
171 panda_file::File::EntityId id = ConstantPool::GetIdFromCache(cp, cpIdx);
172
173 int elementIndex = ptManager_->GetElementsIndexByEntityId(id);
174 if (elementIndex == -1) { // slowpath
175 return;
176 }
177
178 AddProfiling(gate);
179 ElementsKind kind = acc_.TryGetElementsKind(gate);
180 GateRef elementIndexGate = builder_.IntPtr(elementIndex);
181 GateRef cpIdGr = builder_.Int32(cpId);
182 GateRef array =
183 builder_.CreateArrayWithBuffer(kind, ArrayMetaDataAccessor::Mode::CREATE, cpIdGr, index, elementIndexGate);
184 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
185 }
186
LowerNTypedStownByIndex(GateRef gate)187 void NTypeBytecodeLowering::LowerNTypedStownByIndex(GateRef gate)
188 {
189 // 3: number of value inputs
190 ASSERT(acc_.GetNumValueIn(gate) == 3);
191 GateRef receiver = acc_.GetValueIn(gate, 0);
192 GateRef index = acc_.GetValueIn(gate, 1);
193 GateRef value = acc_.GetValueIn(gate, 2);
194 if (acc_.GetOpCode(receiver) != OpCode::CREATE_ARRAY &&
195 acc_.GetOpCode(receiver) != OpCode::CREATE_ARRAY_WITH_BUFFER) {
196 return;
197 }
198 builder_.COWArrayCheck(receiver);
199
200 AddProfiling(gate);
201 uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
202 uint32_t arraySize = acc_.GetArraySize(receiver);
203 if (indexValue > arraySize) {
204 acc_.TrySetElementsKind(receiver, ElementsKind::HOLE);
205 }
206 acc_.SetArraySize(receiver, std::max(arraySize, indexValue + 1));
207 index = builder_.Int32(indexValue);
208 builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, index, value);
209 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
210 }
211
AddProfiling(GateRef gate)212 void NTypeBytecodeLowering::AddProfiling(GateRef gate)
213 {
214 if (IsTraceBC()) {
215 // see stateSplit as a part of JSByteCode if exists
216 GateRef maybeStateSplit = acc_.GetDep(gate);
217 GateRef current = Circuit::NullGate();
218 if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
219 current = maybeStateSplit;
220 } else {
221 current = gate;
222 }
223
224 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
225 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
226 GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
227 GateRef typedPath = builder_.Int32ToTaggedInt(builder_.Int32(1));
228 GateRef traceGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(current),
229 { constOpcode, typedPath }, gate);
230 acc_.SetDep(current, traceGate);
231 builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: trace or STATE_SPLIT
232 }
233
234 if (IsProfiling()) {
235 // see stateSplit as a part of JSByteCode if exists
236 GateRef maybeStateSplit = acc_.GetDep(gate);
237 GateRef current = Circuit::NullGate();
238 if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
239 current = maybeStateSplit;
240 } else {
241 current = gate;
242 }
243
244 if (acc_.HasFrameState(gate)) {
245 GateRef func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
246 GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate)));
247 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
248 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
249 GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
250 GateRef mode =
251 builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::TYPED_PATH)));
252 GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current),
253 { func, bcIndex, constOpcode, mode }, gate);
254 acc_.SetDep(current, profiling);
255 builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: profiling or STATE_SPLIT
256 }
257 }
258 }
259
LowerLdLocalMoudleVar(GateRef gate)260 void NTypeBytecodeLowering::LowerLdLocalMoudleVar(GateRef gate)
261 {
262 AddProfiling(gate);
263 GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
264 GateRef index = acc_.GetValueIn(gate, 0);
265 GateRef result = builder_.LdLocalModuleVar(jsFunc, index);
266 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
267 }
268
LowerStModuleVar(GateRef gate)269 void NTypeBytecodeLowering::LowerStModuleVar(GateRef gate)
270 {
271 AddProfiling(gate);
272 GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
273 GateRef index = acc_.GetValueIn(gate, 0);
274 GateRef value = acc_.GetValueIn(gate, 1);
275 builder_.StoreModuleVar(jsFunc, index, value);
276 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
277 }
278
LowerNTypedStOwnByName(GateRef gate)279 void NTypeBytecodeLowering::LowerNTypedStOwnByName(GateRef gate)
280 {
281 // 3: number of value inputs
282 ASSERT(acc_.GetNumValueIn(gate) == 3);
283 GateRef receiver = acc_.GetValueIn(gate, 1); // 1: receiver
284 if (acc_.GetOpCode(receiver) != OpCode::TYPED_CREATE_OBJ_WITH_BUFFER) {
285 return;
286 }
287
288 GateRef hclassGate = acc_.GetValueIn(receiver, 3); // 3: hclass offset
289 JSTaggedValue taggedHClass(acc_.GetConstantValue(hclassGate));
290 GateRef stringId = acc_.GetValueIn(gate, 0);
291 JSTaggedValue key = TypeInfoAccessor::GetStringFromConstantPool(thread_, acc_.TryGetMethodOffset(gate),
292 acc_.GetConstantValue(stringId));
293 JSHClass *hclass = JSHClass::Cast(taggedHClass.GetTaggedObject());
294 int entry = JSHClass::FindPropertyEntry(thread_, hclass, key);
295 if (entry == -1) {
296 return;
297 }
298
299 LayoutInfo *LayoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
300 PropertyAttributes attr(LayoutInfo->GetAttr(entry));
301 if (attr.IsAccessor()) {
302 return;
303 }
304 if (!attr.IsInlinedProps()) {
305 return;
306 }
307
308 size_t offset = attr.GetOffset();
309 GateRef accValue = acc_.GetValueIn(gate, 2); // 2: accValue
310 builder_.StoreConstOffset(VariableType::JS_ANY(), receiver, hclass->GetInlinedPropertiesOffset(offset), accValue);
311 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
312 }
313 }
314