1 /*
2 * Copyright (c) 2022 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/ts_hcr_lowering.h"
17 #include "ecmascript/compiler/bytecodes.h"
18 #include "ecmascript/compiler/builtins_lowering.h"
19 #include "ecmascript/compiler/circuit.h"
20 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
21 #include "ecmascript/stackmap/llvm_stackmap_parser.h"
22 #include "ecmascript/ts_types/ts_type.h"
23
24 namespace panda::ecmascript::kungfu {
RunTSHCRLowering()25 bool TSHCRLowering::RunTSHCRLowering()
26 {
27 std::vector<GateRef> gateList;
28 circuit_->GetAllGates(gateList);
29 for (const auto &gate : gateList) {
30 auto op = acc_.GetOpCode(gate);
31 if (op == OpCode::JS_BYTECODE) {
32 Lower(gate);
33 allJSBcCount_++;
34 }
35 }
36
37 bool success = true;
38 double typeHitRate = 0.0;
39 auto allTypedOpCount = allJSBcCount_ - allNonTypedOpCount_;
40 if (allTypedOpCount != 0) {
41 typeHitRate = static_cast<double>(hitTypedOpCount_) / static_cast<double>(allTypedOpCount);
42 auto typeThreshold = tsManager_->GetTypeThreshold();
43 if (typeHitRate <= typeThreshold) {
44 success = false;
45 }
46 }
47 acc_.EliminateRedundantPhi();
48
49 if (IsTypeLogEnabled()) {
50 pgoTypeLog_.PrintPGOTypeLog();
51 }
52
53 if (IsLogEnabled()) {
54 LOG_COMPILER(INFO) << "";
55 LOG_COMPILER(INFO) << "\033[34m"
56 << "===================="
57 << " After TSHCRlowering "
58 << "[" << GetMethodName() << "]"
59 << "===================="
60 << "\033[0m";
61 circuit_->PrintAllGatesWithBytecode();
62 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End typeHitRate: "
63 << std::to_string(typeHitRate)
64 << " ===========================" << "\033[0m";
65 for (auto a : bytecodeMap_) {
66 if (bytecodeHitTimeMap_.find(a.first) != bytecodeHitTimeMap_.end()) {
67 double rate = static_cast<double>(bytecodeHitTimeMap_[a.first]) / static_cast<double>(a.second);
68 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
69 << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(rate)
70 << "(" << std::to_string(bytecodeHitTimeMap_[a.first])
71 << " / " << std::to_string(a.second) << ")"
72 << " ===========================" << "\033[0m";
73 } else {
74 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
75 << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(0)
76 << "(" << std::to_string(0)
77 << " / " << std::to_string(a.second) << ")"
78 << " ===========================" << "\033[0m";
79 }
80 }
81 }
82
83 return success;
84 }
85
IsTrustedType(GateRef gate) const86 bool TSHCRLowering::IsTrustedType(GateRef gate) const
87 {
88 if (acc_.IsConstant(gate)) {
89 return true;
90 }
91 auto op = acc_.GetOpCode(gate);
92 if (acc_.IsTypedOperator(gate)) {
93 if (op == OpCode::TYPED_BINARY_OP) {
94 return !acc_.GetGateType(gate).IsIntType();
95 } else {
96 return true;
97 }
98 }
99 if (op == OpCode::JS_BYTECODE) {
100 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
101 switch (ecmaOpcode) {
102 case EcmaOpcode::ADD2_IMM8_V8:
103 case EcmaOpcode::SUB2_IMM8_V8:
104 case EcmaOpcode::MUL2_IMM8_V8:
105 return !acc_.GetGateType(gate).IsIntType();
106 case EcmaOpcode::INC_IMM8:
107 case EcmaOpcode::DEC_IMM8:
108 case EcmaOpcode::LESS_IMM8_V8:
109 case EcmaOpcode::LESSEQ_IMM8_V8:
110 case EcmaOpcode::GREATER_IMM8_V8:
111 case EcmaOpcode::GREATEREQ_IMM8_V8:
112 case EcmaOpcode::EQ_IMM8_V8:
113 case EcmaOpcode::NOTEQ_IMM8_V8:
114 case EcmaOpcode::STRICTEQ_IMM8_V8:
115 case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
116 case EcmaOpcode::ISTRUE:
117 case EcmaOpcode::ISFALSE:
118 return true;
119 default:
120 break;
121 }
122 }
123 return false;
124 }
125
Lower(GateRef gate)126 void TSHCRLowering::Lower(GateRef gate)
127 {
128 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
129 // initialize label manager
130 Environment env(gate, circuit_, &builder_);
131 AddBytecodeCount(ecmaOpcode);
132 switch (ecmaOpcode) {
133 case EcmaOpcode::ADD2_IMM8_V8:
134 LowerTypedBinOp<TypedBinOp::TYPED_ADD>(gate);
135 break;
136 case EcmaOpcode::SUB2_IMM8_V8:
137 LowerTypedBinOp<TypedBinOp::TYPED_SUB>(gate);
138 break;
139 case EcmaOpcode::MUL2_IMM8_V8:
140 LowerTypedBinOp<TypedBinOp::TYPED_MUL>(gate);
141 break;
142 case EcmaOpcode::DIV2_IMM8_V8:
143 LowerTypedDiv(gate);
144 break;
145 case EcmaOpcode::MOD2_IMM8_V8:
146 LowerTypedMod(gate);
147 break;
148 case EcmaOpcode::LESS_IMM8_V8:
149 LowerTypedBinOp<TypedBinOp::TYPED_LESS>(gate);
150 break;
151 case EcmaOpcode::LESSEQ_IMM8_V8:
152 LowerTypedBinOp<TypedBinOp::TYPED_LESSEQ>(gate);
153 break;
154 case EcmaOpcode::GREATER_IMM8_V8:
155 LowerTypedBinOp<TypedBinOp::TYPED_GREATER>(gate);
156 break;
157 case EcmaOpcode::GREATEREQ_IMM8_V8:
158 LowerTypedBinOp<TypedBinOp::TYPED_GREATEREQ>(gate);
159 break;
160 case EcmaOpcode::EQ_IMM8_V8:
161 LowerTypedBinOp<TypedBinOp::TYPED_EQ>(gate);
162 break;
163 case EcmaOpcode::STRICTEQ_IMM8_V8:
164 LowerTypedStrictEq(gate);
165 break;
166 case EcmaOpcode::NOTEQ_IMM8_V8:
167 LowerTypedBinOp<TypedBinOp::TYPED_NOTEQ>(gate);
168 break;
169 case EcmaOpcode::SHL2_IMM8_V8:
170 LowerTypedShl(gate);
171 break;
172 case EcmaOpcode::SHR2_IMM8_V8:
173 LowerTypedShr(gate);
174 break;
175 case EcmaOpcode::ASHR2_IMM8_V8:
176 LowerTypedAshr(gate);
177 break;
178 case EcmaOpcode::AND2_IMM8_V8:
179 LowerTypedAnd(gate);
180 break;
181 case EcmaOpcode::OR2_IMM8_V8:
182 LowerTypedOr(gate);
183 break;
184 case EcmaOpcode::XOR2_IMM8_V8:
185 LowerTypedXor(gate);
186 break;
187 case EcmaOpcode::TONUMERIC_IMM8:
188 LowerTypeToNumeric(gate);
189 break;
190 case EcmaOpcode::NEG_IMM8:
191 LowerTypedNeg(gate);
192 break;
193 case EcmaOpcode::NOT_IMM8:
194 LowerTypedNot(gate);
195 break;
196 case EcmaOpcode::INC_IMM8:
197 LowerTypedInc(gate);
198 break;
199 case EcmaOpcode::DEC_IMM8:
200 LowerTypedDec(gate);
201 break;
202 case EcmaOpcode::ISTRUE:
203 LowerTypedIsTrueOrFalse(gate, true);
204 break;
205 case EcmaOpcode::ISFALSE:
206 LowerTypedIsTrueOrFalse(gate, false);
207 break;
208 case EcmaOpcode::JEQZ_IMM8:
209 case EcmaOpcode::JEQZ_IMM16:
210 case EcmaOpcode::JEQZ_IMM32:
211 LowerConditionJump(gate, false);
212 break;
213 case EcmaOpcode::JNEZ_IMM8:
214 case EcmaOpcode::JNEZ_IMM16:
215 case EcmaOpcode::JNEZ_IMM32:
216 LowerConditionJump(gate, true);
217 break;
218 case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
219 case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
220 case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
221 case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
222 LowerTypedLdObjByName(gate);
223 break;
224 case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
225 case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
226 LowerTypedStObjByName(gate, false);
227 break;
228 case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
229 case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
230 LowerTypedStObjByName(gate, true);
231 break;
232 case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
233 case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
234 case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
235 LowerTypedLdObjByIndex(gate);
236 break;
237 case EcmaOpcode::STOBJBYINDEX_IMM8_V8_IMM16:
238 case EcmaOpcode::STOBJBYINDEX_IMM16_V8_IMM16:
239 case EcmaOpcode::WIDE_STOBJBYINDEX_PREF_V8_IMM32:
240 LowerTypedStObjByIndex(gate);
241 break;
242 case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
243 case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
244 LowerTypedLdObjByValue(gate, false);
245 break;
246 case EcmaOpcode::LDTHISBYVALUE_IMM8:
247 case EcmaOpcode::LDTHISBYVALUE_IMM16:
248 LowerTypedLdObjByValue(gate, true);
249 break;
250 case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
251 case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
252 LowerTypedStObjByValue(gate);
253 break;
254 case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
255 case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
256 case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
257 LowerTypedNewObjRange(gate);
258 break;
259 case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
260 case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
261 LowerTypedSuperCall(gate);
262 break;
263 case EcmaOpcode::CALLARG0_IMM8:
264 LowerTypedCallArg0(gate);
265 break;
266 case EcmaOpcode::CALLARG1_IMM8_V8:
267 LowerTypedCallArg1(gate);
268 break;
269 case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
270 LowerTypedCallArg2(gate);
271 break;
272 case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
273 LowerTypedCallArg3(gate);
274 break;
275 case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
276 LowerTypedCallrange(gate);
277 break;
278 case EcmaOpcode::CALLTHIS0_IMM8_V8:
279 LowerTypedCallthis0(gate);
280 break;
281 case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
282 LowerTypedCallthis1(gate);
283 break;
284 case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
285 LowerTypedCallthis2(gate);
286 break;
287 case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
288 LowerTypedCallthis3(gate);
289 break;
290 case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
291 LowerTypedCallthisrange(gate);
292 break;
293 default:
294 DeleteBytecodeCount(ecmaOpcode);
295 allNonTypedOpCount_++;
296 break;
297 }
298 }
299
300 template<TypedBinOp Op>
LowerTypedBinOp(GateRef gate)301 void TSHCRLowering::LowerTypedBinOp(GateRef gate)
302 {
303 GateRef left = acc_.GetValueIn(gate, 0);
304 GateRef right = acc_.GetValueIn(gate, 1);
305 if (HasNumberType(gate, left, right)) {
306 SpeculateNumbers<Op>(gate);
307 }
308 }
309
LowerTypedMod(GateRef gate)310 void TSHCRLowering::LowerTypedMod(GateRef gate)
311 {
312 GateRef left = acc_.GetValueIn(gate, 0);
313 GateRef right = acc_.GetValueIn(gate, 1);
314 if (HasNumberType(gate, left, right)) {
315 SpeculateNumbers<TypedBinOp::TYPED_MOD>(gate);
316 }
317 }
318
LowerTypedDiv(GateRef gate)319 void TSHCRLowering::LowerTypedDiv(GateRef gate)
320 {
321 GateRef left = acc_.GetValueIn(gate, 0);
322 GateRef right = acc_.GetValueIn(gate, 1);
323 if (HasNumberType(gate, left, right)) {
324 SpeculateNumbers<TypedBinOp::TYPED_DIV>(gate);
325 }
326 }
327
LowerTypedStrictEq(GateRef gate)328 void TSHCRLowering::LowerTypedStrictEq(GateRef gate)
329 {
330 GateRef left = acc_.GetValueIn(gate, 0);
331 GateRef right = acc_.GetValueIn(gate, 1);
332 GateType leftType = acc_.GetGateType(left);
333 GateType rightType = acc_.GetGateType(right);
334 GateType gateType = acc_.GetGateType(gate);
335 PGOSampleType sampleType = acc_.TryGetPGOType(gate);
336 if (acc_.IsConstantUndefined(left) || acc_.IsConstantUndefined(right) || HasNumberType(gate, left, right)) {
337 GateRef result = builder_.TypedBinaryOp<TypedBinOp::TYPED_STRICTEQ>(
338 left, right, leftType, rightType, gateType, sampleType);
339 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
340 }
341 }
342
LowerTypedShl(GateRef gate)343 void TSHCRLowering::LowerTypedShl(GateRef gate)
344 {
345 GateRef left = acc_.GetValueIn(gate, 0);
346 GateRef right = acc_.GetValueIn(gate, 1);
347 if (HasNumberType(gate, left, right)) {
348 SpeculateNumbers<TypedBinOp::TYPED_SHL>(gate);
349 }
350 }
351
LowerTypedShr(GateRef gate)352 void TSHCRLowering::LowerTypedShr(GateRef gate)
353 {
354 GateRef left = acc_.GetValueIn(gate, 0);
355 GateRef right = acc_.GetValueIn(gate, 1);
356 if (HasNumberType(gate, left, right)) {
357 SpeculateNumbers<TypedBinOp::TYPED_SHR>(gate);
358 }
359 }
360
LowerTypedAshr(GateRef gate)361 void TSHCRLowering::LowerTypedAshr(GateRef gate)
362 {
363 GateRef left = acc_.GetValueIn(gate, 0);
364 GateRef right = acc_.GetValueIn(gate, 1);
365 if (HasNumberType(gate, left, right)) {
366 SpeculateNumbers<TypedBinOp::TYPED_ASHR>(gate);
367 }
368 }
369
LowerTypedAnd(GateRef gate)370 void TSHCRLowering::LowerTypedAnd(GateRef gate)
371 {
372 GateRef left = acc_.GetValueIn(gate, 0);
373 GateRef right = acc_.GetValueIn(gate, 1);
374 if (HasNumberType(gate, left, right)) {
375 SpeculateNumbers<TypedBinOp::TYPED_AND>(gate);
376 }
377 }
378
LowerTypedOr(GateRef gate)379 void TSHCRLowering::LowerTypedOr(GateRef gate)
380 {
381 GateRef left = acc_.GetValueIn(gate, 0);
382 GateRef right = acc_.GetValueIn(gate, 1);
383 if (HasNumberType(gate, left, right)) {
384 SpeculateNumbers<TypedBinOp::TYPED_OR>(gate);
385 }
386 }
387
LowerTypedXor(GateRef gate)388 void TSHCRLowering::LowerTypedXor(GateRef gate)
389 {
390 GateRef left = acc_.GetValueIn(gate, 0);
391 GateRef right = acc_.GetValueIn(gate, 1);
392 if (HasNumberType(gate, left, right)) {
393 SpeculateNumbers<TypedBinOp::TYPED_XOR>(gate);
394 }
395 }
396
LowerTypedInc(GateRef gate)397 void TSHCRLowering::LowerTypedInc(GateRef gate)
398 {
399 GateRef value = acc_.GetValueIn(gate, 0);
400 if (HasNumberType(gate, value)) {
401 SpeculateNumber<TypedUnOp::TYPED_INC>(gate);
402 }
403 }
404
LowerTypedDec(GateRef gate)405 void TSHCRLowering::LowerTypedDec(GateRef gate)
406 {
407 GateRef value = acc_.GetValueIn(gate, 0);
408 if (HasNumberType(gate, value)) {
409 SpeculateNumber<TypedUnOp::TYPED_DEC>(gate);
410 }
411 }
412
HasNumberType(GateRef gate,GateRef value) const413 bool TSHCRLowering::HasNumberType(GateRef gate, GateRef value) const
414 {
415 GateType valueType = acc_.GetGateType(value);
416 PGOSampleType sampleType = acc_.TryGetPGOType(gate);
417 if (sampleType.IsNumber() ||
418 (sampleType.IsNone() && valueType.IsNumberType())) {
419 return true;
420 }
421 return false;
422 }
423
HasNumberType(GateRef gate,GateRef left,GateRef right) const424 bool TSHCRLowering::HasNumberType(GateRef gate, GateRef left, GateRef right) const
425 {
426 GateType leftType = acc_.GetGateType(left);
427 GateType rightType = acc_.GetGateType(right);
428
429 PGOSampleType sampleType = acc_.TryGetPGOType(gate);
430 if (sampleType.IsNumber() ||
431 (sampleType.IsNone() && leftType.IsNumberType() && rightType.IsNumberType())) {
432 return true;
433 }
434 return false;
435 }
436
437 template<TypedBinOp Op>
SpeculateNumbers(GateRef gate)438 void TSHCRLowering::SpeculateNumbers(GateRef gate)
439 {
440 AddProfiling(gate);
441 GateRef left = acc_.GetValueIn(gate, 0);
442 GateRef right = acc_.GetValueIn(gate, 1);
443 GateType leftType = acc_.GetGateType(left);
444 GateType rightType = acc_.GetGateType(right);
445 GateType gateType = acc_.GetGateType(gate);
446 PGOSampleType sampleType = acc_.TryGetPGOType(gate);
447 pgoTypeLog_.CollectGateTypeLogInfo(gate, true);
448
449 GateRef result = builder_.TypedBinaryOp<Op>(left, right, leftType, rightType, gateType, sampleType);
450 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
451 }
452
453 template<TypedUnOp Op>
SpeculateNumber(GateRef gate)454 void TSHCRLowering::SpeculateNumber(GateRef gate)
455 {
456 AddProfiling(gate);
457 GateRef value = acc_.GetValueIn(gate, 0);
458 GateType valueType = acc_.GetGateType(value);
459 GateType gateType = acc_.GetGateType(gate);
460 pgoTypeLog_.CollectGateTypeLogInfo(gate, false);
461
462 PGOSampleType sampleType = acc_.TryGetPGOType(gate);
463 if (sampleType.IsNumber()) {
464 if (sampleType.IsInt()) {
465 gateType = GateType::IntType();
466 } else if (sampleType.IsDouble()) {
467 gateType = GateType::DoubleType();
468 } else {
469 gateType = GateType::NumberType();
470 }
471 valueType = gateType;
472 }
473
474 GateRef result = builder_.TypedUnaryOp<Op>(value, valueType, gateType);
475
476 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
477 }
478
LowerTypeToNumeric(GateRef gate)479 void TSHCRLowering::LowerTypeToNumeric(GateRef gate)
480 {
481 GateRef src = acc_.GetValueIn(gate, 0);
482 if (HasNumberType(gate, src)) {
483 AddProfiling(gate);
484 LowerPrimitiveTypeToNumber(gate);
485 }
486 }
487
LowerPrimitiveTypeToNumber(GateRef gate)488 void TSHCRLowering::LowerPrimitiveTypeToNumber(GateRef gate)
489 {
490 GateRef src = acc_.GetValueIn(gate, 0);
491 GateType srcType = acc_.GetGateType(src);
492
493 GateRef result = builder_.PrimitiveToNumber(src, VariableType(MachineType::I64, srcType));
494
495 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
496 }
497
LowerConditionJump(GateRef gate,bool flag)498 void TSHCRLowering::LowerConditionJump(GateRef gate, bool flag)
499 {
500 GateRef condition = acc_.GetValueIn(gate, 0);
501 GateType conditionType = acc_.GetGateType(condition);
502 if (conditionType.IsBooleanType() && IsTrustedType(condition)) {
503 AddProfiling(gate);
504 SpeculateConditionJump(gate, flag);
505 }
506 }
507
SpeculateConditionJump(GateRef gate,bool flag)508 void TSHCRLowering::SpeculateConditionJump(GateRef gate, bool flag)
509 {
510 GateRef value = acc_.GetValueIn(gate, 0);
511 GateType valueType = acc_.GetGateType(value);
512 GateRef jump = Circuit::NullGate();
513 if (flag) {
514 jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JNEZ>(value, valueType);
515 } else {
516 jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JEQZ>(value, valueType);
517 }
518 acc_.ReplaceGate(gate, jump, jump, Circuit::NullGate());
519 }
520
LowerTypedNeg(GateRef gate)521 void TSHCRLowering::LowerTypedNeg(GateRef gate)
522 {
523 GateRef value = acc_.GetValueIn(gate, 0);
524 if (HasNumberType(gate, value)) {
525 SpeculateNumber<TypedUnOp::TYPED_NEG>(gate);
526 }
527 }
528
LowerTypedNot(GateRef gate)529 void TSHCRLowering::LowerTypedNot(GateRef gate)
530 {
531 GateRef value = acc_.GetValueIn(gate, 0);
532 if (HasNumberType(gate, value)) {
533 SpeculateNumber<TypedUnOp::TYPED_NOT>(gate);
534 }
535 }
536
DeleteConstDataIfNoUser(GateRef gate)537 void TSHCRLowering::DeleteConstDataIfNoUser(GateRef gate)
538 {
539 auto uses = acc_.Uses(gate);
540 if (uses.begin() == uses.end()) {
541 builder_.ClearConstantCache(gate);
542 acc_.DeleteGate(gate);
543 }
544 }
545
LowerTypedLdObjByName(GateRef gate)546 void TSHCRLowering::LowerTypedLdObjByName(GateRef gate)
547 {
548 DISALLOW_GARBAGE_COLLECTION;
549 auto constData = acc_.GetValueIn(gate, 1); // 1: valueIn 1
550 uint16_t keyIndex = acc_.GetConstantValue(constData);
551 JSTaggedValue key = tsManager_->GetStringFromConstantPool(keyIndex);
552
553 // 3: number of value inputs
554 ASSERT(acc_.GetNumValueIn(gate) == 3);
555 GateRef receiver = acc_.GetValueIn(gate, 2); // 2: acc or this object
556 LowerNamedAccess(gate, receiver, AccessMode::LOAD, key, Circuit::NullGate());
557 DeleteConstDataIfNoUser(constData);
558 }
559
LowerTypedStObjByName(GateRef gate,bool isThis)560 void TSHCRLowering::LowerTypedStObjByName(GateRef gate, bool isThis)
561 {
562 DISALLOW_GARBAGE_COLLECTION;
563 auto constData = acc_.GetValueIn(gate, 1); // 1: valueIn 1
564 uint16_t keyIndex = acc_.GetConstantValue(constData);
565 JSTaggedValue key = tsManager_->GetStringFromConstantPool(keyIndex);
566
567 GateRef receiver = Circuit::NullGate();
568 GateRef value = Circuit::NullGate();
569 if (isThis) {
570 // 3: number of value inputs
571 ASSERT(acc_.GetNumValueIn(gate) == 3);
572 receiver = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
573 value = acc_.GetValueIn(gate, 2); // 2: acc
574 } else {
575 // 4: number of value inputs
576 ASSERT(acc_.GetNumValueIn(gate) == 4);
577 receiver = acc_.GetValueIn(gate, 2); // 2: receiver
578 value = acc_.GetValueIn(gate, 3); // 3: acc
579 }
580 LowerNamedAccess(gate, receiver, AccessMode::STORE, key, value);
581 DeleteConstDataIfNoUser(constData);
582 }
583
LowerNamedAccess(GateRef gate,GateRef receiver,AccessMode accessMode,JSTaggedValue key,GateRef value)584 void TSHCRLowering::LowerNamedAccess(GateRef gate, GateRef receiver, AccessMode accessMode, JSTaggedValue key,
585 GateRef value)
586 {
587 DISALLOW_GARBAGE_COLLECTION;
588 GateType receiverType = acc_.GetGateType(receiver);
589 receiverType = tsManager_->TryNarrowUnionType(receiverType);
590 if (accessMode == AccessMode::LOAD && TryLowerTypedLdObjByNameForArray(gate, receiverType, key)) {
591 return;
592 }
593
594 ObjectAccessHelper accessHelper(tsManager_, accessMode, receiver, receiverType, key, value);
595 ChunkVector<ObjectAccessInfo> infos(circuit_->chunk());
596 bool continuation = accessHelper.Compute(infos);
597 if (!continuation) {
598 return; // slowpath
599 }
600
601 ASSERT(!infos.empty());
602 AddProfiling(gate);
603
604 // If all elements of the array are objects, and receiver is one of the elements,
605 // no HeapObjectCheck is required.
606 bool isHeapObject = acc_.IsHeapObjectFromElementsKind(receiver);
607
608 // monomorphic
609 if (infos.size() == 1) {
610 int hclassIndex = infos[0].HClassIndex();
611 PropertyLookupResult plr = infos[0].Plr();
612 if (!Uncheck()) {
613 GateRef hclassIndexGate = builder_.IntPtr(hclassIndex);
614 builder_.ObjectTypeCheck(infos[0].Type(), isHeapObject, receiver, hclassIndexGate);
615 }
616
617 GateRef result = BuildNamedPropertyAccess(gate, accessHelper, plr);
618 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
619 return;
620 }
621
622 // polymorphic
623 size_t size = infos.size();
624 GateRef fallthroughState = builder_.GetState();
625 GateRef fallthroughDepend = builder_.GetDepend();
626 std::vector<GateRef> values(size + 1, Circuit::NullGate()); // +1: state for value selector
627 std::vector<GateRef> depends(size + 1, Circuit::NullGate()); // +1: state for depend selector
628 std::vector<GateRef> states(size, Circuit::NullGate());
629 for (size_t i = 0; i < size; ++i) {
630 GateType type = infos[i].Type();
631 int hclassIndex = infos[i].HClassIndex();
632 PropertyLookupResult plr = infos[i].Plr();
633 GateRef hclassIndexGate = builder_.IntPtr(hclassIndex);
634
635 builder_.SetState(fallthroughState);
636 builder_.SetDepend(fallthroughDepend);
637 if (i == size - 1) {
638 builder_.ObjectTypeCheck(type, isHeapObject, receiver, hclassIndexGate);
639 fallthroughState = Circuit::NullGate();
640 fallthroughDepend = Circuit::NullGate();
641 } else {
642 GateRef compare = builder_.ObjectTypeCompare(type, isHeapObject, receiver, hclassIndexGate);
643 GateRef branch = builder_.Branch(builder_.GetState(), compare);
644 GateRef ifTrue = builder_.IfTrue(branch);
645 GateRef ifFalse = builder_.IfFalse(branch);
646 GateRef tDepend = builder_.DependRelay(ifTrue, builder_.GetDepend());
647 fallthroughState = ifFalse;
648 fallthroughDepend = builder_.DependRelay(ifFalse, builder_.GetDepend());
649 builder_.SetState(ifTrue);
650 builder_.SetDepend(tDepend);
651 }
652
653 values[i + 1] = BuildNamedPropertyAccess(gate, accessHelper, plr);
654 depends[i + 1] = builder_.GetDepend();
655 states[i] = builder_.GetState();
656 }
657 ASSERT(fallthroughState == Circuit::NullGate());
658 ASSERT(fallthroughDepend == Circuit::NullGate());
659 GateRef mergeState = circuit_->NewGate(circuit_->Merge(size), states);
660 depends[0] = mergeState;
661 values[0] = mergeState;
662 GateRef dependSelector = circuit_->NewGate(circuit_->DependSelector(size), depends);
663 GateRef result = accessHelper.IsLoading() ?
664 circuit_->NewGate(circuit_->ValueSelector(size), MachineType::I64, size + 1, values.data(), GateType::AnyType())
665 : Circuit::NullGate();
666 acc_.ReplaceHirAndDeleteIfException(gate, StateDepend(mergeState, dependSelector), result);
667 }
668
BuildNamedPropertyAccess(GateRef hir,ObjectAccessHelper accessHelper,PropertyLookupResult plr)669 GateRef TSHCRLowering::BuildNamedPropertyAccess(GateRef hir, ObjectAccessHelper accessHelper, PropertyLookupResult plr)
670 {
671 GateRef receiver = accessHelper.GetReceiver();
672 GateRef plrGate = builder_.Int32(plr.GetData());
673 GateRef result = Circuit::NullGate();
674
675 AccessMode mode = accessHelper.GetAccessMode();
676 switch (mode) {
677 case AccessMode::LOAD: {
678 if (LIKELY(!plr.IsAccessor())) {
679 result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
680 if (UNLIKELY(IsVerifyVTbale())) {
681 BuildNamedPropertyAccessVerifier(hir, receiver, mode, result);
682 }
683 } else {
684 result = builder_.CallGetter(hir, receiver, plrGate);
685 }
686 }
687 break;
688 case AccessMode::STORE: {
689 GateRef value = accessHelper.GetValue();
690 if (LIKELY(plr.IsLocal())) {
691 builder_.StoreProperty(receiver, plrGate, value);
692 if (UNLIKELY(IsVerifyVTbale())) {
693 BuildNamedPropertyAccessVerifier(hir, receiver, mode, value);
694 }
695 } else {
696 builder_.CallSetter(hir, receiver, plrGate, value);
697 }
698 }
699 break;
700 default:
701 break;
702 }
703
704 return result;
705 }
706
BuildNamedPropertyAccessVerifier(GateRef gate,GateRef receiver,AccessMode mode,GateRef value)707 void TSHCRLowering::BuildNamedPropertyAccessVerifier(GateRef gate, GateRef receiver, AccessMode mode, GateRef value)
708 {
709 GateRef constData = acc_.GetValueIn(gate, 1);
710 uint16_t keyIndex = acc_.GetConstantValue(constData);
711 GateRef func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
712 GateRef constPool = builder_.GetConstPool(func);
713 GateRef key = builder_.GetValueFromTaggedArray(constPool, builder_.Int32(keyIndex));
714 int stubId = mode == AccessMode::LOAD ? RTSTUB_ID(VerifyVTableLoading) : RTSTUB_ID(VerifyVTableStoring);
715 builder_.CallRuntime(glue_, stubId, builder_.GetDepend(), { receiver, key, value }, gate);
716 }
717
TryLowerTypedLdObjByNameForArray(GateRef gate,GateType receiverType,JSTaggedValue key)718 bool TSHCRLowering::TryLowerTypedLdObjByNameForArray(GateRef gate, GateType receiverType, JSTaggedValue key)
719 {
720 EcmaString *propString = EcmaString::Cast(key.GetTaggedObject());
721 EcmaString *lengthString = EcmaString::Cast(thread_->GlobalConstants()->GetLengthString().GetTaggedObject());
722 if (propString == lengthString) {
723 if (tsManager_->IsArrayTypeKind(receiverType)) {
724 LowerTypedLdArrayLength(gate);
725 return true;
726 } else if (tsManager_->IsValidTypedArrayType(receiverType)) {
727 LowerTypedLdTypedArrayLength(gate);
728 return true;
729 }
730 }
731 return false;
732 }
733
LowerTypedLdArrayLength(GateRef gate)734 void TSHCRLowering::LowerTypedLdArrayLength(GateRef gate)
735 {
736 AddProfiling(gate);
737 GateRef array = acc_.GetValueIn(gate, 2);
738 if (!Uncheck()) {
739 ElementsKind kind = acc_.TryGetElementsKind(gate);
740 builder_.StableArrayCheck(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
741 }
742
743 GateRef result = builder_.LoadArrayLength(array);
744 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
745 }
746
LowerTypedLdTypedArrayLength(GateRef gate)747 void TSHCRLowering::LowerTypedLdTypedArrayLength(GateRef gate)
748 {
749 AddProfiling(gate);
750 GateRef array = acc_.GetValueIn(gate, 2);
751 GateType arrayType = acc_.GetGateType(array);
752 arrayType = tsManager_->TryNarrowUnionType(arrayType);
753 if (!Uncheck()) {
754 builder_.TypedArrayCheck(arrayType, array);
755 }
756 GateRef result = builder_.LoadTypedArrayLength(arrayType, array);
757 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
758 }
759
LowerTypedLdObjByIndex(GateRef gate)760 void TSHCRLowering::LowerTypedLdObjByIndex(GateRef gate)
761 {
762 // 2: number of value inputs
763 ASSERT(acc_.GetNumValueIn(gate) == 2);
764 GateRef receiver = acc_.GetValueIn(gate, 1);
765 GateType receiverType = acc_.GetGateType(receiver);
766 receiverType = tsManager_->TryNarrowUnionType(receiverType);
767 GateRef result = Circuit::NullGate();
768 if (tsManager_->IsValidTypedArrayType(receiverType)) {
769 AddProfiling(gate);
770 GateRef index = acc_.GetValueIn(gate, 0);
771 uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
772 index = builder_.Int32(indexValue);
773 result = LoadTypedArrayByIndex(receiver, index);
774 } else {
775 return; // slowpath
776 }
777 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
778 }
779
LowerTypedStObjByIndex(GateRef gate)780 void TSHCRLowering::LowerTypedStObjByIndex(GateRef gate)
781 {
782 // 3: number of value inputs
783 ASSERT(acc_.GetNumValueIn(gate) == 3);
784 GateRef receiver = acc_.GetValueIn(gate, 0);
785 GateRef value = acc_.GetValueIn(gate, 2);
786 GateType receiverType = acc_.GetGateType(receiver);
787 GateType valueType = acc_.GetGateType(value);
788 receiverType = tsManager_->TryNarrowUnionType(receiverType);
789 if ((!tsManager_->IsBuiltinInstanceType(BuiltinTypeId::FLOAT32_ARRAY, receiverType)) ||
790 (!valueType.IsNumberType())) { // slowpath
791 return;
792 }
793
794 AddProfiling(gate);
795
796 if (tsManager_->IsBuiltinInstanceType(BuiltinTypeId::FLOAT32_ARRAY, receiverType)) {
797 if (!Uncheck()) {
798 builder_.TypedArrayCheck(receiverType, receiver);
799 }
800 } else {
801 LOG_ECMA(FATAL) << "this branch is unreachable";
802 UNREACHABLE();
803 }
804 GateRef index = acc_.GetValueIn(gate, 1);
805 uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
806 index = builder_.Int32(indexValue);
807 auto length = builder_.LoadTypedArrayLength(receiverType, receiver);
808 if (!Uncheck()) {
809 builder_.IndexCheck(receiverType, length, index);
810 }
811
812 if (tsManager_->IsBuiltinInstanceType(BuiltinTypeId::FLOAT32_ARRAY, receiverType)) {
813 builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, index, value);
814 } else {
815 LOG_ECMA(FATAL) << "this branch is unreachable";
816 UNREACHABLE();
817 }
818
819 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
820 }
821
LowerTypedLdObjByValue(GateRef gate,bool isThis)822 void TSHCRLowering::LowerTypedLdObjByValue(GateRef gate, bool isThis)
823 {
824 GateRef receiver = Circuit::NullGate();
825 GateRef propKey = Circuit::NullGate();
826 if (isThis) {
827 // 2: number of value inputs
828 ASSERT(acc_.GetNumValueIn(gate) == 2);
829 receiver = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
830 propKey = acc_.GetValueIn(gate, 1);
831 } else {
832 // 3: number of value inputs
833 ASSERT(acc_.GetNumValueIn(gate) == 3);
834 receiver = acc_.GetValueIn(gate, 1);
835 propKey = acc_.GetValueIn(gate, 2); // 2: the third parameter
836 }
837 GateType receiverType = acc_.GetGateType(receiver);
838 GateType propKeyType = acc_.GetGateType(propKey);
839 receiverType = tsManager_->TryNarrowUnionType(receiverType);
840 if (!propKeyType.IsNumberType()) {
841 return; // slowpath
842 }
843
844 GateRef result = Circuit::NullGate();
845 if (tsManager_->IsArrayTypeKind(receiverType)) {
846 AddProfiling(gate);
847 ElementsKind kind = acc_.TryGetElementsKind(gate);
848 result = LoadJSArrayByIndex(receiver, propKey, kind);
849 } else if (tsManager_->IsValidTypedArrayType(receiverType)) {
850 AddProfiling(gate);
851 result = LoadTypedArrayByIndex(receiver, propKey);
852 } else {
853 return; // slowpath
854 }
855 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
856 }
857
LoadJSArrayByIndex(GateRef receiver,GateRef propKey,ElementsKind kind)858 GateRef TSHCRLowering::LoadJSArrayByIndex(GateRef receiver, GateRef propKey, ElementsKind kind)
859 {
860 if (!Uncheck()) {
861 GateType receiverType = acc_.GetGateType(receiver);
862 receiverType = tsManager_->TryNarrowUnionType(receiverType);
863 builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
864 GateRef length = builder_.LoadArrayLength(receiver);
865 propKey = builder_.IndexCheck(receiverType, length, propKey);
866 }
867
868 GateRef result = Circuit::NullGate();
869 if (Elements::IsInt(kind)) {
870 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_INT_ELEMENT>(receiver, propKey);
871 } else if (Elements::IsDouble(kind)) {
872 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT>(receiver, propKey);
873 } else if (Elements::IsObject(kind)) {
874 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT>(receiver, propKey);
875 } else if (!Elements::IsHole(kind)) {
876 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT>(receiver, propKey);
877 } else {
878 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_HOLE_TAGGED_ELEMENT>(receiver, propKey);
879 }
880 return result;
881 }
882
LoadTypedArrayByIndex(GateRef receiver,GateRef propKey)883 GateRef TSHCRLowering::LoadTypedArrayByIndex(GateRef receiver, GateRef propKey)
884 {
885 GateType receiverType = acc_.GetGateType(receiver);
886 receiverType = tsManager_->TryNarrowUnionType(receiverType);
887 if (!Uncheck()) {
888 builder_.TypedArrayCheck(receiverType, receiver);
889 GateRef length = builder_.LoadTypedArrayLength(receiverType, receiver);
890 propKey = builder_.IndexCheck(receiverType, length, propKey);
891 }
892 auto builtinTypeId = tsManager_->GetTypedArrayBuiltinId(receiverType);
893 switch (builtinTypeId) {
894 case BuiltinTypeId::INT8_ARRAY:
895 return builder_.LoadElement<TypedLoadOp::INT8ARRAY_LOAD_ELEMENT>(receiver, propKey);
896 case BuiltinTypeId::UINT8_ARRAY:
897 return builder_.LoadElement<TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT>(receiver, propKey);
898 case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
899 return builder_.LoadElement<TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT>(receiver, propKey);
900 case BuiltinTypeId::INT16_ARRAY:
901 return builder_.LoadElement<TypedLoadOp::INT16ARRAY_LOAD_ELEMENT>(receiver, propKey);
902 case BuiltinTypeId::UINT16_ARRAY:
903 return builder_.LoadElement<TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT>(receiver, propKey);
904 case BuiltinTypeId::INT32_ARRAY:
905 return builder_.LoadElement<TypedLoadOp::INT32ARRAY_LOAD_ELEMENT>(receiver, propKey);
906 case BuiltinTypeId::UINT32_ARRAY:
907 return builder_.LoadElement<TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT>(receiver, propKey);
908 case BuiltinTypeId::FLOAT32_ARRAY:
909 return builder_.LoadElement<TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(receiver, propKey);
910 case BuiltinTypeId::FLOAT64_ARRAY:
911 return builder_.LoadElement<TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT>(receiver, propKey);
912 default:
913 LOG_ECMA(FATAL) << "this branch is unreachable";
914 UNREACHABLE();
915 }
916
917 return Circuit::NullGate();
918 }
919
StoreJSArrayByIndex(GateRef receiver,GateRef propKey,GateRef value,ElementsKind kind)920 void TSHCRLowering::StoreJSArrayByIndex(GateRef receiver, GateRef propKey, GateRef value, ElementsKind kind)
921 {
922 if (!Uncheck()) {
923 GateType receiverType = acc_.GetGateType(receiver);
924 receiverType = tsManager_->TryNarrowUnionType(receiverType);
925 builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::STORE_ELEMENT);
926 GateRef length = builder_.LoadArrayLength(receiver);
927 builder_.IndexCheck(receiverType, length, propKey);
928 builder_.COWArrayCheck(receiver);
929
930 if (Elements::IsObject(kind)) {
931 GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
932 builder_.HeapObjectCheck(value, frameState);
933 }
934 }
935 builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, propKey, value);
936 }
937
938
StoreTypedArrayByIndex(GateRef receiver,GateRef propKey,GateRef value)939 void TSHCRLowering::StoreTypedArrayByIndex(GateRef receiver, GateRef propKey, GateRef value)
940 {
941 GateType receiverType = acc_.GetGateType(receiver);
942 receiverType = tsManager_->TryNarrowUnionType(receiverType);
943 if (!Uncheck()) {
944 builder_.TypedArrayCheck(receiverType, receiver);
945 GateRef length = builder_.LoadTypedArrayLength(receiverType, receiver);
946 propKey = builder_.IndexCheck(receiverType, length, propKey);
947 }
948
949 auto builtinTypeId = tsManager_->GetTypedArrayBuiltinId(receiverType);
950 switch (builtinTypeId) {
951 case BuiltinTypeId::INT8_ARRAY:
952 builder_.StoreElement<TypedStoreOp::INT8ARRAY_STORE_ELEMENT>(receiver, propKey, value);
953 break;
954 case BuiltinTypeId::UINT8_ARRAY:
955 builder_.StoreElement<TypedStoreOp::UINT8ARRAY_STORE_ELEMENT>(receiver, propKey, value);
956 break;
957 case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
958 builder_.StoreElement<TypedStoreOp::UINT8CLAMPEDARRAY_STORE_ELEMENT>(receiver, propKey, value);
959 break;
960 case BuiltinTypeId::INT16_ARRAY:
961 builder_.StoreElement<TypedStoreOp::INT16ARRAY_STORE_ELEMENT>(receiver, propKey, value);
962 break;
963 case BuiltinTypeId::UINT16_ARRAY:
964 builder_.StoreElement<TypedStoreOp::UINT16ARRAY_STORE_ELEMENT>(receiver, propKey, value);
965 break;
966 case BuiltinTypeId::INT32_ARRAY:
967 builder_.StoreElement<TypedStoreOp::INT32ARRAY_STORE_ELEMENT>(receiver, propKey, value);
968 break;
969 case BuiltinTypeId::UINT32_ARRAY:
970 builder_.StoreElement<TypedStoreOp::UINT32ARRAY_STORE_ELEMENT>(receiver, propKey, value);
971 break;
972 case BuiltinTypeId::FLOAT32_ARRAY:
973 builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, propKey, value);
974 break;
975 case BuiltinTypeId::FLOAT64_ARRAY:
976 builder_.StoreElement<TypedStoreOp::FLOAT64ARRAY_STORE_ELEMENT>(receiver, propKey, value);
977 break;
978 default:
979 LOG_ECMA(FATAL) << "this branch is unreachable";
980 UNREACHABLE();
981 }
982 }
983
LowerTypedStObjByValue(GateRef gate)984 void TSHCRLowering::LowerTypedStObjByValue(GateRef gate)
985 {
986 ASSERT(acc_.GetNumValueIn(gate) == 4); // 4: num of value ins
987 GateRef receiver = acc_.GetValueIn(gate, 1); // 1: receiver
988 GateRef propKey = acc_.GetValueIn(gate, 2); // 2: key
989 GateRef value = acc_.GetValueIn(gate, 3); // 3: value
990 GateType receiverType = acc_.GetGateType(receiver);
991 GateType propKeyType = acc_.GetGateType(propKey);
992 receiverType = tsManager_->TryNarrowUnionType(receiverType);
993 if (!propKeyType.IsNumberType()) {
994 return; // slowpath
995 }
996
997 if (tsManager_->IsArrayTypeKind(receiverType)) {
998 AddProfiling(gate);
999 ElementsKind kind = acc_.TryGetElementsKind(gate);
1000 StoreJSArrayByIndex(receiver, propKey, value, kind);
1001 } else if (tsManager_->IsValidTypedArrayType(receiverType)) {
1002 AddProfiling(gate);
1003 StoreTypedArrayByIndex(receiver, propKey, value);
1004 } else {
1005 return;
1006 }
1007
1008 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1009 }
1010
LowerTypedIsTrueOrFalse(GateRef gate,bool flag)1011 void TSHCRLowering::LowerTypedIsTrueOrFalse(GateRef gate, bool flag)
1012 {
1013 ASSERT(acc_.GetNumValueIn(gate) == 1);
1014 auto value = acc_.GetValueIn(gate, 0);
1015 auto valueType = acc_.GetGateType(value);
1016 if ((!valueType.IsNumberType()) && (!valueType.IsBooleanType())) {
1017 return;
1018 }
1019
1020 AddProfiling(gate);
1021 GateRef result;
1022 if (!flag) {
1023 result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISFALSE>(value, valueType, GateType::TaggedValue());
1024 } else {
1025 result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISTRUE>(value, valueType, GateType::TaggedValue());
1026 }
1027
1028 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1029 }
1030
LowerTypedNewObjRange(GateRef gate)1031 void TSHCRLowering::LowerTypedNewObjRange(GateRef gate)
1032 {
1033 GateRef ctor = acc_.GetValueIn(gate, 0);
1034 GateType ctorType = acc_.GetGateType(ctor);
1035 if (!tsManager_->IsClassTypeKind(ctorType)) {
1036 return;
1037 }
1038
1039 AddProfiling(gate);
1040
1041 int hclassIndex = tsManager_->GetHClassIndexByClassGateType(ctorType);
1042 GateRef stateSplit = acc_.GetDep(gate);
1043
1044 GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1045 GateRef thisObj = builder_.TypedNewAllocateThis(ctor, builder_.IntPtr(hclassIndex), frameState);
1046
1047 // call constructor
1048 size_t range = acc_.GetNumValueIn(gate);
1049 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(range, EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
1050 std::vector<GateRef> args { glue_, actualArgc, ctor, ctor, thisObj };
1051 for (size_t i = 1; i < range; ++i) { // 1:skip ctor
1052 args.emplace_back(acc_.GetValueIn(gate, i));
1053 }
1054 GateRef constructGate = builder_.Construct(gate, args);
1055 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
1056 }
1057
LowerTypedSuperCall(GateRef gate)1058 void TSHCRLowering::LowerTypedSuperCall(GateRef gate)
1059 {
1060 GateRef ctor = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1061 GateType ctorType = acc_.GetGateType(ctor); // ldfunction in derived constructor get function type
1062 if (!tsManager_->IsClassTypeKind(ctorType) && !tsManager_->IsFunctionTypeKind(ctorType)) {
1063 return;
1064 }
1065
1066 AddProfiling(gate);
1067
1068 // stateSplit maybe not a STATE_SPLIT
1069 GateRef stateSplit = acc_.GetDep(gate);
1070
1071 GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1072 GateRef superCtor = builder_.GetSuperConstructor(ctor);
1073 GateRef newTarget = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
1074 GateRef thisObj = builder_.TypedSuperAllocateThis(superCtor, newTarget, frameState);
1075
1076 // call constructor
1077 size_t range = acc_.GetNumValueIn(gate);
1078 GateRef actualArgc = builder_.Int64(range + 3); // 3: ctor, newTaget, this
1079 std::vector<GateRef> args { glue_, actualArgc, superCtor, newTarget, thisObj };
1080 for (size_t i = 0; i < range; ++i) {
1081 args.emplace_back(acc_.GetValueIn(gate, i));
1082 }
1083
1084 GateRef constructGate = builder_.Construct(gate, args);
1085 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
1086 }
1087
SpeculateCallBuiltin(GateRef gate,GateRef func,GateRef a0,BuiltinsStubCSigns::ID id)1088 void TSHCRLowering::SpeculateCallBuiltin(GateRef gate, GateRef func, GateRef a0, BuiltinsStubCSigns::ID id)
1089 {
1090 if (!Uncheck()) {
1091 builder_.CallTargetCheck(gate, func, builder_.IntPtr(static_cast<int64_t>(id)), a0);
1092 }
1093 GateRef result = builder_.TypedCallBuiltin(gate, a0, id);
1094
1095 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1096 }
1097
SpeculateCallThis3Builtin(GateRef gate,BuiltinsStubCSigns::ID id)1098 void TSHCRLowering::SpeculateCallThis3Builtin(GateRef gate, BuiltinsStubCSigns::ID id)
1099 {
1100 GateRef thisObj = acc_.GetValueIn(gate, 0);
1101 GateRef a0 = acc_.GetValueIn(gate, 1); // 1: the first-para
1102 GateRef a1 = acc_.GetValueIn(gate, 2); // 2: the third-para
1103 GateRef a2 = acc_.GetValueIn(gate, 3); // 3: the fourth-para
1104 GateRef result = builder_.TypedCallThis3Builtin(gate, thisObj, a0, a1, a2, id);
1105
1106 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1107 }
1108
GetBuiltinId(BuiltinTypeId id,GateRef func)1109 BuiltinsStubCSigns::ID TSHCRLowering::GetBuiltinId(BuiltinTypeId id, GateRef func)
1110 {
1111 GateType funcType = acc_.GetGateType(func);
1112 if (!tsManager_->IsBuiltinObjectMethod(id, funcType)) {
1113 return BuiltinsStubCSigns::ID::NONE;
1114 }
1115 std::string name = tsManager_->GetFuncName(funcType);
1116 BuiltinsStubCSigns::ID stubId = BuiltinsStubCSigns::GetBuiltinId(name);
1117 return stubId;
1118 }
1119
CheckCallTargetFromDefineFuncAndLowerCall(GateRef gate,GateRef func,GlobalTSTypeRef funcGt,GateType funcType,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,bool isNoGC)1120 void TSHCRLowering::CheckCallTargetFromDefineFuncAndLowerCall(GateRef gate, GateRef func, GlobalTSTypeRef funcGt,
1121 GateType funcType, const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall, bool isNoGC)
1122 {
1123 if (!Uncheck()) {
1124 builder_.JSCallTargetFromDefineFuncCheck(funcType, func, gate);
1125 }
1126 if (tsManager_->CanFastCall(funcGt)) {
1127 LowerFastCall(gate, func, argsFastCall, isNoGC);
1128 } else {
1129 LowerCall(gate, func, args, isNoGC);
1130 }
1131 }
1132
LowerFastCall(GateRef gate,GateRef func,const std::vector<GateRef> & argsFastCall,bool isNoGC)1133 void TSHCRLowering::LowerFastCall(GateRef gate, GateRef func,
1134 const std::vector<GateRef> &argsFastCall, bool isNoGC)
1135 {
1136 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1137 GateRef result = builder_.TypedFastCall(gate, argsFastCall, isNoGC);
1138 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1139 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1140 }
1141
LowerCall(GateRef gate,GateRef func,const std::vector<GateRef> & args,bool isNoGC)1142 void TSHCRLowering::LowerCall(GateRef gate, GateRef func,
1143 const std::vector<GateRef> &args, bool isNoGC)
1144 {
1145 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1146 GateRef result = builder_.TypedCall(gate, args, isNoGC);
1147 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1148 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1149 }
1150
CheckCallTargetAndLowerCall(GateRef gate,GateRef func,GlobalTSTypeRef funcGt,GateType funcType,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1151 void TSHCRLowering::CheckCallTargetAndLowerCall(GateRef gate, GateRef func, GlobalTSTypeRef funcGt,
1152 GateType funcType, const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1153 {
1154 if (IsLoadVtable(func)) {
1155 CheckThisCallTargetAndLowerCall(gate, func, funcGt, funcType, args, argsFastCall); // func = a.foo, func()
1156 } else {
1157 bool isNoGC = tsManager_->IsNoGC(funcGt);
1158 auto op = acc_.GetOpCode(func);
1159 if (!tsManager_->FastCallFlagIsVaild(funcGt)) {
1160 return;
1161 }
1162 if (op == OpCode::JS_BYTECODE && (acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8 ||
1163 acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) {
1164 CheckCallTargetFromDefineFuncAndLowerCall(gate, func, funcGt, funcType, args, argsFastCall, isNoGC);
1165 return;
1166 }
1167 int methodIndex = tsManager_->GetMethodIndex(funcGt);
1168 if (!tsManager_->MethodOffsetIsVaild(funcGt) || methodIndex == -1) {
1169 return;
1170 }
1171 if (tsManager_->CanFastCall(funcGt)) {
1172 if (!Uncheck()) {
1173 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL_FAST>(funcType,
1174 func, builder_.IntPtr(methodIndex), gate);
1175 }
1176 LowerFastCall(gate, func, argsFastCall, isNoGC);
1177 } else {
1178 if (!Uncheck()) {
1179 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL>(funcType,
1180 func, builder_.IntPtr(methodIndex), gate);
1181 }
1182 LowerCall(gate, func, args, isNoGC);
1183 }
1184 }
1185 }
1186
LowerTypedCallArg0(GateRef gate)1187 void TSHCRLowering::LowerTypedCallArg0(GateRef gate)
1188 {
1189 GateRef func = acc_.GetValueIn(gate, 0);
1190 GateType funcType = acc_.GetGateType(func);
1191 if (!tsManager_->IsFunctionTypeKind(funcType)) {
1192 return;
1193 }
1194 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1195 EcmaOpcode::CALLARG0_IMM8));
1196 LowerTypedCall(gate, func, actualArgc, funcType, 0);
1197 }
1198
LowerTypedCallArg1(GateRef gate)1199 void TSHCRLowering::LowerTypedCallArg1(GateRef gate)
1200 {
1201 GateRef func = acc_.GetValueIn(gate, 1);
1202 GateType funcType = acc_.GetGateType(func);
1203 if (!tsManager_->IsFunctionTypeKind(funcType)) {
1204 return;
1205 }
1206 GateRef a0Value = acc_.GetValueIn(gate, 0);
1207 GateType a0Type = acc_.GetGateType(a0Value);
1208 BuiltinsStubCSigns::ID id = GetBuiltinId(BuiltinTypeId::MATH, func);
1209 if (id != BuiltinsStubCSigns::ID::NONE && a0Type.IsNumberType()) {
1210 AddProfiling(gate);
1211 SpeculateCallBuiltin(gate, func, a0Value, id);
1212 } else {
1213 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1214 EcmaOpcode::CALLARG1_IMM8_V8));
1215 LowerTypedCall(gate, func, actualArgc, funcType, 1);
1216 }
1217 }
1218
LowerTypedCallArg2(GateRef gate)1219 void TSHCRLowering::LowerTypedCallArg2(GateRef gate)
1220 {
1221 GateRef func = acc_.GetValueIn(gate, 2); // 2:function
1222 GateType funcType = acc_.GetGateType(func);
1223 if (!tsManager_->IsFunctionTypeKind(funcType)) {
1224 return;
1225 }
1226 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1227 EcmaOpcode::CALLARGS2_IMM8_V8_V8));
1228 LowerTypedCall(gate, func, actualArgc, funcType, 2); // 2: 2 params
1229 }
1230
LowerTypedCallArg3(GateRef gate)1231 void TSHCRLowering::LowerTypedCallArg3(GateRef gate)
1232 {
1233 GateRef func = acc_.GetValueIn(gate, 3); // 3:function
1234 GateType funcType = acc_.GetGateType(func);
1235 if (!tsManager_->IsFunctionTypeKind(funcType)) {
1236 return;
1237 }
1238 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1239 EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8));
1240 LowerTypedCall(gate, func, actualArgc, funcType, 3); // 3: 3 params
1241 }
1242
LowerTypedCallrange(GateRef gate)1243 void TSHCRLowering::LowerTypedCallrange(GateRef gate)
1244 {
1245 std::vector<GateRef> vec;
1246 std::vector<GateRef> vec1;
1247 size_t numArgs = acc_.GetNumValueIn(gate);
1248 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1249 EcmaOpcode::CALLRANGE_IMM8_IMM8_V8));
1250 const size_t callTargetIndex = 1; // acc
1251 size_t argc = numArgs - callTargetIndex;
1252 GateRef func = acc_.GetValueIn(gate, argc);
1253 GateType funcType = acc_.GetGateType(func);
1254 if (!tsManager_->IsFunctionTypeKind(funcType)) {
1255 return;
1256 }
1257 LowerTypedCall(gate, func, actualArgc, funcType, argc);
1258 }
1259
LowerTypedCall(GateRef gate,GateRef func,GateRef actualArgc,GateType funcType,uint32_t argc)1260 void TSHCRLowering::LowerTypedCall(GateRef gate, GateRef func, GateRef actualArgc, GateType funcType, uint32_t argc)
1261 {
1262 GlobalTSTypeRef funcGt = funcType.GetGTRef();
1263 uint32_t len = tsManager_->GetFunctionTypeLength(funcGt);
1264 GateRef newTarget = builder_.Undefined();
1265 GateRef thisObj = builder_.Undefined();
1266 std::vector<GateRef> argsFastCall { glue_, func, thisObj};
1267 std::vector<GateRef> args { glue_, actualArgc, func, newTarget, thisObj };
1268 for (uint32_t i = 0; i < argc; i++) {
1269 GateRef value = acc_.GetValueIn(gate, i);
1270 argsFastCall.emplace_back(value);
1271 args.emplace_back(value);
1272 }
1273 for (uint32_t i = argc; i < len; i++) {
1274 argsFastCall.emplace_back(builder_.Undefined());
1275 args.emplace_back(builder_.Undefined());
1276 }
1277 CheckCallTargetAndLowerCall(gate, func, funcGt, funcType, args, argsFastCall);
1278 }
1279
IsLoadVtable(GateRef func)1280 bool TSHCRLowering::IsLoadVtable(GateRef func)
1281 {
1282 auto op = acc_.GetOpCode(func);
1283 if (op != OpCode::LOAD_PROPERTY || !acc_.IsVtable(func)) {
1284 return false;
1285 }
1286 return true;
1287 }
1288
CanOptimizeAsFastCall(GateRef func)1289 bool TSHCRLowering::CanOptimizeAsFastCall(GateRef func)
1290 {
1291 GateType funcType = acc_.GetGateType(func);
1292 if (!tsManager_->IsFunctionTypeKind(funcType)) {
1293 return false;
1294 }
1295 auto op = acc_.GetOpCode(func);
1296 if (op != OpCode::LOAD_PROPERTY || !acc_.IsVtable(func)) {
1297 return false;
1298 }
1299 return true;
1300 }
1301
CheckFastCallThisCallTarget(GateRef gate,GateRef func,GlobalTSTypeRef funcGt,GateType funcType,bool isNoGC)1302 void TSHCRLowering::CheckFastCallThisCallTarget(GateRef gate, GateRef func, GlobalTSTypeRef funcGt,
1303 GateType funcType, bool isNoGC)
1304 {
1305 if (noCheck_) {
1306 return;
1307 }
1308 if (isNoGC) {
1309 auto methodOffset = tsManager_->GetFuncMethodOffset(funcGt);
1310 builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST_NOGC>(funcType,
1311 func, builder_.IntPtr(methodOffset), gate);
1312 } else {
1313 builder_.JSCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST>(funcType,
1314 func, gate);
1315 }
1316 }
1317
CheckCallThisCallTarget(GateRef gate,GateRef func,GlobalTSTypeRef funcGt,GateType funcType,bool isNoGC)1318 void TSHCRLowering::CheckCallThisCallTarget(GateRef gate, GateRef func, GlobalTSTypeRef funcGt,
1319 GateType funcType, bool isNoGC)
1320 {
1321 if (noCheck_) {
1322 return;
1323 }
1324 if (isNoGC) {
1325 auto methodOffset = tsManager_->GetFuncMethodOffset(funcGt);
1326 builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_NOGC>(funcType,
1327 func, builder_.IntPtr(methodOffset), gate);
1328 } else {
1329 builder_.JSCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS>(funcType,
1330 func, gate);
1331 }
1332 }
1333
CheckThisCallTargetAndLowerCall(GateRef gate,GateRef func,GlobalTSTypeRef funcGt,GateType funcType,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1334 void TSHCRLowering::CheckThisCallTargetAndLowerCall(GateRef gate, GateRef func, GlobalTSTypeRef funcGt,
1335 GateType funcType, const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1336 {
1337 if (!tsManager_->FastCallFlagIsVaild(funcGt)) {
1338 return;
1339 }
1340 bool isNoGC = tsManager_->IsNoGC(funcGt);
1341 if (tsManager_->CanFastCall(funcGt)) {
1342 CheckFastCallThisCallTarget(gate, func, funcGt, funcType, isNoGC);
1343 LowerFastCall(gate, func, argsFastCall, isNoGC);
1344 } else {
1345 CheckCallThisCallTarget(gate, func, funcGt, funcType, isNoGC);
1346 LowerCall(gate, func, args, isNoGC);
1347 }
1348 }
1349
LowerTypedCallthis0(GateRef gate)1350 void TSHCRLowering::LowerTypedCallthis0(GateRef gate)
1351 {
1352 // 2: number of value inputs
1353 ASSERT(acc_.GetNumValueIn(gate) == 2);
1354 GateRef func = acc_.GetValueIn(gate, 1);
1355 if (!CanOptimizeAsFastCall(func)) {
1356 return;
1357 }
1358 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1359 EcmaOpcode::CALLTHIS0_IMM8_V8));
1360 LowerTypedThisCall(gate, func, actualArgc, 0);
1361 }
1362
LowerTypedCallthis1(GateRef gate)1363 void TSHCRLowering::LowerTypedCallthis1(GateRef gate)
1364 {
1365 // 3: number of value inputs
1366 ASSERT(acc_.GetNumValueIn(gate) == 3);
1367 GateRef a0 = acc_.GetValueIn(gate, 1); // 1:parameter index
1368 GateType a0Type = acc_.GetGateType(a0);
1369 GateRef func = acc_.GetValueIn(gate, 2); // 2:function
1370 BuiltinsStubCSigns::ID id = GetBuiltinId(BuiltinTypeId::MATH, func);
1371 if (id != BuiltinsStubCSigns::ID::NONE && a0Type.IsNumberType()) {
1372 AddProfiling(gate);
1373 SpeculateCallBuiltin(gate, func, a0, id);
1374 } else {
1375 if (!CanOptimizeAsFastCall(func)) {
1376 return;
1377 }
1378 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1379 EcmaOpcode::CALLTHIS1_IMM8_V8_V8));
1380 LowerTypedThisCall(gate, func, actualArgc, 1);
1381 }
1382 }
1383
LowerTypedCallthis2(GateRef gate)1384 void TSHCRLowering::LowerTypedCallthis2(GateRef gate)
1385 {
1386 // 4: number of value inputs
1387 ASSERT(acc_.GetNumValueIn(gate) == 4);
1388 GateRef func = acc_.GetValueIn(gate, 3); // 3: func
1389 if (!CanOptimizeAsFastCall(func)) {
1390 return;
1391 }
1392 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1393 EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8));
1394 LowerTypedThisCall(gate, func, actualArgc, 2); // 2: 2 params
1395 }
1396
LowerTypedCallthis3(GateRef gate)1397 void TSHCRLowering::LowerTypedCallthis3(GateRef gate)
1398 {
1399 // 5: number of value inputs
1400 ASSERT(acc_.GetNumValueIn(gate) == 5);
1401 GateRef func = acc_.GetValueIn(gate, 4); // 4: func
1402 BuiltinsStubCSigns::ID id = GetBuiltinId(BuiltinTypeId::STRING, func);
1403 if (id == BuiltinsStubCSigns::ID::LocaleCompare) {
1404 AddProfiling(gate);
1405 SpeculateCallThis3Builtin(gate, id);
1406 return;
1407 }
1408
1409 if (!CanOptimizeAsFastCall(func)) {
1410 return;
1411 }
1412 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1413 EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8));
1414 LowerTypedThisCall(gate, func, actualArgc, 3); // 3: 3 params
1415 }
1416
LowerTypedThisCall(GateRef gate,GateRef func,GateRef actualArgc,uint32_t argc)1417 void TSHCRLowering::LowerTypedThisCall(GateRef gate, GateRef func, GateRef actualArgc, uint32_t argc)
1418 {
1419 GateType funcType = acc_.GetGateType(func);
1420 GlobalTSTypeRef funcGt = funcType.GetGTRef();
1421 uint32_t len = tsManager_->GetFunctionTypeLength(funcGt);
1422 GateRef newTarget = builder_.Undefined();
1423 GateRef thisObj = acc_.GetValueIn(gate, 0);
1424 std::vector<GateRef> argsFastCall { glue_, func, thisObj};
1425 std::vector<GateRef> args { glue_, actualArgc, func, newTarget, thisObj };
1426 for (uint32_t i = 0; i < argc; i++) {
1427 GateRef value = acc_.GetValueIn(gate, i + 1);
1428 argsFastCall.emplace_back(value);
1429 args.emplace_back(value);
1430 }
1431 for (uint32_t i = argc; i < len; i++) {
1432 argsFastCall.emplace_back(builder_.Undefined());
1433 args.emplace_back(builder_.Undefined());
1434 }
1435 CheckThisCallTargetAndLowerCall(gate, func, funcGt, funcType, args, argsFastCall);
1436 }
1437
1438
LowerTypedCallthisrange(GateRef gate)1439 void TSHCRLowering::LowerTypedCallthisrange(GateRef gate)
1440 {
1441 // this
1442 size_t fixedInputsNum = 1;
1443 ASSERT(acc_.GetNumValueIn(gate) - fixedInputsNum >= 0);
1444 size_t numIns = acc_.GetNumValueIn(gate);
1445 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1446 EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8));
1447 const size_t callTargetIndex = 1; // 1: acc
1448 GateRef func = acc_.GetValueIn(gate, numIns - callTargetIndex); // acc
1449 if (!CanOptimizeAsFastCall(func)) {
1450 return;
1451 }
1452 LowerTypedThisCall(gate, func, actualArgc, numIns - callTargetIndex - fixedInputsNum);
1453 }
1454
AddProfiling(GateRef gate)1455 void TSHCRLowering::AddProfiling(GateRef gate)
1456 {
1457 hitTypedOpCount_++;
1458 AddHitBytecodeCount();
1459 if (IsTraceBC()) {
1460 // see stateSplit as a part of JSByteCode if exists
1461 GateRef maybeStateSplit = acc_.GetDep(gate);
1462 GateRef current = Circuit::NullGate();
1463 if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
1464 current = maybeStateSplit;
1465 } else {
1466 current = gate;
1467 }
1468
1469 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
1470 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
1471 GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
1472 GateRef typedPath = builder_.Int32ToTaggedInt(builder_.Int32(1));
1473 GateRef traceGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(current),
1474 { constOpcode, typedPath }, gate);
1475 acc_.SetDep(current, traceGate);
1476 builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: trace or STATE_SPLIT
1477 }
1478
1479 if (IsProfiling()) {
1480 // see stateSplit as a part of JSByteCode if exists
1481 GateRef maybeStateSplit = acc_.GetDep(gate);
1482 GateRef current = Circuit::NullGate();
1483 if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
1484 current = maybeStateSplit;
1485 } else {
1486 current = gate;
1487 }
1488
1489 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
1490 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
1491 GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
1492 GateRef mode =
1493 builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::TYPED_PATH)));
1494 GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current),
1495 { constOpcode, mode }, gate);
1496 acc_.SetDep(current, profiling);
1497 builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: profiling or STATE_SPLIT
1498 }
1499 }
1500
AddBytecodeCount(EcmaOpcode op)1501 void TSHCRLowering::AddBytecodeCount(EcmaOpcode op)
1502 {
1503 currentOp_ = op;
1504 if (bytecodeMap_.find(op) != bytecodeMap_.end()) {
1505 bytecodeMap_[op]++;
1506 } else {
1507 bytecodeMap_[op] = 1;
1508 }
1509 }
1510
DeleteBytecodeCount(EcmaOpcode op)1511 void TSHCRLowering::DeleteBytecodeCount(EcmaOpcode op)
1512 {
1513 bytecodeMap_.erase(op);
1514 }
1515
AddHitBytecodeCount()1516 void TSHCRLowering::AddHitBytecodeCount()
1517 {
1518 if (bytecodeHitTimeMap_.find(currentOp_) != bytecodeHitTimeMap_.end()) {
1519 bytecodeHitTimeMap_[currentOp_]++;
1520 } else {
1521 bytecodeHitTimeMap_[currentOp_] = 1;
1522 }
1523 }
1524 } // namespace panda::ecmascript
1525