• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 #ifndef PANDA_INST_BUILDER_INL_H
17 #define PANDA_INST_BUILDER_INL_H
18 
19 #include "inst_builder.h"
20 #include "optimizer/code_generator/encode.h"
21 
22 namespace panda::compiler {
23 // NOLINTNEXTLINE(misc-definitions-in-headers,readability-function-size)
24 template <Opcode OPCODE>
BuildCall(const BytecodeInstruction * bcInst,bool isRange,bool accRead,Inst * additionalInput)25 void InstBuilder::BuildCall(const BytecodeInstruction *bcInst, bool isRange, bool accRead, Inst *additionalInput)
26 {
27     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex());
28     if (GetRuntime()->IsMethodIntrinsic(GetMethod(), methodId)) {
29         BuildIntrinsic(bcInst, isRange, accRead);
30         return;
31     }
32     auto pc = GetPc(bcInst->GetAddress());
33     auto saveState = CreateSaveState(Opcode::SaveState, pc);
34     auto hasImplicitArg = !GetRuntime()->IsMethodStatic(GetMethod(), methodId);
35     auto method = GetRuntime()->GetMethodById(GetMethod(), methodId);
36 
37     NullCheckInst *nullCheck = nullptr;
38     uint32_t classId = 0;
39     if (hasImplicitArg) {
40         nullCheck =
41             graph_->CreateInstNullCheck(DataType::REFERENCE, pc, GetArgDefinition(bcInst, 0, accRead), saveState);
42     } else if (method != nullptr) {
43         if (graph_->IsAotMode()) {
44             classId = GetRuntime()->GetClassIdWithinFile(GetMethod(), GetRuntime()->GetClass(method));
45         } else {
46             classId = GetRuntime()->GetClassIdForMethod(GetMethod(), methodId);
47         }
48     }
49 
50     Inst *resolver = nullptr;
51     // NOLINTNEXTLINE(readability-magic-numbers)
52     CallInst *call = BuildCallInst<OPCODE>(method, methodId, pc, &resolver, classId);
53     SetCallArgs(bcInst, isRange, accRead, resolver, call, nullCheck, saveState, hasImplicitArg, methodId,
54                 additionalInput);
55 
56     // Add SaveState
57     AddInstruction(saveState);
58     // Add NullCheck
59     if (hasImplicitArg) {
60         ASSERT(nullCheck != nullptr);
61         AddInstruction(nullCheck);
62     } else if (!call->IsUnresolved() && call->GetCallMethod() != nullptr) {
63         // Initialize class as call is resolved
64         BuildInitClassInstForCallStatic(method, classId, pc, saveState);
65     }
66     // Add resolver
67     if (resolver != nullptr) {
68         if (call->IsStaticCall()) {
69             resolver->SetInput(0, saveState);
70         } else {
71             resolver->SetInput(0, nullCheck);
72             resolver->SetInput(1, saveState);
73         }
74         AddInstruction(resolver);
75     }
76     // Add Call
77     AddInstruction(call);
78     if (call->GetType() != DataType::VOID) {
79         UpdateDefinitionAcc(call);
80     } else {
81         UpdateDefinitionAcc(nullptr);
82     }
83 }
84 
85 template void InstBuilder::BuildCall<Opcode::CallLaunchStatic>(const BytecodeInstruction *bcInst, bool isRange,
86                                                                bool accRead, Inst *additionalInput);
87 template void InstBuilder::BuildCall<Opcode::CallLaunchVirtual>(const BytecodeInstruction *bcInst, bool isRange,
88                                                                 bool accRead, Inst *additionalInput);
89 
90 // NOLINTNEXTLINE(misc-definitions-in-headers)
91 template <typename T>
SetCallArgs(const BytecodeInstruction * bcInst,bool isRange,bool accRead,Inst * resolver,T * call,Inst * nullCheck,SaveStateInst * saveState,bool hasImplicitArg,uint32_t methodId,Inst * additionalInput)92 void InstBuilder::SetCallArgs(const BytecodeInstruction *bcInst, bool isRange, bool accRead, Inst *resolver, T *call,
93                               Inst *nullCheck, SaveStateInst *saveState, bool hasImplicitArg, uint32_t methodId,
94                               Inst *additionalInput)
95 {
96     size_t hiddenArgsCount = hasImplicitArg ? 1 : 0;                  // +1 for non-static call
97     size_t additionalArgsCount = additionalInput == nullptr ? 0 : 1;  // +1 for launch call
98     size_t argsCount = GetMethodArgumentsCount(methodId);
99     size_t totalArgsCount = hiddenArgsCount + argsCount + additionalArgsCount;
100     size_t inputsCount = totalArgsCount + (saveState == nullptr ? 0 : 1) + (resolver == nullptr ? 0 : 1);
101     call->ReserveInputs(inputsCount);
102     call->AllocateInputTypes(GetGraph()->GetAllocator(), inputsCount);
103     if (resolver != nullptr) {
104         call->AppendInput(resolver);
105         call->AddInputType(DataType::POINTER);
106     }
107     if (additionalInput != nullptr) {
108         call->AppendInput(additionalInput);
109         call->AddInputType(DataType::REFERENCE);
110         saveState->AppendBridge(additionalInput);
111     }
112     if (hasImplicitArg) {
113         call->AppendInput(nullCheck);
114         call->AddInputType(DataType::REFERENCE);
115     }
116     if (isRange) {
117         auto startReg = bcInst->GetVReg(0);
118         // start reg for Virtual call was added
119         if (hasImplicitArg) {
120             ++startReg;
121         }
122         for (size_t i = 0; i < argsCount; startReg++, i++) {
123             call->AppendInput(GetDefinition(startReg));
124             call->AddInputType(GetMethodArgumentType(methodId, i));
125         }
126     } else {
127         for (size_t i = 0; i < argsCount; i++) {
128             call->AppendInput(GetArgDefinition(bcInst, i + hiddenArgsCount, accRead));
129             call->AddInputType(GetMethodArgumentType(methodId, i));
130         }
131     }
132     if (saveState != nullptr) {
133         call->AppendInput(saveState);
134         call->AddInputType(DataType::NO_TYPE);
135     }
136 }
137 
138 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildInitClassInstForCallStatic(RuntimeInterface::MethodPtr method,uint32_t classId,size_t pc,Inst * saveState)139 void InstBuilder::BuildInitClassInstForCallStatic(RuntimeInterface::MethodPtr method, uint32_t classId, size_t pc,
140                                                   Inst *saveState)
141 {
142     if (GetClassId() != classId) {
143         auto initClass = graph_->CreateInstInitClass(DataType::NO_TYPE, pc, saveState, classId, GetGraph()->GetMethod(),
144                                                      GetRuntime()->GetClass(method));
145         AddInstruction(initClass);
146     }
147 }
148 
149 // NOLINTNEXTLINE(misc-definitions-in-headers)
150 template <Opcode OPCODE>
BuildCallStaticInst(RuntimeInterface::MethodPtr method,uint32_t methodId,size_t pc,Inst ** resolver,uint32_t classId)151 CallInst *InstBuilder::BuildCallStaticInst(RuntimeInterface::MethodPtr method, uint32_t methodId, size_t pc,
152                                            Inst **resolver, uint32_t classId)
153 {
154     constexpr auto SLOT_KIND = UnresolvedTypesInterface::SlotKind::METHOD;
155     CallInst *call = nullptr;
156     if (method == nullptr || (runtime_->IsMethodStatic(GetMethod(), methodId) && classId == 0) || ForceUnresolved() ||
157         (OPCODE == Opcode::CallLaunchStatic && graph_->IsAotMode())) {
158         ResolveStaticInst *resolveStatic = graph_->CreateInstResolveStatic(DataType::POINTER, pc, methodId, nullptr);
159         *resolver = resolveStatic;
160         if constexpr (OPCODE == Opcode::CallStatic) {
161             call = graph_->CreateInstCallResolvedStatic(GetMethodReturnType(methodId), pc, methodId);
162         } else {
163             call = graph_->CreateInstCallResolvedLaunchStatic(DataType::VOID, pc, methodId);
164         }
165         if (!graph_->IsAotMode() && !graph_->IsBytecodeOptimizer()) {
166             runtime_->GetUnresolvedTypes()->AddTableSlot(GetMethod(), methodId, SLOT_KIND);
167         }
168     } else {
169         if constexpr (OPCODE == Opcode::CallStatic) {
170             call = graph_->CreateInstCallStatic(GetMethodReturnType(methodId), pc, methodId, method);
171         } else {
172             call = graph_->CreateInstCallLaunchStatic(DataType::VOID, pc, methodId, method);
173         }
174     }
175     return call;
176 }
177 
178 // NOLINTNEXTLINE(misc-definitions-in-headers)
179 template <Opcode OPCODE>
BuildCallVirtualInst(RuntimeInterface::MethodPtr method,uint32_t methodId,size_t pc,Inst ** resolver)180 CallInst *InstBuilder::BuildCallVirtualInst(RuntimeInterface::MethodPtr method, uint32_t methodId, size_t pc,
181                                             Inst **resolver)
182 {
183     constexpr auto SLOT_KIND = UnresolvedTypesInterface::SlotKind::VIRTUAL_METHOD;
184     CallInst *call = nullptr;
185     ASSERT(!runtime_->IsMethodStatic(GetMethod(), methodId));
186     if (method != nullptr && (runtime_->IsInterfaceMethod(method) || graph_->IsAotNoChaMode())) {
187         ResolveVirtualInst *resolveVirtual = graph_->CreateInstResolveVirtual(DataType::POINTER, pc, methodId, method);
188         *resolver = resolveVirtual;
189         if constexpr (OPCODE == Opcode::CallVirtual) {
190             call = graph_->CreateInstCallResolvedVirtual(GetMethodReturnType(methodId), pc, methodId, method);
191         } else {
192             call = graph_->CreateInstCallResolvedLaunchVirtual(DataType::VOID, pc, methodId, method);
193         }
194     } else if (method == nullptr || ForceUnresolved()) {
195         ResolveVirtualInst *resolveVirtual = graph_->CreateInstResolveVirtual(DataType::POINTER, pc, methodId, nullptr);
196         *resolver = resolveVirtual;
197         if constexpr (OPCODE == Opcode::CallVirtual) {
198             call = graph_->CreateInstCallResolvedVirtual(GetMethodReturnType(methodId), pc, methodId);
199         } else {
200             call = graph_->CreateInstCallResolvedLaunchVirtual(DataType::VOID, pc, methodId);
201         }
202         if (!graph_->IsAotMode() && !graph_->IsBytecodeOptimizer()) {
203             runtime_->GetUnresolvedTypes()->AddTableSlot(GetMethod(), methodId, SLOT_KIND);
204         }
205     } else {
206         ASSERT(method != nullptr);
207         if constexpr (OPCODE == Opcode::CallVirtual) {
208             call = graph_->CreateInstCallVirtual(GetMethodReturnType(methodId), pc, methodId, method);
209         } else {
210             call = graph_->CreateInstCallLaunchVirtual(DataType::VOID, pc, methodId, method);
211         }
212     }
213     return call;
214 }
215 
216 // NOLINTNEXTLINE(misc-definitions-in-headers)
217 template <Opcode OPCODE>
BuildCallInst(RuntimeInterface::MethodPtr method,uint32_t methodId,size_t pc,Inst ** resolver,uint32_t classId)218 CallInst *InstBuilder::BuildCallInst(RuntimeInterface::MethodPtr method, uint32_t methodId, size_t pc, Inst **resolver,
219                                      [[maybe_unused]] uint32_t classId)
220 {
221     ASSERT(resolver != nullptr);
222     CallInst *call = nullptr;
223     // NOLINTNEXTLINE(readability-magic-numbers,readability-braces-around-statements,bugprone-suspicious-semicolon)
224     if constexpr (OPCODE == Opcode::CallStatic || OPCODE == Opcode::CallLaunchStatic) {
225         call = BuildCallStaticInst<OPCODE>(method, methodId, pc, resolver, classId);
226     }
227     // NOLINTNEXTLINE(readability-magic-numbers,readability-braces-around-statements,bugprone-suspicious-semicolon)
228     if constexpr (OPCODE == Opcode::CallVirtual || OPCODE == Opcode::CallLaunchVirtual) {
229         call = BuildCallVirtualInst<OPCODE>(method, methodId, pc, resolver);
230     }
231     if (UNLIKELY(call == nullptr)) {
232         UNREACHABLE();
233     }
234     call->SetCanNativeException(method == nullptr || runtime_->HasNativeException(method));
235     return call;
236 }
237 
238 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildMonitor(const BytecodeInstruction * bcInst,Inst * def,bool isEnter)239 void InstBuilder::BuildMonitor(const BytecodeInstruction *bcInst, Inst *def, bool isEnter)
240 {
241     auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
242     auto inst = GetGraph()->CreateInstMonitor(DataType::VOID, GetPc(bcInst->GetAddress()));
243     AddInstruction(saveState);
244     if (!isEnter) {
245         inst->CastToMonitor()->SetExit();
246     } else {
247         // Create NullCheck instruction
248         auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, GetPc(bcInst->GetAddress()), def, saveState);
249         def = nullCheck;
250         AddInstruction(nullCheck);
251     }
252     inst->SetInput(0, def);
253     inst->SetInput(1, saveState);
254 
255     AddInstruction(inst);
256 }
257 
258 #include <intrinsics_ir_build.inl>
259 
260 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildDefaultStaticIntrinsic(const BytecodeInstruction * bcInst,bool isRange,bool accRead)261 void InstBuilder::BuildDefaultStaticIntrinsic(const BytecodeInstruction *bcInst, bool isRange, bool accRead)
262 {
263     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex());
264     auto method = GetRuntime()->GetMethodById(GetMethod(), methodId);
265     auto intrinsicId = GetRuntime()->GetIntrinsicId(method);
266     ASSERT(intrinsicId != RuntimeInterface::IntrinsicId::COUNT);
267     auto retType = GetMethodReturnType(methodId);
268     auto pc = GetPc(bcInst->GetAddress());
269     IntrinsicInst *call = GetGraph()->CreateInstIntrinsic(retType, pc, intrinsicId);
270     // If an intrinsic may call runtime then we need a SaveState
271     SaveStateInst *saveState = call->RequireState() ? CreateSaveState(Opcode::SaveState, pc) : nullptr;
272     SetCallArgs(bcInst, isRange, accRead, nullptr, call, nullptr, saveState, false, methodId);
273     if (saveState != nullptr) {
274         AddInstruction(saveState);
275     }
276     /* if there are reference type args to be checked for NULL ('need_nullcheck' intrinsic property) */
277     AddArgNullcheckIfNeeded<false>(intrinsicId, call, saveState, pc);
278     AddInstruction(call);
279     if (call->GetType() != DataType::VOID) {
280         UpdateDefinitionAcc(call);
281     } else {
282         UpdateDefinitionAcc(nullptr);
283     }
284     if (NeedSafePointAfterIntrinsic(intrinsicId)) {
285         AddInstruction(CreateSafePoint(currentBb_));
286     }
287 }
288 
289 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildAbsIntrinsic(const BytecodeInstruction * bcInst,bool accRead)290 void InstBuilder::BuildAbsIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
291 {
292     auto methodIndex = bcInst->GetId(0).AsIndex();
293     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
294     auto inst = GetGraph()->CreateInstAbs(GetMethodReturnType(methodId), GetPc(bcInst->GetAddress()));
295     ASSERT(GetMethodArgumentsCount(methodId) == 1);
296     inst->SetInput(0, GetArgDefinition(bcInst, 0, accRead));
297     AddInstruction(inst);
298     UpdateDefinitionAcc(inst);
299 }
300 
301 template <Opcode OPCODE>
302 static BinaryOperation *CreateBinaryOperation(Graph *graph, DataType::Type returnType, size_t pc) = delete;
303 
304 template <>
305 BinaryOperation *CreateBinaryOperation<Opcode::Min>(Graph *graph, DataType::Type returnType, size_t pc)
306 {
307     return graph->CreateInstMin(returnType, pc);
308 }
309 
310 template <>
311 BinaryOperation *CreateBinaryOperation<Opcode::Max>(Graph *graph, DataType::Type returnType, size_t pc)
312 {
313     return graph->CreateInstMax(returnType, pc);
314 }
315 
316 template <>
317 BinaryOperation *CreateBinaryOperation<Opcode::Mod>(Graph *graph, DataType::Type returnType, size_t pc)
318 {
319     return graph->CreateInstMod(returnType, pc);
320 }
321 
322 template void InstBuilder::BuildBinaryOperationIntrinsic<Opcode::Mod>(const BytecodeInstruction *bcInst, bool accRead);
323 
324 template <Opcode OPCODE>
BuildBinaryOperationIntrinsic(const BytecodeInstruction * bcInst,bool accRead)325 void InstBuilder::BuildBinaryOperationIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
326 {
327     auto methodIndex = bcInst->GetId(0).AsIndex();
328     [[maybe_unused]] auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
329     ASSERT(GetMethodArgumentsCount(methodId) == 2U);
330     // NOLINTNEXTLINE(readability-magic-numbers)
331     auto inst = CreateBinaryOperation<OPCODE>(GetGraph(), GetMethodReturnType(methodId), GetPc(bcInst->GetAddress()));
332     inst->SetInput(0, GetArgDefinition(bcInst, 0, accRead));
333     inst->SetInput(1, GetArgDefinition(bcInst, 1, accRead));
334     AddInstruction(inst);
335     UpdateDefinitionAcc(inst);
336 }
337 
338 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildSqrtIntrinsic(const BytecodeInstruction * bcInst,bool accRead)339 void InstBuilder::BuildSqrtIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
340 {
341     auto methodIndex = bcInst->GetId(0).AsIndex();
342     [[maybe_unused]] auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
343     auto inst = GetGraph()->CreateInstSqrt(GetMethodReturnType(methodId), GetPc(bcInst->GetAddress()));
344     ASSERT(GetMethodArgumentsCount(methodId) == 1);
345     Inst *def = GetArgDefinition(bcInst, 0, accRead);
346     inst->SetInput(0, def);
347     AddInstruction(inst);
348     UpdateDefinitionAcc(inst);
349 }
350 
351 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildIsNanIntrinsic(const BytecodeInstruction * bcInst,bool accRead)352 void InstBuilder::BuildIsNanIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
353 {
354     auto methodIndex = bcInst->GetId(0).AsIndex();
355     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
356     // No need to create specialized node for isNaN. Since NaN != NaN, simple float compare node is fine.
357     // Also, ensure that float comparison node is implemented for specific architecture
358     auto vreg = GetArgDefinition(bcInst, 0, accRead);
359     auto inst = GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), vreg, vreg,
360                                               GetMethodArgumentType(methodId, 0), ConditionCode::CC_NE);
361     inst->SetOperandsType(GetMethodArgumentType(methodId, 0));
362     AddInstruction(inst);
363     UpdateDefinitionAcc(inst);
364 }
365 
366 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildStringLengthIntrinsic(const BytecodeInstruction * bcInst,bool accRead)367 void InstBuilder::BuildStringLengthIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
368 {
369     auto bcAddr = GetPc(bcInst->GetAddress());
370     auto saveState = CreateSaveState(Opcode::SaveState, bcAddr);
371 
372     auto nullCheck =
373         graph_->CreateInstNullCheck(DataType::REFERENCE, bcAddr, GetArgDefinition(bcInst, 0, accRead), saveState);
374     auto arrayLength = graph_->CreateInstLenArray(DataType::INT32, bcAddr, nullCheck, false);
375 
376     AddInstruction(saveState);
377     AddInstruction(nullCheck);
378     AddInstruction(arrayLength);
379 
380     Inst *stringLength;
381     if (graph_->GetRuntime()->IsCompressedStringsEnabled()) {
382         auto constOneInst = graph_->FindOrCreateConstant(1);
383         stringLength = graph_->CreateInstShr(DataType::INT32, bcAddr, arrayLength, constOneInst);
384         AddInstruction(stringLength);
385     } else {
386         stringLength = arrayLength;
387     }
388     UpdateDefinitionAcc(stringLength);
389 }
390 
391 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildStringIsEmptyIntrinsic(const BytecodeInstruction * bcInst,bool accRead)392 void InstBuilder::BuildStringIsEmptyIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
393 {
394     auto bcAddr = GetPc(bcInst->GetAddress());
395     auto saveState = CreateSaveState(Opcode::SaveState, bcAddr);
396     auto nullCheck =
397         graph_->CreateInstNullCheck(DataType::REFERENCE, bcAddr, GetArgDefinition(bcInst, 0, accRead), saveState);
398     auto length = graph_->CreateInstLenArray(DataType::INT32, bcAddr, nullCheck, false);
399     auto zeroConst = graph_->FindOrCreateConstant(0);
400     auto checkZeroLength =
401         graph_->CreateInstCompare(DataType::BOOL, bcAddr, length, zeroConst, DataType::INT32, ConditionCode::CC_EQ);
402     AddInstruction(saveState);
403     AddInstruction(nullCheck);
404     AddInstruction(length);
405     AddInstruction(checkZeroLength);
406     UpdateDefinitionAcc(checkZeroLength);
407 }
408 
409 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCharIsUpperCaseIntrinsic(const BytecodeInstruction * bcInst,bool accRead)410 void InstBuilder::BuildCharIsUpperCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
411 {
412     // IsUpperCase(char) = (char - 'A') < ('Z' - 'A')
413 
414     ASSERT(GetMethodArgumentsCount(GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex())) == 1);
415 
416     // Adding InstCast here as the aternative compiler backend requires inputs of InstSub to be of the same type.
417     // The InstCast instructon makes no harm as normally they are removed by the following compiler stages.
418     auto argInput = GetArgDefinition(bcInst, 0, accRead);
419     auto constInput = graph_->FindOrCreateConstant('A');
420     auto arg = GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), argInput, argInput->GetType());
421     auto constA =
422         GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), constInput, constInput->GetType());
423 
424     auto inst1 = GetGraph()->CreateInstSub(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, constA);
425     auto inst2 =
426         GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), inst1,
427                                       graph_->FindOrCreateConstant('Z' - 'A'), DataType::UINT16, ConditionCode::CC_BE);
428 
429     AddInstruction(arg);
430     AddInstruction(constA);
431     AddInstruction(inst1);
432     AddInstruction(inst2);
433     UpdateDefinitionAcc(inst2);
434 }
435 
436 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCharToUpperCaseIntrinsic(const BytecodeInstruction * bcInst,bool accRead)437 void InstBuilder::BuildCharToUpperCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
438 {
439     // ToUpperCase(char) = ((char - 'a') < ('z' - 'a')) * ('Z' - 'z') + char
440 
441     ASSERT(GetMethodArgumentsCount(GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex())) == 1);
442 
443     auto argInput = GetArgDefinition(bcInst, 0, accRead);
444     auto constInput = graph_->FindOrCreateConstant('a');
445     auto arg = GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), argInput, argInput->GetType());
446     auto constA =
447         GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), constInput, constInput->GetType());
448 
449     auto inst1 = GetGraph()->CreateInstSub(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, constA);
450     auto inst2 =
451         GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), inst1,
452                                       graph_->FindOrCreateConstant('z' - 'a'), DataType::UINT16, ConditionCode::CC_BE);
453     auto inst3 = GetGraph()->CreateInstMul(DataType::UINT16, GetPc(bcInst->GetAddress()), inst2,
454                                            graph_->FindOrCreateConstant('Z' - 'z'));
455     auto inst4 = GetGraph()->CreateInstAdd(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, inst3);
456 
457     AddInstruction(arg);
458     AddInstruction(constA);
459     AddInstruction(inst1);
460     AddInstruction(inst2);
461     AddInstruction(inst3);
462     AddInstruction(inst4);
463     UpdateDefinitionAcc(inst4);
464 }
465 
466 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCharIsLowerCaseIntrinsic(const BytecodeInstruction * bcInst,bool accRead)467 void InstBuilder::BuildCharIsLowerCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
468 {
469     ASSERT(GetMethodArgumentsCount(GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex())) == 1);
470 
471     auto argInput = GetArgDefinition(bcInst, 0, accRead);
472     auto constInput = graph_->FindOrCreateConstant('a');
473     auto arg = GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), argInput, argInput->GetType());
474     auto constA =
475         GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), constInput, constInput->GetType());
476 
477     auto inst1 = GetGraph()->CreateInstSub(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, constA);
478     auto inst2 =
479         GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), inst1,
480                                       graph_->FindOrCreateConstant('z' - 'a'), DataType::UINT16, ConditionCode::CC_BE);
481 
482     AddInstruction(arg);
483     AddInstruction(constA);
484     AddInstruction(inst1);
485     AddInstruction(inst2);
486     UpdateDefinitionAcc(inst2);
487 }
488 
489 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCharToLowerCaseIntrinsic(const BytecodeInstruction * bcInst,bool accRead)490 void InstBuilder::BuildCharToLowerCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
491 {
492     ASSERT(GetMethodArgumentsCount(GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex())) == 1);
493 
494     auto argInput = GetArgDefinition(bcInst, 0, accRead);
495     auto constInput = graph_->FindOrCreateConstant('A');
496     auto arg = GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), argInput, argInput->GetType());
497     auto constA =
498         GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), constInput, constInput->GetType());
499 
500     auto inst1 = GetGraph()->CreateInstSub(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, constA);
501     auto inst2 =
502         GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), inst1,
503                                       graph_->FindOrCreateConstant('Z' - 'A'), DataType::UINT16, ConditionCode::CC_BE);
504     auto inst3 = GetGraph()->CreateInstMul(DataType::UINT16, GetPc(bcInst->GetAddress()), inst2,
505                                            graph_->FindOrCreateConstant('z' - 'Z'));
506     auto inst4 = GetGraph()->CreateInstAdd(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, inst3);
507 
508     AddInstruction(arg);
509     AddInstruction(constA);
510     AddInstruction(inst1);
511     AddInstruction(inst2);
512     AddInstruction(inst3);
513     AddInstruction(inst4);
514     UpdateDefinitionAcc(inst4);
515 }
516 
517 // NOLINTNEXTLINE(misc-definitions-in-headers)
GetArgDefinition(const BytecodeInstruction * bcInst,size_t idx,bool accRead,bool isRange)518 Inst *InstBuilder::GetArgDefinition(const BytecodeInstruction *bcInst, size_t idx, bool accRead, bool isRange)
519 {
520     if (isRange) {
521         return GetArgDefinitionRange(bcInst, idx);
522     }
523     if (accRead) {
524         size_t accPos = bcInst->GetImm64();
525         if (idx < accPos) {
526             return GetDefinition(bcInst->GetVReg(idx));
527         }
528         if (accPos == idx) {
529             return GetDefinitionAcc();
530         }
531         return GetDefinition(bcInst->GetVReg(idx - 1));
532     }
533     return GetDefinition(bcInst->GetVReg(idx));
534 }
535 
536 // NOLINTNEXTLINE(misc-definitions-in-headers)
GetArgDefinitionRange(const BytecodeInstruction * bcInst,size_t idx)537 Inst *InstBuilder::GetArgDefinitionRange(const BytecodeInstruction *bcInst, size_t idx)
538 {
539     auto startReg = bcInst->GetVReg(0);
540     return GetDefinition(startReg + idx);
541 }
542 
543 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildMonitorIntrinsic(const BytecodeInstruction * bcInst,bool isEnter,bool accRead)544 void InstBuilder::BuildMonitorIntrinsic(const BytecodeInstruction *bcInst, bool isEnter, bool accRead)
545 {
546     auto methodIndex = bcInst->GetId(0).AsIndex();
547     [[maybe_unused]] auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
548     ASSERT(GetMethodReturnType(methodId) == DataType::VOID);
549     ASSERT(GetMethodArgumentsCount(methodId) == 1);
550     BuildMonitor(bcInst, GetArgDefinition(bcInst, 0, accRead), isEnter);
551 }
552 
553 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildIntrinsic(const BytecodeInstruction * bcInst,bool isRange,bool accRead)554 void InstBuilder::BuildIntrinsic(const BytecodeInstruction *bcInst, bool isRange, bool accRead)
555 {
556     auto methodIndex = bcInst->GetId(0).AsIndex();
557     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
558     auto method = GetRuntime()->GetMethodById(GetMethod(), methodId);
559     auto intrinsicId = GetRuntime()->GetIntrinsicId(method);
560     auto isVirtual = IsVirtual(intrinsicId);
561     if (!g_options.IsCompilerEncodeIntrinsics()) {
562         BuildDefaultIntrinsic(isVirtual, bcInst, isRange, accRead);
563         return;
564     }
565     if (!isVirtual) {
566         return BuildStaticCallIntrinsic(bcInst, isRange, accRead);
567     }
568     return BuildVirtualCallIntrinsic(bcInst, isRange, accRead);
569 }
570 
571 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildDefaultIntrinsic(bool isVirtual,const BytecodeInstruction * bcInst,bool isRange,bool accRead)572 void InstBuilder::BuildDefaultIntrinsic(bool isVirtual, const BytecodeInstruction *bcInst, bool isRange, bool accRead)
573 {
574     auto methodIndex = bcInst->GetId(0).AsIndex();
575     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
576     auto method = GetRuntime()->GetMethodById(GetMethod(), methodId);
577     auto intrinsicId = GetRuntime()->GetIntrinsicId(method);
578     if (intrinsicId == RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_ENTER ||
579         intrinsicId == RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_EXIT) {
580         BuildMonitorIntrinsic(bcInst, intrinsicId == RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_ENTER,
581                               accRead);
582         return;
583     }
584     // NOLINTNEXTLINE(readability-braces-around-statements)
585     if (!isVirtual) {
586         BuildDefaultStaticIntrinsic(bcInst, isRange, accRead);
587         // NOLINTNEXTLINE(readability-misleading-indentation)
588     } else {
589         BuildDefaultVirtualCallIntrinsic(bcInst, isRange, accRead);
590     }
591 }
592 
593 // do not specify reason for tidy suppression because comment does not fit single line
594 // NOLINTNEXTLINE
BuildStaticCallIntrinsic(const BytecodeInstruction * bcInst,bool isRange,bool accRead)595 void InstBuilder::BuildStaticCallIntrinsic(const BytecodeInstruction *bcInst, bool isRange, bool accRead)
596 {
597     auto methodIndex = bcInst->GetId(0).AsIndex();
598     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
599     auto method = GetRuntime()->GetMethodById(GetMethod(), methodId);
600     auto intrinsicId = GetRuntime()->GetIntrinsicId(method);
601     switch (intrinsicId) {
602         case RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_ENTER:
603         case RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_EXIT: {
604             BuildMonitorIntrinsic(bcInst, intrinsicId == RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_ENTER,
605                                   accRead);
606             break;
607         }
608         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_ABS_I32:
609         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_ABS_I64:
610         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_ABS_F32:
611         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_ABS_F64: {
612             BuildAbsIntrinsic(bcInst, accRead);
613             break;
614         }
615         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_SQRT_F32:
616         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_SQRT_F64: {
617             BuildSqrtIntrinsic(bcInst, accRead);
618             break;
619         }
620         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MIN_I32:
621         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MIN_I64:
622         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MIN_F32:
623         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MIN_F64: {
624             BuildBinaryOperationIntrinsic<Opcode::Min>(bcInst, accRead);
625             break;
626         }
627         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MAX_I32:
628         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MAX_I64:
629         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MAX_F32:
630         case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MAX_F64: {
631             BuildBinaryOperationIntrinsic<Opcode::Max>(bcInst, accRead);
632             break;
633         }
634 #include "intrinsics_ir_build_static_call.inl"
635         default: {
636             BuildDefaultStaticIntrinsic(bcInst, isRange, accRead);
637         }
638     }
639 }
640 
641 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildDefaultVirtualCallIntrinsic(const BytecodeInstruction * bcInst,bool isRange,bool accRead)642 void InstBuilder::BuildDefaultVirtualCallIntrinsic(const BytecodeInstruction *bcInst, bool isRange, bool accRead)
643 {
644     auto methodIndex = bcInst->GetId(0).AsIndex();
645     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
646     auto method = GetRuntime()->GetMethodById(GetMethod(), methodId);
647     auto intrinsicId = GetRuntime()->GetIntrinsicId(method);
648     auto bcAddr = GetPc(bcInst->GetAddress());
649     auto saveState = CreateSaveState(Opcode::SaveState, bcAddr);
650     auto nullCheck =
651         graph_->CreateInstNullCheck(DataType::REFERENCE, bcAddr, GetArgDefinition(bcInst, 0, accRead), saveState);
652 
653     auto call = GetGraph()->CreateInstIntrinsic(GetMethodReturnType(methodId), bcAddr, intrinsicId);
654     SetCallArgs(bcInst, isRange, accRead, nullptr, call, nullCheck, call->RequireState() ? saveState : nullptr, true,
655                 methodId);
656 
657     AddInstruction(saveState);
658     AddInstruction(nullCheck);
659 
660     /* if there are reference type args to be checked for NULL */
661     AddArgNullcheckIfNeeded<true>(intrinsicId, call, saveState, bcAddr);
662 
663     AddInstruction(call);
664     if (call->GetType() != DataType::VOID) {
665         UpdateDefinitionAcc(call);
666     } else {
667         UpdateDefinitionAcc(nullptr);
668     }
669     if (NeedSafePointAfterIntrinsic(intrinsicId)) {
670         AddInstruction(CreateSafePoint(currentBb_));
671     }
672 }
673 
674 // NOLINTNEXTLINE(readability-function-size,misc-definitions-in-headers)
675 template <bool IS_ACC_WRITE>
BuildLoadObject(const BytecodeInstruction * bcInst,DataType::Type type)676 void InstBuilder::BuildLoadObject(const BytecodeInstruction *bcInst, DataType::Type type)
677 {
678     auto pc = GetPc(bcInst->GetAddress());
679     // Create SaveState instruction
680     auto saveState = CreateSaveState(Opcode::SaveState, pc);
681 
682     // Create NullCheck instruction
683     auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, pc,
684                                                  GetDefinition(bcInst->GetVReg(IS_ACC_WRITE ? 0 : 1)), saveState);
685     auto runtime = GetRuntime();
686     auto fieldIndex = bcInst->GetId(0).AsIndex();
687     auto fieldId = runtime->ResolveFieldIndex(GetMethod(), fieldIndex);
688     auto field = runtime->ResolveField(GetMethod(), fieldId, !GetGraph()->IsAotMode(), nullptr);
689     if (type != DataType::REFERENCE) {
690         type = runtime->GetFieldTypeById(GetMethod(), fieldId);
691     }
692 
693     // Create LoadObject instruction
694     Inst *inst;
695     ResolveObjectFieldInst *resolveField = nullptr;
696     if (field == nullptr || ForceUnresolved()) {
697         // 1. Create an instruction to resolve an object's field
698         if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
699             GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), fieldId,
700                                                              UnresolvedTypesInterface::SlotKind::FIELD);
701         }
702         resolveField =
703             graph_->CreateInstResolveObjectField(DataType::UINT32, pc, saveState, fieldId, GetGraph()->GetMethod());
704         // 2. Create an instruction to load a value from the resolved field
705         auto loadField = graph_->CreateInstLoadResolvedObjectField(type, pc, nullCheck, resolveField, fieldId,
706                                                                    GetGraph()->GetMethod());
707         inst = loadField;
708     } else {
709         auto loadField = graph_->CreateInstLoadObject(type, pc, nullCheck, fieldId, GetGraph()->GetMethod(), field,
710                                                       runtime->IsFieldVolatile(field));
711         inst = loadField;
712     }
713 
714     AddInstruction(saveState);
715     AddInstruction(nullCheck);
716     if (resolveField != nullptr) {
717         AddInstruction(resolveField);
718     }
719     AddInstruction(inst);
720 
721     // NOLINTNEXTLINE(readability-braces-around-statements)
722     if constexpr (IS_ACC_WRITE) {
723         UpdateDefinitionAcc(inst);
724         // NOLINTNEXTLINE(readability-misleading-indentation)
725     } else {
726         UpdateDefinition(bcInst->GetVReg(0), inst);
727     }
728 }
729 
730 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildStoreObjectInst(const BytecodeInstruction * bcInst,DataType::Type type,RuntimeInterface::FieldPtr field,size_t fieldId,Inst ** resolveInst)731 Inst *InstBuilder::BuildStoreObjectInst(const BytecodeInstruction *bcInst, DataType::Type type,
732                                         RuntimeInterface::FieldPtr field, size_t fieldId, Inst **resolveInst)
733 {
734     auto pc = GetPc(bcInst->GetAddress());
735     if (field == nullptr || ForceUnresolved()) {
736         // The field is unresolved, so we have to resolve it and then store
737         // 1. Create an instruction to resolve an object's field
738         auto resolveField =
739             graph_->CreateInstResolveObjectField(DataType::UINT32, pc, nullptr, fieldId, GetGraph()->GetMethod());
740         if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
741             GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), fieldId,
742                                                              UnresolvedTypesInterface::SlotKind::FIELD);
743         }
744         // 2. Create an instruction to store a value to the resolved field
745         auto storeField = graph_->CreateInstStoreResolvedObjectField(
746             type, pc, nullptr, nullptr, nullptr, fieldId, GetGraph()->GetMethod(), false, type == DataType::REFERENCE);
747         *resolveInst = resolveField;
748         return storeField;
749     }
750 
751     ASSERT(field != nullptr);
752     auto storeField = graph_->CreateInstStoreObject(type, pc, nullptr, nullptr, fieldId, GetGraph()->GetMethod(), field,
753                                                     GetRuntime()->IsFieldVolatile(field), type == DataType::REFERENCE);
754     *resolveInst = nullptr;  // resolver is not needed in this case
755     return storeField;
756 }
757 
758 // NOLINTNEXTLINE(misc-definitions-in-headers)
759 template <bool IS_ACC_READ>
BuildStoreObject(const BytecodeInstruction * bcInst,DataType::Type type)760 void InstBuilder::BuildStoreObject(const BytecodeInstruction *bcInst, DataType::Type type)
761 {
762     // Create SaveState instruction
763     auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
764 
765     // Create NullCheck instruction
766     auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, GetPc(bcInst->GetAddress()),
767                                                  GetDefinition(bcInst->GetVReg(IS_ACC_READ ? 0 : 1)), saveState);
768 
769     auto runtime = GetRuntime();
770     auto fieldIndex = bcInst->GetId(0).AsIndex();
771     auto fieldId = runtime->ResolveFieldIndex(GetMethod(), fieldIndex);
772     auto field = runtime->ResolveField(GetMethod(), fieldId, !GetGraph()->IsAotMode(), nullptr);
773     if (type != DataType::REFERENCE) {
774         type = runtime->GetFieldTypeById(GetMethod(), fieldId);
775     }
776 
777     // Get a value to store
778     Inst *storeVal = nullptr;
779     // NOLINTNEXTLINE(readability-braces-around-statements)
780     if constexpr (IS_ACC_READ) {
781         storeVal = GetDefinitionAcc();
782     } else {  // NOLINT(readability-misleading-indentation)
783         storeVal = GetDefinition(bcInst->GetVReg(0));
784     }
785 
786     // Create StoreObject instruction
787     Inst *resolveField = nullptr;
788     Inst *storeField = BuildStoreObjectInst(bcInst, type, field, fieldId, &resolveField);
789     storeField->SetInput(0, nullCheck);
790     storeField->SetInput(1, storeVal);
791 
792     AddInstruction(saveState);
793     AddInstruction(nullCheck);
794     if (resolveField != nullptr) {
795         ASSERT(field == nullptr || ForceUnresolved());
796         resolveField->SetInput(0, saveState);
797         storeField->SetInput(2U, resolveField);
798         AddInstruction(resolveField);
799     }
800     AddInstruction(storeField);
801 }
802 
803 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadStaticInst(const BytecodeInstruction * bcInst,DataType::Type type,size_t typeId,Inst * saveState)804 Inst *InstBuilder::BuildLoadStaticInst(const BytecodeInstruction *bcInst, DataType::Type type, size_t typeId,
805                                        Inst *saveState)
806 {
807     AddInstruction(saveState);
808 
809     uint32_t classId;
810     auto field = GetRuntime()->ResolveField(GetMethod(), typeId, !GetGraph()->IsAotMode(), &classId);
811     auto pc = GetPc(bcInst->GetAddress());
812 
813     if (field == nullptr || ForceUnresolved()) {
814         // The static field is unresolved, so we have to resolve it and then load
815         // 1. Create an instruction to resolve an object's static field.
816         //    Its result is a static field memory address (not an offset as there is no object)
817         auto resolveField = graph_->CreateInstResolveObjectFieldStatic(DataType::REFERENCE, pc, saveState, typeId,
818                                                                        GetGraph()->GetMethod());
819         if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
820             GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), typeId,
821                                                              UnresolvedTypesInterface::SlotKind::FIELD);
822         }
823         AddInstruction(resolveField);
824         // 2. Create an instruction to load a value from the resolved static field address
825         auto loadField =
826             graph_->CreateInstLoadResolvedObjectFieldStatic(type, pc, resolveField, typeId, GetGraph()->GetMethod());
827         return loadField;
828     }
829 
830     ASSERT(field != nullptr);
831     auto initClass = graph_->CreateInstLoadAndInitClass(DataType::REFERENCE, pc, saveState, classId,
832                                                         GetGraph()->GetMethod(), GetRuntime()->GetClassForField(field));
833     auto loadField = graph_->CreateInstLoadStatic(type, pc, initClass, typeId, GetGraph()->GetMethod(), field,
834                                                   GetRuntime()->IsFieldVolatile(field));
835     AddInstruction(initClass);
836     return loadField;
837 }
838 
839 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildAnyTypeCheckInst(size_t bcAddr,Inst * input,Inst * saveState,AnyBaseType type,bool typeWasProfiled,profiling::AnyInputType allowedInputType)840 Inst *InstBuilder::BuildAnyTypeCheckInst(size_t bcAddr, Inst *input, Inst *saveState, AnyBaseType type,
841                                          bool typeWasProfiled, profiling::AnyInputType allowedInputType)
842 {
843     auto anyCheck = graph_->CreateInstAnyTypeCheck(DataType::ANY, bcAddr, input, saveState, type);
844     anyCheck->SetAllowedInputType(allowedInputType);
845     anyCheck->SetIsTypeWasProfiled(typeWasProfiled);
846     AddInstruction(anyCheck);
847 
848     return anyCheck;
849 }
850 
851 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadStatic(const BytecodeInstruction * bcInst,DataType::Type type)852 void InstBuilder::BuildLoadStatic(const BytecodeInstruction *bcInst, DataType::Type type)
853 {
854     auto fieldIndex = bcInst->GetId(0).AsIndex();
855     auto fieldId = GetRuntime()->ResolveFieldIndex(GetMethod(), fieldIndex);
856     if (type != DataType::REFERENCE) {
857         type = GetRuntime()->GetFieldTypeById(GetMethod(), fieldId);
858     }
859     auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
860     Inst *inst = BuildLoadStaticInst(bcInst, type, fieldId, saveState);
861     AddInstruction(inst);
862     UpdateDefinitionAcc(inst);
863 }
864 
865 // NOLINTNEXTLINE(readability-function-size,misc-definitions-in-headers)
BuildStoreStaticInst(const BytecodeInstruction * bcInst,DataType::Type type,size_t typeId,Inst * storeInput,Inst * saveState)866 Inst *InstBuilder::BuildStoreStaticInst(const BytecodeInstruction *bcInst, DataType::Type type, size_t typeId,
867                                         Inst *storeInput, Inst *saveState)
868 {
869     AddInstruction(saveState);
870 
871     uint32_t classId;
872     auto field = GetRuntime()->ResolveField(GetMethod(), typeId, !GetGraph()->IsAotMode(), &classId);
873     auto pc = GetPc(bcInst->GetAddress());
874 
875     if (field == nullptr || ForceUnresolved()) {
876         if (type == DataType::REFERENCE) {
877             // 1. Class initialization is needed.
878             // 2. GC Pre/Post write barriers may be needed.
879             // Just call runtime EntrypointId::UNRESOLVED_STORE_STATIC_BARRIERED,
880             // which performs all the necessary steps (see codegen.cpp for the details).
881             auto inst = graph_->CreateInstUnresolvedStoreStatic(type, pc, storeInput, saveState, typeId,
882                                                                 GetGraph()->GetMethod(), true);
883             return inst;
884         }
885         ASSERT(type != DataType::REFERENCE);
886         // 1. Create an instruction to resolve an object's static field.
887         //    Its result is a static field memory address (REFERENCE)
888         auto resolveField = graph_->CreateInstResolveObjectFieldStatic(DataType::REFERENCE, pc, saveState, typeId,
889                                                                        GetGraph()->GetMethod());
890         AddInstruction(resolveField);
891         // 2. Create an instruction to store a value to the resolved static field address
892         auto storeField = graph_->CreateInstStoreResolvedObjectFieldStatic(type, pc, resolveField, storeInput, typeId,
893                                                                            GetGraph()->GetMethod());
894         if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
895             GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), typeId,
896                                                              UnresolvedTypesInterface::SlotKind::FIELD);
897         }
898         return storeField;
899     }
900 
901     ASSERT(field != nullptr);
902     auto initClass = graph_->CreateInstLoadAndInitClass(DataType::REFERENCE, pc, saveState, classId,
903                                                         GetGraph()->GetMethod(), GetRuntime()->GetClassForField(field));
904     auto storeField =
905         graph_->CreateInstStoreStatic(type, pc, initClass, storeInput, typeId, GetGraph()->GetMethod(), field,
906                                       GetRuntime()->IsFieldVolatile(field), type == DataType::REFERENCE);
907     AddInstruction(initClass);
908     return storeField;
909 }
910 
911 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildStoreStatic(const BytecodeInstruction * bcInst,DataType::Type type)912 void InstBuilder::BuildStoreStatic(const BytecodeInstruction *bcInst, DataType::Type type)
913 {
914     auto fieldIndex = bcInst->GetId(0).AsIndex();
915     auto fieldId = GetRuntime()->ResolveFieldIndex(GetMethod(), fieldIndex);
916     if (type != DataType::REFERENCE) {
917         type = GetRuntime()->GetFieldTypeById(GetMethod(), fieldId);
918     }
919     auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
920     Inst *storeInput = GetDefinitionAcc();
921     Inst *inst = BuildStoreStaticInst(bcInst, type, fieldId, storeInput, saveState);
922     AddInstruction(inst);
923 }
924 
925 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildChecksBeforeArray(size_t pc,Inst * arrayRef,Inst ** ss,Inst ** nc,Inst ** al,Inst ** bc,bool withNullcheck)926 void InstBuilder::BuildChecksBeforeArray(size_t pc, Inst *arrayRef, Inst **ss, Inst **nc, Inst **al, Inst **bc,
927                                          bool withNullcheck)
928 {
929     // Create SaveState instruction
930     auto saveState = CreateSaveState(Opcode::SaveState, pc);
931 
932     // Create NullCheck instruction
933     Inst *nullCheck = nullptr;
934     if (withNullcheck) {
935         nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, pc, arrayRef, saveState);
936     } else {
937         nullCheck = arrayRef;
938     }
939 
940     // Create LenArray instruction
941     auto arrayLength = graph_->CreateInstLenArray(DataType::INT32, pc, nullCheck);
942 
943     // Create BoundCheck instruction
944     auto boundsCheck = graph_->CreateInstBoundsCheck(DataType::INT32, pc, arrayLength, nullptr, saveState);
945 
946     *ss = saveState;
947     *nc = nullCheck;
948     *al = arrayLength;
949     *bc = boundsCheck;
950 }
951 
952 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadArray(const BytecodeInstruction * bcInst,DataType::Type type)953 void InstBuilder::BuildLoadArray(const BytecodeInstruction *bcInst, DataType::Type type)
954 {
955     ASSERT(type != DataType::NO_TYPE);
956     Inst *saveState = nullptr;
957     Inst *nullCheck = nullptr;
958     Inst *arrayLength = nullptr;
959     Inst *boundsCheck = nullptr;
960     auto pc = GetPc(bcInst->GetAddress());
961     BuildChecksBeforeArray(pc, GetDefinition(bcInst->GetVReg(0)), &saveState, &nullCheck, &arrayLength, &boundsCheck);
962     ASSERT(saveState != nullptr && nullCheck != nullptr && arrayLength != nullptr && boundsCheck != nullptr);
963 
964     // Create instruction
965     auto inst = graph_->CreateInstLoadArray(type, pc, nullCheck, boundsCheck);
966     boundsCheck->SetInput(1, GetDefinitionAcc());
967     AddInstruction(saveState, nullCheck, arrayLength, boundsCheck, inst);
968     UpdateDefinitionAcc(inst);
969 }
970 
971 template <typename T>
BuildUnfoldLoadConstStringArray(const BytecodeInstruction * bcInst,DataType::Type type,const pandasm::LiteralArray & litArray,NewArrayInst * arrayInst)972 void InstBuilder::BuildUnfoldLoadConstStringArray(const BytecodeInstruction *bcInst, DataType::Type type,
973                                                   const pandasm::LiteralArray &litArray, NewArrayInst *arrayInst)
974 {
975     auto method = GetGraph()->GetMethod();
976     auto arraySize = litArray.literals.size();
977     for (size_t i = 0; i < arraySize; i++) {
978         auto indexInst = graph_->FindOrCreateConstant(i);
979         auto save = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
980         auto loadStringInst = GetGraph()->CreateInstLoadString(DataType::REFERENCE, GetPc(bcInst->GetAddress()), save,
981                                                                std::get<T>(litArray.literals[i].value), method);
982         AddInstruction(save);
983         AddInstruction(loadStringInst);
984         if (GetGraph()->IsDynamicMethod()) {
985             BuildCastToAnyString(bcInst);
986         }
987 
988         BuildStoreArrayInst<false>(bcInst, type, arrayInst, indexInst, loadStringInst);
989     }
990 }
991 
992 template <typename T>
BuildUnfoldLoadConstArray(const BytecodeInstruction * bcInst,DataType::Type type,const pandasm::LiteralArray & litArray)993 void InstBuilder::BuildUnfoldLoadConstArray(const BytecodeInstruction *bcInst, DataType::Type type,
994                                             const pandasm::LiteralArray &litArray)
995 {
996     auto method = GetGraph()->GetMethod();
997     auto arraySize = litArray.literals.size();
998     auto typeId = GetRuntime()->GetLiteralArrayClassIdWithinFile(method, litArray.literals[0].tag);
999 
1000     // Create NewArray instruction
1001     auto sizeInst = graph_->FindOrCreateConstant(arraySize);
1002     auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1003     auto negCheck = graph_->CreateInstNegativeCheck(DataType::INT32, GetPc(bcInst->GetAddress()), sizeInst, saveState);
1004     auto initClass = CreateLoadAndInitClassGeneric(typeId, GetPc(bcInst->GetAddress()));
1005     initClass->SetInput(0, saveState);
1006     auto arrayInst = graph_->CreateInstNewArray(DataType::REFERENCE, GetPc(bcInst->GetAddress()), initClass, negCheck,
1007                                                 saveState, typeId, GetGraph()->GetMethod());
1008     AddInstruction(saveState);
1009     AddInstruction(initClass);
1010     AddInstruction(negCheck);
1011     AddInstruction(arrayInst);
1012     UpdateDefinition(bcInst->GetVReg(0), arrayInst);
1013 
1014     if (arraySize > g_options.GetCompilerUnfoldConstArrayMaxSize()) {
1015         // Create LoadConstArray instruction
1016         auto ss = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1017         auto inst = GetGraph()->CreateInstFillConstArray(type, GetPc(bcInst->GetAddress()), arrayInst, ss,
1018                                                          bcInst->GetId(0).AsFileId().GetOffset(), method, arraySize);
1019         AddInstruction(ss);
1020         AddInstruction(inst);
1021         return;
1022     }
1023 
1024     // Create instructions for array filling
1025     auto tag = litArray.literals[0].tag;
1026     if (tag != panda_file::LiteralTag::ARRAY_STRING) {
1027         for (size_t i = 0; i < arraySize; i++) {
1028             auto indexInst = graph_->FindOrCreateConstant(i);
1029             ConstantInst *valueInst;
1030             if (tag == panda_file::LiteralTag::ARRAY_F32) {
1031                 valueInst = FindOrCreateFloatConstant(static_cast<float>(std::get<T>(litArray.literals[i].value)));
1032             } else if (tag == panda_file::LiteralTag::ARRAY_F64) {
1033                 valueInst = FindOrCreateDoubleConstant(static_cast<double>(std::get<T>(litArray.literals[i].value)));
1034             } else {
1035                 valueInst = FindOrCreateConstant(std::get<T>(litArray.literals[i].value));
1036             }
1037 
1038             BuildStoreArrayInst<false>(bcInst, type, arrayInst, indexInst, valueInst);
1039         }
1040 
1041         return;
1042     }
1043     [[maybe_unused]] auto arrayClass = GetRuntime()->ResolveType(method, typeId);
1044     ASSERT(GetRuntime()->CheckStoreArray(arrayClass, GetRuntime()->GetStringClass(method)));
1045 
1046     // Special case for string array
1047     BuildUnfoldLoadConstStringArray<T>(bcInst, type, litArray, arrayInst);
1048 }
1049 
1050 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadConstStringArray(const BytecodeInstruction * bcInst)1051 void InstBuilder::BuildLoadConstStringArray(const BytecodeInstruction *bcInst)
1052 {
1053     auto literalArrayIdx = bcInst->GetId(0).AsIndex();
1054     auto litArray = GetRuntime()->GetLiteralArray(GetMethod(), literalArrayIdx);
1055     auto arraySize = litArray.literals.size();
1056     ASSERT(arraySize > 0);
1057     if (arraySize > g_options.GetCompilerUnfoldConstArrayMaxSize()) {
1058         // Create LoadConstArray instruction for String array, because we calls runtime for the case.
1059         auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1060         auto method = GetGraph()->GetMethod();
1061         auto inst = GetGraph()->CreateInstLoadConstArray(DataType::REFERENCE, GetPc(bcInst->GetAddress()), saveState,
1062                                                          literalArrayIdx, method);
1063         AddInstruction(saveState);
1064         AddInstruction(inst);
1065         UpdateDefinition(bcInst->GetVReg(0), inst);
1066     } else {
1067         BuildUnfoldLoadConstArray<uint32_t>(bcInst, DataType::REFERENCE, litArray);
1068     }
1069 }
1070 
1071 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadConstArray(const BytecodeInstruction * bcInst)1072 void InstBuilder::BuildLoadConstArray(const BytecodeInstruction *bcInst)
1073 {
1074     auto literalArrayIdx = bcInst->GetId(0).AsIndex();
1075     auto litArray = GetRuntime()->GetLiteralArray(GetMethod(), literalArrayIdx);
1076     // Unfold LoadConstArray instruction
1077     auto tag = litArray.literals[0].tag;
1078     switch (tag) {
1079         case panda_file::LiteralTag::ARRAY_U1: {
1080             BuildUnfoldLoadConstArray<bool>(bcInst, DataType::INT8, litArray);
1081             break;
1082         }
1083         case panda_file::LiteralTag::ARRAY_I8:
1084         case panda_file::LiteralTag::ARRAY_U8: {
1085             BuildUnfoldLoadConstArray<uint8_t>(bcInst, DataType::INT8, litArray);
1086             break;
1087         }
1088         case panda_file::LiteralTag::ARRAY_I16:
1089         case panda_file::LiteralTag::ARRAY_U16: {
1090             BuildUnfoldLoadConstArray<uint16_t>(bcInst, DataType::INT16, litArray);
1091             break;
1092         }
1093         case panda_file::LiteralTag::ARRAY_I32:
1094         case panda_file::LiteralTag::ARRAY_U32: {
1095             BuildUnfoldLoadConstArray<uint32_t>(bcInst, DataType::INT32, litArray);
1096             break;
1097         }
1098         case panda_file::LiteralTag::ARRAY_I64:
1099         case panda_file::LiteralTag::ARRAY_U64: {
1100             BuildUnfoldLoadConstArray<uint64_t>(bcInst, DataType::INT64, litArray);
1101             break;
1102         }
1103         case panda_file::LiteralTag::ARRAY_F32: {
1104             BuildUnfoldLoadConstArray<float>(bcInst, DataType::FLOAT32, litArray);
1105             break;
1106         }
1107         case panda_file::LiteralTag::ARRAY_F64: {
1108             BuildUnfoldLoadConstArray<double>(bcInst, DataType::FLOAT64, litArray);
1109             break;
1110         }
1111         case panda_file::LiteralTag::ARRAY_STRING: {
1112             BuildLoadConstStringArray(bcInst);
1113             break;
1114         }
1115         default: {
1116             UNREACHABLE();
1117             break;
1118         }
1119     }
1120 }
1121 
1122 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildStoreArray(const BytecodeInstruction * bcInst,DataType::Type type)1123 void InstBuilder::BuildStoreArray(const BytecodeInstruction *bcInst, DataType::Type type)
1124 {
1125     BuildStoreArrayInst<true>(bcInst, type, GetDefinition(bcInst->GetVReg(0)), GetDefinition(bcInst->GetVReg(1)),
1126                               GetDefinitionAcc());
1127 }
1128 
1129 // NOLINTNEXTLINE(misc-definitions-in-headers)
1130 template <bool CREATE_REF_CHECK>
BuildStoreArrayInst(const BytecodeInstruction * bcInst,DataType::Type type,Inst * arrayRef,Inst * index,Inst * value)1131 void InstBuilder::BuildStoreArrayInst(const BytecodeInstruction *bcInst, DataType::Type type, Inst *arrayRef,
1132                                       Inst *index, Inst *value)
1133 {
1134     ASSERT(type != DataType::NO_TYPE);
1135     Inst *refCheck = nullptr;
1136     Inst *saveState = nullptr;
1137     Inst *nullCheck = nullptr;
1138     Inst *arrayLength = nullptr;
1139     Inst *boundsCheck = nullptr;
1140     auto pc = GetPc(bcInst->GetAddress());
1141     BuildChecksBeforeArray(pc, arrayRef, &saveState, &nullCheck, &arrayLength, &boundsCheck);
1142     ASSERT(saveState != nullptr && nullCheck != nullptr && arrayLength != nullptr && boundsCheck != nullptr);
1143 
1144     // Create instruction
1145     auto inst = graph_->CreateInstStoreArray(type, pc);
1146     boundsCheck->SetInput(1, index);
1147     auto storeDef = value;
1148     if (type == DataType::REFERENCE) {
1149         // NOLINTNEXTLINE(readability-braces-around-statements,bugprone-suspicious-semicolon)
1150         if constexpr (CREATE_REF_CHECK) {
1151             refCheck = graph_->CreateInstRefTypeCheck(DataType::REFERENCE, pc, nullCheck, storeDef, saveState);
1152             storeDef = refCheck;
1153         }
1154         inst->CastToStoreArray()->SetNeedBarrier(true);
1155     }
1156     inst->SetInput(0, nullCheck);
1157     inst->SetInput(1, boundsCheck);
1158     inst->SetInput(2U, storeDef);
1159     if (refCheck != nullptr) {
1160         AddInstruction(saveState, nullCheck, arrayLength, boundsCheck, refCheck, inst);
1161     } else {
1162         AddInstruction(saveState, nullCheck, arrayLength, boundsCheck, inst);
1163     }
1164 }
1165 
1166 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLenArray(const BytecodeInstruction * bcInst)1167 void InstBuilder::BuildLenArray(const BytecodeInstruction *bcInst)
1168 {
1169     auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1170     auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, GetPc(bcInst->GetAddress()));
1171     nullCheck->SetInput(0, GetDefinition(bcInst->GetVReg(0)));
1172     nullCheck->SetInput(1, saveState);
1173     auto inst = graph_->CreateInstLenArray(DataType::INT32, GetPc(bcInst->GetAddress()), nullCheck);
1174     AddInstruction(saveState);
1175     AddInstruction(nullCheck);
1176     AddInstruction(inst);
1177     UpdateDefinitionAcc(inst);
1178 }
1179 
1180 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildNewArray(const BytecodeInstruction * bcInst)1181 void InstBuilder::BuildNewArray(const BytecodeInstruction *bcInst)
1182 {
1183     auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1184     auto negCheck = graph_->CreateInstNegativeCheck(DataType::INT32, GetPc(bcInst->GetAddress()),
1185                                                     GetDefinition(bcInst->GetVReg(1)), saveState);
1186 
1187     auto typeIndex = bcInst->GetId(0).AsIndex();
1188     auto typeId = GetRuntime()->ResolveTypeIndex(GetMethod(), typeIndex);
1189 
1190     auto initClass = CreateLoadAndInitClassGeneric(typeId, GetPc(bcInst->GetAddress()));
1191     initClass->SetInput(0, saveState);
1192 
1193     auto inst = graph_->CreateInstNewArray(DataType::REFERENCE, GetPc(bcInst->GetAddress()), initClass, negCheck,
1194                                            saveState, typeId, GetGraph()->GetMethod());
1195     AddInstruction(saveState, initClass, negCheck, inst);
1196     UpdateDefinition(bcInst->GetVReg(0), inst);
1197 }
1198 
1199 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildNewObject(const BytecodeInstruction * bcInst)1200 void InstBuilder::BuildNewObject(const BytecodeInstruction *bcInst)
1201 {
1202     auto classId = GetRuntime()->ResolveTypeIndex(GetMethod(), bcInst->GetId(0).AsIndex());
1203     auto pc = GetPc(bcInst->GetAddress());
1204     auto saveState = CreateSaveState(Opcode::SaveState, pc);
1205     auto initClass = CreateLoadAndInitClassGeneric(classId, pc);
1206     auto inst = CreateNewObjectInst(pc, classId, saveState, initClass);
1207     initClass->SetInput(0, saveState);
1208     AddInstruction(saveState, initClass, inst);
1209     UpdateDefinition(bcInst->GetVReg(0), inst);
1210 }
1211 
1212 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildMultiDimensionalArrayObject(const BytecodeInstruction * bcInst,bool isRange)1213 void InstBuilder::BuildMultiDimensionalArrayObject(const BytecodeInstruction *bcInst, bool isRange)
1214 {
1215     auto methodIndex = bcInst->GetId(0).AsIndex();
1216     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
1217     auto pc = GetPc(bcInst->GetAddress());
1218     auto classId = GetRuntime()->GetClassIdForMethod(GetMethod(), methodId);
1219     auto saveState = CreateSaveState(Opcode::SaveState, pc);
1220     auto initClass = CreateLoadAndInitClassGeneric(classId, pc);
1221     size_t argsCount = GetMethodArgumentsCount(methodId);
1222     auto inst = GetGraph()->CreateInstMultiArray(DataType::REFERENCE, pc, methodId);
1223 
1224     initClass->SetInput(0, saveState);
1225 
1226     inst->ReserveInputs(ONE_FOR_OBJECT + argsCount + ONE_FOR_SSTATE);
1227     inst->AllocateInputTypes(GetGraph()->GetAllocator(), ONE_FOR_OBJECT + argsCount + ONE_FOR_SSTATE);
1228     inst->AppendInput(initClass);
1229     inst->AddInputType(DataType::REFERENCE);
1230 
1231     AddInstruction(saveState, initClass);
1232 
1233     if (isRange) {
1234         auto startReg = bcInst->GetVReg(0);
1235         for (size_t i = 0; i < argsCount; startReg++, i++) {
1236             auto negCheck = graph_->CreateInstNegativeCheck(DataType::INT32, pc, GetDefinition(startReg), saveState);
1237             AddInstruction(negCheck);
1238             inst->AppendInput(negCheck);
1239             inst->AddInputType(DataType::INT32);
1240         }
1241     } else {
1242         for (size_t i = 0; i < argsCount; i++) {
1243             auto negCheck =
1244                 graph_->CreateInstNegativeCheck(DataType::INT32, pc, GetDefinition(bcInst->GetVReg(i)), saveState);
1245             AddInstruction(negCheck);
1246             inst->AppendInput(negCheck);
1247             inst->AddInputType(DataType::INT32);
1248         }
1249     }
1250     inst->AppendInput(saveState);
1251     inst->AddInputType(DataType::NO_TYPE);
1252     AddInstruction(inst);
1253     UpdateDefinitionAcc(inst);
1254 }
1255 
1256 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildInitObjectMultiDimensionalArray(const BytecodeInstruction * bcInst,bool isRange)1257 void InstBuilder::BuildInitObjectMultiDimensionalArray(const BytecodeInstruction *bcInst, bool isRange)
1258 {
1259     auto pc = GetPc(bcInst->GetAddress());
1260     auto methodIndex = bcInst->GetId(0).AsIndex();
1261     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
1262     auto classId = GetRuntime()->GetClassIdForMethod(GetMethod(), methodId);
1263     auto saveState = CreateSaveState(Opcode::SaveState, pc);
1264     auto initClass =
1265         graph_->CreateInstLoadAndInitClass(DataType::REFERENCE, pc, saveState, classId, GetGraph()->GetMethod(),
1266                                            GetRuntime()->ResolveType(GetGraph()->GetMethod(), classId));
1267     auto inst = GetGraph()->CreateInstInitObject(DataType::REFERENCE, pc, methodId);
1268 
1269     size_t argsCount = GetMethodArgumentsCount(methodId);
1270 
1271     inst->ReserveInputs(ONE_FOR_OBJECT + argsCount + ONE_FOR_SSTATE);
1272     inst->AllocateInputTypes(GetGraph()->GetAllocator(), ONE_FOR_OBJECT + argsCount + ONE_FOR_SSTATE);
1273     inst->AppendInput(initClass);
1274     inst->AddInputType(DataType::REFERENCE);
1275     if (isRange) {
1276         auto startReg = bcInst->GetVReg(0);
1277         for (size_t i = 0; i < argsCount; startReg++, i++) {
1278             inst->AppendInput(GetDefinition(startReg));
1279             inst->AddInputType(GetMethodArgumentType(methodId, i));
1280         }
1281     } else {
1282         for (size_t i = 0; i < argsCount; i++) {
1283             inst->AppendInput(GetDefinition(bcInst->GetVReg(i)));
1284             inst->AddInputType(GetMethodArgumentType(methodId, i));
1285         }
1286     }
1287     inst->AppendInput(saveState);
1288     inst->AddInputType(DataType::NO_TYPE);
1289     inst->SetCallMethod(GetRuntime()->GetMethodById(GetGraph()->GetMethod(), methodId));
1290 
1291     AddInstruction(saveState, initClass, inst);
1292     UpdateDefinitionAcc(inst);
1293 }
1294 
1295 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCallStaticForInitObject(const BytecodeInstruction * bcInst,uint32_t methodId,Inst ** resolver)1296 CallInst *InstBuilder::BuildCallStaticForInitObject(const BytecodeInstruction *bcInst, uint32_t methodId,
1297                                                     Inst **resolver)
1298 {
1299     auto pc = GetPc(bcInst->GetAddress());
1300     size_t argsCount = GetMethodArgumentsCount(methodId);
1301     size_t inputsCount = ONE_FOR_OBJECT + argsCount + ONE_FOR_SSTATE;
1302     auto method = GetRuntime()->GetMethodById(graph_->GetMethod(), methodId);
1303     CallInst *call = nullptr;
1304     if (method == nullptr || ForceUnresolved()) {
1305         ResolveStaticInst *resolveStatic = graph_->CreateInstResolveStatic(DataType::POINTER, pc, methodId, nullptr);
1306         *resolver = resolveStatic;
1307         call = graph_->CreateInstCallResolvedStatic(GetMethodReturnType(methodId), pc, methodId);
1308         if (!graph_->IsAotMode() && !graph_->IsBytecodeOptimizer()) {
1309             GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), methodId,
1310                                                              UnresolvedTypesInterface::SlotKind::METHOD);
1311         }
1312         inputsCount += 1;  // resolver
1313     } else {
1314         call = graph_->CreateInstCallStatic(GetMethodReturnType(methodId), pc, methodId, method);
1315     }
1316     call->ReserveInputs(inputsCount);
1317     call->AllocateInputTypes(graph_->GetAllocator(), inputsCount);
1318     return call;
1319 }
1320 
1321 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildInitString(const BytecodeInstruction * bcInst)1322 void InstBuilder::BuildInitString(const BytecodeInstruction *bcInst)
1323 {
1324     auto pc = GetPc(bcInst->GetAddress());
1325     auto saveState = CreateSaveState(Opcode::SaveState, pc);
1326     AddInstruction(saveState);
1327 
1328     auto ctorMethodIndex = bcInst->GetId(0).AsIndex();
1329     auto ctorMethodId = GetRuntime()->ResolveMethodIndex(GetMethod(), ctorMethodIndex);
1330     size_t argsCount = GetMethodArgumentsCount(ctorMethodId);
1331 
1332     Inst *inst = nullptr;
1333     if (argsCount == 0) {
1334         inst = GetGraph()->CreateInstInitEmptyString(DataType::REFERENCE, pc, saveState);
1335     } else {
1336         ASSERT(argsCount == 1);
1337         auto nullCheck =
1338             graph_->CreateInstNullCheck(DataType::REFERENCE, pc, GetDefinition(bcInst->GetVReg(0)), saveState);
1339         AddInstruction(nullCheck);
1340 
1341         auto ctorMethod = GetRuntime()->GetMethodById(GetMethod(), ctorMethodId);
1342         auto ctorType = GetRuntime()->GetStringCtorType(ctorMethod);
1343         inst = GetGraph()->CreateInstInitString(DataType::REFERENCE, pc, nullCheck, saveState, ctorType);
1344     }
1345     AddInstruction(inst);
1346     UpdateDefinitionAcc(inst);
1347 }
1348 
1349 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildInitObject(const BytecodeInstruction * bcInst,bool isRange)1350 void InstBuilder::BuildInitObject(const BytecodeInstruction *bcInst, bool isRange)
1351 {
1352     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex());
1353     auto typeId = GetRuntime()->GetClassIdForMethod(GetMethod(), methodId);
1354     if (GetRuntime()->IsArrayClass(GetMethod(), typeId)) {
1355         if (GetGraph()->IsBytecodeOptimizer()) {
1356             BuildInitObjectMultiDimensionalArray(bcInst, isRange);
1357         } else {
1358             BuildMultiDimensionalArrayObject(bcInst, isRange);
1359         }
1360         return;
1361     }
1362 
1363     if (GetRuntime()->IsStringClass(GetMethod(), typeId) && !GetGraph()->IsBytecodeOptimizer()) {
1364         BuildInitString(bcInst);
1365         return;
1366     }
1367 
1368     auto pc = GetPc(bcInst->GetAddress());
1369     auto saveState = CreateSaveState(Opcode::SaveState, pc);
1370     auto initClass = CreateLoadAndInitClassGeneric(typeId, pc);
1371     initClass->SetInput(0, saveState);
1372     auto newObj = CreateNewObjectInst(pc, typeId, saveState, initClass);
1373     UpdateDefinitionAcc(newObj);
1374     Inst *resolver = nullptr;
1375     CallInst *call = BuildCallStaticForInitObject(bcInst, methodId, &resolver);
1376     if (resolver != nullptr) {
1377         call->AppendInput(resolver);
1378         call->AddInputType(DataType::POINTER);
1379     }
1380     call->AppendInput(newObj);
1381     call->AddInputType(DataType::REFERENCE);
1382 
1383     size_t argsCount = GetMethodArgumentsCount(methodId);
1384     if (isRange) {
1385         auto startReg = bcInst->GetVReg(0);
1386         for (size_t i = 0; i < argsCount; startReg++, i++) {
1387             call->AppendInput(GetDefinition(startReg));
1388             call->AddInputType(GetMethodArgumentType(methodId, i));
1389         }
1390     } else {
1391         for (size_t i = 0; i < argsCount; i++) {
1392             call->AppendInput(GetDefinition(bcInst->GetVReg(i)));
1393             call->AddInputType(GetMethodArgumentType(methodId, i));
1394         }
1395     }
1396     auto saveStateForCall = CreateSaveState(Opcode::SaveState, pc);
1397     call->AppendInput(saveStateForCall);
1398     call->AddInputType(DataType::NO_TYPE);
1399     if (resolver != nullptr) {
1400         resolver->SetInput(0, saveStateForCall);
1401         AddInstruction(saveState, initClass, newObj, saveStateForCall, resolver, call);
1402     } else {
1403         AddInstruction(saveState, initClass, newObj, saveStateForCall, call);
1404     }
1405 }
1406 
1407 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCheckCast(const BytecodeInstruction * bcInst)1408 void InstBuilder::BuildCheckCast(const BytecodeInstruction *bcInst)
1409 {
1410     auto typeIndex = bcInst->GetId(0).AsIndex();
1411     auto typeId = GetRuntime()->ResolveTypeIndex(GetMethod(), typeIndex);
1412     auto klassType = GetRuntime()->GetClassType(GetGraph()->GetMethod(), typeId);
1413     auto pc = GetPc(bcInst->GetAddress());
1414     auto saveState = CreateSaveState(Opcode::SaveState, pc);
1415     auto loadClass = BuildLoadClass(typeId, pc, saveState);
1416     auto inst = GetGraph()->CreateInstCheckCast(DataType::NO_TYPE, pc, GetDefinitionAcc(), loadClass, saveState, typeId,
1417                                                 GetGraph()->GetMethod(), klassType);
1418     AddInstruction(saveState, loadClass, inst);
1419 }
1420 
1421 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildIsInstance(const BytecodeInstruction * bcInst)1422 void InstBuilder::BuildIsInstance(const BytecodeInstruction *bcInst)
1423 {
1424     auto typeIndex = bcInst->GetId(0).AsIndex();
1425     auto typeId = GetRuntime()->ResolveTypeIndex(GetMethod(), typeIndex);
1426     auto klassType = GetRuntime()->GetClassType(GetGraph()->GetMethod(), typeId);
1427     auto pc = GetPc(bcInst->GetAddress());
1428     auto saveState = CreateSaveState(Opcode::SaveState, pc);
1429     auto loadClass = BuildLoadClass(typeId, pc, saveState);
1430     auto inst = GetGraph()->CreateInstIsInstance(DataType::BOOL, pc, GetDefinitionAcc(), loadClass, saveState, typeId,
1431                                                  GetGraph()->GetMethod(), klassType);
1432     AddInstruction(saveState, loadClass, inst);
1433     UpdateDefinitionAcc(inst);
1434 }
1435 
1436 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadClass(RuntimeInterface::IdType typeId,size_t pc,Inst * saveState)1437 Inst *InstBuilder::BuildLoadClass(RuntimeInterface::IdType typeId, size_t pc, Inst *saveState)
1438 {
1439     auto inst =
1440         GetGraph()->CreateInstLoadClass(DataType::REFERENCE, pc, saveState, typeId, GetGraph()->GetMethod(), nullptr);
1441     auto klass = GetRuntime()->ResolveType(GetGraph()->GetMethod(), typeId);
1442     if (klass != nullptr) {
1443         inst->SetClass(klass);
1444     } else if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
1445         GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetGraph()->GetMethod(), typeId,
1446                                                          UnresolvedTypesInterface::SlotKind::CLASS);
1447     }
1448     return inst;
1449 }
1450 
1451 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildThrow(const BytecodeInstruction * bcInst)1452 void InstBuilder::BuildThrow(const BytecodeInstruction *bcInst)
1453 {
1454     auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1455     auto inst = graph_->CreateInstThrow(DataType::NO_TYPE, GetPc(bcInst->GetAddress()),
1456                                         GetDefinition(bcInst->GetVReg(0)), saveState);
1457     inst->SetCallMethod(GetMethod());
1458     AddInstruction(saveState);
1459     AddInstruction(inst);
1460 }
1461 
1462 // NOLINTNEXTLINE(misc-definitions-in-headers)
1463 template <Opcode OPCODE>
BuildLoadFromPool(const BytecodeInstruction * bcInst)1464 void InstBuilder::BuildLoadFromPool(const BytecodeInstruction *bcInst)
1465 {
1466     auto method = GetGraph()->GetMethod();
1467     uint32_t typeId;
1468     Inst *inst;
1469     // NOLINTNEXTLINE(readability-magic-numbers,readability-braces-around-statements)
1470     if constexpr (OPCODE == Opcode::LoadType) {
1471         auto typeIndex = bcInst->GetId(0).AsIndex();
1472         typeId = GetRuntime()->ResolveTypeIndex(method, typeIndex);
1473         if (GetRuntime()->ResolveType(method, typeId) == nullptr) {
1474             inst = GetGraph()->CreateInstUnresolvedLoadType(DataType::REFERENCE, GetPc(bcInst->GetAddress()));
1475             if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
1476                 GetRuntime()->GetUnresolvedTypes()->AddTableSlot(method, typeId,
1477                                                                  UnresolvedTypesInterface::SlotKind::MANAGED_CLASS);
1478             }
1479         } else {
1480             inst = GetGraph()->CreateInstLoadType(DataType::REFERENCE, GetPc(bcInst->GetAddress()));
1481         }
1482         // NOLINTNEXTLINE(readability-misleading-indentation)
1483     } else {
1484         // NOLINTNEXTLINE(readability-magic-numbers)
1485         static_assert(OPCODE == Opcode::LoadString);
1486         typeId = bcInst->GetId(0).AsFileId().GetOffset();
1487         if (!GetGraph()->IsDynamicMethod() || GetGraph()->IsBytecodeOptimizer()) {
1488             inst = GetGraph()->CreateInstLoadString(DataType::REFERENCE, GetPc(bcInst->GetAddress()));
1489         } else {
1490             inst = GetGraph()->CreateInstLoadFromConstantPool(DataType::ANY, GetPc(bcInst->GetAddress()));
1491             inst->CastToLoadFromConstantPool()->SetString(true);
1492         }
1493     }
1494     if (!GetGraph()->IsDynamicMethod() || GetGraph()->IsBytecodeOptimizer()) {
1495         // Create SaveState instruction
1496         auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1497         inst->SetInput(0, saveState);
1498         static_cast<LoadFromPool *>(inst)->SetTypeId(typeId);
1499         static_cast<LoadFromPool *>(inst)->SetMethod(method);
1500         AddInstruction(saveState);
1501     } else {
1502         inst->SetInput(0, GetEnvDefinition(CONST_POOL_IDX));
1503         inst->CastToLoadFromConstantPool()->SetTypeId(typeId);
1504         inst->CastToLoadFromConstantPool()->SetMethod(method);
1505     }
1506 
1507     AddInstruction(inst);
1508     UpdateDefinitionAcc(inst);
1509     // NOLINTNEXTLINE(readability-magic-numbers,readability-braces-around-statements,bugprone-suspicious-semicolon)
1510     if constexpr (OPCODE == Opcode::LoadString) {
1511         if (GetGraph()->IsDynamicMethod() && GetGraph()->IsBytecodeOptimizer()) {
1512             BuildCastToAnyString(bcInst);
1513         }
1514     }
1515 }
1516 
1517 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCastToAnyString(const BytecodeInstruction * bcInst)1518 void InstBuilder::BuildCastToAnyString(const BytecodeInstruction *bcInst)
1519 {
1520     auto input = GetDefinitionAcc();
1521     ASSERT(input->GetType() == DataType::REFERENCE);
1522 
1523     auto language = GetRuntime()->GetMethodSourceLanguage(GetMethod());
1524     auto anyType = GetAnyStringType(language);
1525     ASSERT(anyType != AnyBaseType::UNDEFINED_TYPE);
1526 
1527     auto box = graph_->CreateInstCastValueToAnyType(GetPc(bcInst->GetAddress()), anyType, input);
1528     UpdateDefinitionAcc(box);
1529     AddInstruction(box);
1530 }
1531 
1532 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCastToAnyNumber(const BytecodeInstruction * bcInst)1533 void InstBuilder::BuildCastToAnyNumber(const BytecodeInstruction *bcInst)
1534 {
1535     auto input = GetDefinitionAcc();
1536     auto type = input->GetType();
1537     if (input->IsConst() && !DataType::IsFloatType(type)) {
1538         auto constInsn = input->CastToConstant();
1539         if (constInsn->GetType() == DataType::INT64) {
1540             auto value = input->CastToConstant()->GetInt64Value();
1541             if (value == static_cast<uint32_t>(value)) {
1542                 type = DataType::INT32;
1543             }
1544         }
1545     }
1546 
1547     auto language = GetRuntime()->GetMethodSourceLanguage(GetMethod());
1548     auto anyType = NumericDataTypeToAnyType(type, language);
1549     ASSERT(anyType != AnyBaseType::UNDEFINED_TYPE);
1550 
1551     auto box = graph_->CreateInstCastValueToAnyType(GetPc(bcInst->GetAddress()), anyType, input);
1552     UpdateDefinitionAcc(box);
1553     AddInstruction(box);
1554 }
1555 
1556 // NOLINTNEXTLINE(misc-definitions-in-headers)
TryBuildStringCharAtIntrinsic(const BytecodeInstruction * bcInst,bool accRead)1557 bool InstBuilder::TryBuildStringCharAtIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
1558 {
1559     auto bcAddr = GetPc(bcInst->GetAddress());
1560     auto compressionEnabled = graph_->GetRuntime()->IsCompressedStringsEnabled();
1561     auto canEncodeCompressedStrCharAt = graph_->GetEncoder()->CanEncodeCompressedStringCharAt();
1562     if (compressionEnabled && !canEncodeCompressedStrCharAt) {
1563         return false;
1564     }
1565     auto saveStateNullcheck = CreateSaveState(Opcode::SaveState, bcAddr);
1566     auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, bcAddr, GetArgDefinition(bcInst, 0, accRead),
1567                                                  saveStateNullcheck);
1568     auto arrayLength = graph_->CreateInstLenArray(DataType::INT32, bcAddr, nullCheck, false);
1569 
1570     AddInstruction(saveStateNullcheck);
1571     AddInstruction(nullCheck);
1572     AddInstruction(arrayLength);
1573 
1574     Inst *stringLength = nullptr;
1575     if (compressionEnabled) {
1576         auto constOneInst = graph_->FindOrCreateConstant(1);
1577         stringLength = graph_->CreateInstShr(DataType::INT32, bcAddr, arrayLength, constOneInst);
1578         AddInstruction(stringLength);
1579     } else {
1580         stringLength = arrayLength;
1581     }
1582 
1583     auto boundsCheck = graph_->CreateInstBoundsCheck(DataType::INT32, bcAddr, stringLength,
1584                                                      GetArgDefinition(bcInst, 1, accRead), saveStateNullcheck, false);
1585     AddInstruction(boundsCheck);
1586 
1587     Inst *inst = nullptr;
1588     if (compressionEnabled) {
1589         inst =
1590             graph_->CreateInstLoadCompressedStringChar(DataType::UINT16, bcAddr, nullCheck, boundsCheck, arrayLength);
1591     } else {
1592         inst = graph_->CreateInstLoadArray(DataType::UINT16, bcAddr, nullCheck, boundsCheck);
1593     }
1594 
1595     AddInstruction(inst);
1596     UpdateDefinitionAcc(inst);
1597     return true;
1598 }
1599 
1600 }  // namespace panda::compiler
1601 
1602 #endif  // PANDA_INST_BUILDER_INL_H
1603