• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2024 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 
18 #include "ecmascript/compiler/type_info_accessors.h"
19 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
20 #include "ecmascript/js_hclass-inl.h"
21 #include "ecmascript/jit/jit.h"
22 #include "ecmascript/lexical_env.h"
23 
24 namespace panda::ecmascript::kungfu {
25 
RunNTypeBytecodeLowering()26 void NTypeBytecodeLowering::RunNTypeBytecodeLowering()
27 {
28     std::vector<GateRef> gateList;
29     circuit_->GetAllGates(gateList);
30     for (const auto &gate : gateList) {
31         auto op = acc_.GetOpCode(gate);
32         if (op == OpCode::JS_BYTECODE) {
33             Lower(gate);
34         }
35     }
36 
37     if (IsLogEnabled()) {
38         LOG_COMPILER(INFO) << "";
39         LOG_COMPILER(INFO) << "\033[34m"
40                            << "===================="
41                            << " After NTypeBytecodeLowering "
42                            << "[" << GetMethodName() << "]"
43                            << "===================="
44                            << "\033[0m";
45         circuit_->PrintAllGatesWithBytecode();
46         LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
47     }
48 }
49 
Lower(GateRef gate)50 void NTypeBytecodeLowering::Lower(GateRef gate)
51 {
52     [[maybe_unused]] auto scopedGate = circuit_->VisitGateBegin(gate);
53     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
54     // initialize label manager
55     Environment env(gate, circuit_, &builder_);
56     switch (ecmaOpcode) {
57         case EcmaOpcode::CREATEEMPTYARRAY_IMM8:
58         case EcmaOpcode::CREATEEMPTYARRAY_IMM16:
59             LowerNTypedCreateEmptyArray(gate);
60             break;
61         case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
62         case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16: {
63                 Jit::JitLockHolder lock(compilationEnv_, "LowerNTypedCreateArrayWithBuffer");
64                 LowerNTypedCreateArrayWithBuffer(gate);
65             }
66             break;
67         case EcmaOpcode::COPYRESTARGS_IMM8:
68         case EcmaOpcode::WIDE_COPYRESTARGS_PREF_IMM16:
69             LowerNTypedCopyRestArgs(gate);
70             break;
71         case EcmaOpcode::GETUNMAPPEDARGS:
72             LowerNTypedGetUnmappedArgs(gate);
73             break;
74         case EcmaOpcode::STOWNBYINDEX_IMM8_V8_IMM16:
75         case EcmaOpcode::STOWNBYINDEX_IMM16_V8_IMM16:
76         case EcmaOpcode::WIDE_STOWNBYINDEX_PREF_V8_IMM32:
77             LowerNTypedStownByIndex(gate);
78             break;
79         case EcmaOpcode::THROW_UNDEFINEDIFHOLEWITHNAME_PREF_ID16:
80             LowerThrowUndefinedIfHoleWithName(gate);
81             break;
82         case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM8:
83         case EcmaOpcode::THROW_IFSUPERNOTCORRECTCALL_PREF_IMM16:
84             LowerThrowIfSuperNotCorrectCall(gate);
85             break;
86         case EcmaOpcode::THROW_IFNOTOBJECT_PREF_V8:
87             LowerThrowIfNotObject(gate);
88             break;
89         case EcmaOpcode::LDLEXVAR_IMM4_IMM4:
90         case EcmaOpcode::LDLEXVAR_IMM8_IMM8:
91         case EcmaOpcode::WIDE_LDLEXVAR_PREF_IMM16_IMM16:
92             LowerLdLexVar(gate);
93             break;
94         case EcmaOpcode::STLEXVAR_IMM4_IMM4:
95         case EcmaOpcode::STLEXVAR_IMM8_IMM8:
96         case EcmaOpcode::WIDE_STLEXVAR_PREF_IMM16_IMM16:
97             LowerStLexVar(gate);
98             break;
99         case EcmaOpcode::LDLOCALMODULEVAR_IMM8:
100         case EcmaOpcode::WIDE_LDLOCALMODULEVAR_PREF_IMM16:
101             LowerLdLocalMoudleVar(gate);
102             break;
103         case EcmaOpcode::STMODULEVAR_IMM8:
104         case EcmaOpcode::WIDE_STMODULEVAR_PREF_IMM16:
105             LowerStModuleVar(gate);
106             break;
107         case EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8:
108         case EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8: {
109                 Jit::JitLockHolder lock(compilationEnv_, "LowerNTypedStOwnByName");
110                 LowerNTypedStOwnByName(gate);
111             }
112             break;
113         default:
114             break;
115     }
116 }
117 
LowerThrowUndefinedIfHoleWithName(GateRef gate)118 void NTypeBytecodeLowering::LowerThrowUndefinedIfHoleWithName(GateRef gate)
119 {
120     AddProfiling(gate);
121     GateRef value = acc_.GetValueIn(gate, 1); // 1: the second parameter
122     builder_.LexVarIsHoleCheck(value);
123     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
124 }
125 
LowerThrowIfSuperNotCorrectCall(GateRef gate)126 void NTypeBytecodeLowering::LowerThrowIfSuperNotCorrectCall(GateRef gate)
127 {
128     AddProfiling(gate);
129     GateRef index = acc_.GetValueIn(gate, 0);
130     GateRef value = acc_.GetValueIn(gate, 1);
131     uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
132     if (indexValue == CALL_SUPER_BEFORE_THIS_CHECK) {
133         builder_.IsUndefinedOrHoleCheck(value);
134     } else if (indexValue == FORBIDDEN_SUPER_REBIND_THIS_CHECK) {
135         builder_.IsNotUndefinedOrHoleCheck(value);
136     } else {
137         UNREACHABLE();
138     }
139     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), builder_.TaggedTrue());
140 }
141 
LowerThrowIfNotObject(GateRef gate)142 void NTypeBytecodeLowering::LowerThrowIfNotObject(GateRef gate)
143 {
144     AddProfiling(gate);
145     GateRef value = acc_.GetValueIn(gate, 0); // 0: the first parameter
146     builder_.EcmaObjectCheck(value);
147     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
148 }
149 
LowerLdLexVar(GateRef gate)150 void NTypeBytecodeLowering::LowerLdLexVar(GateRef gate)
151 {
152     AddProfiling(gate);
153     GateRef level = acc_.GetValueIn(gate, 0); // 0: first parameter
154     GateRef index = acc_.GetValueIn(gate, 1); // 1: the second parameter
155     GateRef currentEnv = acc_.GetValueIn(gate, 2); // 2: the third parameter
156 
157     uint32_t levelValue = static_cast<uint32_t>(acc_.GetConstantValue(level));
158     uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
159     indexValue += LexicalEnv::RESERVED_ENV_LENGTH;
160     GateRef result = Circuit::NullGate();
161     if (levelValue == 0) {
162         result = builder_.LoadFromTaggedArray(currentEnv, indexValue);
163     } else if (levelValue == 1) { // 1: level 1
164         auto parentEnv = builder_.LoadFromTaggedArray(currentEnv, LexicalEnv::PARENT_ENV_INDEX);
165         result = builder_.LoadFromTaggedArray(parentEnv, indexValue);
166     } else {
167         // level > 1, go slowpath
168         return;
169     }
170     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
171 }
172 
LowerStLexVar(GateRef gate)173 void NTypeBytecodeLowering::LowerStLexVar(GateRef gate)
174 {
175     AddProfiling(gate);
176     GateRef level = acc_.GetValueIn(gate, 0); // 0: first parameter
177     GateRef index = acc_.GetValueIn(gate, 1); // 1: the second parameter
178     GateRef currentEnv = acc_.GetValueIn(gate, 2); // 2: the third parameter
179     GateRef value = acc_.GetValueIn(gate, 3); // 3: the fourth parameter
180 
181     uint32_t levelValue = static_cast<uint32_t>(acc_.GetConstantValue(level));
182     uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
183     indexValue += LexicalEnv::RESERVED_ENV_LENGTH;
184     GateRef result = Circuit::NullGate();
185     if (levelValue == 0) {
186         result = builder_.StoreToTaggedArray(currentEnv, indexValue, value);
187     } else if (levelValue == 1) { // 1: level 1
188         auto parentEnv = builder_.LoadFromTaggedArray(currentEnv, LexicalEnv::PARENT_ENV_INDEX);
189         result = builder_.StoreToTaggedArray(parentEnv, indexValue, value);
190     } else {
191         // level > 1, go slowpath
192         return;
193     }
194     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
195 }
196 
LowerNTypedCreateEmptyArray(GateRef gate)197 void NTypeBytecodeLowering::LowerNTypedCreateEmptyArray(GateRef gate)
198 {
199     // in the future, the type of the elements in the array will be obtained through pgo,
200     // and the type will be used to determine whether to create a typed-array.
201     AddProfiling(gate);
202     ElementsKind kind = acc_.TryGetElementsKind(gate);
203     uint32_t length = acc_.TryGetArrayElementsLength(gate);
204     RegionSpaceFlag flag = acc_.TryGetRegionSpaceFlag(gate);
205     GateRef array = builder_.CreateArray(kind, 0, builder_.Int64(length), flag);
206     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
207 }
208 
LowerNTypedCreateArrayWithBuffer(GateRef gate)209 void NTypeBytecodeLowering::LowerNTypedCreateArrayWithBuffer(GateRef gate)
210 {
211     // 1: number of value inputs
212     ASSERT(acc_.GetNumValueIn(gate) == 1);
213     GateRef index = acc_.GetValueIn(gate, 0);
214     auto methodOffset = acc_.TryGetMethodOffset(gate);
215     uint32_t cpId = ptManager_->GetConstantPoolIDByMethodOffset(methodOffset);
216 
217     uint32_t constPoolIndex = static_cast<uint32_t>(acc_.GetConstantValue(index));
218     JSTaggedValue arr = GetArrayLiteralValue(cpId, constPoolIndex);
219     // Since jit has no lazy loading array from constantpool, arr might be undefined.
220     if (arr.IsUndefined()) {
221         return;
222     }
223     AddProfiling(gate);
224     ElementsKind kind = acc_.TryGetElementsKind(gate);
225     RegionSpaceFlag flag = acc_.TryGetRegionSpaceFlag(gate);
226     GateRef cpIdGr = builder_.Int32(cpId);
227     GateRef array =
228         builder_.CreateArrayWithBuffer(kind, ArrayMetaDataAccessor::Mode::CREATE,
229                                        cpIdGr, index, flag);
230     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
231 }
232 
LowerNTypedCopyRestArgs(GateRef gate)233 void NTypeBytecodeLowering::LowerNTypedCopyRestArgs(GateRef gate)
234 {
235     ASSERT(acc_.GetNumValueIn(gate) == 1);
236     GateRef restIdx = acc_.GetValueIn(gate, 0);
237     AddProfiling(gate);
238     ElementsKind kind = acc_.TryGetElementsKind(gate);
239     GateRef arguments =
240         builder_.CreateArguments(kind, CreateArgumentsAccessor::Mode::REST_ARGUMENTS, restIdx);
241     ReplaceGateWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), arguments);
242 }
243 
LowerNTypedGetUnmappedArgs(GateRef gate)244 void NTypeBytecodeLowering::LowerNTypedGetUnmappedArgs(GateRef gate)
245 {
246     ASSERT(acc_.GetNumValueIn(gate) == 0);
247     GateRef restIdx = builder_.Int32(0);
248     AddProfiling(gate);
249     ElementsKind kind = acc_.TryGetElementsKind(gate);
250     GateRef arguments =
251         builder_.CreateArguments(kind, CreateArgumentsAccessor::Mode::UNMAPPED_ARGUMENTS, restIdx);
252     ReplaceGateWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), arguments);
253 }
254 
LowerNTypedStownByIndex(GateRef gate)255 void NTypeBytecodeLowering::LowerNTypedStownByIndex(GateRef gate)
256 {
257     // 3: number of value inputs
258     ASSERT(acc_.GetNumValueIn(gate) == 3);
259     GateRef receiver = acc_.GetValueIn(gate, 0);
260     GateRef index = acc_.GetValueIn(gate, 1);
261     GateRef value = acc_.GetValueIn(gate, 2);
262     if (acc_.GetOpCode(receiver) != OpCode::CREATE_ARRAY &&
263         acc_.GetOpCode(receiver) != OpCode::CREATE_ARRAY_WITH_BUFFER) {
264         return;
265     }
266     builder_.COWArrayCheck(receiver);
267 
268     AddProfiling(gate);
269     uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
270     uint32_t arraySize = acc_.GetArraySize(receiver);
271     if (indexValue > arraySize) {
272         acc_.TrySetElementsKind(receiver, ElementsKind::HOLE);
273     }
274     acc_.SetArraySize(receiver, std::max(arraySize, indexValue + 1));
275     index = builder_.Int32(indexValue);
276     builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, index, value);
277     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
278 }
279 
AddProfiling(GateRef gate)280 void NTypeBytecodeLowering::AddProfiling(GateRef gate)
281 {
282     if (IsTraceBC()) {
283         // see stateSplit as a part of JSByteCode if exists
284         GateRef maybeStateSplit = acc_.GetDep(gate);
285         GateRef current = Circuit::NullGate();
286         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
287             current = maybeStateSplit;
288         } else {
289             current = gate;
290         }
291 
292         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
293         auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
294         GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
295         GateRef typedPath = builder_.Int32ToTaggedInt(builder_.Int32(1));
296         GateRef traceGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(current),
297                                                  { constOpcode, typedPath }, gate);
298         acc_.SetDep(current, traceGate);
299         builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: trace or STATE_SPLIT
300     }
301 
302     if (IsProfiling()) {
303         // see stateSplit as a part of JSByteCode if exists
304         GateRef maybeStateSplit = acc_.GetDep(gate);
305         GateRef current = Circuit::NullGate();
306         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
307             current = maybeStateSplit;
308         } else {
309             current = gate;
310         }
311 
312         GateRef func = builder_.Undefined();
313         if (acc_.HasFrameState(gate)) {
314             func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
315         }
316 
317         GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate)));
318         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
319         auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
320         GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
321         GateRef mode =
322             builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::TYPED_PATH)));
323         GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current),
324             { func, bcIndex, constOpcode, mode }, gate);
325         acc_.SetDep(current, profiling);
326         builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: profiling or STATE_SPLIT
327     }
328 }
329 
LowerLdLocalMoudleVar(GateRef gate)330 void NTypeBytecodeLowering::LowerLdLocalMoudleVar(GateRef gate)
331 {
332     AddProfiling(gate);
333     GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
334     GateRef index = acc_.GetValueIn(gate, 0);
335     GateRef result = builder_.LdLocalModuleVar(jsFunc, index);
336     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
337 }
338 
LowerStModuleVar(GateRef gate)339 void NTypeBytecodeLowering::LowerStModuleVar(GateRef gate)
340 {
341     AddProfiling(gate);
342     GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
343     GateRef index = acc_.GetValueIn(gate, 0);
344     GateRef value = acc_.GetValueIn(gate, 1);
345     builder_.StoreModuleVar(jsFunc, index, value);
346     ReplaceGateWithPendingException(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
347 }
348 
LowerNTypedStOwnByName(GateRef gate)349 void NTypeBytecodeLowering::LowerNTypedStOwnByName(GateRef gate)
350 {
351     // 3: number of value inputs
352     ASSERT(acc_.GetNumValueIn(gate) == 3);
353     GateRef receiver = acc_.GetValueIn(gate, 1); // 1: receiver
354     if (acc_.GetOpCode(receiver) != OpCode::TYPED_CREATE_OBJ_WITH_BUFFER) {
355         return;
356     }
357 
358     GateRef hclassGate = acc_.GetValueIn(receiver, 2); // 2: hclass offset
359     JSTaggedValue taggedHClass(acc_.GetConstantValue(hclassGate));
360     GateRef stringId = acc_.GetValueIn(gate, 0);
361     JSTaggedValue key = compilationEnv_->GetStringFromConstantPool(acc_.TryGetMethodOffset(gate),
362                                                                    acc_.GetConstantValue(stringId));
363     if (key.IsUndefined()) {
364         return;
365     }
366     JSHClass *hclass = JSHClass::Cast(taggedHClass.GetTaggedObject());
367     int entry = JSHClass::FindPropertyEntry(compilationEnv_->GetJSThread(), hclass, key);
368     if (entry == -1) {
369         return;
370     }
371 
372     LayoutInfo *LayoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
373     PropertyAttributes attr(LayoutInfo->GetAttr(entry));
374     if (attr.IsAccessor()) {
375         return;
376     }
377     if (!attr.IsInlinedProps()) {
378         return;
379     }
380 
381     size_t offset = attr.GetOffset();
382     GateRef accValue = acc_.GetValueIn(gate, 2); // 2: accValue
383     builder_.StoreConstOffset(VariableType::JS_ANY(), receiver, hclass->GetInlinedPropertiesOffset(offset), accValue);
384     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
385 }
386 
ReplaceGateWithPendingException(GateRef gate,GateRef state,GateRef depend,GateRef value)387 void NTypeBytecodeLowering::ReplaceGateWithPendingException(GateRef gate, GateRef state, GateRef depend, GateRef value)
388 {
389     auto glue = acc_.GetGlueFromArgList();
390     auto condition = builder_.HasPendingException(glue);
391     GateRef ifBranch = builder_.Branch(state, condition, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
392     GateRef ifTrue = builder_.IfTrue(ifBranch);
393     GateRef ifFalse = builder_.IfFalse(ifBranch);
394     GateRef eDepend = builder_.DependRelay(ifTrue, depend);
395     GateRef sDepend = builder_.DependRelay(ifFalse, depend);
396 
397     StateDepend success(ifFalse, sDepend);
398     StateDepend exception(ifTrue, eDepend);
399     acc_.ReplaceHirWithIfBranch(gate, success, exception, value);
400 }
401 }
402