• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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