• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "compiler/optimizer/code_generator/codegen.h"
17 
18 namespace ark::compiler {
19 
EtsGetNativeMethod(IntrinsicInst * inst,Reg dst,SRCREGS & src)20 void Codegen::EtsGetNativeMethod(IntrinsicInst *inst, Reg dst, [[maybe_unused]] SRCREGS &src)
21 {
22     auto *encoder = GetEncoder();
23     ScopedTmpReg methodReg(encoder);
24 
25     if (GetGraph()->IsJitOrOsrMode()) {
26         auto *method = inst->GetCallMethod();
27         encoder->EncodeMov(methodReg, Imm(bit_cast<uintptr_t>(method)));
28     } else {
29         ScopedTmpReg addrReg(encoder);
30         auto *aotData = GetGraph()->GetAotData();
31         auto methodId = inst->GetCallMethodId();
32         intptr_t offset = aotData->GetCommonSlotOffset(encoder->GetCursorOffset(), methodId);
33         encoder->MakeLoadAotTableAddr(offset, addrReg, methodReg);
34 
35         auto skipLabel = encoder->CreateLabel();
36         encoder->EncodeJump(skipLabel, methodReg, Condition::NE);
37         LoadMethod(methodReg);
38         CallRuntime(inst, EntrypointId::GET_CALLEE_METHOD, methodReg, RegMask::GetZeroMask(), methodReg,
39                     TypedImm(methodId));
40         encoder->EncodeStr(methodReg, MemRef(addrReg));
41         encoder->BindLabel(skipLabel);
42     }
43 
44     auto successLabel = encoder->CreateLabel();
45     auto failLabel = encoder->CreateLabel();
46 
47     // If native method is not registered, deoptimize
48     ScopedTmpReg tmpReg(encoder);
49     encoder->EncodeLdr(tmpReg, false, MemRef(methodReg, GetRuntime()->GetNativePointerOffset(GetArch())));
50     encoder->EncodeJump(failLabel, tmpReg, Condition::EQ);
51 
52     // Don't support deprecated Native API and currently Function native mode in new API
53     // NOTE: add Function mode support
54     if (GetRuntime()->CanNativeMethodUseObjects(inst->GetCallMethod())) {
55         tmpReg.ChangeType(INT32_TYPE);
56         encoder->EncodeLdr(tmpReg, false, MemRef(methodReg, GetRuntime()->GetAccessFlagsOffset(GetArch())));
57         auto unsupportedMask = GetRuntime()->GetDeprecatedNativeApiMask();
58         encoder->EncodeAnd(tmpReg, tmpReg, Imm(unsupportedMask));
59         encoder->EncodeJump(failLabel, tmpReg, Condition::NE);
60     }
61     encoder->EncodeMov(dst, methodReg);
62     encoder->EncodeJump(successLabel);
63 
64     encoder->BindLabel(failLabel);
65     encoder->EncodeMov(dst, Imm(0));
66 
67     encoder->BindLabel(successLabel);
68 }
69 
EtsGetNativeMethodManagedClass(IntrinsicInst * inst,Reg dst,SRCREGS & src)70 void Codegen::EtsGetNativeMethodManagedClass(IntrinsicInst *inst, Reg dst, SRCREGS &src)
71 {
72     if (GetGraph()->IsJitOrOsrMode()) {
73         auto *method = inst->GetCallMethod();
74         auto runtimeClass = bit_cast<uintptr_t>(GetRuntime()->GetClass(method));
75         auto managedClass = runtimeClass - GetRuntime()->GetRuntimeClassOffset(GetArch());
76         GetEncoder()->EncodeMov(dst, Imm(managedClass));
77     } else {
78         auto methodReg = src[0U];
79         GetEncoder()->EncodeLdr(dst, false, MemRef(methodReg, GetRuntime()->GetClassOffset(GetArch())));
80         GetEncoder()->EncodeSub(dst, dst, Imm(GetRuntime()->GetRuntimeClassOffset(GetArch())));
81     }
82 }
83 
EtsGetMethodNativePointer(IntrinsicInst * inst,Reg dst,SRCREGS & src)84 void Codegen::EtsGetMethodNativePointer(IntrinsicInst *inst, Reg dst, SRCREGS &src)
85 {
86     auto *method = inst->GetCallMethod();
87     auto *nativePointer = GetRuntime()->GetMethodNativePointer(method);
88     if (GetGraph()->IsJitOrOsrMode() && nativePointer != nullptr) {
89         GetEncoder()->EncodeMov(dst, Imm(bit_cast<uintptr_t>(nativePointer)));
90     } else {
91         auto methodReg = src[0U];
92         GetEncoder()->EncodeLdr(dst, false, MemRef(methodReg, GetRuntime()->GetNativePointerOffset(GetArch())));
93     }
94 }
95 
EtsGetNativeApiEnv(IntrinsicInst * inst,Reg dst,SRCREGS & src)96 void Codegen::EtsGetNativeApiEnv([[maybe_unused]] IntrinsicInst *inst, Reg dst, [[maybe_unused]] SRCREGS &src)
97 {
98     GetEncoder()->EncodeLdr(dst, false, MemRef(ThreadReg(), GetRuntime()->GetTlsNativeApiOffset(GetArch())));
99 }
100 
EtsBeginNativeMethod(IntrinsicInst * inst,Reg dst,SRCREGS & src)101 void Codegen::EtsBeginNativeMethod(IntrinsicInst *inst, [[maybe_unused]] Reg dst, [[maybe_unused]] SRCREGS &src)
102 {
103     ASSERT(!HasLiveCallerSavedRegs(inst));
104     ASSERT(inst->GetSaveState()->GetRootsRegsMask().none());
105 
106     {
107         SCOPED_DISASM_STR(this, "Prepare for begin native");
108         GetEncoder()->EncodeStr(FpReg(), MemRef(ThreadReg(), GetRuntime()->GetTlsFrameOffset(GetArch())));
109 
110         CreateStackMap(inst);
111         ScopedTmpReg pc(GetEncoder());
112         GetEncoder()->EncodeGetCurrentPc(pc);
113         GetEncoder()->EncodeStr(pc, MemRef(ThreadReg(), GetRuntime()->GetTlsNativePcOffset(GetArch())));
114     }
115 
116     {
117         SCOPED_DISASM_STR(this, "Call begin native intrinsic");
118         bool switchesToNative = GetRuntime()->IsNecessarySwitchThreadState(inst->GetCallMethod());
119         auto id =
120             switchesToNative ? EntrypointId::BEGIN_GENERAL_NATIVE_METHOD : EntrypointId::BEGIN_QUICK_NATIVE_METHOD;
121         MemRef entry(ThreadReg(), GetRuntime()->GetEntrypointTlsOffset(GetArch(), id));
122         GetEncoder()->MakeCall(entry);
123     }
124 }
125 
EtsEndNativeMethodPrim(IntrinsicInst * inst,Reg dst,SRCREGS & src)126 void Codegen::EtsEndNativeMethodPrim(IntrinsicInst *inst, Reg dst, SRCREGS &src)
127 {
128     EtsEndNativeMethod(inst, dst, src, false);
129 }
130 
EtsEndNativeMethodObj(IntrinsicInst * inst,Reg dst,SRCREGS & src)131 void Codegen::EtsEndNativeMethodObj(IntrinsicInst *inst, Reg dst, SRCREGS &src)
132 {
133     EtsEndNativeMethod(inst, dst, src, true);
134 }
135 
EtsEndNativeMethod(IntrinsicInst * inst,Reg dst,SRCREGS & src,bool isObject)136 void Codegen::EtsEndNativeMethod(IntrinsicInst *inst, [[maybe_unused]] Reg dst, [[maybe_unused]] SRCREGS &src,
137                                  bool isObject)
138 {
139     ASSERT(!HasLiveCallerSavedRegs(inst));
140     ASSERT(inst->GetSaveState()->GetRootsRegsMask().none());
141 
142     {
143         SCOPED_DISASM_STR(this, "Call end native intrinsic");
144         bool switchesToNative = GetRuntime()->IsNecessarySwitchThreadState(inst->GetCallMethod());
145         EntrypointId id = EntrypointId::INVALID;
146         if (switchesToNative) {
147             id = isObject ? EntrypointId::END_GENERAL_NATIVE_METHOD_OBJ : EntrypointId::END_GENERAL_NATIVE_METHOD_PRIM;
148         } else {
149             id = isObject ? EntrypointId::END_QUICK_NATIVE_METHOD_OBJ : EntrypointId::END_QUICK_NATIVE_METHOD_PRIM;
150         }
151         MemRef entry(ThreadReg(), GetRuntime()->GetEntrypointTlsOffset(GetArch(), id));
152         GetEncoder()->MakeCall(entry);
153     }
154 }
155 
EtsCheckNativeException(IntrinsicInst * inst,Reg dst,SRCREGS & src)156 void Codegen::EtsCheckNativeException(IntrinsicInst *inst, [[maybe_unused]] Reg dst, [[maybe_unused]] SRCREGS &src)
157 {
158     ASSERT(inst->CanThrow());
159     auto throwLabel = CreateSlowPath<SlowPathEntrypoint>(inst, EntrypointId::THROW_NATIVE_EXCEPTION)->GetLabel();
160 
161     ScopedTmpReg tmpReg(GetEncoder());
162     GetEncoder()->EncodeLdr(tmpReg, false, MemRef(ThreadReg(), GetRuntime()->GetExceptionOffset(GetArch())));
163     GetEncoder()->EncodeJump(throwLabel, tmpReg, Condition::NE);
164 }
165 
EtsWrapObjectNative(WrapObjectNativeInst * wrapObject)166 void Codegen::EtsWrapObjectNative(WrapObjectNativeInst *wrapObject)
167 {
168     Inst *obj = wrapObject->GetDataFlowInput(0);
169     ASSERT(obj != nullptr);
170     CallInst *callNative = wrapObject->GetUsers().Front().GetInst()->CastToCallNative();
171     ASSERT(callNative != nullptr);
172 
173     ASSERT(GetGraph()->IsAnalysisValid<LivenessAnalyzer>());
174     auto &la = GetGraph()->GetAnalysis<LivenessAnalyzer>();
175     auto targetLifeNumber = la.GetInstLifeIntervals(callNative)->GetBegin();
176 
177     auto *interval = la.GetInstLifeIntervals(obj)->FindSiblingAt(targetLifeNumber);
178     ASSERT(interval != nullptr);
179     auto location = interval->GetLocation();
180     ASSERT(location.GetKind() == LocationType::STACK_PARAMETER || location.GetKind() == LocationType::STACK);
181 
182     auto dstReg = ConvertRegister(wrapObject->GetDstReg(), wrapObject->GetType());
183     GetEncoder()->EncodeAdd(dstReg, SpReg(), Imm(GetStackOffset(location)));
184     // don't apply stack ref mask, since it is empty
185     ASSERT(GetRuntime()->GetStackReferenceMask() == 0U);
186 }
187 
ResolveCallByNameCodegen(ResolveVirtualInst * resolver)188 bool Codegen::ResolveCallByNameCodegen(ResolveVirtualInst *resolver)
189 {
190     SCOPED_DISASM_STR(this, "Create runtime call to resolve a call by name");
191     ASSERT(resolver->GetOpcode() == Opcode::ResolveByName);
192     ASSERT(resolver->GetCallMethod() != nullptr);
193 
194     auto methodReg = ConvertRegister(resolver->GetDstReg(), resolver->GetType());
195     auto objectReg = ConvertRegister(resolver->GetSrcReg(0), DataType::REFERENCE);
196     ScopedTmpReg tmpMethodReg(GetEncoder());
197     LoadMethod(tmpMethodReg);
198 
199     CallRuntime(resolver, EntrypointId::RESOLVE_CALL_BY_NAME, tmpMethodReg, {}, tmpMethodReg, objectReg,
200                 TypedImm(resolver->GetCallMethodId()));
201     GetEncoder()->EncodeMov(methodReg, tmpMethodReg);
202     return true;
203 }
204 
205 }  // namespace ark::compiler
206