1 /*
2 * Copyright (c) 2024 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/escape_analysis.h"
17
18 namespace panda::ecmascript::kungfu {
19
VirtualObject(size_t numIn, Chunk* chunk)20 VirtualObject::VirtualObject(size_t numIn, Chunk* chunk)
21 : fields_(chunk), users_(chunk)
22 {
23 for (size_t i = 0; i < numIn; i++) {
24 FieldLocation tmp;
25 fields_.emplace_back(tmp);
26 }
27 }
28
SetEscaped()29 void VirtualObject::SetEscaped()
30 {
31 escaped_ = true;
32 }
33
IsEscaped() const34 bool VirtualObject::IsEscaped() const
35 {
36 return escaped_;
37 }
38
GetField(size_t offset)39 FieldLocation VirtualObject::GetField(size_t offset)
40 {
41 constexpr size_t fieldSize = 8;
42 ASSERT(offset % fieldSize == 0);
43 if (offset / fieldSize >= fields_.size()) {
44 return FieldLocation::Invalid();
45 }
46 return fields_.at(offset/fieldSize);
47 }
48
49 size_t FieldLocation::maxid = 0;
50
GetUsers()51 ChunkVector<GateRef>& VirtualObject::GetUsers()
52 {
53 return users_;
54 }
55
ClearUsers()56 void VirtualObject::ClearUsers()
57 {
58 users_.clear();
59 }
60
AddUser(GateRef gate)61 void VirtualObject::AddUser(GateRef gate)
62 {
63 users_.push_back(gate);
64 }
65
GateInfo(Circuit* circuit, GateRef curGate, EscapeAnalysis* escapeAnalysis, Chunk* chunk)66 GateInfo::GateInfo(Circuit* circuit, GateRef curGate, EscapeAnalysis* escapeAnalysis, Chunk* chunk)
67 : circuit_(circuit), acc_(circuit), curGate_(curGate), escapeAnalysis_(escapeAnalysis), state_(chunk)
68 {
69 if (acc_.GetOpCode(curGate) == OpCode::DEPEND_SELECTOR) {
70 state_ = MergeState(curGate);
71 } else {
72 ASSERT(acc_.GetDependCount(curGate) <= 1);
73 if (acc_.GetDependCount(curGate) == 1) {
74 state_ = escapeAnalysis_->GetOrCreateState(acc_.GetDep(curGate));
75 }
76 }
77 }
78
~GateInfo()79 GateInfo::~GateInfo()
80 {
81 State& preState = escapeAnalysis_->GetOrCreateState(curGate_);
82 if (state_.IsMapEqual(preState) ||
83 object_ != escapeAnalysis_->TryGetVirtualObject(curGate_)) {
84 escapeAnalysis_->SetReplaceGate(curGate_);
85 }
86 escapeAnalysis_->SetState(curGate_, state_);
87
88 escapeAnalysis_->SetVirtualObject(curGate_, object_);
89 escapeAnalysis_->SetReplacement(curGate_, replacement_);
90 }
91
GetCurrentGate() const92 GateRef GateInfo::GetCurrentGate() const
93 {
94 return curGate_;
95 }
96
MergeState(GateRef gate)97 State GateInfo::MergeState(GateRef gate)
98 {
99 size_t numIn = acc_.GetDependCount(gate);
100 State& preState = escapeAnalysis_->GetOrCreateState(acc_.GetDep(gate, 0));
101 State result = preState;
102 for (auto fieldValue : preState) {
103 FieldLocation field = fieldValue.first;
104 GateRef value = fieldValue.second;
105 ASSERT(field != FieldLocation::Invalid());
106 if (value != Circuit::NullGate()) {
107 std::vector<GateRef> input;
108 input.push_back(acc_.GetState(gate));
109 input.push_back(value);
110 size_t numAliveState = 1;
111 bool differentFlag = false;
112 for (size_t i = 1; i < numIn; i++) {
113 State& inputState = escapeAnalysis_->GetOrCreateState(acc_.GetDep(gate, i));
114 GateRef inputValue = inputState.GetFieldValue(field);
115 if (inputValue != Circuit::NullGate()) {
116 numAliveState++;
117 }
118 if (inputValue != value) {
119 differentFlag = true;
120 }
121 input.push_back(inputValue);
122 }
123
124 if (numAliveState == 1 && acc_.GetOpCode(acc_.GetState(gate)) == OpCode::LOOP_BEGIN) {
125 result.SetFieldValue(field, value);
126 } else if (numAliveState < numIn) {
127 result.SetFieldValue(field, Circuit::NullGate());
128 } else {
129 if (!differentFlag) {
130 result.SetFieldValue(field, value);
131 } else {
132 State& oldState = escapeAnalysis_->GetOrCreateState(gate);
133 GateRef oldValue = oldState.GetFieldValue(field);
134 if (oldValue != Circuit::NullGate() &&
135 acc_.GetOpCode(oldValue) == OpCode::DEPEND_SELECTOR &&
136 acc_.GetState(oldValue) == acc_.GetState(gate)) {
137 for (size_t i = 0; i < numIn; i++) {
138 ASSERT(input[i + 1] != Circuit::NullGate());
139 if (acc_.GetValueIn(oldValue, i) != input[i + 1]) {
140 acc_.ReplaceValueIn(oldValue, input[i + 1], i);
141 escapeAnalysis_->RevisitGate(oldValue);
142 }
143 }
144 result.SetFieldValue(field, oldValue);
145 } else {
146 MachineType machineType = acc_.GetMachineType(value);
147 auto gateType = acc_.GetGateType(value);
148 const GateMetaData* meta = circuit_->ValueSelector(numIn);
149 GateRef valueSelector = circuit_->NewGate(meta, machineType, input.size(),
150 input.data(), gateType);
151 result.SetFieldValue(field, valueSelector);
152 escapeAnalysis_->RevisitGate(valueSelector);
153 }
154 }
155 }
156 }
157 }
158 return result;
159 }
160
GetFieldValue(FieldLocation field) const161 GateRef GateInfo::GetFieldValue(FieldLocation field) const
162 {
163 return state_.GetFieldValue(field);
164 }
165
SetFieldValue(FieldLocation field, GateRef value)166 void GateInfo::SetFieldValue(FieldLocation field, GateRef value)
167 {
168 state_.SetFieldValue(field, value);
169 }
170
SetEliminated()171 void GateInfo::SetEliminated()
172 {
173 replacement_ = circuit_->DeadGate();
174 object_ = nullptr;
175 }
176
SetReplacement(GateRef replacement)177 void GateInfo::SetReplacement(GateRef replacement)
178 {
179 replacement_ = replacement;
180 object_ = escapeAnalysis_->TryGetVirtualObject(replacement);
181 }
182
SetVirtualObject(VirtualObject* object)183 void GateInfo::SetVirtualObject(VirtualObject* object)
184 {
185 object_ = object;
186 }
187
SetFieldValue(FieldLocation field, GateRef gate)188 void State::SetFieldValue(FieldLocation field, GateRef gate)
189 {
190 map_[field] = gate;
191 }
192
GetFieldValue(FieldLocation field) const193 GateRef State::GetFieldValue(FieldLocation field) const
194 {
195 auto result = map_.find(field);
196 if (result == map_.end()) {
197 return Circuit::NullGate();
198 }
199 return result->second;
200 }
201
IsMapEqual(const State &state) const202 bool State::IsMapEqual(const State &state) const
203 {
204 return map_.size() == state.map_.size() &&
205 std::equal(map_.begin(), map_.end(), state.map_.begin());
206 }
207
SetReplacement(GateRef gate, GateRef replacement)208 void EscapeAnalysis::SetReplacement(GateRef gate, GateRef replacement)
209 {
210 replacements_[gate] = replacement;
211 }
212
TryGetReplacement(GateRef gate) const213 GateRef EscapeAnalysis::TryGetReplacement(GateRef gate) const
214 {
215 if (!replacements_.count(gate)) {
216 return Circuit::NullGate();
217 }
218 return replacements_.at(gate);
219 }
220
GetCurrentGate(GateRef gate) const221 GateRef EscapeAnalysis::GetCurrentGate(GateRef gate) const
222 {
223 GateRef replacement = TryGetReplacement(gate);
224 if (replacement == Circuit::NullGate()) {
225 return gate;
226 }
227 return replacement;
228 }
229
TryGetVirtualObject(GateRef gate) const230 VirtualObject* EscapeAnalysis::TryGetVirtualObject(GateRef gate) const
231 {
232 if (gateToVirtualObject_.count(gate)) {
233 VirtualObject* vObj = gateToVirtualObject_.at(gate);
234 return vObj;
235 }
236 return nullptr;
237 }
238
TryGetVirtualObjectAndAddUser(GateRef gate, GateRef currentGate)239 VirtualObject* EscapeAnalysis::TryGetVirtualObjectAndAddUser(GateRef gate, GateRef currentGate)
240 {
241 if (gateToVirtualObject_.count(gate)) {
242 VirtualObject* vObj = gateToVirtualObject_[gate];
243 if (vObj != nullptr) {
244 vObj->AddUser(currentGate);
245 }
246 return vObj;
247 }
248 return nullptr;
249 }
250
251
SetVirtualObject(GateRef gate, VirtualObject* object)252 void EscapeAnalysis::SetVirtualObject(GateRef gate, VirtualObject* object)
253 {
254 gateToVirtualObject_[gate] = object;
255 }
256
RevisitUser(VirtualObject* vObj)257 void EscapeAnalysis::RevisitUser(VirtualObject* vObj)
258 {
259 auto& users = vObj->GetUsers();
260 for (auto user : users) {
261 if (isTraced_) {
262 LOG_COMPILER(INFO) << "[escape analysis] revisit user : " <<acc_.GetId(user);
263 }
264 visitor_->ReVisitGate(user);
265 }
266 vObj->ClearUsers();
267 }
268
SetEscaped(GateRef gate)269 void EscapeAnalysis::SetEscaped(GateRef gate)
270 {
271 if (isTraced_) {
272 LOG_COMPILER(INFO) << "[escape analysis] set escaped: " << acc_.GetId(gate);
273 }
274 VirtualObject* vObj = TryGetVirtualObject(gate);
275 if (vObj != nullptr && !vObj->IsEscaped()) {
276 vObj->SetEscaped();
277 RevisitUser(vObj);
278 }
279 }
280
GetOrCreateVirtualObject(size_t numIn, GateInfo* info)281 VirtualObject* EscapeAnalysis::GetOrCreateVirtualObject(size_t numIn, GateInfo* info)
282 {
283 GateRef gate = info->GetCurrentGate();
284 VirtualObject* vobj = TryGetVirtualObject(gate);
285 if (vobj == nullptr) {
286 vobj = chunk_->New<VirtualObject>(numIn, chunk_);
287 }
288 vobj->AddUser(gate);
289 info->SetVirtualObject(vobj);
290 return vobj;
291 }
292
293
VisitCreateObjectWithBuffer(GateRef gate, GateInfo* info)294 GateRef EscapeAnalysis::VisitCreateObjectWithBuffer(GateRef gate, GateInfo* info)
295 {
296 constexpr size_t startIn = 4; // 4 : start of props
297 constexpr size_t fieldSize = 8; // 8 : bytes per field
298 constexpr size_t stride = 2; // 2: offset and value
299 auto numIn = acc_.GetNumValueIn(gate);
300 size_t size = acc_.GetConstantValue(acc_.GetValueIn(gate, 0)) / fieldSize;
301 VirtualObject* vObj = GetOrCreateVirtualObject(size, info);
302
303 for (size_t i = startIn; i < numIn; i += stride) {
304 GateRef value = acc_.GetValueIn(gate, i);
305 GateRef offset = acc_.GetValueIn(gate, i + 1);
306 if (vObj != nullptr && !vObj->IsEscaped() &&
307 vObj->GetField(acc_.GetConstantValue(offset)) != FieldLocation::Invalid()) {
308 info->SetFieldValue(vObj->GetField(acc_.GetConstantValue(offset)), value);
309 } else {
310 SetEscaped(value);
311 SetEscaped(gate);
312 }
313 }
314 info->SetVirtualObject(vObj);
315 return replaceGate_;
316 }
317
VisitLoadProperty(GateRef gate, GateInfo* info)318 GateRef EscapeAnalysis::VisitLoadProperty(GateRef gate, GateInfo* info)
319 {
320 GateRef object = acc_.GetValueIn(gate, 0);
321 GateRef offset = acc_.GetValueIn(gate, 1);
322 VirtualObject* vObj = TryGetVirtualObjectAndAddUser(object, gate);
323
324 PropertyLookupResult plr(acc_.GetConstantValue(offset));
325
326 if (vObj != nullptr && !vObj->IsEscaped() && vObj->GetField(plr.GetOffset()) != FieldLocation::Invalid()) {
327 GateRef value = info->GetFieldValue(vObj->GetField(plr.GetOffset()));
328 if (value != Circuit::NullGate()) {
329 if (isTraced_) {
330 LOG_COMPILER(INFO) << "[escape analysis] replace" << acc_.GetId(gate) << " with " << acc_.GetId(value);
331 }
332 info->SetReplacement(value);
333 } else {
334 SetEscaped(object);
335 }
336 } else {
337 SetEscaped(object);
338 }
339 return replaceGate_;
340 }
341
VisitLoadConstOffset(GateRef gate, GateInfo* info)342 GateRef EscapeAnalysis::VisitLoadConstOffset(GateRef gate, GateInfo* info)
343 {
344 GateRef object = acc_.GetValueIn(gate, 0);
345 size_t offset = acc_.GetOffset(gate);
346 VirtualObject* vObj = TryGetVirtualObjectAndAddUser(object, gate);
347
348 if (vObj != nullptr && !vObj->IsEscaped() && vObj->GetField(offset) != FieldLocation::Invalid()) {
349 GateRef value = info->GetFieldValue(vObj->GetField(offset));
350 if (value != Circuit::NullGate()) {
351 if (isTraced_) {
352 LOG_COMPILER(INFO) << "[escape analysis] replace " <<
353 acc_.GetId(gate) << " with " << acc_.GetId(value);
354 }
355 info->SetReplacement(value);
356 } else {
357 SetEscaped(object);
358 }
359 } else {
360 SetEscaped(object);
361 }
362 return replaceGate_;
363 }
364
365
VisitStoreProperty(GateRef gate, GateInfo* info)366 GateRef EscapeAnalysis::VisitStoreProperty(GateRef gate, GateInfo* info)
367 {
368 GateRef object = acc_.GetValueIn(gate, 0);
369 GateRef offset = acc_.GetValueIn(gate, 1);
370 GateRef value = acc_.GetValueIn(gate, 2);
371 VirtualObject* vObj = TryGetVirtualObjectAndAddUser(object, gate);
372 PropertyLookupResult plr(acc_.GetConstantValue(offset));
373
374 if (vObj != nullptr && !vObj->IsEscaped() && vObj->GetField(plr.GetOffset()) != FieldLocation::Invalid()) {
375 info->SetFieldValue(vObj->GetField(plr.GetOffset()), value);
376 info->SetEliminated();
377 } else {
378 SetEscaped(value);
379 SetEscaped(object);
380 }
381 return replaceGate_;
382 }
383
VisitObjectTypeCheck(GateRef gate, GateInfo* info)384 GateRef EscapeAnalysis::VisitObjectTypeCheck(GateRef gate, GateInfo* info)
385 {
386 info->SetVirtualObject(TryGetVirtualObject(acc_.GetValueIn(gate)));
387 return Circuit::NullGate();
388 }
389
GetOrCreateState(GateRef gate)390 State& EscapeAnalysis::GetOrCreateState(GateRef gate)
391 {
392 auto it = gateToState_.find(gate);
393 if (it == gateToState_.end()) {
394 State tmp(chunk_);
395 auto result = gateToState_.insert(std::make_pair(gate, std::move(tmp)));
396 return result.first->second;
397 }
398 return it->second;
399 }
400
SetState(GateRef gate, State state)401 void EscapeAnalysis::SetState(GateRef gate, State state)
402 {
403 auto it = gateToState_.find(gate);
404 if (it == gateToState_.end()) {
405 gateToState_.insert(std::make_pair(gate, std::move(state)));
406 } else {
407 it->second = state;
408 }
409 }
410
RevisitGate(GateRef gate)411 void EscapeAnalysis::RevisitGate(GateRef gate)
412 {
413 visitor_->ReVisitGate(gate);
414 }
415
SetReplaceGate(GateRef gate)416 void EscapeAnalysis::SetReplaceGate(GateRef gate)
417 {
418 replaceGate_ = gate;
419 }
420
VisitGate(GateRef gate)421 GateRef EscapeAnalysis::VisitGate(GateRef gate)
422 {
423 GateInfo info(circuit_, gate, this, chunk_);
424 auto opcode = acc_.GetOpCode(gate);
425 replaceGate_ = Circuit::NullGate();
426 switch (opcode) {
427 case OpCode::STORE_PROPERTY:
428 case OpCode::STORE_PROPERTY_NO_BARRIER:
429 return VisitStoreProperty(gate, &info);
430 case OpCode::LOAD_PROPERTY:
431 return VisitLoadProperty(gate, &info);
432 case OpCode::LOAD_CONST_OFFSET:
433 return VisitLoadConstOffset(gate, &info);
434 case OpCode::TYPED_CREATE_OBJ_WITH_BUFFER:
435 return VisitCreateObjectWithBuffer(gate, &info);
436 case OpCode::OBJECT_TYPE_CHECK:
437 case OpCode::CHECK_AND_CONVERT:
438 return VisitObjectTypeCheck(gate, &info);
439 case OpCode::FRAME_VALUES:
440 case OpCode::STATE_SPLIT:
441 case OpCode::FRAME_STATE:
442 break;
443 default : {
444 size_t numIns = acc_.GetNumValueIn(gate);
445 for (size_t i = 0; i < numIns; i++) {
446 GateRef in = GetCurrentGate(acc_.GetValueIn(gate, i));
447 SetEscaped(in);
448 }
449 }
450 }
451 return Circuit::NullGate();
452 }
453
454 }