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