1 /*
2 * Copyright (c) 2022-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
17 #include "ecmascript/compiler/typed_bytecode_lowering.h"
18
19 #include "ecmascript/compiler/circuit_builder_helper.h"
20 #include "ecmascript/compiler/variable_type.h"
21 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
22 #include "ecmascript/jit/jit.h"
23 #include "ecmascript/js_object-inl.h"
24 #include "ecmascript/js_tagged_value.h"
25 #include "ecmascript/js_tagged_value_internals.h"
26
27 namespace panda::ecmascript::kungfu {
RunTypedBytecodeLowering()28 void TypedBytecodeLowering::RunTypedBytecodeLowering()
29 {
30 std::vector<GateRef> gateList;
31 circuit_->GetAllGates(gateList);
32 ParseOptBytecodeRange();
33 for (const auto &gate : gateList) {
34 auto op = acc_.GetOpCode(gate);
35 if (op == OpCode::JS_BYTECODE) {
36 Lower(gate);
37 }
38 }
39
40 if (IsTypeLogEnabled()) {
41 pgoTypeLog_.PrintPGOTypeLog();
42 }
43
44 if (IsLogEnabled()) {
45 LOG_COMPILER(INFO) << "";
46 LOG_COMPILER(INFO) << "\033[34m"
47 << "===================="
48 << " After TypedBytecodeLowering "
49 << "[" << GetMethodName() << "]"
50 << "===================="
51 << "\033[0m";
52 for (auto a : bytecodeMap_) {
53 if (bytecodeHitTimeMap_.find(a.first) != bytecodeHitTimeMap_.end()) {
54 double rate = static_cast<double>(bytecodeHitTimeMap_[a.first]) / static_cast<double>(a.second);
55 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
56 << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(rate)
57 << "(" << std::to_string(bytecodeHitTimeMap_[a.first])
58 << " / " << std::to_string(a.second) << ")"
59 << " ===========================" << "\033[0m";
60 } else {
61 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
62 << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(0)
63 << "(" << std::to_string(0)
64 << " / " << std::to_string(a.second) << ")"
65 << " ===========================" << "\033[0m";
66 }
67 }
68 }
69 }
70
ParseOptBytecodeRange()71 void TypedBytecodeLowering::ParseOptBytecodeRange()
72 {
73 std::vector<std::string> splitStrs = base::StringHelper::SplitString(optBCRange_, ",");
74 for (const auto &optBCRange : splitStrs) {
75 std::vector<std::string> splitRange = base::StringHelper::SplitString(optBCRange, ":");
76 // 2:Used to determine whether the size of the split string array splitRange is as expected.
77 if (splitRange.size() == 2) {
78 std::vector<int32_t> range;
79 std::string start = splitRange[0];
80 std::string end = splitRange[1];
81 uint32_t startNumber = std::strtoull(start.c_str(), nullptr, 10);
82 uint32_t endNumber = std::strtoull(end.c_str(), nullptr, 10);
83 range.push_back(static_cast<int32_t>(startNumber));
84 range.push_back(static_cast<int32_t>(endNumber));
85 optBCRangeList_.push_back(range);
86 }
87 }
88 }
89
CheckIsInOptBCIgnoreRange(int32_t index,EcmaOpcode ecmaOpcode)90 bool TypedBytecodeLowering::CheckIsInOptBCIgnoreRange(int32_t index, EcmaOpcode ecmaOpcode)
91 {
92 for (std::vector<int32_t> range : optBCRangeList_) {
93 if (index >= range[0] && index <= range[1]) {
94 LOG_COMPILER(INFO) << "TypedBytecodeLowering ignore opcode:" << GetEcmaOpcodeStr(ecmaOpcode);
95 return true;
96 }
97 }
98 return false;
99 }
100
Lower(GateRef gate)101 void TypedBytecodeLowering::Lower(GateRef gate)
102 {
103 [[maybe_unused]] auto scopedGate = circuit_->VisitGateBegin(gate);
104 // not all opcode will visit heap, but now jit lock all opcode
105 Jit::JitLockHolder lock(compilationEnv_, "TypedBytecodeLowering::Lower");
106
107 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
108 // initialize label manager
109 Environment env(gate, circuit_, &builder_);
110 AddBytecodeCount(ecmaOpcode);
111 // The order in the switch is referred to in ecmascript/compiler/ecma_opcode_des.h
112 int32_t index = GetEcmaOpCodeListIndex(ecmaOpcode);
113 if (optBCRangeList_.size() > 0 && CheckIsInOptBCIgnoreRange(index, ecmaOpcode)) {
114 DeleteBytecodeCount(ecmaOpcode);
115 allNonTypedOpCount_++;
116 return;
117 }
118 switch (ecmaOpcode) {
119 case EcmaOpcode::GETITERATOR_IMM8:
120 case EcmaOpcode::GETITERATOR_IMM16:
121 LowerGetIterator(gate);
122 break;
123 case EcmaOpcode::CREATEEMPTYOBJECT:
124 LowerCreateEmptyObject(gate);
125 break;
126 case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
127 case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM16_ID16:
128 LowerCreateObjectWithBuffer(gate);
129 break;
130 case EcmaOpcode::ADD2_IMM8_V8:
131 LowerTypedBinOp<TypedBinOp::TYPED_ADD>(gate);
132 break;
133 case EcmaOpcode::SUB2_IMM8_V8:
134 LowerTypedBinOp<TypedBinOp::TYPED_SUB>(gate);
135 break;
136 case EcmaOpcode::MUL2_IMM8_V8:
137 LowerTypedBinOp<TypedBinOp::TYPED_MUL>(gate);
138 break;
139 case EcmaOpcode::DIV2_IMM8_V8:
140 LowerTypedBinOp<TypedBinOp::TYPED_DIV>(gate);
141 break;
142 case EcmaOpcode::MOD2_IMM8_V8:
143 LowerTypedBinOp<TypedBinOp::TYPED_MOD>(gate);
144 break;
145 case EcmaOpcode::EQ_IMM8_V8:
146 LowerTypedEqOrNotEq<TypedBinOp::TYPED_EQ>(gate);
147 break;
148 case EcmaOpcode::NOTEQ_IMM8_V8:
149 LowerTypedEqOrNotEq<TypedBinOp::TYPED_NOTEQ>(gate);
150 break;
151 case EcmaOpcode::LESS_IMM8_V8:
152 LowerTypedBinOp<TypedBinOp::TYPED_LESS>(gate);
153 break;
154 case EcmaOpcode::LESSEQ_IMM8_V8:
155 LowerTypedBinOp<TypedBinOp::TYPED_LESSEQ>(gate);
156 break;
157 case EcmaOpcode::GREATER_IMM8_V8:
158 LowerTypedBinOp<TypedBinOp::TYPED_GREATER>(gate);
159 break;
160 case EcmaOpcode::GREATEREQ_IMM8_V8:
161 LowerTypedBinOp<TypedBinOp::TYPED_GREATEREQ>(gate);
162 break;
163 case EcmaOpcode::SHL2_IMM8_V8:
164 LowerTypedBinOp<TypedBinOp::TYPED_SHL>(gate);
165 break;
166 case EcmaOpcode::SHR2_IMM8_V8:
167 LowerTypedBinOp<TypedBinOp::TYPED_SHR>(gate);
168 break;
169 case EcmaOpcode::ASHR2_IMM8_V8:
170 LowerTypedBinOp<TypedBinOp::TYPED_ASHR>(gate);
171 break;
172 case EcmaOpcode::AND2_IMM8_V8:
173 LowerTypedBinOp<TypedBinOp::TYPED_AND>(gate);
174 break;
175 case EcmaOpcode::OR2_IMM8_V8:
176 LowerTypedBinOp<TypedBinOp::TYPED_OR>(gate);
177 break;
178 case EcmaOpcode::XOR2_IMM8_V8:
179 LowerTypedBinOp<TypedBinOp::TYPED_XOR>(gate);
180 break;
181 case EcmaOpcode::TYPEOF_IMM8:
182 case EcmaOpcode::TYPEOF_IMM16:
183 LowerTypedTypeOf(gate);
184 break;
185 case EcmaOpcode::TONUMERIC_IMM8:
186 LowerTypeToNumeric(gate);
187 break;
188 case EcmaOpcode::NEG_IMM8:
189 LowerTypedUnOp<TypedUnOp::TYPED_NEG>(gate);
190 break;
191 case EcmaOpcode::NOT_IMM8:
192 LowerTypedUnOp<TypedUnOp::TYPED_NOT>(gate);
193 break;
194 case EcmaOpcode::INC_IMM8:
195 LowerTypedUnOp<TypedUnOp::TYPED_INC>(gate);
196 break;
197 case EcmaOpcode::DEC_IMM8:
198 LowerTypedUnOp<TypedUnOp::TYPED_DEC>(gate);
199 break;
200 case EcmaOpcode::INSTANCEOF_IMM8_V8:
201 LowerInstanceOf(gate);
202 break;
203 case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
204 LowerTypedEqOrNotEq<TypedBinOp::TYPED_STRICTNOTEQ>(gate);
205 break;
206 case EcmaOpcode::STRICTEQ_IMM8_V8:
207 LowerTypedEqOrNotEq<TypedBinOp::TYPED_STRICTEQ>(gate);
208 break;
209 case EcmaOpcode::ISTRUE:
210 case EcmaOpcode::CALLRUNTIME_ISTRUE_PREF_IMM8:
211 LowerTypedIsTrueOrFalse(gate, true);
212 break;
213 case EcmaOpcode::ISFALSE:
214 case EcmaOpcode::CALLRUNTIME_ISFALSE_PREF_IMM8:
215 LowerTypedIsTrueOrFalse(gate, false);
216 break;
217 case EcmaOpcode::CALLARG0_IMM8:
218 LowerTypedCallArg0(gate);
219 break;
220 case EcmaOpcode::CALLARG1_IMM8_V8:
221 LowerTypedCallArg1(gate);
222 break;
223 case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
224 LowerTypedCallArg2(gate);
225 break;
226 case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
227 LowerTypedCallArg3(gate);
228 break;
229 case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
230 LowerTypedCallrange(gate);
231 break;
232 case EcmaOpcode::CALLTHIS0_IMM8_V8:
233 LowerTypedCallthis0(gate);
234 break;
235 case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
236 LowerTypedCallthis1(gate);
237 break;
238 case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
239 LowerTypedCallthis2(gate);
240 break;
241 case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
242 LowerTypedCallthis3(gate);
243 break;
244 case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
245 LowerTypedCallthisrange(gate);
246 break;
247 case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8:
248 LowerTypedCallInit(gate);
249 break;
250 case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
251 case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
252 LowerTypedSuperCall(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::STPRIVATEPROPERTY_IMM8_IMM16_IMM16_V8:
260 LowerTypedStPrivateProperty(gate);
261 break;
262 case EcmaOpcode::LDPRIVATEPROPERTY_IMM8_IMM16_IMM16:
263 LowerTypedLdPrivateProperty(gate);
264 break;
265 case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
266 case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
267 case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
268 case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
269 LowerTypedLdObjByName(gate);
270 break;
271 case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
272 case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
273 case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
274 case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
275 case EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8:
276 case EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8:
277 LowerTypedStObjByName(gate);
278 break;
279 case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
280 case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
281 case EcmaOpcode::LDTHISBYVALUE_IMM8:
282 case EcmaOpcode::LDTHISBYVALUE_IMM16:
283 LowerTypedLdObjByValue(gate);
284 break;
285 case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
286 case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
287 LowerTypedStObjByValue(gate);
288 break;
289 case EcmaOpcode::STOWNBYVALUE_IMM8_V8_V8:
290 case EcmaOpcode::STOWNBYVALUE_IMM16_V8_V8:
291 LowerTypedStOwnByValue(gate);
292 break;
293 case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
294 case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
295 case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
296 LowerTypedLdObjByIndex(gate);
297 break;
298 case EcmaOpcode::STOBJBYINDEX_IMM8_V8_IMM16:
299 case EcmaOpcode::STOBJBYINDEX_IMM16_V8_IMM16:
300 case EcmaOpcode::WIDE_STOBJBYINDEX_PREF_V8_IMM32:
301 LowerTypedStObjByIndex(gate);
302 break;
303 case EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16:
304 case EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16:
305 LowerTypedTryLdGlobalByName(gate);
306 break;
307 case EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8:
308 case EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8:
309 LowerTypedStOwnByName(gate);
310 break;
311 case EcmaOpcode::JEQZ_IMM8:
312 case EcmaOpcode::JEQZ_IMM16:
313 case EcmaOpcode::JEQZ_IMM32:
314 LowerConditionJump(gate, false);
315 break;
316 case EcmaOpcode::JNEZ_IMM8:
317 case EcmaOpcode::JNEZ_IMM16:
318 case EcmaOpcode::JNEZ_IMM32:
319 LowerConditionJump(gate, true);
320 break;
321 default:
322 DeleteBytecodeCount(ecmaOpcode);
323 allNonTypedOpCount_++;
324 break;
325 }
326 }
327
GetEcmaOpCodeListIndex(EcmaOpcode ecmaOpCode)328 int32_t TypedBytecodeLowering::GetEcmaOpCodeListIndex(EcmaOpcode ecmaOpCode)
329 {
330 std::vector<EcmaOpcode> opcodeList = GetEcmaCodeListForRange();
331 int32_t index = static_cast<int32_t>(opcodeList.size());
332 int32_t size = static_cast<int32_t>(opcodeList.size());
333 for (int32_t i = 0; i < size; i++) {
334 if (opcodeList[i] == ecmaOpCode) {
335 index = i;
336 break;
337 }
338 }
339 if (index != size) {
340 return index;
341 } else {
342 return -1;
343 }
344 }
345
346 template<TypedBinOp Op>
LowerTypedBinOp(GateRef gate)347 void TypedBytecodeLowering::LowerTypedBinOp(GateRef gate)
348 {
349 BinOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
350 if (Op == TypedBinOp::TYPED_SHR && tacc.GetParamType().IsIntOverflowType()) {
351 return;
352 }
353 if (tacc.HasNumberType()) {
354 SpeculateNumbers<Op>(tacc);
355 } else if (tacc.IsInternStringType()) {
356 SpeculateInternStrings<Op>(tacc);
357 } else if (tacc.IsStringType()) {
358 SpeculateStrings<Op>(tacc);
359 }
360 }
361
362 template<TypedUnOp Op>
LowerTypedUnOp(GateRef gate)363 void TypedBytecodeLowering::LowerTypedUnOp(GateRef gate)
364 {
365 UnOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
366 // NOTICE-PGO: wx add support for PrimitiveNumberType
367 if (Op == TypedUnOp::TYPED_NEG && tacc.GetParamType().IsIntOverflowType()) {
368 return;
369 }
370 if (tacc.HasNumberType()) {
371 SpeculateNumber<Op>(tacc);
372 }
373 }
374
375 template<TypedBinOp Op>
LowerTypedEqOrNotEq(GateRef gate)376 void TypedBytecodeLowering::LowerTypedEqOrNotEq(GateRef gate)
377 {
378 BinOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
379 if (tacc.LeftOrRightIsUndefinedOrNull()) {
380 AddProfiling(gate);
381 GateRef left = tacc.GetLeftGate();
382 GateRef right = tacc.GetReightGate();
383 GateRef result = builder_.TypedBinaryOp<Op>(left, right, tacc.GetParamType());
384 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
385 } else {
386 LowerTypedBinOp<Op>(gate);
387 }
388 }
389
InternStringCheck(GateRef value)390 GateRef TypedBytecodeLowering::InternStringCheck(GateRef value)
391 {
392 // Marking a string as an Intern String is a runtime behavior.
393 // The tag of Intern String in JIT process will not become invalid and can be used during compilation.
394 if (compilationEnv_->IsJitCompiler()) {
395 // We believe that the Intern String tag of a constant string will not change during interpreted execution,
396 // JIT compilation, and JIT code execution. Therefore, the check for the constant Intern String can be removed
397 // during JIT compilation.
398 JSTaggedValue stringObject = JSTaggedValue::Undefined();
399 if (acc_.GetOpCode(value) == OpCode::JS_BYTECODE && acc_.GetByteCodeOpcode(value) == EcmaOpcode::LDA_STR_ID16) {
400 uint16_t stringIndex = acc_.GetConstantValue(acc_.GetValueIn(value, 0));
401 auto methodOffset = acc_.TryGetMethodOffset(value);
402 stringObject = compilationEnv_->GetStringFromConstantPool(methodOffset, stringIndex);
403 }
404 if (stringObject.IsHeapObject()) {
405 EcmaString* ecmaString = EcmaString::Cast(stringObject.GetTaggedObject());
406 EcmaStringAccessor ecmaStringAccessor(ecmaString);
407 if (ecmaStringAccessor.IsInternString()) {
408 return builder_.True();
409 }
410 }
411 }
412 return builder_.InternStringCheck(value);
413 }
414
415 template<TypedBinOp Op>
SpeculateInternStrings(const BinOpTypeInfoAccessor & tacc)416 void TypedBytecodeLowering::SpeculateInternStrings(const BinOpTypeInfoAccessor &tacc)
417 {
418 if (Op != TypedBinOp::TYPED_STRICTEQ && Op != TypedBinOp::TYPED_STRICTNOTEQ) {
419 SpeculateStrings<Op>(tacc);
420 return;
421 }
422 AddProfiling(tacc.GetGate());
423 GateRef left = tacc.GetLeftGate();
424 GateRef right = tacc.GetReightGate();
425 InternStringCheck(left);
426 InternStringCheck(right);
427 GateRef result = builder_.TypedBinaryOp<Op>(left, right, tacc.GetParamType());
428 acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
429 }
430
431 template<TypedBinOp Op>
SpeculateStrings(const BinOpTypeInfoAccessor & tacc)432 void TypedBytecodeLowering::SpeculateStrings(const BinOpTypeInfoAccessor &tacc)
433 {
434 if (Op == TypedBinOp::TYPED_EQ || Op == TypedBinOp::TYPED_ADD) {
435 AddProfiling(tacc.GetGate());
436 GateRef left = tacc.GetLeftGate();
437 GateRef right = tacc.GetReightGate();
438 if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, left)) {
439 if (!Uncheck()) {
440 builder_.EcmaStringCheck(left);
441 }
442 }
443 if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, right)) {
444 if (!Uncheck()) {
445 builder_.EcmaStringCheck(right);
446 }
447 }
448 GateRef result = builder_.TypedBinaryOp<Op>(left, right, tacc.GetParamType());
449 acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
450 }
451 }
452
453 template<TypedBinOp Op>
SpeculateNumbers(const BinOpTypeInfoAccessor & tacc)454 void TypedBytecodeLowering::SpeculateNumbers(const BinOpTypeInfoAccessor &tacc)
455 {
456 AddProfiling(tacc.GetGate());
457 pgoTypeLog_.CollectGateTypeLogInfo(tacc.GetGate(), true);
458 GateRef left = tacc.GetLeftGate();
459 GateRef right = tacc.GetReightGate();
460 GateRef result = builder_.TypedBinaryOp<Op>(left, right, tacc.GetParamType());
461 acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
462 }
463
464 template<TypedUnOp Op>
SpeculateNumber(const UnOpTypeInfoAccessor & tacc)465 void TypedBytecodeLowering::SpeculateNumber(const UnOpTypeInfoAccessor &tacc)
466 {
467 AddProfiling(tacc.GetGate());
468 pgoTypeLog_.CollectGateTypeLogInfo(tacc.GetGate(), false);
469 GateRef result = builder_.TypedUnaryOp<Op>(tacc.GetValue(), tacc.GetParamType());
470 acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
471 }
472
CheckedNumberToString(CircuitBuilder * builder,GateRef numOrStr,Label * exit)473 GateRef CheckedNumberToString(CircuitBuilder *builder, GateRef numOrStr, Label *exit)
474 {
475 auto isNum = builder->TaggedIsNumber(numOrStr);
476 Label numberBranch(builder);
477 Label notNumberBranch(builder);
478
479 DEFVALUE(res, builder, VariableType::JS_ANY(), numOrStr);
480 builder->Branch(isNum, &numberBranch, ¬NumberBranch, BranchWeight::ONE_WEIGHT, BranchWeight::ONE_WEIGHT,
481 "IsNumber");
482 builder->Bind(&numberBranch);
483 {
484 res = builder->NumberToString(numOrStr);
485 builder->Jump(exit);
486 }
487 builder->Bind(¬NumberBranch);
488 {
489 builder->EcmaStringCheck(numOrStr);
490 res = numOrStr;
491 builder->Jump(exit);
492 }
493 builder->Bind(exit);
494
495 return *res;
496 }
497
498 template<TypedBinOp Op>
SpeculateNumbersOrString(const BinOpTypeInfoAccessor & tacc)499 void TypedBytecodeLowering::SpeculateNumbersOrString(const BinOpTypeInfoAccessor &tacc)
500 {
501 if (Op == TypedBinOp::TYPED_ADD) {
502 AddProfiling(tacc.GetGate());
503 GateRef left = tacc.GetLeftGate();
504 GateRef right = tacc.GetReightGate();
505
506 Label exit(&builder_);
507 if (TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, left)) {
508 right = CheckedNumberToString(&builder_, right, &exit);
509 ASSERT(tacc.GetParamType() == ParamType::StringType());
510 GateRef result = builder_.TypedBinaryOp<Op>(left, right, ParamType::StringType());
511 acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
512 } else if (TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, right)) {
513 left = CheckedNumberToString(&builder_, left, &exit);
514 ASSERT(tacc.GetParamType() == ParamType::StringType());
515 GateRef result = builder_.TypedBinaryOp<Op>(left, right, ParamType::StringType());
516 acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
517 }
518 }
519 }
520
LowerTypeToNumeric(GateRef gate)521 void TypedBytecodeLowering::LowerTypeToNumeric(GateRef gate)
522 {
523 UnOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
524 if (tacc.HasNumberType()) {
525 AddProfiling(gate);
526 LowerPrimitiveTypeToNumber(tacc);
527 }
528 }
529
LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor & tacc)530 void TypedBytecodeLowering::LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor &tacc)
531 {
532 GateRef result = builder_.PrimitiveToNumber(tacc.GetValue(), tacc.GetParamType());
533 acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
534 }
535
LowerConditionJump(GateRef gate,bool flag)536 void TypedBytecodeLowering::LowerConditionJump(GateRef gate, bool flag)
537 {
538 ConditionJumpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
539 if (TypeInfoAccessor::IsTrustedBooleanType(acc_, tacc.GetValue())) {
540 AddProfiling(gate);
541 SpeculateConditionJump(tacc, flag);
542 }
543 }
544
SpeculateConditionJump(const ConditionJumpTypeInfoAccessor & tacc,bool flag)545 void TypedBytecodeLowering::SpeculateConditionJump(const ConditionJumpTypeInfoAccessor &tacc, bool flag)
546 {
547 GateRef value = tacc.GetValue();
548 ParamType paramType = ParamType::BooleanType();
549 uint32_t weight = tacc.GetBranchWeight();
550 GateRef jump = Circuit::NullGate();
551 if (flag) {
552 jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JNEZ>(value, paramType, weight);
553 } else {
554 jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JEQZ>(value, paramType, weight);
555 }
556 acc_.ReplaceGate(tacc.GetGate(), jump, jump, Circuit::NullGate());
557 }
558
DeleteConstDataIfNoUser(GateRef gate)559 void TypedBytecodeLowering::DeleteConstDataIfNoUser(GateRef gate)
560 {
561 auto uses = acc_.Uses(gate);
562 if (uses.begin() == uses.end()) {
563 builder_.ClearConstantCache(gate);
564 acc_.DeleteGate(gate);
565 }
566 }
567
LowerTypedLdObjByName(GateRef gate)568 void TypedBytecodeLowering::LowerTypedLdObjByName(GateRef gate)
569 {
570 LoadObjByNameTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
571
572 if (TryLowerTypedLdobjBynameFromGloablBuiltin(gate)) {
573 return;
574 }
575 if (TryLowerTypedLdObjByNameForBuiltin(gate)) {
576 return;
577 }
578 if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
579 return;
580 }
581
582 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
583 size_t typeCount = tacc.GetTypeCount();
584 std::vector<Label> loaders;
585 std::vector<Label> fails;
586 ASSERT(typeCount > 0);
587 for (size_t i = 0; i < typeCount - 1; ++i) {
588 loaders.emplace_back(Label(&builder_));
589 fails.emplace_back(Label(&builder_));
590 }
591 Label exit(&builder_);
592 AddProfiling(gate);
593 GateRef frameState = acc_.GetFrameState(gate);
594 if (tacc.IsMono()) {
595 GateRef receiver = tacc.GetReceiver();
596 builder_.ObjectTypeCheck(false, receiver,
597 builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
598 if (tacc.IsReceiverEqHolder(0)) {
599 result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
600 } else {
601 builder_.ProtoChangeMarkerCheck(receiver, frameState);
602 PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
603 GateRef plrGate = builder_.Int32(plr.GetData());
604 GateRef unsharedConstPoool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
605 size_t holderHClassIndex = static_cast<size_t>(tacc.GetAccessInfo(0).HClassIndex());
606 if (LIKELY(!plr.IsAccessor())) {
607 result = builder_.MonoLoadPropertyOnProto(receiver, plrGate, unsharedConstPoool, holderHClassIndex);
608 } else {
609 result = builder_.MonoCallGetterOnProto(gate, receiver, plrGate, unsharedConstPoool, holderHClassIndex);
610 }
611 }
612 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
613 DeleteConstDataIfNoUser(tacc.GetKey());
614 return;
615 }
616 builder_.HeapObjectCheck(tacc.GetReceiver(), frameState);
617 auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), tacc.GetReceiver(),
618 TaggedObject::HCLASS_OFFSET);
619 for (size_t i = 0; i < typeCount; ++i) {
620 auto expected = builder_.GetHClassGateFromIndex(gate, tacc.GetExpectedHClassIndex(i));
621 if (i != typeCount - 1) {
622 BRANCH_CIR(builder_.Equal(receiverHC, expected), &loaders[i], &fails[i]);
623 builder_.Bind(&loaders[i]);
624 } else {
625 // Deopt if fails at last hclass compare
626 builder_.DeoptCheck(builder_.Equal(receiverHC, expected), frameState, DeoptType::INCONSISTENTHCLASS1);
627 }
628
629 if (tacc.IsReceiverEqHolder(i)) {
630 result = BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
631 tacc.GetAccessInfo(i).Plr());
632 builder_.Jump(&exit);
633 } else {
634 // prototype change marker check
635 builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
636 // lookup from receiver for holder
637 auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
638 // lookup from receiver for holder
639 ObjectAccessTypeInfoAccessor::ObjectAccessInfo info = tacc.GetAccessInfo(i);
640 auto holderHC = builder_.GetHClassGateFromIndex(gate, info.HClassIndex());
641 DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
642 Label loopHead(&builder_);
643 Label loadHolder(&builder_);
644 Label lookUpProto(&builder_);
645 builder_.Jump(&loopHead);
646
647 builder_.LoopBegin(&loopHead);
648 builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS2);
649 auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET);
650 BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
651
652 builder_.Bind(&lookUpProto);
653 current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
654 builder_.LoopEnd(&loopHead);
655
656 builder_.Bind(&loadHolder);
657 result = BuildNamedPropertyAccess(gate, tacc.GetReceiver(), *current, tacc.GetAccessInfo(i).Plr());
658 builder_.Jump(&exit);
659 }
660 if (i != typeCount - 1) {
661 builder_.Bind(&fails[i]);
662 }
663 }
664 builder_.Bind(&exit);
665 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
666 DeleteConstDataIfNoUser(tacc.GetKey());
667 }
668
LowerTypedLdPrivateProperty(GateRef gate)669 void TypedBytecodeLowering::LowerTypedLdPrivateProperty(GateRef gate)
670 {
671 LoadPrivatePropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
672
673 if (tacc.HasIllegalType()) {
674 return;
675 }
676
677 AddProfiling(gate);
678 Label exit(&builder_);
679
680 GateRef receiver = tacc.GetReceiver();
681 GateRef levelIndex = tacc.GetLevelIndex();
682 GateRef slotIndex = tacc.GetSlotIndex();
683
684 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
685 GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
686 GateRef key = builder_.GetKeyFromLexivalEnv(
687 tacc.GetLexicalEnv(), builder_.TaggedGetInt(levelIndex), builder_.TaggedGetInt(slotIndex));
688
689 builder_.HeapObjectCheck(key, frameState);
690 if (tacc.IsAccessor()) {
691 builder_.DeoptCheck(builder_.IsJSFunction(key), frameState, DeoptType::NOTJSFUNCTION);
692 result = builder_.CallPrivateGetter(gate, receiver, key);
693 builder_.Jump(&exit);
694 } else {
695 builder_.DeoptCheck(builder_.TaggedIsSymbol(key), frameState, DeoptType::NOTSYMBOL);
696 builder_.ObjectTypeCheck(false, receiver, builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
697 result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
698 builder_.Jump(&exit);
699 }
700
701 builder_.Bind(&exit);
702 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
703 DeleteConstDataIfNoUser(key);
704 }
705
LowerTypedStPrivateProperty(GateRef gate)706 void TypedBytecodeLowering::LowerTypedStPrivateProperty(GateRef gate)
707 {
708 StorePrivatePropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
709
710 if (tacc.HasIllegalType()) {
711 return;
712 }
713
714 AddProfiling(gate);
715 Label exit(&builder_);
716
717 GateRef receiver = tacc.GetReceiver();
718 GateRef levelIndex = tacc.GetLevelIndex();
719 GateRef slotIndex = tacc.GetSlotIndex();
720 GateRef value = tacc.GetValue();
721
722 GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
723 GateRef key = builder_.GetKeyFromLexivalEnv(
724 tacc.GetLexicalEnv(), builder_.TaggedGetInt(levelIndex), builder_.TaggedGetInt(slotIndex));
725
726 builder_.HeapObjectCheck(key, frameState);
727 if (tacc.IsAccessor()) {
728 builder_.DeoptCheck(builder_.IsJSFunction(key), frameState, DeoptType::NOTJSFUNCTION);
729 builder_.CallPrivateSetter(gate, receiver, key, value);
730 builder_.Jump(&exit);
731 } else {
732 builder_.DeoptCheck(builder_.TaggedIsSymbol(key), frameState, DeoptType::NOTSYMBOL);
733 builder_.ObjectTypeCheck(false, receiver, builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
734 BuildNamedPropertyAccess(
735 gate, receiver, receiver, value, tacc.GetAccessInfo(0).Plr(), tacc.GetExpectedHClassIndex(0));
736 builder_.Jump(&exit);
737 }
738
739 builder_.Bind(&exit);
740 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
741 DeleteConstDataIfNoUser(key);
742 }
743
LowerTypedStObjByName(GateRef gate)744 void TypedBytecodeLowering::LowerTypedStObjByName(GateRef gate)
745 {
746 StoreObjByNameTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
747 if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
748 return;
749 }
750 size_t typeCount = tacc.GetTypeCount();
751 std::vector<Label> loaders;
752 std::vector<Label> fails;
753 ASSERT(typeCount > 0);
754 for (size_t i = 0; i < typeCount - 1; ++i) {
755 loaders.emplace_back(Label(&builder_));
756 fails.emplace_back(Label(&builder_));
757 }
758 Label exit(&builder_);
759 AddProfiling(gate);
760 GateRef frameState = Circuit::NullGate();
761 auto opcode = acc_.GetByteCodeOpcode(gate);
762 // The framestate of Call and Accessor related instructions directives is placed on IR. Using the depend edge to
763 // climb up and find the nearest framestate for other instructions
764 if (opcode == EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8 ||
765 opcode == EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8) {
766 frameState = acc_.FindNearestFrameState(builder_.GetDepend());
767 } else if (opcode == EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8 ||
768 opcode == EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8 ||
769 opcode == EcmaOpcode::STTHISBYNAME_IMM8_ID16 ||
770 opcode == EcmaOpcode::STTHISBYNAME_IMM16_ID16 ||
771 opcode == EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8 ||
772 opcode == EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8) {
773 frameState = acc_.GetFrameState(gate);
774 } else {
775 UNREACHABLE();
776 }
777 if (tacc.IsMono()) {
778 GateRef receiver = tacc.GetReceiver();
779 builder_.ObjectTypeCheck(false, receiver,
780 builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
781 if (tacc.IsReceiverNoEqNewHolder(0)) {
782 builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
783 PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
784 GateRef plrGate = builder_.Int32(plr.GetData());
785 GateRef unsharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
786 size_t holderHClassIndex = static_cast<size_t>(tacc.GetAccessInfo(0).HClassIndex());
787 GateRef value = tacc.GetValue();
788 if (tacc.IsHolderEqNewHolder(0)) {
789 builder_.MonoStorePropertyLookUpProto(tacc.GetReceiver(), plrGate, unsharedConstPool, holderHClassIndex,
790 value);
791 } else {
792 builder_.MonoStoreProperty(tacc.GetReceiver(), plrGate, unsharedConstPool, holderHClassIndex, value,
793 builder_.TruncInt64ToInt32(tacc.GetKey()),
794 builder_.Boolean(tacc.IsPrototypeHclass(0)), frameState);
795 }
796 } else if (tacc.IsReceiverEqHolder(0)) {
797 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
798 tacc.GetValue(), tacc.GetAccessInfo(0).Plr(), tacc.GetExpectedHClassIndex(0));
799 }
800 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
801 DeleteConstDataIfNoUser(tacc.GetKey());
802 return;
803 }
804 builder_.HeapObjectCheck(tacc.GetReceiver(), frameState);
805 auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), tacc.GetReceiver(),
806 TaggedObject::HCLASS_OFFSET);
807 for (size_t i = 0; i < typeCount; ++i) {
808 auto expected = builder_.GetHClassGateFromIndex(gate, tacc.GetExpectedHClassIndex(i));
809 if (i != typeCount - 1) {
810 BRANCH_CIR(builder_.Equal(receiverHC, expected),
811 &loaders[i], &fails[i]);
812 builder_.Bind(&loaders[i]);
813 } else {
814 builder_.DeoptCheck(builder_.Equal(receiverHC, expected), frameState, DeoptType::INCONSISTENTHCLASS3);
815 }
816 if (tacc.IsReceiverNoEqNewHolder(i)) {
817 builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
818 if (tacc.IsHolderEqNewHolder(i)) {
819 // lookup from receiver for holder
820 auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC,
821 JSHClass::PROTOTYPE_OFFSET);
822 auto holderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
823 DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
824 Label loopHead(&builder_);
825 Label loadHolder(&builder_);
826 Label lookUpProto(&builder_);
827 builder_.Jump(&loopHead);
828
829 builder_.LoopBegin(&loopHead);
830 builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS4);
831 auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current,
832 TaggedObject::HCLASS_OFFSET);
833 BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
834
835 builder_.Bind(&lookUpProto);
836 current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
837 builder_.LoopEnd(&loopHead);
838
839 builder_.Bind(&loadHolder);
840 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), *current, tacc.GetValue(),
841 tacc.GetAccessInfo(i).Plr());
842 builder_.Jump(&exit);
843 } else {
844 TypedStObjByNameTransition(gate, receiverHC, frameState, exit, tacc, i);
845 }
846 } else if (tacc.IsReceiverEqHolder(i)) {
847 // Local
848 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
849 tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
850 builder_.Jump(&exit);
851 } else {
852 // find in prototype, same as transition
853 UNREACHABLE();
854 return;
855 }
856 if (i != typeCount - 1) {
857 // process fastpath for next type
858 builder_.Bind(&fails[i]);
859 }
860 }
861 builder_.Bind(&exit);
862 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
863 DeleteConstDataIfNoUser(tacc.GetKey());
864 }
865
TypedStObjByNameTransition(GateRef gate,GateRef receiverHC,GateRef frameState,Label & exit,StoreObjByNameTypeInfoAccessor & tacc,size_t i)866 void TypedBytecodeLowering::TypedStObjByNameTransition(GateRef gate, GateRef receiverHC, GateRef frameState,
867 Label &exit, StoreObjByNameTypeInfoAccessor &tacc, size_t i)
868 {
869 Label notProto(&builder_);
870 Label isProto(&builder_);
871 auto newHolderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
872 if (compilationEnv_->IsAotCompiler()) {
873 auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
874 builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype);
875 }
876 if (!tacc.IsPrototypeHclass(i)) {
877 builder_.DeoptCheck(builder_.BoolNot(builder_.IsPrototypeHClass(receiverHC)), frameState,
878 DeoptType::PROTOTYPECHANGED2);
879 } else {
880 builder_.Branch(builder_.IsPrototypeHClass(receiverHC), &isProto, ¬Proto,
881 BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "isPrototypeHClass");
882 builder_.Bind(&isProto);
883 GateRef propKey =
884 builder_.GetObjectByIndexFromConstPool(glue_, gate, frameState,
885 builder_.TruncInt64ToInt32(tacc.GetKey()), ConstPoolType::STRING);
886 builder_.CallRuntime(glue_, RTSTUB_ID(UpdateAOTHClass), Gate::InvalidGateRef,
887 { receiverHC, newHolderHC, propKey }, gate);
888 builder_.Jump(¬Proto);
889 builder_.Bind(¬Proto);
890 }
891 MemoryAttribute mAttr = MemoryAttribute::NeedBarrierAndAtomic();
892 builder_.StoreConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(), TaggedObject::HCLASS_OFFSET,
893 newHolderHC, mAttr);
894 if (!tacc.GetAccessInfo(i).Plr().IsInlinedProps()) {
895 auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(),
896 JSObject::PROPERTIES_OFFSET);
897 auto capacity = builder_.LoadConstOffset(VariableType::INT32(), properties, TaggedArray::LENGTH_OFFSET);
898 auto index = builder_.Int32(tacc.GetAccessInfo(i).Plr().GetOffset());
899 Label needExtend(&builder_);
900 Label notExtend(&builder_);
901 BRANCH_CIR(builder_.Int32UnsignedLessThan(index, capacity), ¬Extend, &needExtend);
902 builder_.Bind(¬Extend);
903 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(), tacc.GetValue(),
904 tacc.GetAccessInfo(i).Plr());
905 builder_.Jump(&exit);
906 builder_.Bind(&needExtend);
907 builder_.CallRuntime(glue_, RTSTUB_ID(PropertiesSetValue), Gate::InvalidGateRef,
908 { tacc.GetReceiver(), tacc.GetValue(), properties, builder_.Int32ToTaggedInt(capacity),
909 builder_.Int32ToTaggedInt(index) }, gate);
910 builder_.Jump(&exit);
911 } else {
912 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(), tacc.GetValue(),
913 tacc.GetAccessInfo(i).Plr());
914 builder_.Jump(&exit);
915 }
916 }
917
LowerTypedStOwnByName(GateRef gate)918 void TypedBytecodeLowering::LowerTypedStOwnByName(GateRef gate)
919 {
920 LowerTypedStObjByName(gate);
921 }
922
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,PropertyLookupResult plr)923 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
924 GateRef hir, GateRef receiver, GateRef holder, PropertyLookupResult plr)
925 {
926 GateRef plrGate = builder_.Int32(plr.GetData());
927 GateRef result = Circuit::NullGate();
928 if (LIKELY(!plr.IsAccessor())) {
929 result = builder_.LoadProperty(holder, plrGate, plr.IsFunction());
930 } else {
931 result = builder_.CallGetter(hir, receiver, holder, plrGate);
932 }
933 return result;
934 }
935
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,GateRef value,PropertyLookupResult plr,uint32_t receiverHClassIndex)936 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
937 GateRef hir, GateRef receiver, GateRef holder, GateRef value, PropertyLookupResult plr,
938 uint32_t receiverHClassIndex)
939 {
940 GateRef plrGate = builder_.Int32(plr.GetData());
941 GateRef result = Circuit::NullGate();
942 if (LIKELY(!plr.IsAccessor())) {
943 builder_.StoreProperty(receiver, plrGate, value, receiverHClassIndex);
944 } else {
945 builder_.CallSetter(hir, receiver, holder, plrGate, value);
946 }
947 return result;
948 }
949
TryLowerTypedLdObjByNameForBuiltin(GateRef gate)950 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate)
951 {
952 LoadBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
953 // Just supported mono.
954 if (tacc.IsMono()) {
955 if (tacc.IsBuiltinsType()) {
956 auto builtinsId = tacc.GetBuiltinsTypeId();
957 if (builtinsId.has_value()) {
958 if (TryLowerTypedLdObjByNameForBuiltin(tacc)) {
959 return true;
960 }
961 return TryLowerTypedLdObjByNameForBuiltinMethod(tacc, builtinsId.value());
962 }
963 } else if (tacc.IsGlobalsType()) {
964 auto globalsId = tacc.GetGlobalsId();
965 if (globalsId.has_value()) {
966 return TryLowerTypedLdObjByNameForGlobalsId(tacc, globalsId.value());
967 }
968 }
969 } else if (tacc.GetTypeCount() > 0) {
970 auto builtinsId = tacc.GetBuiltinsTypeId();
971 if (builtinsId.has_value()) {
972 return TryLowerTypedLdObjByNameForBuiltin(tacc);
973 }
974 }
975 return false; // No lowering performed
976 }
977
TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor & tacc)978 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor &tacc)
979 {
980 JSTaggedValue key = tacc.GetKeyTaggedValue();
981 if (key.IsUndefined()) {
982 return false;
983 }
984 EcmaString *propString = EcmaString::Cast(key.GetTaggedObject());
985 // (1) get length
986 EcmaString *lengthString =
987 EcmaString::Cast(compilationEnv_->GlobalConstants()->GetLengthString().GetTaggedObject());
988 if (propString == lengthString) {
989 if (tacc.IsBuiltinsArray()) {
990 LowerTypedLdArrayLength(tacc);
991 return true;
992 }
993 if (tacc.IsBuiltinsString()) {
994 LowerTypedLdStringLength(tacc);
995 return true;
996 }
997 if (tacc.IsBuiltinsTypeArray()) {
998 LowerTypedLdTypedArrayLength(tacc);
999 return true;
1000 }
1001 }
1002
1003 EcmaString *sizeString = EcmaString::Cast(compilationEnv_->GlobalConstants()->GetSizeString().GetTaggedObject());
1004 if (propString == sizeString) {
1005 if (tacc.IsBuiltinsMap()) {
1006 LowerTypedLdMapSize(tacc);
1007 return true;
1008 }
1009 }
1010
1011 // (2) other functions
1012 return false;
1013 }
1014
TryLowerTypedLdObjByNameForGlobalsId(const LoadBulitinObjTypeInfoAccessor & tacc,GlobalIndex globalsId)1015 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForGlobalsId(const LoadBulitinObjTypeInfoAccessor &tacc,
1016 GlobalIndex globalsId)
1017 {
1018 GateRef receiver = tacc.GetReceiver();
1019 GateRef gate = tacc.GetGate();
1020 JSTaggedValue key = tacc.GetKeyTaggedValue();
1021 if (key.IsUndefined()) {
1022 return false;
1023 }
1024 GateRef frameState = acc_.FindNearestFrameState(gate);
1025 if (globalsId.IsGlobalConstId()) {
1026 ConstantIndex index = static_cast<ConstantIndex>(globalsId.GetGlobalConstId());
1027 JSHClass *hclass = JSHClass::Cast(compilationEnv_->GlobalConstants()->GetGlobalConstantObject(
1028 static_cast<size_t>(index)).GetTaggedObject());
1029 PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1030 if (!plr.IsFound() || plr.IsAccessor()) {
1031 return false;
1032 }
1033 AddProfiling(gate);
1034 // 1. check hclass
1035 builder_.HeapObjectCheck(receiver, frameState);
1036 GateRef receiverHClass = builder_.LoadHClassByConstOffset(receiver);
1037 GateRef expectedHClass = builder_.GetGlobalConstantValue(index);
1038 builder_.DeoptCheck(builder_.Equal(receiverHClass, expectedHClass), frameState,
1039 DeoptType::INCONSISTENTHCLASS11);
1040 // 2. load property
1041 GateRef plrGate = builder_.Int32(plr.GetData());
1042 GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1043 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1044 DeleteConstDataIfNoUser(tacc.GetKey());
1045 return true;
1046 } else if (globalsId.IsGlobalEnvId()) { // ctor Hclass
1047 GlobalEnvField index = static_cast<GlobalEnvField>(globalsId.GetGlobalEnvId());
1048 JSHClass *hclass = JSHClass::Cast(compilationEnv_->GetGlobalEnv()->GetGlobalEnvObjectByIndex(
1049 static_cast<size_t>(index))->GetTaggedObject()->GetClass());
1050 PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1051 if (!plr.IsFound() || plr.IsAccessor()) {
1052 return false;
1053 }
1054 AddProfiling(gate);
1055 // 1. check hclass
1056 builder_.HeapObjectCheck(receiver, frameState);
1057 GateRef globalEnvObj = builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), static_cast<size_t>(index));
1058 builder_.DeoptCheck(builder_.Equal(receiver, globalEnvObj), frameState,
1059 DeoptType::INCONSISTENTHCLASS12);
1060 // 2. load property
1061 GateRef plrGate = builder_.Int32(plr.GetData());
1062 GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1063 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1064 DeleteConstDataIfNoUser(tacc.GetKey());
1065 return true;
1066 }
1067 return false;
1068 }
1069
TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)1070 bool TypedBytecodeLowering::TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)
1071 {
1072 LoadBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1073 GateRef receiver = tacc.GetReceiver();
1074 if (acc_.GetOpCode(receiver) != OpCode::LOAD_BUILTIN_OBJECT) {
1075 return false;
1076 }
1077 JSHandle<GlobalEnv> globalEnv = compilationEnv_->GetGlobalEnv();
1078 uint64_t index = acc_.TryGetValue(receiver);
1079 BuiltinType type = static_cast<BuiltinType>(index);
1080 if (type == BuiltinType::BT_MATH) {
1081 auto math = globalEnv->GetMathFunction();
1082 JSHClass *hclass = math.GetTaggedValue().GetTaggedObject()->GetClass();
1083 JSTaggedValue key = tacc.GetKeyTaggedValue();
1084 if (key.IsUndefined()) {
1085 return false;
1086 }
1087 PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1088 if (!plr.IsFound() || plr.IsAccessor()) {
1089 return false;
1090 }
1091 AddProfiling(gate);
1092 builder_.MathHClassConsistencyCheck(receiver);
1093 GateRef plrGate = builder_.Int32(plr.GetData());
1094 GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1095 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1096 DeleteConstDataIfNoUser(tacc.GetKey());
1097 return true;
1098 }
1099 return false;
1100 }
1101
LowerTypedLdArrayLength(const LoadBulitinObjTypeInfoAccessor & tacc)1102 void TypedBytecodeLowering::LowerTypedLdArrayLength(const LoadBulitinObjTypeInfoAccessor &tacc)
1103 {
1104 GateRef gate = tacc.GetGate();
1105 GateRef array = tacc.GetReceiver();
1106 ElementsKind kind = acc_.TryGetElementsKind(gate);
1107 AddProfiling(gate);
1108 if (!Uncheck()) {
1109 if (!acc_.IsCreateArray(array)) {
1110 builder_.StableArrayCheck(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1111 }
1112 }
1113
1114 GateRef result = builder_.LoadArrayLength(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1115 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1116 }
1117
LowerTypedLdTypedArrayLength(const LoadBulitinObjTypeInfoAccessor & tacc)1118 void TypedBytecodeLowering::LowerTypedLdTypedArrayLength(const LoadBulitinObjTypeInfoAccessor &tacc)
1119 {
1120 GateRef gate = tacc.GetGate();
1121 GateRef array = tacc.GetReceiver();
1122 AddProfiling(gate);
1123 ParamType arrayType = tacc.GetParamType();
1124 OnHeapMode onHeap = acc_.TryGetOnHeapMode(gate);
1125 if (!Uncheck()) {
1126 builder_.TypedArrayCheck(array, arrayType, TypedArrayMetaDataAccessor::Mode::LOAD_LENGTH, onHeap);
1127 }
1128 GateRef result = builder_.LoadTypedArrayLength(array, arrayType, onHeap);
1129 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1130 }
1131
LowerTypedLdStringLength(const LoadBulitinObjTypeInfoAccessor & tacc)1132 void TypedBytecodeLowering::LowerTypedLdStringLength(const LoadBulitinObjTypeInfoAccessor &tacc)
1133 {
1134 GateRef gate = tacc.GetGate();
1135 GateRef str = tacc.GetReceiver();
1136 AddProfiling(gate);
1137 if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, str)) {
1138 if (!Uncheck()) {
1139 builder_.EcmaStringCheck(str);
1140 }
1141 }
1142 GateRef result = builder_.LoadStringLength(str);
1143 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1144 }
1145
LowerTypedLdMapSize(const LoadBulitinObjTypeInfoAccessor & tacc)1146 void TypedBytecodeLowering::LowerTypedLdMapSize(const LoadBulitinObjTypeInfoAccessor &tacc)
1147 {
1148 GateRef gate = tacc.GetGate();
1149 GateRef jsMap = tacc.GetReceiver();
1150 AddProfiling(gate);
1151 if (!Uncheck()) {
1152 builder_.EcmaMapCheck(jsMap);
1153 }
1154 GateRef result = builder_.LoadMapSize(jsMap);
1155 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1156 }
1157
TryLowerTypedLdObjByNameForBuiltinMethod(const LoadBulitinObjTypeInfoAccessor & tacc,BuiltinTypeId type)1158 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltinMethod(const LoadBulitinObjTypeInfoAccessor &tacc,
1159 BuiltinTypeId type)
1160 {
1161 GateRef gate = tacc.GetGate();
1162 JSTaggedValue key = tacc.GetKeyTaggedValue();
1163 std::optional<GlobalEnvField> protoField = ToGlobelEnvPrototypeField(type);
1164 if (key.IsUndefined() || !protoField.has_value()) {
1165 return false;
1166 }
1167 size_t protoFieldIndex = static_cast<size_t>(*protoField);
1168 JSHandle<GlobalEnv> globalEnv = compilationEnv_->GetGlobalEnv();
1169 JSHClass *prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass();
1170 PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(compilationEnv_->GetJSThread(),
1171 prototypeHClass, key);
1172 bool isPrototypeOfPrototype = false;
1173 // Unable to handle accessor at the moment
1174 if (!plr.IsFound() || plr.IsAccessor()) {
1175 if (type == BuiltinTypeId::ARRAY_ITERATOR) {
1176 protoField = ToGlobelEnvPrototypeField(BuiltinTypeId::ITERATOR);
1177 if (!protoField.has_value()) {
1178 return false;
1179 }
1180 protoFieldIndex = static_cast<size_t>(*protoField);
1181 prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass();
1182 plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(compilationEnv_->GetJSThread(),
1183 prototypeHClass, key);
1184 if (!plr.IsFound() || plr.IsAccessor()) {
1185 return false;
1186 } else {
1187 isPrototypeOfPrototype = true;
1188 }
1189 } else {
1190 return false;
1191 }
1192 }
1193 AddProfiling(gate);
1194 GateRef receiver = acc_.GetValueIn(gate, 2);
1195 if (!Uncheck()) {
1196 // For Array type only: array stability shall be ensured.
1197 ElementsKind kind = ElementsKind::NONE;
1198 if (type == BuiltinTypeId::ARRAY) {
1199 builder_.StableArrayCheck(receiver, ElementsKind::GENERIC, ArrayMetaDataAccessor::CALL_BUILTIN_METHOD);
1200 kind = tacc.TryGetArrayElementsKind();
1201 }
1202
1203 builder_.BuiltinPrototypeHClassCheck(receiver, type, kind, isPrototypeOfPrototype);
1204 }
1205 // Successfully goes to typed path
1206 GateRef plrGate = builder_.Int32(plr.GetData());
1207 GateRef prototype = builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), static_cast<size_t>(*protoField));
1208 GateRef result = builder_.LoadProperty(prototype, plrGate, plr.IsFunction());
1209 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1210 return true;
1211 }
1212
TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)1213 bool TypedBytecodeLowering::TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)
1214 {
1215 LoadBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1216 GateRef result = Circuit::NullGate();
1217 // Just supported mono.
1218 if (tacc.IsMono()) {
1219 if (tacc.IsBuiltinsTypeArray()) { // pgo need dump profile type
1220 AddProfiling(gate);
1221 result = LoadTypedArrayByIndex(tacc);
1222 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1223 return true;
1224 }
1225 }
1226 return false;
1227 }
1228
LowerTypedLdObjByIndex(GateRef gate)1229 void TypedBytecodeLowering::LowerTypedLdObjByIndex(GateRef gate)
1230 {
1231 if (TryLowerTypedLdObjByIndexForBuiltin(gate)) {
1232 return;
1233 }
1234 }
1235
TryLowerTypedStObjByIndexForBuiltin(GateRef gate)1236 bool TypedBytecodeLowering::TryLowerTypedStObjByIndexForBuiltin(GateRef gate)
1237 {
1238 StoreBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1239 if (tacc.HasNoType()) {
1240 return false;
1241 }
1242 if (tacc.GetBuiltinsJSType() != JSType::JS_FLOAT32_ARRAY) {
1243 return false;
1244 }
1245 AddProfiling(gate);
1246 GateRef receiver = tacc.GetReceiver();
1247 ParamType receiverType = tacc.GetParamType();
1248 if (!Uncheck()) {
1249 OnHeapMode onHeap = tacc.TryGetHeapMode();
1250 builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1251 }
1252 GateRef index = builder_.Int32(tacc.TryConvertKeyToInt());
1253 GateRef value = tacc.GetValue();
1254 OnHeapMode onHeap = tacc.TryGetHeapMode();
1255 auto length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1256 if (!Uncheck()) {
1257 builder_.IndexCheck(length, index);
1258 }
1259 builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, index, value, onHeap);
1260 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1261 return true;
1262 }
1263
LowerTypedStObjByIndex(GateRef gate)1264 void TypedBytecodeLowering::LowerTypedStObjByIndex(GateRef gate)
1265 {
1266 if (TryLowerTypedStObjByIndexForBuiltin(gate)) {
1267 return;
1268 }
1269 }
1270
TryLowerTypedLdObjByValueForBuiltin(GateRef gate)1271 bool TypedBytecodeLowering::TryLowerTypedLdObjByValueForBuiltin(GateRef gate)
1272 {
1273 LoadBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1274 GateRef result = Circuit::NullGate();
1275 // Just supported mono.
1276 if (tacc.IsMono()) {
1277 if (tacc.IsBuiltinsString()) {
1278 AddProfiling(gate);
1279 result = LoadStringByIndex(tacc);
1280 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1281 return true;
1282 } else if (tacc.IsBuiltinsArray()) {
1283 AddProfiling(gate);
1284 result = LoadJSArrayByIndex(tacc);
1285 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1286 return true;
1287 } else if (tacc.IsBuiltinsTypeArray()) {
1288 AddProfiling(gate);
1289 result = LoadTypedArrayByIndex(tacc);
1290 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1291 return true;
1292 }
1293 }
1294 return false;
1295 }
1296
LowerTypedLdObjByValue(GateRef gate)1297 void TypedBytecodeLowering::LowerTypedLdObjByValue(GateRef gate)
1298 {
1299 if (TryLowerTypedLdObjByValueForBuiltin(gate)) {
1300 return;
1301 }
1302 }
1303
LoadStringByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1304 GateRef TypedBytecodeLowering::LoadStringByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1305 {
1306 GateRef receiver = tacc.GetReceiver();
1307 GateRef propKey = tacc.GetKey();
1308 acc_.SetGateType(propKey, GateType::NumberType());
1309 if (!Uncheck()) {
1310 if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, receiver)) {
1311 builder_.EcmaStringCheck(receiver);
1312 }
1313 GateRef length = builder_.LoadStringLength(receiver);
1314 propKey = builder_.IndexCheck(length, propKey);
1315 receiver = builder_.FlattenTreeStringCheck(receiver);
1316 }
1317 return builder_.LoadElement<TypedLoadOp::STRING_LOAD_ELEMENT>(receiver, propKey);
1318 }
1319
LoadJSArrayByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1320 GateRef TypedBytecodeLowering::LoadJSArrayByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1321 {
1322 GateRef receiver = tacc.GetReceiver();
1323 GateRef propKey = tacc.GetKey();
1324 acc_.SetGateType(propKey, GateType::NumberType());
1325 ElementsKind kind = tacc.TryGetArrayElementsKind();
1326 if (!Uncheck()) {
1327 if (!acc_.IsCreateArray(receiver)) {
1328 builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
1329 builder_.ElementsKindCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
1330 }
1331 GateRef length = builder_.LoadArrayLength(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1332 propKey = builder_.IndexCheck(length, propKey);
1333 }
1334
1335 GateRef result = Circuit::NullGate();
1336 if (Elements::IsInt(kind)) {
1337 // When elementskind switch on, need to add retype for loadInt
1338 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_INT_ELEMENT>(receiver, propKey);
1339 } else if (Elements::IsNumber(kind)) {
1340 // When elementskind switch on, need to add retype for loadNumber
1341 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT>(receiver, propKey);
1342 } else if (Elements::IsObject(kind)) {
1343 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT>(receiver, propKey);
1344 } else if (!Elements::IsHole(kind)) {
1345 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT>(receiver, propKey);
1346 } else {
1347 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_HOLE_TAGGED_ELEMENT>(receiver, propKey);
1348 }
1349 return result;
1350 }
1351
LoadElmentFromFloat64Array(const LoadBulitinObjTypeInfoAccessor & tacc)1352 GateRef TypedBytecodeLowering::LoadElmentFromFloat64Array(const LoadBulitinObjTypeInfoAccessor &tacc)
1353 {
1354 GateRef receiver = tacc.GetReceiver();
1355 GateRef propKey = tacc.GetKey();
1356 OnHeapMode onHeap = tacc.TryGetHeapMode();
1357 auto resTemp = builder_.LoadElement<TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1358 Label entry(&builder_);
1359 builder_.SubCfgEntry(&entry);
1360 Label ifTrue(&builder_);
1361 Label ifFalse(&builder_);
1362 Label exit(&builder_);
1363 Variable result(builder_.GetCurrentEnvironment(),
1364 VariableType::JS_ANY(), builder_.NextVariableId(), builder_.Undefined());
1365
1366 builder_.Branch(builder_.DoubleIsImpureNaN(resTemp), &ifTrue, &ifFalse);
1367 builder_.Bind(&ifTrue);
1368 {
1369 result = builder_.Double(base::NAN_VALUE);
1370 builder_.Jump(&exit);
1371 }
1372 builder_.Bind(&ifFalse);
1373 {
1374 result = resTemp;
1375 builder_.Jump(&exit);
1376 }
1377 builder_.Bind(&exit);
1378 auto res = *result;
1379 builder_.SubCfgExit();
1380 return res;
1381 }
1382
LoadTypedArrayByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1383 GateRef TypedBytecodeLowering::LoadTypedArrayByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1384 {
1385 GateRef receiver = tacc.GetReceiver();
1386 ParamType receiverType = tacc.GetParamType();
1387 GateRef propKey = tacc.GetKey();
1388 OnHeapMode onHeap = tacc.TryGetHeapMode();
1389 JSType builtinsType = tacc.GetBuiltinsJSType();
1390 if (!Uncheck()) {
1391 builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1392 GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1393 propKey = builder_.IndexCheck(length, propKey);
1394 }
1395 switch (builtinsType) {
1396 case JSType::JS_INT8_ARRAY:
1397 return builder_.LoadElement<TypedLoadOp::INT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1398 case JSType::JS_UINT8_ARRAY:
1399 return builder_.LoadElement<TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1400 case JSType::JS_UINT8_CLAMPED_ARRAY:
1401 return builder_.LoadElement<TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1402 case JSType::JS_INT16_ARRAY:
1403 return builder_.LoadElement<TypedLoadOp::INT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1404 case JSType::JS_UINT16_ARRAY:
1405 return builder_.LoadElement<TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1406 case JSType::JS_INT32_ARRAY:
1407 return builder_.LoadElement<TypedLoadOp::INT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1408 case JSType::JS_UINT32_ARRAY:
1409 return builder_.LoadElement<TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1410 case JSType::JS_FLOAT32_ARRAY:
1411 return builder_.LoadElement<TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1412 case JSType::JS_FLOAT64_ARRAY: {
1413 return LoadElmentFromFloat64Array(tacc);
1414 }
1415 default:
1416 LOG_ECMA(FATAL) << "this branch is unreachable";
1417 UNREACHABLE();
1418 }
1419
1420 return Circuit::NullGate();
1421 }
1422
StoreJSArrayByIndex(const StoreBulitinObjTypeInfoAccessor & tacc)1423 void TypedBytecodeLowering::StoreJSArrayByIndex(const StoreBulitinObjTypeInfoAccessor &tacc)
1424 {
1425 GateRef receiver = tacc.GetReceiver();
1426 GateRef propKey = tacc.GetKey();
1427 GateRef value = tacc.GetValue();
1428 ElementsKind kind = tacc.TryGetArrayElementsKind();
1429 if (!Uncheck()) {
1430 if (!acc_.IsCreateArray(receiver)) {
1431 builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::STORE_ELEMENT);
1432 }
1433 GateRef length = builder_.LoadArrayLength(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1434 builder_.IndexCheck(length, propKey);
1435 builder_.COWArrayCheck(receiver);
1436
1437 if (Elements::IsObject(kind)) {
1438 GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
1439 builder_.HeapObjectCheck(value, frameState);
1440 }
1441 }
1442 builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, propKey, value);
1443 }
1444
StoreTypedArrayByIndex(const StoreBulitinObjTypeInfoAccessor & tacc)1445 void TypedBytecodeLowering::StoreTypedArrayByIndex(const StoreBulitinObjTypeInfoAccessor &tacc)
1446 {
1447 GateRef receiver = tacc.GetReceiver();
1448 ParamType receiverType = tacc.GetParamType();
1449 GateRef propKey = tacc.GetKey();
1450 GateRef value = tacc.GetValue();
1451 OnHeapMode onHeap = tacc.TryGetHeapMode();
1452 if (!Uncheck()) {
1453 builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1454 GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1455 propKey = builder_.IndexCheck(length, propKey);
1456 }
1457
1458 JSType builtinsType = tacc.GetBuiltinsJSType();
1459 switch (builtinsType) {
1460 case JSType::JS_INT8_ARRAY:
1461 builder_.StoreElement<TypedStoreOp::INT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1462 break;
1463 case JSType::JS_UINT8_ARRAY:
1464 builder_.StoreElement<TypedStoreOp::UINT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1465 break;
1466 case JSType::JS_UINT8_CLAMPED_ARRAY:
1467 builder_.StoreElement<TypedStoreOp::UINT8CLAMPEDARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1468 break;
1469 case JSType::JS_INT16_ARRAY:
1470 builder_.StoreElement<TypedStoreOp::INT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1471 break;
1472 case JSType::JS_UINT16_ARRAY:
1473 builder_.StoreElement<TypedStoreOp::UINT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1474 break;
1475 case JSType::JS_INT32_ARRAY:
1476 builder_.StoreElement<TypedStoreOp::INT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1477 break;
1478 case JSType::JS_UINT32_ARRAY:
1479 builder_.StoreElement<TypedStoreOp::UINT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1480 break;
1481 case JSType::JS_FLOAT32_ARRAY:
1482 builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1483 break;
1484 case JSType::JS_FLOAT64_ARRAY:
1485 builder_.StoreElement<TypedStoreOp::FLOAT64ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1486 break;
1487 default:
1488 LOG_ECMA(FATAL) << "this branch is unreachable";
1489 UNREACHABLE();
1490 }
1491 }
1492
TryLowerTypedStObjByValueForBuiltin(GateRef gate)1493 bool TypedBytecodeLowering::TryLowerTypedStObjByValueForBuiltin(GateRef gate)
1494 {
1495 StoreBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1496 // Just supported mono.
1497 if (tacc.IsMono() && !tacc.IsStoreOutOfBounds()) {
1498 if (tacc.IsBuiltinsArray()) {
1499 AddProfiling(gate);
1500 StoreJSArrayByIndex(tacc);
1501 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1502 return true;
1503 } else if (tacc.IsBuiltinsTypeArray()) {
1504 AddProfiling(gate);
1505 StoreTypedArrayByIndex(tacc);
1506 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1507 return true;
1508 }
1509 }
1510
1511 return false;
1512 }
1513
LowerTypedStObjByValue(GateRef gate)1514 void TypedBytecodeLowering::LowerTypedStObjByValue(GateRef gate)
1515 {
1516 if (TryLowerTypedStObjByValueForBuiltin(gate)) {
1517 return;
1518 }
1519 }
1520
IsTrueOrFalseHasProfileType(GateRef gate) const1521 bool TypedBytecodeLowering::IsTrueOrFalseHasProfileType(GateRef gate) const
1522 {
1523 ASSERT(acc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
1524 return acc_.GetByteCodeOpcode(gate) == EcmaOpcode::CALLRUNTIME_ISTRUE_PREF_IMM8 ||
1525 acc_.GetByteCodeOpcode(gate) == EcmaOpcode::CALLRUNTIME_ISFALSE_PREF_IMM8;
1526 }
1527
LowerTypedIsTrueOrFalse(GateRef gate,bool flag)1528 void TypedBytecodeLowering::LowerTypedIsTrueOrFalse(GateRef gate, bool flag)
1529 {
1530 UnOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
1531 ParamType paramType;
1532 if (TypeInfoAccessor::IsTrustedBooleanType(acc_, tacc.GetValue()) ||
1533 (IsTrueOrFalseHasProfileType(gate) && tacc.IsBooleanType())) {
1534 paramType = ParamType::BooleanType();
1535 } else if (TypeInfoAccessor::IsTrustedNumberType(acc_, tacc.GetValue()) ||
1536 (IsTrueOrFalseHasProfileType(gate) && tacc.HasNumberType())) {
1537 paramType = ParamType::NumberType();
1538 } else {
1539 return;
1540 }
1541 AddProfiling(gate);
1542 GateRef result;
1543 if (!flag) {
1544 result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISFALSE>(tacc.GetValue(), paramType);
1545 } else {
1546 result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISTRUE>(tacc.GetValue(), paramType);
1547 }
1548
1549 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1550 }
1551
TryLowerNewNumber(CircuitBuilder * builder,GateAccessor acc,GateRef gate)1552 bool TryLowerNewNumber(CircuitBuilder *builder, GateAccessor acc, GateRef gate)
1553 {
1554 auto loadBuiltin = acc.GetValueIn(gate, 0);
1555 if ((acc.GetOpCode(loadBuiltin) == OpCode::LOAD_BUILTIN_OBJECT) &&
1556 (acc.GetIndex(loadBuiltin) == static_cast<size_t>(BuiltinType::BT_NUMBER))) {
1557 auto arg = builder->ToTaggedIntPtr(builder->Int32(0));
1558 if (acc.GetNumValueIn(gate) > 1) {
1559 arg = acc.GetValueIn(gate, 1);
1560 }
1561
1562 auto currentLabel = builder->GetCurrentEnvironment()->GetCurrentLabel();
1563 auto currentControl = currentLabel->GetControl();
1564 auto currentDepend = currentLabel->GetDepend();
1565 GateRef frameState = acc.FindNearestFrameState(gate);
1566 GateRef newNumber = acc.GetCircuit()->NewGate(acc.GetCircuit()->NewNumber(),
1567 MachineType::I64,
1568 {currentControl, currentDepend, loadBuiltin, arg, frameState},
1569 GateType::TaggedPointer());
1570
1571 currentLabel->SetControl(newNumber);
1572 currentLabel->SetDepend(newNumber);
1573
1574 acc.ReplaceHirAndDeleteIfException(gate, builder->GetStateDepend(), newNumber);
1575 return true;
1576 }
1577 return false;
1578 }
1579
LowerTypedNewObjRange(GateRef gate)1580 void TypedBytecodeLowering::LowerTypedNewObjRange(GateRef gate)
1581 {
1582 if (TryLowerNewBuiltinConstructor(gate)) {
1583 return;
1584 }
1585 if (TryLowerNewNumber(&builder_, acc_, gate)) {
1586 return;
1587 }
1588 NewObjRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1589 if (!tacc.FindHClass() || !tacc.IsValidCallMethodId()) {
1590 return;
1591 }
1592 size_t methodId = tacc.GetCallMethodId();
1593 MethodLiteral* method = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
1594 JSTaggedValue value = tacc.GetHClass();
1595 JSHClass *hclass = JSHClass::Cast(value.GetTaggedObject());
1596 if (method == nullptr || !value.IsJSHClass() || hclass->GetObjectType() != JSType::JS_OBJECT) {
1597 return ;
1598 }
1599 AddProfiling(gate);
1600 GateRef ctor = tacc.GetValue();
1601 GateRef hclassIndex = tacc.GetHClassIndex();
1602 GateRef stateSplit = acc_.GetDep(gate);
1603 GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1604 GateRef ihclass = builder_.GetHClassGateFromIndex(frameState, hclassIndex);
1605 GateRef size = builder_.IntPtr(hclass->GetObjectSize());
1606 // call target check
1607 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JS_NEWOBJRANGE>(ctor, builder_.IntPtr(INVALID_INDEX), gate);
1608 // check IHC
1609 GateRef protoOrHclass = builder_.LoadConstOffset(VariableType::JS_ANY(), ctor,
1610 JSFunction::PROTO_OR_DYNCLASS_OFFSET);
1611 GateRef checkProto = builder_.Equal(ihclass, protoOrHclass);
1612 builder_.DeoptCheck(checkProto, frameState, DeoptType::NOTNEWOBJ2);
1613 // construct
1614 GateRef thisObj = builder_.TypedNewAllocateThis(ctor, ihclass, size, frameState);
1615 size_t range = acc_.GetNumValueIn(gate);
1616 size_t expectedArgc = method->GetNumArgs();
1617 size_t actualArgc = static_cast<size_t>(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1618 EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
1619 GateRef argc = builder_.Int64(actualArgc);
1620 GateRef argv = builder_.IntPtr(0);
1621 std::vector<GateRef> args { glue_, argc, argv, ctor, ctor, thisObj }; // func thisobj numofargs
1622 for (size_t i = 1; i < range; ++i) { // 1:skip ctor
1623 args.emplace_back(acc_.GetValueIn(gate, i));
1624 }
1625 bool needPushArgv = (expectedArgc != actualArgc);
1626 GateRef result = builder_.CallNew(gate, args, needPushArgv);
1627 ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1628 builder_.GetDepend(), result);
1629 }
1630
TryLowerNewBuiltinConstructor(GateRef gate)1631 bool TypedBytecodeLowering::TryLowerNewBuiltinConstructor(GateRef gate)
1632 {
1633 NewBuiltinCtorTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
1634
1635 GateRef ctor = tacc.GetValue();
1636 GateRef constructGate = Circuit::NullGate();
1637 if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::ArrayConstructor)) {
1638 return false;
1639 } else if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::ObjectConstructor)) {
1640 AddProfiling(gate);
1641 if (!Uncheck()) {
1642 builder_.ObjectConstructorCheck(ctor);
1643 }
1644 constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::ObjectConstructor, gate);
1645 } else if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::BooleanConstructor)) {
1646 if (acc_.GetNumValueIn(gate) <= 2) { // 2: ctor and first arg
1647 AddProfiling(gate);
1648 if (!Uncheck()) {
1649 builder_.BooleanConstructorCheck(ctor);
1650 }
1651 constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::BooleanConstructor, gate);
1652 }
1653 } else if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::Float32ArrayConstructor)) {
1654 if (acc_.GetNumValueIn(gate) <= 2) { // 2: ctor and first arg
1655 AddProfiling(gate);
1656 if (!Uncheck()) {
1657 builder_.Float32ArrayConstructorCheck(ctor);
1658 }
1659 constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::Float32ArrayConstructor, gate);
1660 }
1661 }
1662 if (constructGate == Circuit::NullGate()) {
1663 return false;
1664 }
1665 ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1666 builder_.GetDepend(), constructGate);
1667 return true;
1668 }
1669
LowerTypedSuperCall(GateRef gate)1670 void TypedBytecodeLowering::LowerTypedSuperCall(GateRef gate)
1671 {
1672 SuperCallTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
1673
1674 auto methodId = tacc.GetMethodId();
1675 if (methodId == 0) {
1676 return;
1677 }
1678 auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
1679 if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
1680 return;
1681 }
1682 if (!tacc.IsValidCallMethodId()) {
1683 return;
1684 }
1685 AddProfiling(gate);
1686
1687 GateRef ctor = tacc.GetCtor();
1688 // stateSplit maybe not a STATE_SPLIT
1689 GateRef stateSplit = acc_.GetDep(gate);
1690
1691 GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1692 GateRef superCtor = builder_.GetSuperConstructor(ctor);
1693 GateRef newTarget = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
1694 GateRef thisObj = builder_.TypedSuperAllocateThis(superCtor, newTarget, frameState);
1695
1696 // call constructor
1697 size_t range = acc_.GetNumValueIn(gate);
1698 GateRef actualArgc = builder_.Int64(range + 3); // 3: ctor, newTaget, this
1699 GateRef actualArgv = builder_.IntPtr(0);
1700 std::vector<GateRef> args { glue_, actualArgc, actualArgv, superCtor, newTarget, thisObj };
1701 for (size_t i = 0; i < range; ++i) {
1702 args.emplace_back(acc_.GetValueIn(gate, i));
1703 }
1704
1705 GateRef constructGate = builder_.Construct(gate, args);
1706 ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1707 builder_.GetDepend(), constructGate);
1708 }
1709
SpeculateCallBuiltin(GateRef gate,GateRef func,const std::vector<GateRef> & args,BuiltinsStubCSigns::ID id,bool isThrow)1710 void TypedBytecodeLowering::SpeculateCallBuiltin(GateRef gate, GateRef func, const std::vector<GateRef> &args,
1711 BuiltinsStubCSigns::ID id, bool isThrow)
1712 {
1713 if (!Uncheck()) {
1714 builder_.CallTargetCheck(gate, func, builder_.IntPtr(static_cast<int64_t>(id)), {args[0]});
1715 }
1716
1717 GateRef result = builder_.TypedCallBuiltin(gate, args, id, IS_SIDE_EFFECT_BUILTINS_ID(id));
1718
1719 if (isThrow) {
1720 ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1721 builder_.GetDepend(), result);
1722 } else {
1723 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1724 }
1725 }
1726
SpeculateCallBuiltinFromGlobal(GateRef gate,const std::vector<GateRef> & args,BuiltinsStubCSigns::ID id,bool isThrow,bool isSideEffect)1727 void TypedBytecodeLowering::SpeculateCallBuiltinFromGlobal(GateRef gate, const std::vector<GateRef> &args,
1728 BuiltinsStubCSigns::ID id, bool isThrow, bool isSideEffect)
1729 {
1730 GateRef result = builder_.TypedCallBuiltin(gate, args, id, isSideEffect);
1731
1732 if (isThrow) {
1733 ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1734 builder_.GetDepend(), result);
1735 } else {
1736 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1737 }
1738 }
1739
LowerFastCall(GateRef gate,GateRef func,const std::vector<GateRef> & argsFastCall,bool isNoGC)1740 void TypedBytecodeLowering::LowerFastCall(GateRef gate, GateRef func,
1741 const std::vector<GateRef> &argsFastCall, bool isNoGC)
1742 {
1743 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1744 GateRef result = builder_.TypedFastCall(gate, argsFastCall, isNoGC);
1745 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1746 ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1747 builder_.GetDepend(), result);
1748 }
1749
LowerCall(GateRef gate,GateRef func,const std::vector<GateRef> & args,bool isNoGC)1750 void TypedBytecodeLowering::LowerCall(GateRef gate, GateRef func,
1751 const std::vector<GateRef> &args, bool isNoGC)
1752 {
1753 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1754 GateRef result = builder_.TypedCall(gate, args, isNoGC);
1755 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1756 ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1757 builder_.GetDepend(), result);
1758 }
1759
1760 template<class TypeAccessor>
CheckFastCallThisCallTarget(const TypeAccessor & tacc)1761 void TypedBytecodeLowering::CheckFastCallThisCallTarget(const TypeAccessor &tacc)
1762 {
1763 if (noCheck_) {
1764 return;
1765 }
1766 GateRef func = tacc.GetFunc();
1767 GateRef gate = tacc.GetGate();
1768 GateRef methodIndex = builder_.IntPtr(tacc.GetFuncMethodOffset());
1769 if (tacc.IsNoGC()) {
1770 builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST_NOGC>(func, methodIndex, gate);
1771 } else {
1772 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST>(func, methodIndex, gate);
1773 }
1774 }
1775
1776 template<class TypeAccessor>
CheckCallThisCallTarget(const TypeAccessor & tacc)1777 void TypedBytecodeLowering::CheckCallThisCallTarget(const TypeAccessor &tacc)
1778 {
1779 if (noCheck_) {
1780 return;
1781 }
1782 GateRef func = tacc.GetFunc();
1783 GateRef gate = tacc.GetGate();
1784 GateRef methodIndex = builder_.IntPtr(tacc.GetFuncMethodOffset());
1785 if (tacc.IsNoGC()) {
1786 builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_NOGC>(func, methodIndex, gate);
1787 } else {
1788 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS>(func, methodIndex, gate);
1789 }
1790 }
1791
1792 template<class TypeAccessor>
CheckThisCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1793 void TypedBytecodeLowering::CheckThisCallTargetAndLowerCall(const TypeAccessor &tacc,
1794 const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1795 {
1796 GateRef func = tacc.GetFunc();
1797 GateRef gate = tacc.GetGate();
1798 bool isNoGC = tacc.IsNoGC();
1799 if (tacc.CanFastCall()) {
1800 CheckFastCallThisCallTarget(tacc);
1801 LowerFastCall(gate, func, argsFastCall, isNoGC);
1802 } else {
1803 CheckCallThisCallTarget(tacc);
1804 LowerCall(gate, func, args, isNoGC);
1805 }
1806 }
1807
1808 template<class TypeAccessor>
CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,bool isNoGC)1809 void TypedBytecodeLowering::CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor &tacc,
1810 const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall, bool isNoGC)
1811 {
1812 GateRef func = tacc.GetFunc();
1813 GateRef gate = tacc.GetGate();
1814 // NO CHECK
1815 if (!Uncheck()) {
1816 builder_.CallTargetIsCompiledCheck(func, gate);
1817 }
1818 if (tacc.CanFastCall()) {
1819 LowerFastCall(gate, func, argsFastCall, isNoGC);
1820 } else {
1821 LowerCall(gate, func, args, isNoGC);
1822 }
1823 }
1824
1825 template<class TypeAccessor>
InSameConstPool(const TypeAccessor & tacc) const1826 bool TypedBytecodeLowering::InSameConstPool(const TypeAccessor &tacc) const
1827 {
1828 auto pandaFile = ctx_->GetJSPandaFile();
1829 auto targetPandaFile = tacc.GetPandaFile();
1830 if (pandaFile != targetPandaFile) {
1831 return false;
1832 }
1833 auto targetMethodId = tacc.GetMethodId();
1834 panda_file::IndexAccessor indexAccessor(*(targetPandaFile->GetPandaFile()),
1835 panda_file::File::EntityId(targetMethodId));
1836 auto targetCpId = static_cast<uint32_t>(indexAccessor.GetHeaderIndex());
1837 if (constPoolId_ != targetCpId) {
1838 return false;
1839 }
1840 return true;
1841 }
1842
1843 template<class TypeAccessor>
CheckCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1844 void TypedBytecodeLowering::CheckCallTargetAndLowerCall(const TypeAccessor &tacc,
1845 const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1846 {
1847 GateRef func = tacc.GetFunc();
1848 if (IsLoadVtable(func)) {
1849 CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall); // func = a.foo, func()
1850 } else {
1851 bool isNoGC = tacc.IsNoGC();
1852 auto op = acc_.GetOpCode(func);
1853 if (op == OpCode::JS_BYTECODE && (acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8 ||
1854 acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) {
1855 CheckCallTargetFromDefineFuncAndLowerCall(tacc, args, argsFastCall, isNoGC);
1856 return;
1857 }
1858 int methodIndex = tacc.GetMethodIndex();
1859 if (!tacc.MethodOffsetIsVaild() || methodIndex == -1) {
1860 return;
1861 }
1862 if (!InSameConstPool(tacc)) {
1863 return;
1864 }
1865
1866 GateRef gate = tacc.GetGate();
1867 if (tacc.CanFastCall()) {
1868 if (!Uncheck()) {
1869 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL_FAST>(func,
1870 builder_.IntPtr(methodIndex), gate);
1871 }
1872 LowerFastCall(gate, func, argsFastCall, isNoGC);
1873 } else {
1874 if (!Uncheck()) {
1875 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL>(func,
1876 builder_.IntPtr(methodIndex), gate);
1877 }
1878 LowerCall(gate, func, args, isNoGC);
1879 }
1880 }
1881 }
1882
1883 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedCall(const TypeAccessor & tacc)1884 void TypedBytecodeLowering::LowerTypedCall(const TypeAccessor &tacc)
1885 {
1886 if (!tacc.IsHotnessFunc()) {
1887 return;
1888 }
1889 auto methodId = tacc.GetMethodId();
1890 if (methodId == 0) {
1891 return;
1892 }
1893 auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
1894 if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
1895 return;
1896 }
1897 uint32_t argc = tacc.GetArgc();
1898 GateRef gate = tacc.GetGate();
1899 GateRef actualArgc = Circuit::NullGate();
1900 GateRef actualArgv = builder_.IntPtr(0);
1901 switch (Op) {
1902 case EcmaOpcode::CALLARG0_IMM8: {
1903 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1904 EcmaOpcode::CALLARG0_IMM8));
1905 break;
1906 }
1907 case EcmaOpcode::CALLARG1_IMM8_V8: {
1908 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1909 EcmaOpcode::CALLARG1_IMM8_V8));
1910 break;
1911 }
1912 case EcmaOpcode::CALLARGS2_IMM8_V8_V8: {
1913 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1914 EcmaOpcode::CALLARGS2_IMM8_V8_V8));
1915 break;
1916 }
1917 case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8: {
1918 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1919 EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8));
1920 break;
1921 }
1922 case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8: {
1923 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1924 EcmaOpcode::CALLRANGE_IMM8_IMM8_V8));
1925 break;
1926 }
1927 default:
1928 UNREACHABLE();
1929 }
1930 uint32_t len = tacc.GetFunctionTypeLength();
1931 if (len == tacc.INVALID_LEN) {
1932 return;
1933 }
1934 GateRef func = tacc.GetFunc();
1935 GateRef newTarget = builder_.Undefined();
1936 GateRef thisObj = builder_.Undefined();
1937 std::vector<GateRef> argsFastCall { glue_, func, thisObj};
1938 std::vector<GateRef> args { glue_, actualArgc, actualArgv, func, newTarget, thisObj };
1939 for (uint32_t i = 0; i < argc; i++) {
1940 GateRef value = acc_.GetValueIn(gate, i);
1941 argsFastCall.emplace_back(value);
1942 args.emplace_back(value);
1943 }
1944 for (uint32_t i = argc; i < len; i++) {
1945 argsFastCall.emplace_back(builder_.Undefined());
1946 args.emplace_back(builder_.Undefined());
1947 }
1948 if (argc != len) {
1949 return ;
1950 }
1951 AddProfiling(gate);
1952 CheckCallTargetAndLowerCall(tacc, args, argsFastCall);
1953 }
1954
GetCalleePandaFile(GateRef gate)1955 const JSPandaFile* TypedBytecodeLowering::GetCalleePandaFile(GateRef gate)
1956 {
1957 auto profileType = acc_.TryGetPGOType(gate).GetPGOSampleType();
1958 bool haveProfileType = profileType->IsProfileType() && !profileType->IsProfileTypeNone();
1959 if (haveProfileType) {
1960 if (compilationEnv_->IsJitCompiler()) {
1961 return compilationEnv_->GetJSPandaFile();
1962 }
1963 auto abcId = profileType->GetProfileType().GetAbcId();
1964 CString fileDesc;
1965 if (!decoder_->GetAbcNameById(abcId, fileDesc)) {
1966 UNREACHABLE();
1967 }
1968 fileDesc = JSPandaFile::GetNormalizedFileDesc(fileDesc);
1969 return JSPandaFileManager::GetInstance()->FindJSPandaFileByNormalizedName(fileDesc).get();
1970 }
1971 // nullptr if no pgo info
1972 return nullptr;
1973 }
1974
LowerTypedCallArg0(GateRef gate)1975 void TypedBytecodeLowering::LowerTypedCallArg0(GateRef gate)
1976 {
1977 if (GetCalleePandaFile(gate) == nullptr) {
1978 return;
1979 }
1980 CallArg0TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
1981 if (!tacc.IsValidCallMethodId()) {
1982 return;
1983 }
1984 LowerTypedCall<EcmaOpcode::CALLARG0_IMM8>(tacc);
1985 }
1986
LowerTypedCallArg1(GateRef gate)1987 void TypedBytecodeLowering::LowerTypedCallArg1(GateRef gate)
1988 {
1989 if (GetCalleePandaFile(gate) == nullptr) {
1990 return;
1991 }
1992 CallArg1TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
1993 GateRef func = tacc.GetFunc();
1994 GateRef a0Value = tacc.GetValue();
1995 BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinMethodId();
1996 if (!IS_INVALID_ID(id) && (IS_TYPED_BUILTINS_NUMBER_ID(id) || IS_TYPED_BUILTINS_GLOBAL_ID(id))) {
1997 if (IS_TYPED_INLINE_BUILTINS_ID(id)) {
1998 return;
1999 }
2000 AddProfiling(gate);
2001 if (IsFuncFromGlobal(func)) {
2002 // No need to do CallTargetCheck if func is from LOAD_BUILTIN_OBJECT.
2003 SpeculateCallBuiltinFromGlobal(gate, { a0Value }, id, true);
2004 } else {
2005 SpeculateCallBuiltin(gate, func, { a0Value }, id, true);
2006 }
2007 } else {
2008 if (!tacc.IsValidCallMethodId()) {
2009 return;
2010 }
2011 LowerTypedCall<EcmaOpcode::CALLARG1_IMM8_V8>(tacc);
2012 }
2013 }
2014
LowerTypedCallArg2(GateRef gate)2015 void TypedBytecodeLowering::LowerTypedCallArg2(GateRef gate)
2016 {
2017 if (GetCalleePandaFile(gate) == nullptr) {
2018 return;
2019 }
2020 CallArg2TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2021 if (!tacc.IsValidCallMethodId()) {
2022 return;
2023 }
2024 LowerTypedCall<EcmaOpcode::CALLARGS2_IMM8_V8_V8>(tacc);
2025 }
2026
LowerTypedCallArg3(GateRef gate)2027 void TypedBytecodeLowering::LowerTypedCallArg3(GateRef gate)
2028 {
2029 if (GetCalleePandaFile(gate) == nullptr) {
2030 return;
2031 }
2032 CallArg3TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2033 if (!tacc.IsValidCallMethodId()) {
2034 return;
2035 }
2036 LowerTypedCall<EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8>(tacc);
2037 }
2038
LowerTypedCallrange(GateRef gate)2039 void TypedBytecodeLowering::LowerTypedCallrange(GateRef gate)
2040 {
2041 if (GetCalleePandaFile(gate) == nullptr) {
2042 return;
2043 }
2044 CallRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2045 if (!tacc.IsValidCallMethodId()) {
2046 return;
2047 }
2048 LowerTypedCall<EcmaOpcode::CALLRANGE_IMM8_IMM8_V8>(tacc);
2049 }
2050
IsLoadVtable(GateRef func)2051 bool TypedBytecodeLowering::IsLoadVtable(GateRef func)
2052 {
2053 auto op = acc_.GetOpCode(func);
2054 if (op != OpCode::LOAD_PROPERTY) {
2055 return false;
2056 }
2057 return true;
2058 }
2059
2060 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedThisCall(const TypeAccessor & tacc)2061 void TypedBytecodeLowering::LowerTypedThisCall(const TypeAccessor &tacc)
2062 {
2063 auto methodId = tacc.GetMethodId();
2064 if (methodId == 0) {
2065 return;
2066 }
2067 auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
2068 if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
2069 return;
2070 }
2071 if (!tacc.IsHotnessFunc()) {
2072 return;
2073 }
2074 uint32_t argc = tacc.GetArgc();
2075 GateRef gate = tacc.GetGate();
2076 GateRef actualArgc = Circuit::NullGate();
2077 GateRef actualArgv = builder_.IntPtr(0);
2078 switch (Op) {
2079 case EcmaOpcode::CALLTHIS0_IMM8_V8: {
2080 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2081 EcmaOpcode::CALLTHIS0_IMM8_V8));
2082 break;
2083 }
2084 case EcmaOpcode::CALLTHIS1_IMM8_V8_V8: {
2085 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2086 EcmaOpcode::CALLTHIS1_IMM8_V8_V8));
2087 break;
2088 }
2089 case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8: {
2090 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2091 EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8));
2092 break;
2093 }
2094 case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8: {
2095 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2096 EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8));
2097 break;
2098 }
2099 case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: {
2100 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2101 EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8));
2102 break;
2103 }
2104 default:
2105 UNREACHABLE();
2106 }
2107
2108 uint32_t len = tacc.GetFunctionTypeLength();
2109 if (len == tacc.INVALID_LEN) {
2110 return;
2111 }
2112 GateRef func = tacc.GetFunc();
2113 GateRef newTarget = builder_.Undefined();
2114 GateRef thisObj = tacc.GetThisObj();
2115 std::vector<GateRef> argsFastCall { glue_, func, thisObj};
2116 std::vector<GateRef> args { glue_, actualArgc, actualArgv, func, newTarget, thisObj };
2117 for (uint32_t i = 0; i < argc; i++) {
2118 GateRef value = acc_.GetValueIn(gate, i + 1);
2119 argsFastCall.emplace_back(value);
2120 args.emplace_back(value);
2121 }
2122 for (uint32_t i = argc; i < len; i++) {
2123 argsFastCall.emplace_back(builder_.Undefined());
2124 args.emplace_back(builder_.Undefined());
2125 }
2126 AddProfiling(gate);
2127 CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall);
2128 }
2129
LowerTypedCallthis0(GateRef gate)2130 void TypedBytecodeLowering::LowerTypedCallthis0(GateRef gate)
2131 {
2132 if (GetCalleePandaFile(gate) == nullptr) {
2133 return;
2134 }
2135 CallThis0TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2136 BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2137 if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS0(pgoFuncId)) {
2138 AddProfiling(gate);
2139 SpeculateCallBuiltin(gate, tacc.GetFunc(), {tacc.GetThisObj()}, pgoFuncId, true);
2140 return;
2141 }
2142 if (!tacc.CanOptimizeAsFastCall()) {
2143 return;
2144 }
2145 LowerTypedThisCall<EcmaOpcode::CALLTHIS0_IMM8_V8>(tacc);
2146 }
2147
LowerTypedCallthis1(GateRef gate)2148 void TypedBytecodeLowering::LowerTypedCallthis1(GateRef gate)
2149 {
2150 if (GetCalleePandaFile(gate) == nullptr) {
2151 return;
2152 }
2153 CallThis1TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2154 BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2155 if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS1(pgoFuncId)) {
2156 AddProfiling(gate);
2157 SpeculateCallBuiltin(gate, tacc.GetFunc(), {tacc.GetArgs()}, pgoFuncId, true);
2158 return;
2159 }
2160 if (!tacc.CanOptimizeAsFastCall()) {
2161 return;
2162 }
2163 LowerTypedThisCall<EcmaOpcode::CALLTHIS1_IMM8_V8_V8>(tacc);
2164 }
2165
LowerTypedCallthis2(GateRef gate)2166 void TypedBytecodeLowering::LowerTypedCallthis2(GateRef gate)
2167 {
2168 if (GetCalleePandaFile(gate) == nullptr) {
2169 return;
2170 }
2171 CallThis2TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2172 BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2173 if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS2(pgoFuncId)) {
2174 AddProfiling(gate);
2175 SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArgs() }, pgoFuncId, true);
2176 return;
2177 }
2178 if (!tacc.CanOptimizeAsFastCall()) {
2179 return;
2180 }
2181 LowerTypedThisCall<EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8>(tacc);
2182 }
2183
LowerTypedCallthis3(GateRef gate)2184 void TypedBytecodeLowering::LowerTypedCallthis3(GateRef gate)
2185 {
2186 if (GetCalleePandaFile(gate) == nullptr) {
2187 return;
2188 }
2189 CallThis3TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2190 BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2191 if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS3(pgoFuncId)) {
2192 AddProfiling(gate);
2193 SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArgs() }, pgoFuncId, true);
2194 return;
2195 }
2196 if (!tacc.CanOptimizeAsFastCall()) {
2197 return;
2198 }
2199 LowerTypedThisCall<EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8>(tacc);
2200 }
2201
LowerTypedCallthisrange(GateRef gate)2202 void TypedBytecodeLowering::LowerTypedCallthisrange(GateRef gate)
2203 {
2204 if (GetCalleePandaFile(gate) == nullptr) {
2205 return;
2206 }
2207 CallThisRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2208 if (!tacc.CanOptimizeAsFastCall()) {
2209 return;
2210 }
2211 LowerTypedThisCall<EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8>(tacc);
2212 }
2213
LowerTypedCallInit(GateRef gate)2214 void TypedBytecodeLowering::LowerTypedCallInit(GateRef gate)
2215 {
2216 // same as callthis0
2217 LowerTypedCallthis0(gate);
2218 }
2219
AddProfiling(GateRef gate)2220 void TypedBytecodeLowering::AddProfiling(GateRef gate)
2221 {
2222 hitTypedOpCount_++;
2223 AddHitBytecodeCount();
2224 if (IsTraceBC()) {
2225 // see stateSplit as a part of JSByteCode if exists
2226 GateRef maybeStateSplit = acc_.GetDep(gate);
2227 GateRef current = Circuit::NullGate();
2228 if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
2229 current = maybeStateSplit;
2230 } else {
2231 current = gate;
2232 }
2233
2234 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
2235 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
2236 GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
2237 GateRef typedPath = builder_.Int32ToTaggedInt(builder_.Int32(1));
2238 GateRef traceGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(current),
2239 { constOpcode, typedPath }, gate);
2240 acc_.SetDep(current, traceGate);
2241 builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: trace or STATE_SPLIT
2242 }
2243
2244 if (IsProfiling()) {
2245 // see stateSplit as a part of JSByteCode if exists
2246 GateRef maybeStateSplit = acc_.GetDep(gate);
2247 GateRef current = Circuit::NullGate();
2248 if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
2249 current = maybeStateSplit;
2250 } else {
2251 current = gate;
2252 }
2253
2254 GateRef func = builder_.Undefined();
2255 if (acc_.HasFrameState(gate)) {
2256 func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
2257 }
2258
2259 GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate)));
2260 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
2261 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
2262 GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
2263 GateRef mode =
2264 builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::TYPED_PATH)));
2265 GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current),
2266 { func, bcIndex, constOpcode, mode }, gate);
2267 acc_.SetDep(current, profiling);
2268 builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: profiling or STATE_SPLIT
2269 }
2270 }
2271
AddBytecodeCount(EcmaOpcode op)2272 void TypedBytecodeLowering::AddBytecodeCount(EcmaOpcode op)
2273 {
2274 currentOp_ = op;
2275 if (bytecodeMap_.find(op) != bytecodeMap_.end()) {
2276 bytecodeMap_[op]++;
2277 } else {
2278 bytecodeMap_[op] = 1;
2279 }
2280 }
2281
DeleteBytecodeCount(EcmaOpcode op)2282 void TypedBytecodeLowering::DeleteBytecodeCount(EcmaOpcode op)
2283 {
2284 bytecodeMap_.erase(op);
2285 }
2286
AddHitBytecodeCount()2287 void TypedBytecodeLowering::AddHitBytecodeCount()
2288 {
2289 if (bytecodeHitTimeMap_.find(currentOp_) != bytecodeHitTimeMap_.end()) {
2290 bytecodeHitTimeMap_[currentOp_]++;
2291 } else {
2292 bytecodeHitTimeMap_[currentOp_] = 1;
2293 }
2294 }
2295
LowerTypedTypeOf(GateRef gate)2296 void TypedBytecodeLowering::LowerTypedTypeOf(GateRef gate)
2297 {
2298 TypeOfTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
2299 if (tacc.IsIllegalType()) {
2300 return;
2301 }
2302 AddProfiling(gate);
2303 if (!Uncheck()) {
2304 builder_.TypeOfCheck(tacc.GetValue(), tacc.GetParamType());
2305 }
2306 GateRef result = builder_.TypedTypeOf(tacc.GetParamType());
2307 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
2308 }
2309
LowerGetIterator(GateRef gate)2310 void TypedBytecodeLowering::LowerGetIterator(GateRef gate)
2311 {
2312 if (GetCalleePandaFile(gate) == nullptr) {
2313 return;
2314 }
2315 GetIteratorTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2316 BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinMethodId();
2317 if (IS_INVALID_ID(id) || id == BuiltinsStubCSigns::ID::NONE) {
2318 return;
2319 }
2320 AddProfiling(gate);
2321 GateRef obj = tacc.GetCallee();
2322 SpeculateCallBuiltin(gate, obj, { obj }, id, true);
2323 }
2324
LowerTypedTryLdGlobalByName(GateRef gate)2325 void TypedBytecodeLowering::LowerTypedTryLdGlobalByName(GateRef gate)
2326 {
2327 if (!enableLoweringBuiltin_) {
2328 return;
2329 }
2330 LoadGlobalObjByNameTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
2331 JSTaggedValue key = tacc.GetKeyTaggedValue();
2332 if (key.IsUndefined()) {
2333 return;
2334 }
2335
2336 BuiltinIndex& builtin = BuiltinIndex::GetInstance();
2337 auto index = builtin.GetBuiltinIndex(key);
2338 if (index == builtin.NOT_FOUND) {
2339 return;
2340 }
2341 AddProfiling(gate);
2342 GateRef result = builder_.LoadBuiltinObject(index);
2343 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
2344 DeleteConstDataIfNoUser(tacc.GetKey());
2345 }
2346
LowerInstanceOf(GateRef gate)2347 void TypedBytecodeLowering::LowerInstanceOf(GateRef gate)
2348 {
2349 InstanceOfTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
2350 if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
2351 return;
2352 }
2353 AddProfiling(gate);
2354 size_t typeCount = tacc.GetTypeCount();
2355 std::vector<GateRef> expectedHCIndexes;
2356 for (size_t i = 0; i < typeCount; ++i) {
2357 GateRef temp = builder_.Int32(tacc.GetExpectedHClassIndex(i));
2358 expectedHCIndexes.emplace_back(temp);
2359 }
2360 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
2361 // RuntimeCheck -
2362 // 1. pgo.hclass == ctor.hclass
2363 // 2. ctor.hclass has a prototype chain up to Function.prototype
2364 GateRef obj = tacc.GetReceiver();
2365 GateRef target = tacc.GetTarget();
2366
2367 builder_.ObjectTypeCheck(false, target, expectedHCIndexes[0]);
2368 builder_.ProtoChangeMarkerCheck(target);
2369
2370 result = builder_.OrdinaryHasInstance(obj, target);
2371 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
2372 }
2373
LowerCreateEmptyObject(GateRef gate)2374 void TypedBytecodeLowering::LowerCreateEmptyObject(GateRef gate)
2375 {
2376 AddProfiling(gate);
2377 GateRef globalEnv = builder_.GetGlobalEnv();
2378 GateRef hclass = builder_.GetGlobalEnvObjHClass(globalEnv, GlobalEnv::OBJECT_FUNCTION_INDEX);
2379
2380 JSHandle<JSFunction> objectFunc(compilationEnv_->GetGlobalEnv()->GetObjectFunction());
2381 JSTaggedValue protoOrHClass = objectFunc->GetProtoOrHClass();
2382 JSHClass *objectHC = JSHClass::Cast(protoOrHClass.GetTaggedObject());
2383 size_t objectSize = objectHC->GetObjectSize();
2384
2385 GateRef emptyArray = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
2386 GateRef size = builder_.IntPtr(objectHC->GetObjectSize());
2387
2388 builder_.StartAllocate();
2389 GateRef object = builder_.HeapAlloc(glue_, size, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
2390
2391 // initialization
2392 for (size_t offset = JSObject::SIZE; offset < objectSize; offset += JSTaggedValue::TaggedTypeSize()) {
2393 builder_.StoreConstOffset(VariableType::INT64(), object, offset, builder_.Undefined());
2394 }
2395 builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::HCLASS_OFFSET, hclass,
2396 MemoryAttribute::NeedBarrierAndAtomic());
2397 builder_.StoreConstOffset(VariableType::INT64(), object, JSObject::HASH_OFFSET,
2398 builder_.Int64(JSTaggedValue(0).GetRawData()));
2399 builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::PROPERTIES_OFFSET, emptyArray,
2400 MemoryAttribute::NoBarrier());
2401 builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::ELEMENTS_OFFSET, emptyArray,
2402 MemoryAttribute::NoBarrier());
2403 GateRef result = builder_.FinishAllocate(object);
2404
2405 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
2406 }
2407
LowerTypedStOwnByValue(GateRef gate)2408 void TypedBytecodeLowering::LowerTypedStOwnByValue(GateRef gate)
2409 {
2410 // StOwnByValue is rarely used, so the callruntime solution is used
2411 AddProfiling(gate);
2412 return;
2413 }
2414
LowerCreateObjectWithBuffer(GateRef gate)2415 void TypedBytecodeLowering::LowerCreateObjectWithBuffer(GateRef gate)
2416 {
2417 CreateObjWithBufferTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, recordName_, chunk_);
2418 if (!tacc.CanOptimize()) {
2419 return;
2420 }
2421 JSTaggedValue hclassVal = tacc.GetHClass();
2422 if (hclassVal.IsUndefined()) {
2423 return;
2424 }
2425 JSHClass *newClass = JSHClass::Cast(hclassVal.GetTaggedObject());
2426 GateRef index = tacc.GetIndex();
2427 JSTaggedValue obj = tacc.GetObject();
2428 if (obj.IsUndefined()) {
2429 return;
2430 }
2431 JSObject *objhandle = JSObject::Cast(obj);
2432 std::vector<uint64_t> inlinedProps;
2433 auto layout = LayoutInfo::Cast(newClass->GetLayout().GetTaggedObject());
2434 uint32_t numOfProps = newClass->NumberOfProps();
2435 uint32_t numInlinedProps = newClass->GetInlinedProperties();
2436 for (uint32_t i = 0; i < numOfProps; i++) {
2437 auto attr = layout->GetAttr(i);
2438 JSTaggedValue value = objhandle->GetPropertyInlinedProps(i);
2439 if ((!attr.IsTaggedRep()) || value.IsUndefinedOrNull() ||
2440 value.IsNumber() || value.IsBoolean() || value.IsException()) {
2441 auto converted = JSObject::ConvertValueWithRep(attr, value);
2442 if (!converted.first) {
2443 return;
2444 }
2445 // CanOptimize.GetObject had convert value, just used directly
2446 inlinedProps.emplace_back(value.GetRawData());
2447 } else {
2448 return;
2449 }
2450 }
2451
2452 AddProfiling(gate);
2453 auto size = newClass->GetObjectSize();
2454 std::vector<GateRef> valueIn;
2455 valueIn.emplace_back(builder_.IntPtr(size));
2456 valueIn.emplace_back(index);
2457 valueIn.emplace_back(builder_.Int64(JSTaggedValue(newClass).GetRawData()));
2458 valueIn.emplace_back(acc_.GetValueIn(gate, 1));
2459 for (uint32_t i = 0; i < numOfProps; i++) {
2460 auto attr = layout->GetAttr(i);
2461 GateRef prop;
2462 if (attr.IsIntRep()) {
2463 prop = builder_.Int32(inlinedProps.at(i));
2464 } else if (attr.IsTaggedRep()) {
2465 prop = circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(inlinedProps.at(i)),
2466 MachineType::I64, GateType::AnyType());
2467 } else if (attr.IsDoubleRep()) {
2468 prop = circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(inlinedProps.at(i)),
2469 MachineType::F64, GateType::NJSValue());
2470 } else {
2471 prop = builder_.Int64(inlinedProps.at(i));
2472 }
2473 valueIn.emplace_back(prop);
2474 valueIn.emplace_back(builder_.Int32(newClass->GetInlinedPropertiesOffset(i)));
2475 }
2476 GateRef prop = newClass->IsAOT() ? builder_.Hole() : builder_.Undefined();
2477 for (uint32_t i = numOfProps; i < numInlinedProps; i++) {
2478 valueIn.emplace_back(prop);
2479 valueIn.emplace_back(builder_.Int32(newClass->GetInlinedPropertiesOffset(i)));
2480 }
2481 GateRef ret = builder_.TypedCreateObjWithBuffer(valueIn);
2482 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret);
2483 }
2484
ReplaceGateWithPendingException(GateRef glue,GateRef gate,GateRef state,GateRef depend,GateRef value)2485 void TypedBytecodeLowering::ReplaceGateWithPendingException(GateRef glue, GateRef gate, GateRef state, GateRef depend,
2486 GateRef value)
2487 {
2488 auto condition = builder_.HasPendingException(glue);
2489 GateRef ifBranch = builder_.Branch(state, condition, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
2490 GateRef ifTrue = builder_.IfTrue(ifBranch);
2491 GateRef ifFalse = builder_.IfFalse(ifBranch);
2492 GateRef eDepend = builder_.DependRelay(ifTrue, depend);
2493 GateRef sDepend = builder_.DependRelay(ifFalse, depend);
2494
2495 StateDepend success(ifFalse, sDepend);
2496 StateDepend exception(ifTrue, eDepend);
2497 acc_.ReplaceHirWithIfBranch(gate, success, exception, value);
2498 }
2499 } // namespace panda::ecmascript
2500