• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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