• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #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