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 ElementsKind kind = builder_->GetElementsKindForCreater(gate);
95 if (Elements::IsGeneric(kind)) {
96 return;
97 }
98
99 acc_.TrySetElementsKind(gate, kind);
100 }
101
InferAccessObjByValue(GateRef gate)102 void PGOTypeInfer::InferAccessObjByValue(GateRef gate)
103 {
104 if (!builder_->ShouldPGOTypeInfer(gate)) {
105 return;
106 }
107 GateRef propKey = Circuit::NullGate();
108 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
109 switch (ecmaOpcode) {
110 case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
111 case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
112 case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
113 case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
114 propKey = acc_.GetValueIn(gate, 2); // 2: the third parameter
115 break;
116 case EcmaOpcode::LDTHISBYVALUE_IMM8:
117 case EcmaOpcode::LDTHISBYVALUE_IMM16:
118 case EcmaOpcode::STTHISBYVALUE_IMM8_V8:
119 case EcmaOpcode::STTHISBYVALUE_IMM16_V8:
120 propKey = acc_.GetValueIn(gate, 1);
121 break;
122 default:
123 LOG_ECMA(FATAL) << "this branch is unreachable";
124 UNREACHABLE();
125 }
126 TrySetPropKeyKind(gate, propKey);
127 TrySetElementsKind(gate);
128 TrySetTransitionElementsKind(gate);
129 TrySetOnHeapMode(gate);
130 }
131
TrySetElementsKind(GateRef gate)132 void PGOTypeInfer::TrySetElementsKind(GateRef gate)
133 {
134 auto kinds = builder_->GetElementsKindsForUser(gate);
135 if (kinds.empty()) {
136 return;
137 }
138 for (auto kind : kinds) {
139 acc_.TrySetElementsKind(gate, kind);
140 }
141 }
142
TrySetTransitionElementsKind(GateRef gate)143 void PGOTypeInfer::TrySetTransitionElementsKind(GateRef gate)
144 {
145 // The kinds array here has [transitioned elementsKind] stored.
146 auto kinds = builder_->GetTransitionElementsKindsForUser(gate);
147 if (kinds.empty()) {
148 return;
149 }
150 for (auto kind : kinds) {
151 acc_.TrySetTransitionElementsKind(gate, kind);
152 }
153 }
154
TrySetPropKeyKind(GateRef gate,GateRef propKey)155 void PGOTypeInfer::TrySetPropKeyKind(GateRef gate, GateRef propKey)
156 {
157 auto pgoTypes = acc_.TryGetPGOType(gate);
158 const PGORWOpType *pgoRwTypes = pgoTypes.GetPGORWOpType();
159 GateType oldType = acc_.GetGateType(propKey);
160 if (oldType.IsAnyType() && IsMonoNumberType(*pgoRwTypes)) {
161 acc_.SetGateType(propKey, GateType::NumberType());
162 }
163 }
164
TrySetOnHeapMode(GateRef gate)165 void PGOTypeInfer::TrySetOnHeapMode(GateRef gate)
166 {
167 PGOTypeRef pgoTypes = acc_.TryGetPGOType(gate);
168 const PGORWOpType *pgoRwTypes = pgoTypes.GetPGORWOpType();
169 std::vector<OnHeapMode> modes;
170
171 for (uint32_t i = 0; i < pgoRwTypes->GetCount(); i++) {
172 ProfileType profileType = pgoRwTypes->GetObjectInfo(i).GetProfileType();
173 if (profileType.IsBuiltinsType()) {
174 ProfileType::BuiltinsTypedArrayId id(profileType.GetId());
175 modes.emplace_back(id.GetOnHeapMode());
176 }
177 }
178
179 if (modes.empty()) {
180 return;
181 }
182
183 // monomorphic
184 if (modes.size() == 1) {
185 acc_.TrySetOnHeapMode(gate, modes[0]);
186 return;
187 }
188
189 // polymorphism
190 // If the modes can be merged into monomorphic, still optimize it. Otherwise degrade it to NONE.
191 OnHeapMode mode = modes[0];
192 for (uint32_t i = 1; i < modes.size(); i++) {
193 mode = OnHeap::Merge(mode, modes[i]);
194 if (OnHeap::IsNone(mode)) {
195 break;
196 }
197 }
198 acc_.TrySetOnHeapMode(gate, mode);
199 }
200 } // namespace panda::ecmascript
201