• 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_hcr_lowering.h"
17 #include "ecmascript/compiler/circuit_builder-inl.h"
18 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
19 
20 namespace panda::ecmascript::kungfu {
RunNTypeHCRLowering()21 void NTypeHCRLowering::RunNTypeHCRLowering()
22 {
23     std::vector<GateRef> gateList;
24     circuit_->GetAllGates(gateList);
25     for (const auto &gate : gateList) {
26         auto op = acc_.GetOpCode(gate);
27         if (op == OpCode::JS_BYTECODE) {
28             Lower(gate);
29         }
30     }
31 
32     if (IsLogEnabled()) {
33         LOG_COMPILER(INFO) << "";
34         LOG_COMPILER(INFO) << "\033[34m"
35                            << "===================="
36                            << " After NTypeHCRlowering "
37                            << "[" << GetMethodName() << "]"
38                            << "===================="
39                            << "\033[0m";
40         circuit_->PrintAllGatesWithBytecode();
41         LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
42     }
43 }
44 
Lower(GateRef gate)45 void NTypeHCRLowering::Lower(GateRef gate)
46 {
47     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
48     // initialize label manager
49     Environment env(gate, circuit_, &builder_);
50     switch (ecmaOpcode) {
51         case EcmaOpcode::CREATEEMPTYARRAY_IMM8:
52         case EcmaOpcode::CREATEEMPTYARRAY_IMM16:
53             LowerNTypedCreateEmptyArray(gate);
54             break;
55         case EcmaOpcode::STOWNBYINDEX_IMM8_V8_IMM16:
56         case EcmaOpcode::STOWNBYINDEX_IMM16_V8_IMM16:
57         case EcmaOpcode::WIDE_STOWNBYINDEX_PREF_V8_IMM32:
58             LowerNTypedStownByIndex(gate);
59             break;
60         case EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8:
61         case EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8:
62             LowerNTypedStOwnByName(gate);
63             break;
64         case EcmaOpcode::THROW_UNDEFINEDIFHOLEWITHNAME_PREF_ID16:
65             LowerThrowUndefinedIfHoleWithName(gate);
66             break;
67         case EcmaOpcode::LDLEXVAR_IMM4_IMM4:
68         case EcmaOpcode::LDLEXVAR_IMM8_IMM8:
69         case EcmaOpcode::WIDE_LDLEXVAR_PREF_IMM16_IMM16:
70             LowerLdLexVar(gate);
71             break;
72         case EcmaOpcode::STLEXVAR_IMM4_IMM4:
73         case EcmaOpcode::STLEXVAR_IMM8_IMM8:
74         case EcmaOpcode::WIDE_STLEXVAR_PREF_IMM16_IMM16:
75             LowerStLexVar(gate);
76             break;
77         default:
78             break;
79     }
80 }
81 
LowerThrowUndefinedIfHoleWithName(GateRef gate)82 void NTypeHCRLowering::LowerThrowUndefinedIfHoleWithName(GateRef gate)
83 {
84     GateRef value = acc_.GetValueIn(gate, 1); // 1: the second parameter
85     builder_.LexVarIsHoleCheck(value);
86     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
87 }
88 
LowerLdLexVar(GateRef gate)89 void NTypeHCRLowering::LowerLdLexVar(GateRef gate)
90 {
91     AddProfiling(gate);
92     GateRef level = acc_.GetValueIn(gate, 0); // 0: first parameter
93     GateRef index = acc_.GetValueIn(gate, 1); // 1: the second parameter
94     GateRef currentEnv = acc_.GetValueIn(gate, 2); // 2: the third parameter
95 
96     uint32_t levelValue = static_cast<uint32_t>(acc_.GetConstantValue(level));
97     uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
98     indexValue += LexicalEnv::RESERVED_ENV_LENGTH;
99     GateRef result = Circuit::NullGate();
100     if (levelValue == 0) {
101         result = builder_.LoadFromTaggedArray(currentEnv, indexValue);
102     } else if (levelValue == 1) { // 1: level 1
103         auto parentEnv = builder_.LoadFromTaggedArray(currentEnv, LexicalEnv::PARENT_ENV_INDEX);
104         result = builder_.LoadFromTaggedArray(parentEnv, indexValue);
105     } else {
106         // level > 1, go slowpath
107         return;
108     }
109     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
110 }
111 
LowerStLexVar(GateRef gate)112 void NTypeHCRLowering::LowerStLexVar(GateRef gate)
113 {
114     AddProfiling(gate);
115     GateRef level = acc_.GetValueIn(gate, 0); // 0: first parameter
116     GateRef index = acc_.GetValueIn(gate, 1); // 1: the second parameter
117     GateRef currentEnv = acc_.GetValueIn(gate, 2); // 2: the third parameter
118     GateRef value = acc_.GetValueIn(gate, 3); // 3: the fourth parameter
119 
120     uint32_t levelValue = static_cast<uint32_t>(acc_.GetConstantValue(level));
121     uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
122     indexValue += LexicalEnv::RESERVED_ENV_LENGTH;
123     GateRef result = Circuit::NullGate();
124     if (levelValue == 0) {
125         result = builder_.StoreToTaggedArray(currentEnv, indexValue, value);
126     } else if (levelValue == 1) { // 1: level 1
127         auto parentEnv = builder_.LoadFromTaggedArray(currentEnv, LexicalEnv::PARENT_ENV_INDEX);
128         result = builder_.StoreToTaggedArray(parentEnv, indexValue, value);
129     } else {
130         // level > 1, go slowpath
131         return;
132     }
133     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
134 }
135 
LowerNTypedCreateEmptyArray(GateRef gate)136 void NTypeHCRLowering::LowerNTypedCreateEmptyArray(GateRef gate)
137 {
138     // in the future, the type of the elements in the array will be obtained through pgo,
139     // and the type will be used to determine whether to create a typed-array.
140     AddProfiling(gate);
141     GateRef array = builder_.CreateArray(0);
142     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
143 }
144 
LowerNTypedCreateArrayWithBuffer(GateRef gate)145 void NTypeHCRLowering::LowerNTypedCreateArrayWithBuffer(GateRef gate)
146 {
147     // 1: number of value inputs
148     ASSERT(acc_.GetNumValueIn(gate) == 1);
149     GateRef index = acc_.GetValueIn(gate, 0);
150     auto thread = tsManager_->GetEcmaVM()->GetJSThread();
151     uint32_t cpIdx = static_cast<uint32_t>(acc_.GetConstantValue(index));
152     JSHandle<ConstantPool> constpoolHandle(tsManager_->GetConstantPool());
153     JSTaggedValue arr = ConstantPool::GetLiteralFromCache<ConstPoolType::ARRAY_LITERAL>(
154         thread, constpoolHandle.GetTaggedValue(), cpIdx, recordName_);
155     JSHandle<JSArray> arrayHandle(thread, arr);
156     JSHandle<JSHClass> oldHClass(thread, arrayHandle->GetClass());
157     JSHandle<JSHClass> hclass = JSHClass::Clone(thread, oldHClass);
158 
159     GateType gateType = acc_.GetGateType(gate);
160     panda_file::File::EntityId id = ConstantPool::GetIdFromCache(constpoolHandle.GetTaggedValue(), cpIdx);
161     JSHandle<TaggedArray> elements(thread, arrayHandle->GetElements());
162     tsManager_->AddArrayTSHClass(id, hclass);
163     tsManager_->AddArrayTSElements(id, elements);
164     gateType = tsManager_->TryNarrowUnionType(gateType);
165 
166     int hclassIndex = -1;
167     int elementIndex = -1;
168     if (tsManager_->IsArrayTypeKind(gateType)) {
169         hclassIndex = tsManager_->GetHClassIndexByArrayType(gateType, id);
170         elementIndex = tsManager_->GetElementsIndexByArrayType(gateType, id);
171     }
172     if (hclassIndex == -1 || elementIndex == -1) { // slowpath
173         return;
174     }
175 
176     AddProfiling(gate);
177     GateRef elementIndexGate = builder_.IntPtr(elementIndex);
178     GateRef array = builder_.CreateArrayWithBuffer(0, index, elementIndexGate);
179     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), array);
180 }
181 
LowerNTypedStownByIndex(GateRef gate)182 void NTypeHCRLowering::LowerNTypedStownByIndex(GateRef gate)
183 {
184     // 3: number of value inputs
185     ASSERT(acc_.GetNumValueIn(gate) == 3);
186     GateRef receiver = acc_.GetValueIn(gate, 0);
187     GateRef index = acc_.GetValueIn(gate, 1);
188     GateRef value = acc_.GetValueIn(gate, 2);
189     if (acc_.GetOpCode(receiver) != OpCode::CREATE_ARRAY &&
190         acc_.GetOpCode(receiver) != OpCode::CREATE_ARRAY_WITH_BUFFER) {
191         return;
192     }
193 
194     AddProfiling(gate);
195     uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
196     uint32_t arraySize = acc_.GetArraySize(receiver);
197     acc_.SetArraySize(receiver, std::max(arraySize, indexValue + 1));
198     index = builder_.Int32(indexValue);
199     builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, index, value);
200     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
201 }
202 
LowerNTypedStOwnByName(GateRef gate)203 void NTypeHCRLowering::LowerNTypedStOwnByName(GateRef gate)
204 {
205     // 3: number of value inputs
206     ASSERT(acc_.GetNumValueIn(gate) == 3);
207     auto constData = acc_.GetValueIn(gate, 0);
208     uint16_t propIndex = acc_.GetConstantValue(constData);
209     auto thread = tsManager_->GetEcmaVM()->GetJSThread();
210     auto propKey = tsManager_->GetStringFromConstantPool(propIndex);
211 
212     GateRef receiver = acc_.GetValueIn(gate, 1);
213     GateRef value = acc_.GetValueIn(gate, 2);
214 
215     GateType receiverType = acc_.GetGateType(receiver);
216     receiverType = tsManager_->TryNarrowUnionType(receiverType);
217 
218     int hclassIndex = -1;
219     if (tsManager_->IsObjectTypeKind(receiverType)) {
220         hclassIndex = tsManager_->GetHClassIndexByObjectType(receiverType);
221     }
222     if (hclassIndex == -1) { // slowpath
223         return;
224     }
225     JSHClass *hclass = JSHClass::Cast(tsManager_->GetValueFromCache(hclassIndex).GetTaggedObject());
226 
227     PropertyLookupResult plr = JSHClass::LookupPropertyInAotHClass(thread, hclass, propKey);
228     if (!plr.IsFound() || !plr.IsLocal() || plr.IsAccessor() || !plr.IsWritable()) {  // slowpath
229         return;
230     }
231     AddProfiling(gate);
232 
233     GateRef pfrGate = builder_.Int32(plr.GetData());
234     builder_.StoreProperty(receiver, pfrGate, value);
235 
236     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
237 }
238 
AddProfiling(GateRef gate)239 void NTypeHCRLowering::AddProfiling(GateRef gate)
240 {
241     if (IsTraceBC()) {
242         // see stateSplit as a part of JSByteCode if exists
243         GateRef maybeStateSplit = acc_.GetDep(gate);
244         GateRef current = Circuit::NullGate();
245         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
246             current = maybeStateSplit;
247         } else {
248             current = gate;
249         }
250 
251         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
252         auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
253         GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
254         GateRef typedPath = builder_.Int32ToTaggedInt(builder_.Int32(1));
255         GateRef traceGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(current),
256                                                  { constOpcode, typedPath }, gate);
257         acc_.SetDep(current, traceGate);
258         builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: trace or STATE_SPLIT
259     }
260 
261     if (IsProfiling()) {
262         // see stateSplit as a part of JSByteCode if exists
263         GateRef maybeStateSplit = acc_.GetDep(gate);
264         GateRef current = Circuit::NullGate();
265         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
266             current = maybeStateSplit;
267         } else {
268             current = gate;
269         }
270 
271         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
272         auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
273         GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
274         GateRef mode =
275             builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::TYPED_PATH)));
276         GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current),
277                                                  { constOpcode, mode }, gate);
278         acc_.SetDep(current, profiling);
279         builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: profiling or STATE_SPLIT
280     }
281 }
282 }
283