1 /*
2 * Copyright (c) 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 "ecmascript/compiler/type_inference/pgo_type_infer.h"
17 #include "ecmascript/compiler/bytecode_circuit_builder.h"
18
19 namespace panda::ecmascript::kungfu {
Run()20 void PGOTypeInfer::Run()
21 {
22 std::vector<GateRef> gateList;
23 circuit_->GetAllGates(gateList);
24 for (const auto &gate : gateList) {
25 auto op = acc_.GetOpCode(gate);
26 if (op == OpCode::JS_BYTECODE) {
27 RunTypeInfer(gate);
28 }
29 }
30 }
31
RunTypeInfer(GateRef gate)32 void PGOTypeInfer::RunTypeInfer(GateRef gate)
33 {
34 ASSERT(acc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
35 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
36 switch (ecmaOpcode) {
37 case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
38 case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
39 case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
40 case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
41 InferLdObjByName(gate);
42 break;
43 case EcmaOpcode::STOWNBYINDEX_IMM8_V8_IMM16:
44 case EcmaOpcode::STOWNBYINDEX_IMM16_V8_IMM16:
45 InferStOwnByIndex(gate);
46 break;
47 case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
48 case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
49 case EcmaOpcode::LDTHISBYVALUE_IMM8:
50 case EcmaOpcode::LDTHISBYVALUE_IMM16:
51 case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
52 case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
53 case EcmaOpcode::STTHISBYVALUE_IMM8_V8:
54 case EcmaOpcode::STTHISBYVALUE_IMM16_V8:
55 InferAccessObjByValue(gate);
56 break;
57 case EcmaOpcode::CREATEEMPTYARRAY_IMM8:
58 case EcmaOpcode::CREATEEMPTYARRAY_IMM16:
59 case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
60 case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
61 InferCreateArray(gate);
62 break;
63 default:
64 break;
65 }
66 }
67
InferLdObjByName(GateRef gate)68 void PGOTypeInfer::InferLdObjByName(GateRef gate)
69 {
70 if (!builder_->ShouldPGOTypeInfer(gate)) {
71 return;
72 }
73
74 TrySetElementsKind(gate);
75 }
76
InferStOwnByIndex(GateRef gate)77 void PGOTypeInfer::InferStOwnByIndex(GateRef gate)
78 {
79 if (!builder_->ShouldPGOTypeInfer(gate)) {
80 return;
81 }
82 TrySetElementsKind(gate);
83 TrySetTransitionElementsKind(gate);
84 TrySetOnHeapMode(gate);
85 }
86
InferCreateArray(GateRef gate)87 void PGOTypeInfer::InferCreateArray(GateRef gate)
88 {
89 if (!builder_->ShouldPGOTypeInfer(gate)) {
90 return;
91 }
92 auto length = builder_->GetArrayElementsLength(gate);
93 acc_.TrySetArrayElementsLength(gate, length);
94 auto regionSpaceFlag = builder_->GetRegionSpaceFlag(gate);
95 acc_.TrySetRegionSpaceFlag(gate, regionSpaceFlag);
96 ElementsKind kind = builder_->GetElementsKindForCreater(gate);
97 if (Elements::IsGeneric(kind)) {
98 return;
99 }
100
101 acc_.TrySetElementsKind(gate, kind);
102 }
103
InferAccessObjByValue(GateRef gate)104 void PGOTypeInfer::InferAccessObjByValue(GateRef gate)
105 {
106 if (!builder_->ShouldPGOTypeInfer(gate)) {
107 return;
108 }
109 GateRef propKey = Circuit::NullGate();
110 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
111 switch (ecmaOpcode) {
112 case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
113 case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
114 case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
115 case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
116 propKey = acc_.GetValueIn(gate, 2); // 2: the third parameter
117 break;
118 case EcmaOpcode::LDTHISBYVALUE_IMM8:
119 case EcmaOpcode::LDTHISBYVALUE_IMM16:
120 case EcmaOpcode::STTHISBYVALUE_IMM8_V8:
121 case EcmaOpcode::STTHISBYVALUE_IMM16_V8:
122 propKey = acc_.GetValueIn(gate, 1);
123 break;
124 default:
125 LOG_ECMA(FATAL) << "this branch is unreachable";
126 UNREACHABLE();
127 }
128 TrySetPropKeyKind(gate, propKey);
129 TrySetElementsKind(gate);
130 TrySetTransitionElementsKind(gate);
131 TrySetOnHeapMode(gate);
132 }
133
TrySetElementsKind(GateRef gate)134 void PGOTypeInfer::TrySetElementsKind(GateRef gate)
135 {
136 auto kinds = builder_->GetElementsKindsForUser(gate);
137 if (kinds.empty()) {
138 return;
139 }
140 for (auto kind : kinds) {
141 acc_.TrySetElementsKind(gate, kind);
142 }
143 }
144
TrySetTransitionElementsKind(GateRef gate)145 void PGOTypeInfer::TrySetTransitionElementsKind(GateRef gate)
146 {
147 // The kinds array here has [transitioned elementsKind] stored.
148 auto kinds = builder_->GetTransitionElementsKindsForUser(gate);
149 if (kinds.empty()) {
150 return;
151 }
152 for (auto kind : kinds) {
153 acc_.TrySetTransitionElementsKind(gate, kind);
154 }
155 }
156
TrySetPropKeyKind(GateRef gate,GateRef propKey)157 void PGOTypeInfer::TrySetPropKeyKind(GateRef gate, GateRef propKey)
158 {
159 auto pgoTypes = acc_.TryGetPGOType(gate);
160 const PGORWOpType *pgoRwTypes = pgoTypes.GetPGORWOpType();
161 GateType oldType = acc_.GetGateType(propKey);
162 if (oldType.IsAnyType() && IsMonoNumberType(*pgoRwTypes)) {
163 acc_.SetGateType(propKey, GateType::NumberType());
164 }
165 }
166
TrySetOnHeapMode(GateRef gate)167 void PGOTypeInfer::TrySetOnHeapMode(GateRef gate)
168 {
169 PGOTypeRef pgoTypes = acc_.TryGetPGOType(gate);
170 const PGORWOpType *pgoRwTypes = pgoTypes.GetPGORWOpType();
171 std::vector<OnHeapMode> modes;
172
173 for (uint32_t i = 0; i < pgoRwTypes->GetCount(); i++) {
174 ProfileType profileType = pgoRwTypes->GetObjectInfo(i).GetProfileType();
175 if (profileType.IsBuiltinsType()) {
176 ProfileType::BuiltinsTypedArrayId id(profileType.GetId());
177 modes.emplace_back(id.GetOnHeapMode());
178 }
179 }
180
181 if (modes.empty()) {
182 return;
183 }
184
185 // monomorphic
186 if (modes.size() == 1) {
187 acc_.TrySetOnHeapMode(gate, modes[0]);
188 return;
189 }
190
191 // polymorphism
192 // If the modes can be merged into monomorphic, still optimize it. Otherwise degrade it to NONE.
193 OnHeapMode mode = modes[0];
194 for (uint32_t i = 1; i < modes.size(); i++) {
195 mode = OnHeap::Merge(mode, modes[i]);
196 if (OnHeap::IsNone(mode)) {
197 break;
198 }
199 }
200 acc_.TrySetOnHeapMode(gate, mode);
201 }
202 } // namespace panda::ecmascript
203