• 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     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