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