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