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 #include "object_type_propagation.h"
17 #include "optimizer/ir/basicblock.h"
18 #include "optimizer/ir/inst.h"
19
20 namespace panda::compiler {
RunImpl()21 bool ObjectTypePropagation::RunImpl()
22 {
23 VisitGraph();
24 visited_ = GetGraph()->NewMarker();
25 for (auto bb : GetGraph()->GetBlocksRPO()) {
26 for (auto phi : bb->PhiInsts()) {
27 auto typeInfo = GetPhiTypeInfo(phi);
28 for (auto visitedPhi : visitedPhis_) {
29 ASSERT(visitedPhi->GetObjectTypeInfo() == ObjectTypeInfo::UNKNOWN);
30 visitedPhi->SetObjectTypeInfo(typeInfo);
31 }
32 visitedPhis_.clear();
33 }
34 }
35 GetGraph()->EraseMarker(visited_);
36 return true;
37 }
38
VisitNewObject(GraphVisitor * v,Inst * i)39 void ObjectTypePropagation::VisitNewObject(GraphVisitor *v, Inst *i)
40 {
41 auto self = static_cast<ObjectTypePropagation *>(v);
42 auto inst = i->CastToNewObject();
43 auto klass = self->GetGraph()->GetRuntime()->GetClass(inst->GetMethod(), inst->GetTypeId());
44 if (klass != nullptr) {
45 inst->SetObjectTypeInfo({klass, true});
46 }
47 }
48
VisitNewArray(GraphVisitor * v,Inst * i)49 void ObjectTypePropagation::VisitNewArray(GraphVisitor *v, Inst *i)
50 {
51 auto self = static_cast<ObjectTypePropagation *>(v);
52 auto inst = i->CastToNewArray();
53 auto klass = self->GetGraph()->GetRuntime()->GetClass(inst->GetMethod(), inst->GetTypeId());
54 if (klass != nullptr) {
55 inst->SetObjectTypeInfo({klass, true});
56 }
57 }
58
VisitLoadString(GraphVisitor * v,Inst * i)59 void ObjectTypePropagation::VisitLoadString(GraphVisitor *v, Inst *i)
60 {
61 auto self = static_cast<ObjectTypePropagation *>(v);
62 auto inst = i->CastToLoadString();
63 auto klass = self->GetGraph()->GetRuntime()->GetStringClass(inst->GetMethod());
64 if (klass != nullptr) {
65 inst->SetObjectTypeInfo({klass, true});
66 }
67 }
68
VisitLoadArray(GraphVisitor * v,Inst * i)69 void ObjectTypePropagation::VisitLoadArray([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *i)
70 {
71 // LoadArray should be processed more carefully, because it may contain object of the derived class with own method
72 // implementation. We need to check all array stores and method calls between NewArray and LoadArray.
73 // NOTE(mshertennikov): Support it.
74 }
75
VisitLoadObject(GraphVisitor * v,Inst * i)76 void ObjectTypePropagation::VisitLoadObject(GraphVisitor *v, Inst *i)
77 {
78 if (i->GetType() != DataType::REFERENCE || i->CastToLoadObject()->GetObjectType() != ObjectType::MEM_OBJECT) {
79 return;
80 }
81 auto self = static_cast<ObjectTypePropagation *>(v);
82 auto inst = i->CastToLoadObject();
83 auto fieldId = inst->GetTypeId();
84 if (fieldId == 0) {
85 return;
86 }
87 auto runtime = self->GetGraph()->GetRuntime();
88 auto method = inst->GetMethod();
89 auto typeId = runtime->GetFieldValueTypeId(method, fieldId);
90 auto klass = runtime->GetClass(method, typeId);
91 if (klass != nullptr) {
92 auto isExact = runtime->GetClassType(method, typeId) == ClassType::FINAL_CLASS;
93 inst->SetObjectTypeInfo({klass, isExact});
94 }
95 }
96
VisitCallStatic(GraphVisitor * v,Inst * i)97 void ObjectTypePropagation::VisitCallStatic(GraphVisitor *v, Inst *i)
98 {
99 ProcessManagedCall(v, i->CastToCallStatic());
100 }
101
VisitCallVirtual(GraphVisitor * v,Inst * i)102 void ObjectTypePropagation::VisitCallVirtual(GraphVisitor *v, Inst *i)
103 {
104 ProcessManagedCall(v, i->CastToCallVirtual());
105 }
106
VisitNullCheck(GraphVisitor * v,Inst * i)107 void ObjectTypePropagation::VisitNullCheck([[maybe_unused]] GraphVisitor *v, Inst *i)
108 {
109 auto inst = i->CastToNullCheck();
110 inst->SetObjectTypeInfo(inst->GetInput(0).GetInst()->GetObjectTypeInfo());
111 }
112
VisitRefTypeCheck(GraphVisitor * v,Inst * i)113 void ObjectTypePropagation::VisitRefTypeCheck([[maybe_unused]] GraphVisitor *v, Inst *i)
114 {
115 auto inst = i->CastToRefTypeCheck();
116 inst->SetObjectTypeInfo(inst->GetInput(0).GetInst()->GetObjectTypeInfo());
117 }
118
VisitParameter(GraphVisitor * v,Inst * i)119 void ObjectTypePropagation::VisitParameter([[maybe_unused]] GraphVisitor *v, Inst *i)
120 {
121 auto inst = i->CastToParameter();
122 auto graph = i->GetBasicBlock()->GetGraph();
123 if (inst->GetType() != DataType::REFERENCE || graph->IsBytecodeOptimizer() || inst->HasObjectTypeInfo()) {
124 return;
125 }
126 auto refNum = inst->GetArgRefNumber();
127 auto runtime = graph->GetRuntime();
128 auto method = graph->GetMethod();
129 RuntimeInterface::ClassPtr klass;
130 if (refNum == ParameterInst::INVALID_ARG_REF_NUM) {
131 // This parametr doesn't have ArgRefNumber
132 if (inst->GetArgNumber() != 0 || runtime->IsMethodStatic(method)) {
133 return;
134 }
135 klass = runtime->GetClass(method);
136 } else {
137 auto typeId = runtime->GetMethodArgReferenceTypeId(method, refNum);
138 klass = runtime->GetClass(method, typeId);
139 }
140 if (klass != nullptr) {
141 auto isExact = runtime->GetClassType(klass) == ClassType::FINAL_CLASS;
142 inst->SetObjectTypeInfo({klass, isExact});
143 }
144 }
145
ProcessManagedCall(GraphVisitor * v,CallInst * inst)146 void ObjectTypePropagation::ProcessManagedCall(GraphVisitor *v, CallInst *inst)
147 {
148 if (inst->GetType() != DataType::REFERENCE) {
149 return;
150 }
151 auto self = static_cast<ObjectTypePropagation *>(v);
152 auto runtime = self->GetGraph()->GetRuntime();
153 auto method = inst->GetCallMethod();
154 auto typeId = runtime->GetMethodReturnTypeId(method);
155 auto klass = runtime->GetClass(method, typeId);
156 if (klass != nullptr) {
157 auto isExact = runtime->GetClassType(method, typeId) == ClassType::FINAL_CLASS;
158 inst->SetObjectTypeInfo({klass, isExact});
159 }
160 }
161
GetPhiTypeInfo(Inst * inst)162 ObjectTypeInfo ObjectTypePropagation::GetPhiTypeInfo(Inst *inst)
163 {
164 if (!inst->IsPhi() || inst->SetMarker(visited_)) {
165 return inst->GetObjectTypeInfo();
166 }
167 auto typeInfo = ObjectTypeInfo::UNKNOWN;
168 inst->SetObjectTypeInfo(typeInfo);
169 bool needUpdate = false;
170 for (auto input : inst->GetInputs()) {
171 auto inputInfo = GetPhiTypeInfo(input.GetInst());
172 if (inputInfo == ObjectTypeInfo::UNKNOWN) {
173 ASSERT(input.GetInst()->IsPhi());
174 needUpdate = true;
175 continue;
176 }
177 if (inputInfo == ObjectTypeInfo::INVALID ||
178 (typeInfo.IsValid() && typeInfo.GetClass() != inputInfo.GetClass())) {
179 inst->SetObjectTypeInfo(ObjectTypeInfo::INVALID);
180 return ObjectTypeInfo::INVALID;
181 }
182 if (typeInfo == ObjectTypeInfo::UNKNOWN) {
183 typeInfo = inputInfo;
184 continue;
185 }
186 typeInfo = {typeInfo.GetClass(), typeInfo.IsExact() && inputInfo.IsExact()};
187 }
188 if (needUpdate) {
189 visitedPhis_.push_back(inst);
190 } else {
191 inst->SetObjectTypeInfo(typeInfo);
192 }
193 return typeInfo;
194 }
195
196 } // namespace panda::compiler
197