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_.ReplaceHirAndReplaceDeadIfException(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_.ReplaceHirAndReplaceDeadIfException(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 if (Op == TypedBinOp::TYPED_ADD) {
450 ReplaceGateWithPendingException(glue_, tacc.GetGate(), builder_.GetState(), builder_.GetDepend(), result);
451 } else {
452 acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
453 }
454 }
455 }
456
457 template<TypedBinOp Op>
SpeculateNumbers(const BinOpTypeInfoAccessor & tacc)458 void TypedBytecodeLowering::SpeculateNumbers(const BinOpTypeInfoAccessor &tacc)
459 {
460 AddProfiling(tacc.GetGate());
461 pgoTypeLog_.CollectGateTypeLogInfo(tacc.GetGate(), true);
462 GateRef left = tacc.GetLeftGate();
463 GateRef right = tacc.GetReightGate();
464 GateRef result = builder_.TypedBinaryOp<Op>(left, right, tacc.GetParamType());
465 acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
466 }
467
468 template<TypedUnOp Op>
SpeculateNumber(const UnOpTypeInfoAccessor & tacc)469 void TypedBytecodeLowering::SpeculateNumber(const UnOpTypeInfoAccessor &tacc)
470 {
471 AddProfiling(tacc.GetGate());
472 pgoTypeLog_.CollectGateTypeLogInfo(tacc.GetGate(), false);
473 GateRef result = builder_.TypedUnaryOp<Op>(tacc.GetValue(), tacc.GetParamType());
474 acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
475 }
476
CheckedNumberToString(CircuitBuilder * builder,GateRef numOrStr,Label * exit)477 GateRef CheckedNumberToString(CircuitBuilder *builder, GateRef numOrStr, Label *exit)
478 {
479 auto isNum = builder->TaggedIsNumber(numOrStr);
480 Label numberBranch(builder);
481 Label notNumberBranch(builder);
482
483 DEFVALUE(res, builder, VariableType::JS_ANY(), numOrStr);
484 builder->Branch(isNum, &numberBranch, ¬NumberBranch, BranchWeight::ONE_WEIGHT, BranchWeight::ONE_WEIGHT,
485 "IsNumber");
486 builder->Bind(&numberBranch);
487 {
488 res = builder->NumberToString(numOrStr);
489 builder->Jump(exit);
490 }
491 builder->Bind(¬NumberBranch);
492 {
493 builder->EcmaStringCheck(numOrStr);
494 res = numOrStr;
495 builder->Jump(exit);
496 }
497 builder->Bind(exit);
498
499 return *res;
500 }
501
502 template<TypedBinOp Op>
SpeculateNumbersOrString(const BinOpTypeInfoAccessor & tacc)503 void TypedBytecodeLowering::SpeculateNumbersOrString(const BinOpTypeInfoAccessor &tacc)
504 {
505 if (Op == TypedBinOp::TYPED_ADD) {
506 AddProfiling(tacc.GetGate());
507 GateRef left = tacc.GetLeftGate();
508 GateRef right = tacc.GetReightGate();
509
510 Label exit(&builder_);
511 if (TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, left)) {
512 right = CheckedNumberToString(&builder_, right, &exit);
513 ASSERT(tacc.GetParamType() == ParamType::StringType());
514 GateRef result = builder_.TypedBinaryOp<Op>(left, right, ParamType::StringType());
515 acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
516 } else if (TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, right)) {
517 left = CheckedNumberToString(&builder_, left, &exit);
518 ASSERT(tacc.GetParamType() == ParamType::StringType());
519 GateRef result = builder_.TypedBinaryOp<Op>(left, right, ParamType::StringType());
520 acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
521 }
522 }
523 }
524
LowerTypeToNumeric(GateRef gate)525 void TypedBytecodeLowering::LowerTypeToNumeric(GateRef gate)
526 {
527 UnOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
528 if (tacc.HasNumberType()) {
529 AddProfiling(gate);
530 LowerPrimitiveTypeToNumber(tacc);
531 }
532 }
533
LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor & tacc)534 void TypedBytecodeLowering::LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor &tacc)
535 {
536 GateRef result = builder_.PrimitiveToNumber(tacc.GetValue(), tacc.GetParamType());
537 acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
538 }
539
LowerConditionJump(GateRef gate,bool flag)540 void TypedBytecodeLowering::LowerConditionJump(GateRef gate, bool flag)
541 {
542 ConditionJumpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
543 if (TypeInfoAccessor::IsTrustedBooleanType(acc_, tacc.GetValue())) {
544 AddProfiling(gate);
545 SpeculateConditionJump(tacc, flag);
546 }
547 }
548
SpeculateConditionJump(const ConditionJumpTypeInfoAccessor & tacc,bool flag)549 void TypedBytecodeLowering::SpeculateConditionJump(const ConditionJumpTypeInfoAccessor &tacc, bool flag)
550 {
551 GateRef value = tacc.GetValue();
552 ParamType paramType = ParamType::BooleanType();
553 uint32_t weight = tacc.GetBranchWeight();
554 GateRef jump = Circuit::NullGate();
555 if (flag) {
556 jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JNEZ>(value, paramType, weight);
557 } else {
558 jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JEQZ>(value, paramType, weight);
559 }
560 acc_.ReplaceGate(tacc.GetGate(), jump, jump, Circuit::NullGate());
561 }
562
DeleteConstDataIfNoUser(GateRef gate)563 void TypedBytecodeLowering::DeleteConstDataIfNoUser(GateRef gate)
564 {
565 auto uses = acc_.Uses(gate);
566 if (uses.begin() == uses.end()) {
567 builder_.ClearConstantCache(gate);
568 acc_.DeleteGate(gate);
569 }
570 }
571
GeneratePrimitiveTypeCheck(CircuitBuilder & builder,GateRef receiver,PrimitiveType primitiveType)572 static void GeneratePrimitiveTypeCheck(CircuitBuilder &builder, GateRef receiver, PrimitiveType primitiveType)
573 {
574 switch (primitiveType) {
575 case PrimitiveType::PRIMITIVE_BOOLEAN:
576 builder.TryPrimitiveTypeCheck(GateType::BooleanType(), receiver);
577 break;
578 case PrimitiveType::PRIMITIVE_NUMBER:
579 builder.TryPrimitiveTypeCheck(GateType::NumberType(), receiver);
580 break;
581 default:
582 LOG_ECMA(FATAL) << "Implementation Error: Unreachable branch.";
583 UNREACHABLE();
584 break;
585 }
586 }
587
GetPrimitiveTypeProto(PrimitiveType primitiveType)588 GateRef TypedBytecodeLowering::GetPrimitiveTypeProto(PrimitiveType primitiveType)
589 {
590 size_t index = -1;
591 if (primitiveType == PrimitiveType::PRIMITIVE_BOOLEAN) {
592 index = GlobalEnv::BOOLEAN_PROTOTYPE_INDEX;
593 } else if (primitiveType == PrimitiveType::PRIMITIVE_NUMBER) {
594 index = GlobalEnv::NUMBER_PROTOTYPE_INDEX;
595 } else {
596 LOG_ECMA(FATAL) << "Implementation Error: Unreachable branch, not supported primitiveType currently";
597 UNREACHABLE();
598 }
599 ASSERT(index != static_cast<size_t>(-1));
600 return builder_.GetGlobalEnvValue(VariableType::JS_ANY(), glue_, circuit_->GetGlobalEnvCache(), index);
601 }
602
PolyPrimitiveTypeCheckAndLoad(LoadObjByNameDataInfo & info,std::map<size_t,uint32_t> & typeIndex2HeapConstantIndex)603 void TypedBytecodeLowering::PolyPrimitiveTypeCheckAndLoad(LoadObjByNameDataInfo &info,
604 std::map<size_t, uint32_t> &typeIndex2HeapConstantIndex)
605 {
606 GateRef receiver = info.tacc.GetReceiver();
607 auto itr = typeIndex2HeapConstantIndex.begin();
608 size_t typeCount = info.tacc.GetTypeCount();
609 GateRef gate = info.tacc.GetGate();
610 GateRef frameState = acc_.GetFrameState(gate);
611 for (size_t i = 0; i < typeIndex2HeapConstantIndex.size(); ++i) {
612 auto primitiveType = info.tacc.GetPrimitiveType(itr->first);
613 // only boolean and number are supported currently
614 ASSERT(primitiveType == PrimitiveType::PRIMITIVE_BOOLEAN || primitiveType == PrimitiveType::PRIMITIVE_NUMBER);
615 Label isDesignatePrimitiveType(&builder_);
616 if (i != typeCount - 1) {
617 if (primitiveType == PrimitiveType::PRIMITIVE_NUMBER) {
618 BRANCH_CIR(builder_.TaggedIsNumber(receiver), &isDesignatePrimitiveType, &info.fails[i]);
619 } else {
620 BRANCH_CIR(builder_.TaggedIsBoolean(receiver), &isDesignatePrimitiveType, &info.fails[i]);
621 }
622 } else {
623 GeneratePrimitiveTypeCheck(builder_, receiver, primitiveType);
624 builder_.Jump(&isDesignatePrimitiveType);
625 }
626 builder_.Bind(&isDesignatePrimitiveType);
627 GateRef protoType = GetPrimitiveTypeProto(primitiveType);
628 builder_.PrimitiveTypeProtoChangeMarkerCheck(protoType, frameState);
629 GateRef protoConstant = builder_.HeapConstant(itr->second);
630 info.result = BuildNamedPropertyAccess(gate, receiver, protoConstant, info.tacc.GetAccessInfo(i).Plr());
631 builder_.Jump(&info.exit);
632
633 if (i != typeCount - 1) {
634 builder_.Bind(&info.fails[i]);
635 }
636 itr++;
637 }
638 }
639
LoadOnPrototypeForHeapObjectReceiver(const LoadObjPropertyTypeInfoAccessor & tacc,Variable & result,LoadObjByNameOnProtoTypeInfo ldProtoInfo)640 void TypedBytecodeLowering::LoadOnPrototypeForHeapObjectReceiver(const LoadObjPropertyTypeInfoAccessor &tacc,
641 Variable &result, LoadObjByNameOnProtoTypeInfo ldProtoInfo)
642 {
643 auto gate = tacc.GetGate();
644 // prototype change marker check
645 if (!TryLazyDeoptStableProtoChain(tacc, ldProtoInfo.typeIndex, gate)) {
646 builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), ldProtoInfo.frameState);
647 }
648 // lookup from receiver for holder
649 auto prototype = builder_.LoadPrototype(glue_, ldProtoInfo.receiverHC);
650 // lookup from receiver for holder
651 ObjectAccessTypeInfoAccessor::ObjectAccessInfo info = tacc.GetAccessInfo(ldProtoInfo.typeIndex);
652 bool protoConstantFound = false;
653 if (compilationEnv_->SupportHeapConstant()) {
654 auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
655 const auto &holderHClassIndex2HeapConstantIndex =
656 jitCompilationEnv->GetHolderHClassIndex2HeapConstantIndex();
657 auto holderHClassIndex = info.HClassIndex();
658 auto itr = holderHClassIndex2HeapConstantIndex.find(holderHClassIndex);
659 if (itr != holderHClassIndex2HeapConstantIndex.end()) {
660 // holder is HeapConstant, which is recorded at jit profiler. so don't need to visit protochain
661 GateRef protoConstant = builder_.HeapConstant(itr->second);
662 result = BuildNamedPropertyAccess(
663 gate, tacc.GetReceiver(), protoConstant, tacc.GetAccessInfo(ldProtoInfo.typeIndex).Plr());
664 builder_.Jump(ldProtoInfo.exit);
665 protoConstantFound = true;
666 }
667 }
668 if (!protoConstantFound) {
669 auto holderHC = builder_.GetHClassGateFromIndex(gate, info.HClassIndex());
670 DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
671 Label loopHead(&builder_);
672 Label loadHolder(&builder_);
673 Label lookUpProto(&builder_);
674 builder_.Jump(&loopHead);
675
676 builder_.LoopBegin(&loopHead);
677 builder_.DeoptCheck(builder_.TaggedIsNotNull(*current),
678 ldProtoInfo.frameState, DeoptType::INCONSISTENTHCLASS2);
679 auto curHC = builder_.LoadHClassByConstOffset(glue_, *current);
680 BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
681
682 builder_.Bind(&lookUpProto);
683 current = builder_.LoadPrototype(glue_, curHC);
684 builder_.LoopEnd(&loopHead);
685
686 builder_.Bind(&loadHolder);
687 result = BuildNamedPropertyAccess(gate, tacc.GetReceiver(),
688 *current, tacc.GetAccessInfo(ldProtoInfo.typeIndex).Plr());
689 builder_.Jump(ldProtoInfo.exit);
690 }
691 }
692
LowerTypedMonoLdObjByNameOnProto(const LoadObjPropertyTypeInfoAccessor & tacc,Variable & result)693 void TypedBytecodeLowering::LowerTypedMonoLdObjByNameOnProto(const LoadObjPropertyTypeInfoAccessor &tacc,
694 Variable &result)
695 {
696 GateRef receiver = tacc.GetReceiver();
697 GateRef gate = tacc.GetGate();
698 PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
699 GateRef plrGate = builder_.Int32(plr.GetData());
700 GateRef unsharedConstPool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
701 size_t holderHClassIndex = static_cast<size_t>(tacc.GetAccessInfo(0).HClassIndex());
702 if (LIKELY(!plr.IsAccessor())) {
703 result = builder_.MonoLoadPropertyOnProto(receiver, plrGate, unsharedConstPool, holderHClassIndex);
704 } else {
705 result = builder_.MonoCallGetterOnProto(gate, receiver, plrGate, unsharedConstPool, holderHClassIndex);
706 }
707 }
708
LowerTypedMonoLdObjByName(const LoadObjPropertyTypeInfoAccessor & tacc)709 void TypedBytecodeLowering::LowerTypedMonoLdObjByName(const LoadObjPropertyTypeInfoAccessor &tacc)
710 {
711 GateRef receiver = tacc.GetReceiver();
712 GateRef gate = tacc.GetGate();
713 PrimitiveType primitiveType = tacc.GetPrimitiveType(0);
714 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
715 GateRef frameState = acc_.GetFrameState(gate);
716 if ((primitiveType != PrimitiveType::PRIMITIVE_TYPE_INVALID) && compilationEnv_->SupportHeapConstant()) {
717 Label notPrimitive(&builder_);
718 Label isPrimitive(&builder_);
719 if (primitiveType == PrimitiveType::PRIMITIVE_NUMBER) {
720 Label isNumber(&builder_);
721 BRANCH_CIR(builder_.TaggedIsNumber(receiver), &isNumber, ¬Primitive);
722 builder_.Bind(&isNumber);
723 GateRef protoType = GetPrimitiveTypeProto(PrimitiveType::PRIMITIVE_NUMBER);
724 builder_.PrimitiveTypeProtoChangeMarkerCheck(protoType, frameState);
725 builder_.Jump(&isPrimitive);
726 } else {
727 ASSERT(primitiveType == PrimitiveType::PRIMITIVE_BOOLEAN);
728 Label isBoolean(&builder_);
729 BRANCH_CIR(builder_.TaggedIsBoolean(receiver), &isBoolean, ¬Primitive);
730 builder_.Bind(&isBoolean);
731 GateRef prototype = GetPrimitiveTypeProto(PrimitiveType::PRIMITIVE_BOOLEAN);
732 builder_.PrimitiveTypeProtoChangeMarkerCheck(prototype, frameState);
733 builder_.Jump(&isPrimitive);
734 }
735 builder_.Bind(¬Primitive);
736 {
737 builder_.ObjectTypeCheck(false, receiver, tacc.GetExpectedHClassIndexList(0), frameState);
738 builder_.ProtoChangeMarkerCheck(receiver, frameState);
739 builder_.Jump(&isPrimitive);
740 }
741 builder_.Bind(&isPrimitive);
742 LowerTypedMonoLdObjByNameOnProto(tacc, result);
743 } else {
744 builder_.ObjectTypeCheck(false, receiver, tacc.GetExpectedHClassIndexList(0), frameState);
745 if (IsNonExist(tacc, 0)) {
746 if (TryLazyDeoptStableProtoChain(tacc, 0, gate)) {
747 result = builder_.Undefined();
748 } else {
749 builder_.DeoptCheck(builder_.Boolean(false), frameState, DeoptType::PROTOTYPECHANGED4);
750 }
751 } else {
752 if (tacc.IsReceiverEqHolder(0)) {
753 result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
754 } else {
755 if (!TryLazyDeoptStableProtoChain(tacc, 0, gate)) {
756 builder_.ProtoChangeMarkerCheck(receiver, frameState);
757 }
758 LowerTypedMonoLdObjByNameOnProto(tacc, result);
759 }
760 }
761 }
762 ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), *result,
763 tacc.GetAccessInfo(0).Plr().IsAccessor());
764 DeleteConstDataIfNoUser(tacc.GetKey());
765 }
766
GenerateMergedHClassListCheck(LoadObjByNameDataInfo & info,Label & hclassCheckExit,Variable & checkResult,size_t index,GateRef receiverHC)767 void TypedBytecodeLowering::GenerateMergedHClassListCheck(LoadObjByNameDataInfo &info, Label &hclassCheckExit,
768 Variable &checkResult, size_t index, GateRef receiverHC)
769 {
770 std::vector<Label> ifFalse;
771 Label resultIsTrue(&builder_);
772 Label resultIsFalse(&builder_);
773 const auto& hclassList = info.tacc.GetExpectedHClassIndexList(index);
774 size_t hclassCount = hclassList.size();
775
776 for (size_t j = 0; j < hclassCount - 1; j++) {
777 ifFalse.emplace_back(Label(&builder_));
778 }
779 for (size_t j = 0; j < hclassCount; j++) {
780 auto expected = builder_.GetHClassGateFromIndex(info.tacc.GetGate(), hclassList[j]);
781 if (j != hclassCount - 1) {
782 BRANCH_CIR(builder_.Equal(receiverHC, expected), &resultIsTrue, &ifFalse[j]);
783 builder_.Bind(&ifFalse[j]);
784 } else {
785 BRANCH_CIR(builder_.Equal(receiverHC, expected), &resultIsTrue, &resultIsFalse);
786 }
787 }
788 builder_.Bind(&resultIsFalse);
789 {
790 checkResult = builder_.Boolean(false);
791 builder_.Jump(&hclassCheckExit);
792 }
793 builder_.Bind(&resultIsTrue);
794 {
795 checkResult = builder_.Boolean(true);
796 builder_.Jump(&hclassCheckExit);
797 }
798 }
799
PolyHeapObjectCheckAndLoad(LoadObjByNameDataInfo & info,const std::map<size_t,uint32_t> & typeIndex2HeapConstantIndex)800 void TypedBytecodeLowering::PolyHeapObjectCheckAndLoad(LoadObjByNameDataInfo &info,
801 const std::map<size_t, uint32_t> &typeIndex2HeapConstantIndex)
802 {
803 GateRef gate = info.tacc.GetGate();
804 GateRef frameState = acc_.GetFrameState(gate);
805 builder_.HeapObjectCheck(info.tacc.GetReceiver(), frameState);
806 auto receiverHC = builder_.LoadHClassByConstOffset(glue_, info.tacc.GetReceiver());
807 size_t labelIndex = typeIndex2HeapConstantIndex.size();
808 size_t typeCount = info.tacc.GetTypeCount();
809 for (size_t i = 0; i < typeCount; ++i) {
810 if (typeIndex2HeapConstantIndex.find(i) != typeIndex2HeapConstantIndex.end()) {
811 continue;
812 }
813 Label hclassCheckExit(&builder_);
814 DEFVALUE(checkResult, (&builder_), VariableType::BOOL(), builder_.Boolean(false));
815 GenerateMergedHClassListCheck(info, hclassCheckExit, checkResult, i, receiverHC);
816 builder_.Bind(&hclassCheckExit);
817 if (labelIndex != typeCount - 1) {
818 BRANCH_CIR(*checkResult, &info.loaders[labelIndex], &info.fails[labelIndex]);
819 builder_.Bind(&info.loaders[labelIndex]);
820 } else {
821 // Deopt if fails at last hclass compare
822 builder_.DeoptCheck(*checkResult, frameState, DeoptType::INCONSISTENTHCLASS1);
823 }
824
825 if (IsNonExist(info.tacc, i)) {
826 if (TryLazyDeoptStableProtoChain(info.tacc, i, gate)) {
827 info.result = builder_.Undefined();
828 builder_.Jump(&info.exit);
829 } else {
830 builder_.DeoptCheck(builder_.Boolean(false), frameState, DeoptType::PROTOTYPECHANGED4);
831 builder_.Jump(&info.exit);
832 }
833 } else {
834 if (info.tacc.IsReceiverEqHolder(i)) {
835 info.result = BuildNamedPropertyAccess(gate, info.tacc.GetReceiver(), info.tacc.GetReceiver(),
836 info.tacc.GetAccessInfo(i).Plr());
837 builder_.Jump(&info.exit);
838 } else {
839 LoadOnPrototypeForHeapObjectReceiver(info.tacc, info.result,
840 { gate, frameState, receiverHC, &info.exit, i });
841 }
842 }
843 if (labelIndex != typeCount - 1) {
844 builder_.Bind(&info.fails[labelIndex]);
845 }
846 labelIndex++;
847 }
848 }
849
LowerTypedPolyLdObjByName(const LoadObjPropertyTypeInfoAccessor & tacc)850 void TypedBytecodeLowering::LowerTypedPolyLdObjByName(const LoadObjPropertyTypeInfoAccessor &tacc)
851 {
852 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
853 size_t typeCount = tacc.GetTypeCount();
854 std::vector<Label> loaders;
855 std::vector<Label> fails;
856 ASSERT(typeCount > 0);
857 bool hasGetter = false;
858 for (size_t i = 0; i < typeCount; ++i) {
859 hasGetter |= tacc.GetAccessInfo(i).Plr().IsAccessor();
860 }
861 for (size_t i = 0; i < typeCount - 1; ++i) {
862 loaders.emplace_back(Label(&builder_));
863 fails.emplace_back(Label(&builder_));
864 }
865 Label exit(&builder_);
866 GateRef gate = tacc.GetGate();
867 std::map<size_t, uint32_t> typeIndex2HeapConstantIndex = tacc.CollectPrimitiveTypeInfo(compilationEnv_);
868 LoadObjByNameDataInfo info(loaders, fails, tacc, result, exit);
869 if (!typeIndex2HeapConstantIndex.empty()) {
870 PolyPrimitiveTypeCheckAndLoad(info, typeIndex2HeapConstantIndex);
871 }
872
873 if (typeIndex2HeapConstantIndex.size() < typeCount) {
874 PolyHeapObjectCheckAndLoad(info, typeIndex2HeapConstantIndex);
875 }
876 builder_.Bind(&exit);
877 ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), *result,
878 hasGetter);
879 DeleteConstDataIfNoUser(tacc.GetKey());
880 }
881
LowerTypedLdObjByName(GateRef gate)882 void TypedBytecodeLowering::LowerTypedLdObjByName(GateRef gate)
883 {
884 LoadObjPropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
885
886 if (TryLowerTypedLdobjBynameFromGloablBuiltin(gate)) {
887 return;
888 }
889 if (TryLowerTypedLdObjByNameForBuiltin(gate)) {
890 return;
891 }
892 if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
893 return;
894 }
895 if (enableMergePoly_) {
896 tacc.TryMergeExpectedHClass();
897 }
898 AddProfiling(gate);
899 if (tacc.IsMono()) {
900 LowerTypedMonoLdObjByName(tacc);
901 return;
902 }
903 LowerTypedPolyLdObjByName(tacc);
904 }
905
LowerTypedLdPrivateProperty(GateRef gate)906 void TypedBytecodeLowering::LowerTypedLdPrivateProperty(GateRef gate)
907 {
908 LoadPrivatePropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
909
910 if (tacc.HasIllegalType()) {
911 return;
912 }
913
914 AddProfiling(gate);
915 Label exit(&builder_);
916
917 GateRef receiver = tacc.GetReceiver();
918 GateRef levelIndex = tacc.GetLevelIndex();
919 GateRef slotIndex = tacc.GetSlotIndex();
920
921 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
922 GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
923 GateRef key = builder_.GetKeyFromLexivalEnv(glue_,
924 tacc.GetLexicalEnv(), builder_.TaggedGetInt(levelIndex), builder_.TaggedGetInt(slotIndex));
925
926 builder_.HeapObjectCheck(key, frameState);
927 if (tacc.IsAccessor()) {
928 builder_.DeoptCheck(builder_.IsJSFunction(glue_, key), frameState, DeoptType::NOTJSFUNCTION);
929 result = builder_.CallPrivateGetter(gate, receiver, key);
930 builder_.Jump(&exit);
931 } else {
932 builder_.DeoptCheck(builder_.TaggedIsSymbol(glue_, key), frameState, DeoptType::NOTSYMBOL);
933 builder_.ObjectTypeCheck(false, receiver, builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
934 result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
935 builder_.Jump(&exit);
936 }
937
938 builder_.Bind(&exit);
939 ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), *result, tacc.IsAccessor());
940 DeleteConstDataIfNoUser(key);
941 }
942
LowerTypedStPrivateProperty(GateRef gate)943 void TypedBytecodeLowering::LowerTypedStPrivateProperty(GateRef gate)
944 {
945 StorePrivatePropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
946
947 if (tacc.HasIllegalType()) {
948 return;
949 }
950
951 AddProfiling(gate);
952 Label exit(&builder_);
953
954 GateRef receiver = tacc.GetReceiver();
955 GateRef levelIndex = tacc.GetLevelIndex();
956 GateRef slotIndex = tacc.GetSlotIndex();
957 GateRef value = tacc.GetValue();
958
959 GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
960 GateRef key = builder_.GetKeyFromLexivalEnv(glue_,
961 tacc.GetLexicalEnv(), builder_.TaggedGetInt(levelIndex), builder_.TaggedGetInt(slotIndex));
962
963 builder_.HeapObjectCheck(key, frameState);
964 if (tacc.IsAccessor()) {
965 builder_.DeoptCheck(builder_.IsJSFunction(glue_, key), frameState, DeoptType::NOTJSFUNCTION);
966 builder_.CallPrivateSetter(gate, receiver, key, value);
967 builder_.Jump(&exit);
968 } else {
969 builder_.DeoptCheck(builder_.TaggedIsSymbol(glue_, key), frameState, DeoptType::NOTSYMBOL);
970 builder_.ObjectTypeCheck(false, receiver, builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
971 BuildNamedPropertyAccess(
972 gate, receiver, receiver, value, tacc.GetAccessInfo(0).Plr(), tacc.GetExpectedHClassIndex(0));
973 builder_.Jump(&exit);
974 }
975
976 builder_.Bind(&exit);
977 ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), Circuit::NullGate(), tacc.IsAccessor());
978 DeleteConstDataIfNoUser(key);
979 }
980
RecordGate2HeapConstantIndex(CompilationEnv * compilationEnv,uint32_t methodOffset,uint32_t keyIndex,GateRef resultGate)981 static void RecordGate2HeapConstantIndex(CompilationEnv *compilationEnv, uint32_t methodOffset,
982 uint32_t keyIndex, GateRef resultGate)
983 {
984 if (!compilationEnv->SupportHeapConstant()) {
985 return;
986 }
987 auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv);
988 JSTaggedValue strObj = jitCompilationEnv->GetStringFromConstantPool(methodOffset, keyIndex, false);
989 if (strObj.IsUndefined()) {
990 return;
991 }
992 JSHandle<JSTaggedValue> strObjHandle = jitCompilationEnv->NewJSHandle(strObj);
993 auto constpool = jitCompilationEnv->GetConstantPoolByMethodOffset(methodOffset);
994 ASSERT(!constpool.IsUndefined());
995 auto constpoolId = static_cast<uint32_t>(
996 ConstantPool::Cast(constpool.GetTaggedObject())->GetSharedConstpoolId().GetInt());
997 uint32_t indexInConstantTable = jitCompilationEnv->RecordHeapConstant(
998 { constpoolId, keyIndex, JitCompilationEnv::IN_SHARED_CONSTANTPOOL }, strObjHandle);
999 jitCompilationEnv->RecordGate2HeapConstantIndex(resultGate, indexInConstantTable);
1000 }
1001
LowerTypedStObjByName(GateRef gate)1002 void TypedBytecodeLowering::LowerTypedStObjByName(GateRef gate)
1003 {
1004 StoreObjByNameTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1005 if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
1006 return;
1007 }
1008 size_t typeCount = tacc.GetTypeCount();
1009 std::vector<Label> loaders;
1010 std::vector<Label> fails;
1011 ASSERT(typeCount > 0);
1012 for (size_t i = 0; i < typeCount - 1; ++i) {
1013 loaders.emplace_back(Label(&builder_));
1014 fails.emplace_back(Label(&builder_));
1015 }
1016 Label exit(&builder_);
1017 AddProfiling(gate);
1018 GateRef frameState = Circuit::NullGate();
1019 auto opcode = acc_.GetByteCodeOpcode(gate);
1020 // The framestate of Call and Accessor related instructions directives is placed on IR. Using the depend edge to
1021 // climb up and find the nearest framestate for other instructions
1022 if (opcode == EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8 ||
1023 opcode == EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8) {
1024 frameState = acc_.FindNearestFrameState(builder_.GetDepend());
1025 } else if (opcode == EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8 ||
1026 opcode == EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8 ||
1027 opcode == EcmaOpcode::STTHISBYNAME_IMM8_ID16 ||
1028 opcode == EcmaOpcode::STTHISBYNAME_IMM16_ID16 ||
1029 opcode == EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8 ||
1030 opcode == EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8) {
1031 frameState = acc_.GetFrameState(gate);
1032 } else {
1033 UNREACHABLE();
1034 }
1035 if (tacc.IsMono()) {
1036 GateRef receiver = tacc.GetReceiver();
1037 builder_.ObjectTypeCheck(false, receiver,
1038 builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
1039 if (tacc.IsReceiverNoEqNewHolder(0)) {
1040 if (!TryLazyDeoptStableProtoChain(tacc, 0, gate)) {
1041 builder_.ProtoChangeMarkerCheck(receiver, frameState);
1042 }
1043 PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
1044 GateRef plrGate = builder_.Int32(plr.GetData());
1045 GateRef unsharedConstPool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
1046 size_t holderHClassIndex = static_cast<size_t>(tacc.GetAccessInfo(0).HClassIndex());
1047 GateRef value = tacc.GetValue();
1048 if (tacc.IsHolderEqNewHolder(0)) {
1049 builder_.MonoStorePropertyLookUpProto(tacc.GetReceiver(), plrGate, unsharedConstPool, holderHClassIndex,
1050 value);
1051 } else {
1052 if (!tacc.IsPrototypeHclass(0)) {
1053 if (!TryLazyDeoptNotPrototype(tacc, 0, gate)) {
1054 builder_.DeoptCheck(builder_.BoolNot(builder_.IsPrototypeHClass(tacc.GetReceiver())),
1055 frameState, DeoptType::PROTOTYPECHANGED3);
1056 }
1057 }
1058 GateRef ret = builder_.MonoStoreProperty(tacc.GetReceiver(), plrGate, unsharedConstPool,
1059 holderHClassIndex, value, builder_.TruncInt64ToInt32(tacc.GetKey()),
1060 builder_.Boolean(tacc.IsPrototypeHclass(0)), frameState);
1061 auto methodOffset = acc_.TryGetMethodOffset(gate);
1062 uint32_t keyIndex = static_cast<uint32_t>(acc_.GetConstantValue(tacc.GetKey()));
1063 RecordGate2HeapConstantIndex(compilationEnv_, methodOffset, keyIndex, ret);
1064 }
1065 } else if (tacc.IsReceiverEqHolder(0)) {
1066 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
1067 tacc.GetValue(), tacc.GetAccessInfo(0).Plr(), tacc.GetExpectedHClassIndex(0));
1068 }
1069 ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), Circuit::NullGate(),
1070 tacc.GetAccessInfo(0).Plr().IsAccessor());
1071 DeleteConstDataIfNoUser(tacc.GetKey());
1072 return;
1073 }
1074 builder_.HeapObjectCheck(tacc.GetReceiver(), frameState);
1075 auto receiverHC = builder_.LoadHClassByConstOffset(glue_, tacc.GetReceiver());
1076 bool hasSetter = false;
1077 for (size_t i = 0; i < typeCount; ++i) {
1078 hasSetter |= tacc.GetAccessInfo(i).Plr().IsAccessor();
1079 auto expected = builder_.GetHClassGateFromIndex(gate, tacc.GetExpectedHClassIndex(i));
1080 if (i != typeCount - 1) {
1081 BRANCH_CIR(builder_.Equal(receiverHC, expected),
1082 &loaders[i], &fails[i]);
1083 builder_.Bind(&loaders[i]);
1084 } else {
1085 builder_.DeoptCheck(builder_.Equal(receiverHC, expected), frameState, DeoptType::INCONSISTENTHCLASS3);
1086 }
1087 if (tacc.IsReceiverNoEqNewHolder(i)) {
1088 if (!TryLazyDeoptStableProtoChain(tacc, i, gate)) {
1089 builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
1090 }
1091 if (tacc.IsHolderEqNewHolder(i)) {
1092 // lookup from receiver for holder
1093 auto prototype = builder_.LoadPrototype(glue_, receiverHC);
1094 auto holderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
1095 DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
1096 Label loopHead(&builder_);
1097 Label loadHolder(&builder_);
1098 Label lookUpProto(&builder_);
1099 builder_.Jump(&loopHead);
1100
1101 builder_.LoopBegin(&loopHead);
1102 builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS4);
1103 auto curHC = builder_.LoadHClassByConstOffset(glue_, *current);
1104 BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
1105
1106 builder_.Bind(&lookUpProto);
1107 current = builder_.LoadPrototype(glue_, curHC);
1108 builder_.LoopEnd(&loopHead);
1109
1110 builder_.Bind(&loadHolder);
1111 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), *current, tacc.GetValue(),
1112 tacc.GetAccessInfo(i).Plr());
1113 builder_.Jump(&exit);
1114 } else {
1115 TypedStObjByNameTransition(gate, receiverHC, frameState, exit, tacc, i);
1116 }
1117 } else if (tacc.IsReceiverEqHolder(i)) {
1118 // Local
1119 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
1120 tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
1121 builder_.Jump(&exit);
1122 } else {
1123 // find in prototype, same as transition
1124 UNREACHABLE();
1125 return;
1126 }
1127 if (i != typeCount - 1) {
1128 // process fastpath for next type
1129 builder_.Bind(&fails[i]);
1130 }
1131 }
1132 builder_.Bind(&exit);
1133 ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), Circuit::NullGate(), hasSetter);
1134 DeleteConstDataIfNoUser(tacc.GetKey());
1135 }
1136
TypedStObjByNameTransition(GateRef gate,GateRef receiverHC,GateRef frameState,Label & exit,StoreObjByNameTypeInfoAccessor & tacc,size_t i)1137 void TypedBytecodeLowering::TypedStObjByNameTransition(GateRef gate, GateRef receiverHC, GateRef frameState,
1138 Label &exit, StoreObjByNameTypeInfoAccessor &tacc, size_t i)
1139 {
1140 Label notProto(&builder_);
1141 Label isProto(&builder_);
1142 auto newHolderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
1143 if (compilationEnv_->IsAotCompiler()) {
1144 auto prototype = builder_.LoadPrototype(glue_, receiverHC);
1145 builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype);
1146 }
1147 if (!tacc.IsPrototypeHclass(i)) {
1148 if (!TryLazyDeoptNotPrototype(tacc, i, gate)) {
1149 builder_.DeoptCheck(builder_.BoolNot(builder_.IsPrototypeHClass(tacc.GetReceiver())),
1150 frameState, DeoptType::PROTOTYPECHANGED3);
1151 }
1152 } else {
1153 builder_.Branch(builder_.IsPrototypeHClass(receiverHC), &isProto, ¬Proto,
1154 BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "isPrototypeHClass");
1155 builder_.Bind(&isProto);
1156 GateRef propKey =
1157 builder_.GetObjectByIndexFromConstPool(glue_, gate, frameState,
1158 builder_.TruncInt64ToInt32(tacc.GetKey()), ConstPoolType::STRING);
1159 builder_.CallRuntime(glue_, RTSTUB_ID(UpdateAOTHClass), Gate::InvalidGateRef,
1160 { receiverHC, newHolderHC, propKey }, gate);
1161 builder_.Jump(¬Proto);
1162 builder_.Bind(¬Proto);
1163 }
1164 MemoryAttribute mAttr = MemoryAttribute::NeedBarrierAndAtomic();
1165 builder_.TransitionHClassByConstOffset(glue_, tacc.GetReceiver(), newHolderHC, mAttr);
1166 if (!tacc.GetAccessInfo(i).Plr().IsInlinedProps()) {
1167 auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(),
1168 JSObject::PROPERTIES_OFFSET);
1169 auto capacity = builder_.LoadConstOffset(VariableType::INT32(), properties, TaggedArray::LENGTH_OFFSET);
1170 auto index = builder_.Int32(tacc.GetAccessInfo(i).Plr().GetOffset());
1171 Label needExtend(&builder_);
1172 Label notExtend(&builder_);
1173 BRANCH_CIR(builder_.Int32UnsignedLessThan(index, capacity), ¬Extend, &needExtend);
1174 builder_.Bind(¬Extend);
1175 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(), tacc.GetValue(),
1176 tacc.GetAccessInfo(i).Plr());
1177 builder_.Jump(&exit);
1178 builder_.Bind(&needExtend);
1179 builder_.CallRuntime(glue_, RTSTUB_ID(PropertiesSetValue), Gate::InvalidGateRef,
1180 { tacc.GetReceiver(), tacc.GetValue(), properties, builder_.Int32ToTaggedInt(capacity),
1181 builder_.Int32ToTaggedInt(index) }, gate);
1182 builder_.Jump(&exit);
1183 } else {
1184 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(), tacc.GetValue(),
1185 tacc.GetAccessInfo(i).Plr());
1186 builder_.Jump(&exit);
1187 }
1188 }
1189
LowerTypedStOwnByName(GateRef gate)1190 void TypedBytecodeLowering::LowerTypedStOwnByName(GateRef gate)
1191 {
1192 LowerTypedStObjByName(gate);
1193 }
1194
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,PropertyLookupResult plr)1195 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
1196 GateRef hir, GateRef receiver, GateRef holder, PropertyLookupResult plr)
1197 {
1198 GateRef plrGate = builder_.Int32(plr.GetData());
1199 GateRef result = Circuit::NullGate();
1200 if (LIKELY(!plr.IsAccessor())) {
1201 result = builder_.LoadProperty(holder, plrGate, plr.IsFunction());
1202 } else {
1203 result = builder_.CallGetter(hir, receiver, holder, plrGate);
1204 }
1205 return result;
1206 }
1207
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,GateRef value,PropertyLookupResult plr,uint32_t receiverHClassIndex)1208 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
1209 GateRef hir, GateRef receiver, GateRef holder, GateRef value, PropertyLookupResult plr,
1210 uint32_t receiverHClassIndex)
1211 {
1212 GateRef plrGate = builder_.Int32(plr.GetData());
1213 GateRef result = Circuit::NullGate();
1214 if (LIKELY(!plr.IsAccessor())) {
1215 builder_.StoreProperty(receiver, plrGate, value, receiverHClassIndex);
1216 } else {
1217 builder_.CallSetter(hir, receiver, holder, plrGate, value);
1218 }
1219 return result;
1220 }
1221
TryLowerTypedLdObjByNameForBuiltin(GateRef gate)1222 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate)
1223 {
1224 LoadBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1225 // Just supported mono.
1226 if (tacc.IsMono()) {
1227 if (tacc.IsBuiltinsType()) {
1228 auto builtinsId = tacc.GetBuiltinsTypeId();
1229 if (builtinsId.has_value()) {
1230 if (TryLowerTypedLdObjByNameForBuiltin(tacc)) {
1231 return true;
1232 }
1233 return TryLowerTypedLdObjByNameForBuiltinMethod(tacc, builtinsId.value());
1234 }
1235 } else if (tacc.IsGlobalsType()) {
1236 auto globalsId = tacc.GetGlobalsId();
1237 if (globalsId.has_value()) {
1238 return TryLowerTypedLdObjByNameForGlobalsId(tacc, globalsId.value());
1239 }
1240 }
1241 } else if (tacc.GetTypeCount() > 0) {
1242 auto builtinsId = tacc.GetBuiltinsTypeId();
1243 if (builtinsId.has_value()) {
1244 return TryLowerTypedLdObjByNameForBuiltin(tacc);
1245 }
1246 }
1247 return false; // No lowering performed
1248 }
1249
TryLowerTypedLdObjByNameForBuiltin(const LoadBuiltinObjTypeInfoAccessor & tacc)1250 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(const LoadBuiltinObjTypeInfoAccessor &tacc)
1251 {
1252 JSTaggedValue key = tacc.GetKeyTaggedValue();
1253 if (key.IsUndefined()) {
1254 return false;
1255 }
1256 EcmaString *propString = EcmaString::Cast(key.GetTaggedObject());
1257 // (1) get length
1258 EcmaString *lengthString =
1259 EcmaString::Cast(compilationEnv_->GlobalConstants()->GetLengthString().GetTaggedObject());
1260 if (propString == lengthString) {
1261 if (tacc.IsBuiltinsArray()) {
1262 LowerTypedLdArrayLength(tacc);
1263 return true;
1264 }
1265 if (tacc.IsBuiltinsString()) {
1266 LowerTypedLdStringLength(tacc);
1267 return true;
1268 }
1269 if (tacc.IsBuiltinsTypeArray()) {
1270 LowerTypedLdTypedArrayLength(tacc);
1271 return true;
1272 }
1273 }
1274
1275 EcmaString *sizeString = EcmaString::Cast(compilationEnv_->GlobalConstants()->GetSizeString().GetTaggedObject());
1276 if (propString == sizeString) {
1277 if (tacc.IsBuiltinsMap()) {
1278 LowerTypedLdMapSize(tacc);
1279 return true;
1280 }
1281 }
1282
1283 // (2) other functions
1284 return false;
1285 }
1286
SetPlrLdFromIterResult(GlobalEnvField index,PropertyLookupResult & plr)1287 static void SetPlrLdFromIterResult(GlobalEnvField index, PropertyLookupResult &plr)
1288 {
1289 if (index == GlobalEnvField::ITERATOR_RESULT_CLASS_INDEX) {
1290 plr.SetIsLoadFromIterResult(true);
1291 }
1292 }
1293
TryLowerTypedLdObjByNameForGlobalsId(const LoadBuiltinObjTypeInfoAccessor & tacc,GlobalIndex globalsId)1294 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForGlobalsId(const LoadBuiltinObjTypeInfoAccessor &tacc,
1295 GlobalIndex globalsId)
1296 {
1297 GateRef receiver = tacc.GetReceiver();
1298 GateRef gate = tacc.GetGate();
1299 JSTaggedValue key = tacc.GetKeyTaggedValue();
1300 if (key.IsUndefined()) {
1301 return false;
1302 }
1303 GateRef frameState = acc_.FindNearestFrameState(gate);
1304 if (globalsId.IsGlobalConstId()) {
1305 ConstantIndex index = static_cast<ConstantIndex>(globalsId.GetGlobalConstId());
1306 JSHClass *hclass = JSHClass::Cast(compilationEnv_->GlobalConstants()->GetGlobalConstantObject(
1307 static_cast<size_t>(index)).GetTaggedObject());
1308 PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1309 if (!plr.IsFound() || plr.IsAccessor()) {
1310 return false;
1311 }
1312 AddProfiling(gate);
1313 // 1. check hclass
1314 builder_.HeapObjectCheck(receiver, frameState);
1315 GateRef receiverHClass = builder_.LoadHClassByConstOffset(glue_, receiver);
1316 GateRef expectedHClass = builder_.GetGlobalConstantValue(index);
1317 builder_.DeoptCheck(builder_.Equal(receiverHClass, expectedHClass), frameState,
1318 DeoptType::INCONSISTENTHCLASS11);
1319 // 2. load property
1320 GateRef plrGate = builder_.Int32(plr.GetData());
1321 GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1322 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1323 DeleteConstDataIfNoUser(tacc.GetKey());
1324 return true;
1325 } else if (globalsId.IsGlobalEnvId()) { // ctor Hclass
1326 GlobalEnvField index = static_cast<GlobalEnvField>(globalsId.GetGlobalEnvId());
1327 JSHClass *hclass = JSHClass::Cast(compilationEnv_->GetGlobalEnv()->GetGlobalEnvObjectByIndex(
1328 static_cast<size_t>(index))->GetTaggedObject());
1329 PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1330 if (!plr.IsFound() || plr.IsAccessor()) {
1331 return false;
1332 }
1333 SetPlrLdFromIterResult(index, plr);
1334 AddProfiling(gate);
1335 // 1. check hclass
1336 builder_.HeapObjectCheck(receiver, frameState);
1337 GateRef receiverHClass = builder_.LoadHClassByConstOffset(glue_, receiver);
1338 GateRef globalEnvObj = builder_.GetGlobalEnvObj(circuit_->GetGlobalEnvCache(), static_cast<size_t>(index));
1339 builder_.DeoptCheck(builder_.Equal(receiverHClass, globalEnvObj), frameState,
1340 DeoptType::INCONSISTENTHCLASS12);
1341 // 2. load property
1342 GateRef plrGate = builder_.Int32(plr.GetData());
1343 GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1344 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1345 DeleteConstDataIfNoUser(tacc.GetKey());
1346 return true;
1347 }
1348 return false;
1349 }
1350
TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)1351 bool TypedBytecodeLowering::TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)
1352 {
1353 LoadBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1354 GateRef receiver = tacc.GetReceiver();
1355 if (acc_.GetOpCode(receiver) != OpCode::LOAD_BUILTIN_OBJECT) {
1356 return false;
1357 }
1358 JSHandle<GlobalEnv> globalEnv = compilationEnv_->GetGlobalEnv();
1359 uint64_t index = acc_.TryGetValue(receiver);
1360 BuiltinType type = static_cast<BuiltinType>(index);
1361 if (type == BuiltinType::BT_MATH) {
1362 auto math = globalEnv->GetMathFunction();
1363 JSHClass *hclass = math.GetTaggedValue().GetTaggedObject()->GetClass();
1364 JSTaggedValue key = tacc.GetKeyTaggedValue();
1365 if (key.IsUndefined()) {
1366 return false;
1367 }
1368 PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1369 if (!plr.IsFound() || plr.IsAccessor()) {
1370 return false;
1371 }
1372 AddProfiling(gate);
1373 builder_.MathHClassConsistencyCheck(receiver);
1374 GateRef plrGate = builder_.Int32(plr.GetData());
1375 GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1376 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1377 DeleteConstDataIfNoUser(tacc.GetKey());
1378 return true;
1379 }
1380 return false;
1381 }
1382
LowerTypedLdArrayLength(const LoadBuiltinObjTypeInfoAccessor & tacc)1383 void TypedBytecodeLowering::LowerTypedLdArrayLength(const LoadBuiltinObjTypeInfoAccessor &tacc)
1384 {
1385 GateRef gate = tacc.GetGate();
1386 GateRef array = tacc.GetReceiver();
1387 ElementsKind kind = acc_.TryGetElementsKind(gate);
1388 AddProfiling(gate);
1389 if (!Uncheck()) {
1390 if (!acc_.IsCreateArray(array)) {
1391 builder_.StableArrayCheck(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1392 }
1393 }
1394
1395 GateRef result = builder_.LoadArrayLength(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1396 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1397 }
1398
LowerTypedLdTypedArrayLength(const LoadBuiltinObjTypeInfoAccessor & tacc)1399 void TypedBytecodeLowering::LowerTypedLdTypedArrayLength(const LoadBuiltinObjTypeInfoAccessor &tacc)
1400 {
1401 GateRef gate = tacc.GetGate();
1402 GateRef array = tacc.GetReceiver();
1403 AddProfiling(gate);
1404 ParamType arrayType = tacc.GetParamType();
1405 OnHeapMode onHeap = acc_.TryGetOnHeapMode(gate);
1406 if (!Uncheck()) {
1407 builder_.TypedArrayCheck(array, arrayType, TypedArrayMetaDataAccessor::Mode::LOAD_LENGTH, onHeap);
1408 }
1409 GateRef result = builder_.LoadTypedArrayLength(array, arrayType, onHeap);
1410 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1411 }
1412
LowerTypedLdStringLength(const LoadBuiltinObjTypeInfoAccessor & tacc)1413 void TypedBytecodeLowering::LowerTypedLdStringLength(const LoadBuiltinObjTypeInfoAccessor &tacc)
1414 {
1415 GateRef gate = tacc.GetGate();
1416 GateRef str = tacc.GetReceiver();
1417 AddProfiling(gate);
1418 if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, str)) {
1419 if (!Uncheck()) {
1420 builder_.EcmaStringCheck(str);
1421 }
1422 }
1423 GateRef result = builder_.LoadStringLength(str);
1424 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1425 }
1426
LowerTypedLdMapSize(const LoadBuiltinObjTypeInfoAccessor & tacc)1427 void TypedBytecodeLowering::LowerTypedLdMapSize(const LoadBuiltinObjTypeInfoAccessor &tacc)
1428 {
1429 GateRef gate = tacc.GetGate();
1430 GateRef jsMap = tacc.GetReceiver();
1431 AddProfiling(gate);
1432 if (!Uncheck()) {
1433 builder_.EcmaMapCheck(jsMap);
1434 }
1435 GateRef result = builder_.LoadMapSize(jsMap);
1436 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1437 }
1438
TryLowerTypedLdObjByNameForBuiltinMethod(const LoadBuiltinObjTypeInfoAccessor & tacc,BuiltinTypeId type)1439 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltinMethod(const LoadBuiltinObjTypeInfoAccessor &tacc,
1440 BuiltinTypeId type)
1441 {
1442 GateRef gate = tacc.GetGate();
1443 JSTaggedValue key = tacc.GetKeyTaggedValue();
1444 std::optional<GlobalEnvField> protoField = ToGlobalEnvPrototypeField(type);
1445 if (key.IsUndefined() || !protoField.has_value()) {
1446 return false;
1447 }
1448 size_t protoFieldIndex = static_cast<size_t>(*protoField);
1449 JSHandle<GlobalEnv> globalEnv = compilationEnv_->GetGlobalEnv();
1450 JSHClass *prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass();
1451 PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(compilationEnv_->GetJSThread(),
1452 prototypeHClass, key);
1453 bool isPrototypeOfPrototype = false;
1454 // Unable to handle accessor at the moment
1455 if (!plr.IsFound() || plr.IsAccessor()) {
1456 if (type == BuiltinTypeId::ARRAY_ITERATOR) {
1457 protoField = ToGlobalEnvPrototypeField(BuiltinTypeId::ITERATOR);
1458 if (!protoField.has_value()) {
1459 return false;
1460 }
1461 protoFieldIndex = static_cast<size_t>(*protoField);
1462 prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass();
1463 plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(compilationEnv_->GetJSThread(),
1464 prototypeHClass, key);
1465 if (!plr.IsFound() || plr.IsAccessor()) {
1466 return false;
1467 } else {
1468 isPrototypeOfPrototype = true;
1469 }
1470 } else {
1471 return false;
1472 }
1473 }
1474 AddProfiling(gate);
1475 GateRef receiver = acc_.GetValueIn(gate, 2);
1476 if (!Uncheck()) {
1477 /**
1478 * Fixme: Cannot detect changes to Number.prototype.
1479 */
1480 ElementsKind kind = ElementsKind::NONE;
1481 if (type == BuiltinTypeId::ARRAY) {
1482 kind = tacc.TryGetArrayElementsKind();
1483 }
1484 if (enableLazyDeopt_) {
1485 builder_.BuiltinInstanceHClassCheck(receiver, type, kind, isPrototypeOfPrototype);
1486 if (!TryLazyDeoptBuiltinStableProtoChain(const_cast<LoadBuiltinObjTypeInfoAccessor&>(tacc), 0,
1487 gate, compilationEnv_->GetGlobalEnv())) {
1488 return false;
1489 }
1490 if (type == BuiltinTypeId::ARRAY) {
1491 if (!TryLazyDeoptArrayGuardianCheck(gate)) {
1492 return false;
1493 }
1494 }
1495 } else {
1496 // For Array type only: array stability shall be ensured.
1497 if (type == BuiltinTypeId::ARRAY) {
1498 builder_.StableArrayCheck(receiver, ElementsKind::GENERIC, ArrayMetaDataAccessor::CALL_BUILTIN_METHOD);
1499 }
1500 builder_.BuiltinPrototypeHClassCheck(receiver, type, kind, isPrototypeOfPrototype);
1501 }
1502 }
1503 // Successfully goes to typed path
1504 GateRef plrGate = builder_.Int32(plr.GetData());
1505 GateRef prototype = builder_.GetGlobalEnvObj(circuit_->GetGlobalEnvCache(), static_cast<size_t>(*protoField));
1506 GateRef result = builder_.LoadProperty(prototype, plrGate, plr.IsFunction());
1507 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1508 return true;
1509 }
1510
TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)1511 bool TypedBytecodeLowering::TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)
1512 {
1513 LoadBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1514 GateRef result = Circuit::NullGate();
1515 // Just supported mono.
1516 if (tacc.IsMono()) {
1517 if (tacc.IsBuiltinsTypeArray()) { // pgo need dump profile type
1518 AddProfiling(gate);
1519 result = LoadTypedArrayByIndex(tacc);
1520 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1521 return true;
1522 }
1523 }
1524 return false;
1525 }
1526
LowerTypedLdObjByIndex(GateRef gate)1527 void TypedBytecodeLowering::LowerTypedLdObjByIndex(GateRef gate)
1528 {
1529 if (TryLowerTypedLdObjByIndexForBuiltin(gate)) {
1530 return;
1531 }
1532 }
1533
TryLowerTypedStObjByIndexForBuiltin(GateRef gate)1534 bool TypedBytecodeLowering::TryLowerTypedStObjByIndexForBuiltin(GateRef gate)
1535 {
1536 StoreBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1537 if (tacc.HasNoType()) {
1538 return false;
1539 }
1540 if (tacc.GetBuiltinsJSType() != JSType::JS_FLOAT32_ARRAY) {
1541 return false;
1542 }
1543 AddProfiling(gate);
1544 GateRef receiver = tacc.GetReceiver();
1545 ParamType receiverType = tacc.GetParamType();
1546 if (!Uncheck()) {
1547 OnHeapMode onHeap = tacc.TryGetHeapMode();
1548 builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1549 }
1550 GateRef index = builder_.Int32(tacc.TryConvertKeyToInt());
1551 GateRef value = tacc.GetValue();
1552 OnHeapMode onHeap = tacc.TryGetHeapMode();
1553 auto length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1554 if (!Uncheck()) {
1555 builder_.IndexCheck(length, index);
1556 }
1557 builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, index, value, onHeap);
1558 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1559 return true;
1560 }
1561
LowerTypedStObjByIndex(GateRef gate)1562 void TypedBytecodeLowering::LowerTypedStObjByIndex(GateRef gate)
1563 {
1564 if (TryLowerTypedStObjByIndexForBuiltin(gate)) {
1565 return;
1566 }
1567 }
1568
TryLowerTypedLdObjByValueForBuiltin(GateRef gate)1569 bool TypedBytecodeLowering::TryLowerTypedLdObjByValueForBuiltin(GateRef gate)
1570 {
1571 LoadBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1572 GateRef result = Circuit::NullGate();
1573 // Just supported mono.
1574 if (tacc.IsMono()) {
1575 if (tacc.IsBuiltinsString()) {
1576 AddProfiling(gate);
1577 result = LoadStringByIndex(tacc);
1578 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1579 return true;
1580 } else if (tacc.IsBuiltinsArray()) {
1581 AddProfiling(gate);
1582 result = LoadJSArrayByIndex(tacc);
1583 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1584 return true;
1585 } else if (tacc.IsBuiltinsTypeArray()) {
1586 AddProfiling(gate);
1587 result = LoadTypedArrayByIndex(tacc);
1588 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1589 return true;
1590 }
1591 }
1592 return false;
1593 }
1594
LowerTypedLdObjByValue(GateRef gate)1595 void TypedBytecodeLowering::LowerTypedLdObjByValue(GateRef gate)
1596 {
1597 if (TryLowerTypedLdObjByValueForBuiltin(gate)) {
1598 return;
1599 }
1600 if (!compilationEnv_->SupportHeapConstant() || !compilationEnv_->GetJSOptions().IsLdObjValueOpt()) {
1601 return;
1602 }
1603 LoadObjPropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_, true);
1604 // only support for string named key.
1605 if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
1606 return;
1607 }
1608 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
1609 AddProfiling(gate);
1610 GateRef frameState = acc_.FindNearestFrameState(gate);
1611 if (tacc.IsMono()) {
1612 if (!tacc.GetName()->IsString()) {
1613 return;
1614 }
1615 GateRef receiver = tacc.GetReceiver();
1616 EcmaString* ecmaString = EcmaString::Cast(tacc.GetName()->GetTaggedObject());
1617 EcmaStringAccessor ecmaStringAccessor(ecmaString);
1618 if (ecmaStringAccessor.IsInternString()) {
1619 builder_.InternStringKeyCheck(tacc.GetKey(), builder_.HeapConstant(tacc.GetNameIdx()));
1620 } else {
1621 builder_.StringKeyCheck(tacc.GetKey(), builder_.HeapConstant(tacc.GetNameIdx()));
1622 }
1623 builder_.ObjectTypeCheck(false, receiver,
1624 builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
1625 if (tacc.IsReceiverEqHolder(0)) {
1626 result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
1627 } else {
1628 builder_.ProtoChangeMarkerCheck(receiver, frameState);
1629 PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
1630 GateRef plrGate = builder_.Int32(plr.GetData());
1631 GateRef unsharedConstPoool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
1632 size_t holderHClassIndex = static_cast<size_t>(tacc.GetAccessInfo(0).HClassIndex());
1633 if (LIKELY(!plr.IsAccessor())) {
1634 result = builder_.MonoLoadPropertyOnProto(receiver, plrGate, unsharedConstPoool, holderHClassIndex);
1635 } else {
1636 result = builder_.MonoCallGetterOnProto(gate, receiver, plrGate, unsharedConstPoool, holderHClassIndex);
1637 }
1638 }
1639 ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), *result,
1640 tacc.GetAccessInfo(0).Plr().IsAccessor());
1641 return;
1642 }
1643 }
1644
LoadStringByIndex(const LoadBuiltinObjTypeInfoAccessor & tacc)1645 GateRef TypedBytecodeLowering::LoadStringByIndex(const LoadBuiltinObjTypeInfoAccessor &tacc)
1646 {
1647 GateRef receiver = tacc.GetReceiver();
1648 GateRef propKey = tacc.GetKey();
1649 acc_.SetGateType(propKey, GateType::NumberType());
1650 if (!Uncheck()) {
1651 if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, receiver)) {
1652 builder_.EcmaStringCheck(receiver);
1653 }
1654 GateRef length = builder_.LoadStringLength(receiver);
1655 propKey = builder_.IndexCheck(length, propKey);
1656 receiver = builder_.FlattenTreeStringCheck(receiver);
1657 }
1658 return builder_.LoadElement<TypedLoadOp::STRING_LOAD_ELEMENT>(receiver, propKey);
1659 }
1660
LoadJSArrayByIndex(const LoadBuiltinObjTypeInfoAccessor & tacc)1661 GateRef TypedBytecodeLowering::LoadJSArrayByIndex(const LoadBuiltinObjTypeInfoAccessor &tacc)
1662 {
1663 GateRef receiver = tacc.GetReceiver();
1664 GateRef propKey = tacc.GetKey();
1665 acc_.SetGateType(propKey, GateType::NumberType());
1666 ElementsKind kind = tacc.TryGetArrayElementsKind();
1667 if (!Uncheck()) {
1668 if (!acc_.IsCreateArray(receiver)) {
1669 builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
1670 builder_.ElementsKindCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
1671 }
1672 GateRef length = builder_.LoadArrayLength(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1673 propKey = builder_.IndexCheck(length, propKey);
1674 }
1675
1676 GateRef result = Circuit::NullGate();
1677 if (Elements::IsInt(kind)) {
1678 // When elementskind switch on, need to add retype for loadInt
1679 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_INT_ELEMENT>(receiver, propKey);
1680 } else if (Elements::IsNumber(kind)) {
1681 // When elementskind switch on, need to add retype for loadNumber
1682 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT>(receiver, propKey);
1683 } else if (Elements::IsObject(kind)) {
1684 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT>(receiver, propKey);
1685 } else if (!Elements::IsHole(kind)) {
1686 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT>(receiver, propKey);
1687 } else {
1688 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_HOLE_TAGGED_ELEMENT>(receiver, propKey);
1689 }
1690 return result;
1691 }
1692
LoadElmentFromFloat64Array(const LoadBuiltinObjTypeInfoAccessor & tacc)1693 GateRef TypedBytecodeLowering::LoadElmentFromFloat64Array(const LoadBuiltinObjTypeInfoAccessor &tacc)
1694 {
1695 GateRef receiver = tacc.GetReceiver();
1696 GateRef propKey = tacc.GetKey();
1697 OnHeapMode onHeap = tacc.TryGetHeapMode();
1698 auto resTemp = builder_.LoadElement<TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1699 Label entry(&builder_);
1700 builder_.SubCfgEntry(&entry);
1701 Label ifTrue(&builder_);
1702 Label ifFalse(&builder_);
1703 Label exit(&builder_);
1704 Variable result(builder_.GetCurrentEnvironment(),
1705 VariableType::JS_ANY(), builder_.NextVariableId(), builder_.Undefined());
1706
1707 builder_.Branch(builder_.DoubleIsImpureNaN(resTemp), &ifTrue, &ifFalse);
1708 builder_.Bind(&ifTrue);
1709 {
1710 result = builder_.Double(base::NAN_VALUE);
1711 builder_.Jump(&exit);
1712 }
1713 builder_.Bind(&ifFalse);
1714 {
1715 result = resTemp;
1716 builder_.Jump(&exit);
1717 }
1718 builder_.Bind(&exit);
1719 auto res = *result;
1720 builder_.SubCfgExit();
1721 return res;
1722 }
1723
LoadTypedArrayByIndex(const LoadBuiltinObjTypeInfoAccessor & tacc)1724 GateRef TypedBytecodeLowering::LoadTypedArrayByIndex(const LoadBuiltinObjTypeInfoAccessor &tacc)
1725 {
1726 GateRef receiver = tacc.GetReceiver();
1727 ParamType receiverType = tacc.GetParamType();
1728 GateRef propKey = tacc.GetKey();
1729 OnHeapMode onHeap = tacc.TryGetHeapMode();
1730 JSType builtinsType = tacc.GetBuiltinsJSType();
1731 if (!Uncheck()) {
1732 builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1733 GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1734 propKey = builder_.IndexCheck(length, propKey);
1735 }
1736 switch (builtinsType) {
1737 case JSType::JS_INT8_ARRAY:
1738 return builder_.LoadElement<TypedLoadOp::INT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1739 case JSType::JS_UINT8_ARRAY:
1740 return builder_.LoadElement<TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1741 case JSType::JS_UINT8_CLAMPED_ARRAY:
1742 return builder_.LoadElement<TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1743 case JSType::JS_INT16_ARRAY:
1744 return builder_.LoadElement<TypedLoadOp::INT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1745 case JSType::JS_UINT16_ARRAY:
1746 return builder_.LoadElement<TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1747 case JSType::JS_INT32_ARRAY:
1748 return builder_.LoadElement<TypedLoadOp::INT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1749 case JSType::JS_UINT32_ARRAY:
1750 return builder_.LoadElement<TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1751 case JSType::JS_FLOAT32_ARRAY:
1752 return builder_.LoadElement<TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1753 case JSType::JS_FLOAT64_ARRAY: {
1754 return LoadElmentFromFloat64Array(tacc);
1755 }
1756 default:
1757 LOG_ECMA(FATAL) << "this branch is unreachable";
1758 UNREACHABLE();
1759 }
1760
1761 return Circuit::NullGate();
1762 }
1763
StoreJSArrayByIndex(const StoreBuiltinObjTypeInfoAccessor & tacc)1764 void TypedBytecodeLowering::StoreJSArrayByIndex(const StoreBuiltinObjTypeInfoAccessor &tacc)
1765 {
1766 GateRef receiver = tacc.GetReceiver();
1767 GateRef propKey = tacc.GetKey();
1768 GateRef value = tacc.GetValue();
1769 ElementsKind kind = tacc.TryGetArrayElementsKind();
1770 if (!Uncheck()) {
1771 if (!acc_.IsCreateArray(receiver)) {
1772 builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::STORE_ELEMENT);
1773 }
1774 GateRef length = builder_.LoadArrayLength(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1775 builder_.IndexCheck(length, propKey);
1776 builder_.COWArrayCheck(receiver);
1777
1778 if (Elements::IsObject(kind)) {
1779 GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
1780 builder_.HeapObjectCheck(value, frameState);
1781 }
1782 }
1783 builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, propKey, value);
1784 }
1785
StoreTypedArrayByIndex(const StoreBuiltinObjTypeInfoAccessor & tacc)1786 void TypedBytecodeLowering::StoreTypedArrayByIndex(const StoreBuiltinObjTypeInfoAccessor &tacc)
1787 {
1788 GateRef receiver = tacc.GetReceiver();
1789 ParamType receiverType = tacc.GetParamType();
1790 GateRef propKey = tacc.GetKey();
1791 GateRef value = tacc.GetValue();
1792 OnHeapMode onHeap = tacc.TryGetHeapMode();
1793 if (!Uncheck()) {
1794 builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1795 GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1796 propKey = builder_.IndexCheck(length, propKey);
1797 }
1798
1799 JSType builtinsType = tacc.GetBuiltinsJSType();
1800 switch (builtinsType) {
1801 case JSType::JS_INT8_ARRAY:
1802 builder_.StoreElement<TypedStoreOp::INT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1803 break;
1804 case JSType::JS_UINT8_ARRAY:
1805 builder_.StoreElement<TypedStoreOp::UINT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1806 break;
1807 case JSType::JS_UINT8_CLAMPED_ARRAY:
1808 builder_.StoreElement<TypedStoreOp::UINT8CLAMPEDARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1809 break;
1810 case JSType::JS_INT16_ARRAY:
1811 builder_.StoreElement<TypedStoreOp::INT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1812 break;
1813 case JSType::JS_UINT16_ARRAY:
1814 builder_.StoreElement<TypedStoreOp::UINT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1815 break;
1816 case JSType::JS_INT32_ARRAY:
1817 builder_.StoreElement<TypedStoreOp::INT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1818 break;
1819 case JSType::JS_UINT32_ARRAY:
1820 builder_.StoreElement<TypedStoreOp::UINT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1821 break;
1822 case JSType::JS_FLOAT32_ARRAY:
1823 builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1824 break;
1825 case JSType::JS_FLOAT64_ARRAY:
1826 builder_.StoreElement<TypedStoreOp::FLOAT64ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1827 break;
1828 default:
1829 LOG_ECMA(FATAL) << "this branch is unreachable";
1830 UNREACHABLE();
1831 }
1832 }
1833
TryLowerTypedStObjByValueForBuiltin(GateRef gate)1834 bool TypedBytecodeLowering::TryLowerTypedStObjByValueForBuiltin(GateRef gate)
1835 {
1836 StoreBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1837 // Just supported mono.
1838 if (tacc.IsMono() && !tacc.IsStoreOutOfBounds()) {
1839 if (tacc.IsBuiltinsArray()) {
1840 AddProfiling(gate);
1841 StoreJSArrayByIndex(tacc);
1842 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1843 return true;
1844 } else if (tacc.IsBuiltinsTypeArray()) {
1845 AddProfiling(gate);
1846 StoreTypedArrayByIndex(tacc);
1847 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1848 return true;
1849 }
1850 }
1851
1852 return false;
1853 }
1854
LowerTypedStObjByValue(GateRef gate)1855 void TypedBytecodeLowering::LowerTypedStObjByValue(GateRef gate)
1856 {
1857 if (TryLowerTypedStObjByValueForBuiltin(gate)) {
1858 return;
1859 }
1860 }
1861
IsTrueOrFalseHasProfileType(GateRef gate) const1862 bool TypedBytecodeLowering::IsTrueOrFalseHasProfileType(GateRef gate) const
1863 {
1864 ASSERT(acc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
1865 return acc_.GetByteCodeOpcode(gate) == EcmaOpcode::CALLRUNTIME_ISTRUE_PREF_IMM8 ||
1866 acc_.GetByteCodeOpcode(gate) == EcmaOpcode::CALLRUNTIME_ISFALSE_PREF_IMM8;
1867 }
1868
LowerTypedIsTrueOrFalse(GateRef gate,bool flag)1869 void TypedBytecodeLowering::LowerTypedIsTrueOrFalse(GateRef gate, bool flag)
1870 {
1871 UnOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
1872 ParamType paramType;
1873 if (TypeInfoAccessor::IsTrustedBooleanType(acc_, tacc.GetValue()) ||
1874 (IsTrueOrFalseHasProfileType(gate) && tacc.IsBooleanType())) {
1875 paramType = ParamType::BooleanType();
1876 } else if (TypeInfoAccessor::IsTrustedNumberType(acc_, tacc.GetValue()) ||
1877 (IsTrueOrFalseHasProfileType(gate) && tacc.HasNumberType())) {
1878 paramType = ParamType::NumberType();
1879 } else {
1880 return;
1881 }
1882 AddProfiling(gate);
1883 GateRef result;
1884 if (!flag) {
1885 result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISFALSE>(tacc.GetValue(), paramType);
1886 } else {
1887 result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISTRUE>(tacc.GetValue(), paramType);
1888 }
1889
1890 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1891 }
1892
TryLowerNewNumber(CircuitBuilder * builder,GateAccessor acc,GateRef gate)1893 bool TryLowerNewNumber(CircuitBuilder *builder, GateAccessor acc, GateRef gate)
1894 {
1895 auto loadBuiltin = acc.GetValueIn(gate, 0);
1896 if ((acc.GetOpCode(loadBuiltin) == OpCode::LOAD_BUILTIN_OBJECT) &&
1897 (acc.GetIndex(loadBuiltin) == static_cast<size_t>(BuiltinType::BT_NUMBER))) {
1898 auto arg = builder->ToTaggedIntPtr(builder->Int32(0));
1899 if (acc.GetNumValueIn(gate) > 1) {
1900 arg = acc.GetValueIn(gate, 1);
1901 }
1902
1903 auto currentLabel = builder->GetCurrentEnvironment()->GetCurrentLabel();
1904 auto currentControl = currentLabel->GetControl();
1905 auto currentDepend = currentLabel->GetDepend();
1906 GateRef frameState = acc.FindNearestFrameState(gate);
1907 GateRef newNumber = acc.GetCircuit()->NewGate(acc.GetCircuit()->NewNumber(),
1908 MachineType::I64,
1909 {currentControl, currentDepend, loadBuiltin, arg, frameState},
1910 GateType::TaggedPointer());
1911
1912 currentLabel->SetControl(newNumber);
1913 currentLabel->SetDepend(newNumber);
1914
1915 acc.ReplaceHirAndReplaceDeadIfException(gate, builder->GetStateDepend(), newNumber);
1916 return true;
1917 }
1918 return false;
1919 }
1920
LowerTypedNewObjRange(GateRef gate)1921 void TypedBytecodeLowering::LowerTypedNewObjRange(GateRef gate)
1922 {
1923 if (TryLowerNewNumber(&builder_, acc_, gate) || TryLowerNewBuiltinConstructor(gate)) {
1924 return;
1925 }
1926 NewObjRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1927 if (!tacc.FindHClass() || !tacc.IsValidCallMethodId()) {
1928 return;
1929 }
1930 size_t methodId = tacc.GetCallMethodId();
1931 MethodLiteral* method = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
1932 JSTaggedValue value = tacc.GetHClass();
1933 JSHClass *hclass = JSHClass::Cast(value.GetTaggedObject());
1934 if (method == nullptr || !value.IsJSHClass() || hclass->GetObjectType() != JSType::JS_OBJECT) {
1935 return ;
1936 }
1937 AddProfiling(gate);
1938 GateRef ctor = tacc.GetValue();
1939 GateRef hclassIndex = tacc.GetHClassIndex();
1940 GateRef stateSplit = acc_.GetDep(gate);
1941 GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1942 GateRef ihclass = builder_.GetHClassGateFromIndex(frameState, hclassIndex);
1943 GateRef size = builder_.IntPtr(hclass->GetObjectSize());
1944
1945 auto heapConstantIndex = tacc.TryGetHeapConstantConstructorIndex(methodId);
1946 if (heapConstantIndex != JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
1947 GateRef res = builder_.HeapConstant(heapConstantIndex);
1948 builder_.DeoptCheck(builder_.Equal(ctor, res), frameState, DeoptType::NOTCALLTARGETHEAPOBJECT);
1949 } else {
1950 // call target check
1951 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JS_NEWOBJRANGE>(ctor,
1952 builder_.IntPtr(INVALID_INDEX), gate);
1953 }
1954 // check IHC
1955 GateRef protoOrHclass = builder_.LoadConstOffset(VariableType::JS_ANY(), ctor,
1956 JSFunction::PROTO_OR_DYNCLASS_OFFSET);
1957 GateRef checkProto = builder_.Equal(ihclass, protoOrHclass);
1958 builder_.DeoptCheck(checkProto, frameState, DeoptType::NOTNEWOBJ2);
1959 // construct
1960 GateRef thisObj = builder_.TypedNewAllocateThis(ctor, ihclass, size, frameState);
1961 size_t range = acc_.GetNumValueIn(gate);
1962 size_t expectedArgc = method->GetNumArgs();
1963 size_t actualArgc = static_cast<size_t>(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1964 EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
1965 std::vector<GateRef> args {glue_, builder_.Int64(actualArgc), builder_.IntPtr(0), ctor, ctor,
1966 thisObj};
1967 for (size_t i = 1; i < range; ++i) { // 1:skip ctor
1968 args.emplace_back(acc_.GetValueIn(gate, i));
1969 }
1970 bool needPushArgv = (expectedArgc != actualArgc);
1971 bool isFastCall = method->IsFastCall();
1972 GateRef result = builder_.CallNew(gate, args, needPushArgv, isFastCall);
1973 ReplaceGateWithPendingException(glue_, gate, builder_.GetState(), builder_.GetDepend(), result);
1974 }
1975
TryLowerNewBuiltinConstructor(GateRef gate)1976 bool TypedBytecodeLowering::TryLowerNewBuiltinConstructor(GateRef gate)
1977 {
1978 NewBuiltinCtorTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
1979 auto id = tacc.GetPGOBuiltinMethodId();
1980 if (id == BuiltinsStubCSigns::ID::NONE) {
1981 return false;
1982 }
1983
1984 GateRef ctor = tacc.GetValue();
1985 GateRef constructGate = Circuit::NullGate();
1986 if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::ObjectConstructor)) {
1987 AddProfiling(gate);
1988 if (!Uncheck()) {
1989 builder_.ObjectConstructorCheck(ctor);
1990 }
1991 constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::ObjectConstructor, gate);
1992 } else if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::BooleanConstructor)) {
1993 if (acc_.GetNumValueIn(gate) <= 2) { // 2: ctor and first arg
1994 AddProfiling(gate);
1995 if (!Uncheck()) {
1996 builder_.BooleanConstructorCheck(ctor);
1997 }
1998 constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::BooleanConstructor, gate);
1999 }
2000 } else if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::Float32ArrayConstructor)) {
2001 if (acc_.GetNumValueIn(gate) <= 2) { // 2: ctor and first arg
2002 AddProfiling(gate);
2003 if (!Uncheck()) {
2004 builder_.Float32ArrayConstructorCheck(ctor);
2005 }
2006 constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::Float32ArrayConstructor, gate);
2007 }
2008 }
2009 if (constructGate == Circuit::NullGate()) {
2010 // for other builtin constructor, do necessory check and just call runtime JSCallNew.
2011 AddProfiling(gate);
2012 if (!Uncheck()) {
2013 builder_.TypedConstructorCheck(ctor, GET_TYPED_GLOBAL_ENV_INDEX(id));
2014 }
2015 GateRef actualArgc = builder_.Int64(
2016 BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate), EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
2017 GateRef actualArgv = builder_.IntPtr(0);
2018 GateRef thisObj = builder_.Undefined();
2019 size_t range = acc_.GetNumValueIn(gate);
2020 std::vector<GateRef> args {glue_, actualArgc, actualArgv, ctor, ctor, thisObj};
2021 for (size_t i = 1; i < range; ++i) {
2022 args.emplace_back(acc_.GetValueIn(gate, i));
2023 }
2024 constructGate = builder_.CallNewBuiltin(gate, args);
2025 }
2026 ReplaceGateWithPendingException(glue_, gate, builder_.GetState(), builder_.GetDepend(), constructGate);
2027 return true;
2028 }
2029
LowerTypedSuperCall(GateRef gate)2030 void TypedBytecodeLowering::LowerTypedSuperCall(GateRef gate)
2031 {
2032 SuperCallTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2033
2034 auto methodId = tacc.GetMethodId();
2035 if (methodId == 0) {
2036 return;
2037 }
2038 auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
2039 if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
2040 return;
2041 }
2042 if (!tacc.IsValidCallMethodId()) {
2043 return;
2044 }
2045 AddProfiling(gate);
2046
2047 GateRef ctor = tacc.GetCtor();
2048
2049 GateRef superCtor = builder_.GetSuperConstructor(ctor);
2050 GateRef newTarget = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
2051 GateRef thisObj = builder_.TypedSuperAllocateThis(superCtor, newTarget);
2052
2053 // call constructor
2054 size_t range = acc_.GetNumValueIn(gate);
2055 GateRef actualArgc = builder_.Int64(range + 3); // 3: ctor, newTaget, this
2056 GateRef actualArgv = builder_.IntPtr(0);
2057 std::vector<GateRef> args { glue_, actualArgc, actualArgv, superCtor, newTarget, thisObj };
2058 for (size_t i = 0; i < range; ++i) {
2059 args.emplace_back(acc_.GetValueIn(gate, i));
2060 }
2061
2062 GateRef constructGate = builder_.Construct(gate, args);
2063 ReplaceGateWithPendingException(glue_, gate, builder_.GetState(),
2064 builder_.GetDepend(), constructGate);
2065 }
2066
SpeculateCallBuiltin(GateRef gate,GateRef func,const std::vector<GateRef> & args,BuiltinsStubCSigns::ID id,bool isThrow)2067 void TypedBytecodeLowering::SpeculateCallBuiltin(GateRef gate, GateRef func, const std::vector<GateRef> &args,
2068 BuiltinsStubCSigns::ID id, bool isThrow)
2069 {
2070 if (!Uncheck()) {
2071 builder_.CallTargetCheck(gate, func, builder_.IntPtr(static_cast<int64_t>(id)), {args[0]});
2072 }
2073
2074 GateRef result = builder_.TypedCallBuiltin(gate, args, id, IS_SIDE_EFFECT_BUILTINS_ID(id));
2075
2076 if (isThrow) {
2077 ReplaceGateWithPendingException(glue_, gate, builder_.GetState(),
2078 builder_.GetDepend(), result);
2079 } else {
2080 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
2081 }
2082 }
2083
SpeculateCallBuiltinFromGlobal(GateRef gate,const std::vector<GateRef> & args,BuiltinsStubCSigns::ID id,bool isThrow,bool isSideEffect)2084 void TypedBytecodeLowering::SpeculateCallBuiltinFromGlobal(GateRef gate, const std::vector<GateRef> &args,
2085 BuiltinsStubCSigns::ID id, bool isThrow, bool isSideEffect)
2086 {
2087 GateRef result = builder_.TypedCallBuiltin(gate, args, id, isSideEffect);
2088
2089 if (isThrow) {
2090 ReplaceGateWithPendingException(glue_, gate, builder_.GetState(),
2091 builder_.GetDepend(), result);
2092 } else {
2093 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
2094 }
2095 }
2096
LowerFastCall(GateRef gate,GateRef func,const std::vector<GateRef> & argsFastCall,bool isNoGC)2097 void TypedBytecodeLowering::LowerFastCall(GateRef gate, GateRef func,
2098 const std::vector<GateRef> &argsFastCall, bool isNoGC)
2099 {
2100 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
2101 GateRef result = builder_.TypedFastCall(gate, argsFastCall, isNoGC);
2102 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
2103 ReplaceGateWithPendingException(glue_, gate, builder_.GetState(),
2104 builder_.GetDepend(), result);
2105 }
2106
LowerCall(GateRef gate,GateRef func,const std::vector<GateRef> & args,bool isNoGC)2107 void TypedBytecodeLowering::LowerCall(GateRef gate, GateRef func,
2108 const std::vector<GateRef> &args, bool isNoGC)
2109 {
2110 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
2111 GateRef result = builder_.TypedCall(gate, args, isNoGC);
2112 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
2113 ReplaceGateWithPendingException(glue_, gate, builder_.GetState(),
2114 builder_.GetDepend(), result);
2115 }
2116
2117 template<class TypeAccessor>
CheckFastCallThisCallTarget(const TypeAccessor & tacc)2118 void TypedBytecodeLowering::CheckFastCallThisCallTarget(const TypeAccessor &tacc)
2119 {
2120 if (noCheck_) {
2121 return;
2122 }
2123 GateRef func = tacc.GetFunc();
2124 GateRef gate = tacc.GetGate();
2125 GateRef methodIndex = builder_.IntPtr(tacc.GetFuncMethodOffset());
2126 if (tacc.IsNoGC()) {
2127 builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST_NOGC>(func, methodIndex, gate);
2128 } else {
2129 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST>(func, methodIndex, gate);
2130 }
2131 }
2132
2133 template<class TypeAccessor>
CheckCallThisCallTarget(const TypeAccessor & tacc)2134 void TypedBytecodeLowering::CheckCallThisCallTarget(const TypeAccessor &tacc)
2135 {
2136 if (noCheck_) {
2137 return;
2138 }
2139 GateRef func = tacc.GetFunc();
2140 GateRef gate = tacc.GetGate();
2141 GateRef methodIndex = builder_.IntPtr(tacc.GetFuncMethodOffset());
2142 if (tacc.IsNoGC()) {
2143 builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_NOGC>(func, methodIndex, gate);
2144 } else {
2145 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS>(func, methodIndex, gate);
2146 }
2147 }
2148
2149 template<class TypeAccessor>
CheckThisCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)2150 void TypedBytecodeLowering::CheckThisCallTargetAndLowerCall(const TypeAccessor &tacc,
2151 const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
2152 {
2153 GateRef func = tacc.GetFunc();
2154 GateRef gate = tacc.GetGate();
2155 bool isNoGC = tacc.IsNoGC();
2156 auto heapConstantIndex = tacc.TryGetHeapConstantFunctionIndex(tacc.GetMethodId());
2157 if (heapConstantIndex != JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2158 ConvertCallTargetCheckToHeapConstantCheckAndLowerCall(tacc, args, argsFastCall, heapConstantIndex, isNoGC);
2159 return;
2160 }
2161 if (tacc.CanFastCall()) {
2162 CheckFastCallThisCallTarget(tacc);
2163 LowerFastCall(gate, func, argsFastCall, isNoGC);
2164 } else {
2165 CheckCallThisCallTarget(tacc);
2166 LowerCall(gate, func, args, isNoGC);
2167 }
2168 }
2169
2170 template<class TypeAccessor>
CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,bool isNoGC)2171 void TypedBytecodeLowering::CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor &tacc,
2172 const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall, bool isNoGC)
2173 {
2174 GateRef func = tacc.GetFunc();
2175 GateRef gate = tacc.GetGate();
2176 auto heapConstantIndex = tacc.TryGetHeapConstantFunctionIndex(tacc.GetMethodId());
2177 if (heapConstantIndex != JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2178 ConvertCallTargetCheckToHeapConstantCheckAndLowerCall(tacc, args, argsFastCall, heapConstantIndex, isNoGC);
2179 return;
2180 }
2181 // NO CHECK
2182 if (!Uncheck()) {
2183 builder_.CallTargetIsCompiledCheck(func, gate);
2184 }
2185 if (tacc.CanFastCall()) {
2186 LowerFastCall(gate, func, argsFastCall, isNoGC);
2187 } else {
2188 LowerCall(gate, func, args, isNoGC);
2189 }
2190 }
2191
2192 template<class TypeAccessor>
InSameConstPool(const TypeAccessor & tacc) const2193 bool TypedBytecodeLowering::InSameConstPool(const TypeAccessor &tacc) const
2194 {
2195 auto pandaFile = ctx_->GetJSPandaFile();
2196 auto targetPandaFile = tacc.GetPandaFile();
2197 if (pandaFile != targetPandaFile) {
2198 return false;
2199 }
2200 auto targetMethodId = tacc.GetMethodId();
2201 panda_file::IndexAccessor indexAccessor(*(targetPandaFile->GetPandaFile()),
2202 panda_file::File::EntityId(targetMethodId));
2203 auto targetCpId = static_cast<uint32_t>(indexAccessor.GetHeaderIndex());
2204 if (constPoolId_ != targetCpId) {
2205 return false;
2206 }
2207 return true;
2208 }
2209
2210 template<class TypeAccessor>
ConvertCallTargetCheckToHeapConstantCheckAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,uint32_t heapConstantIndex,bool isNoGC)2211 void TypedBytecodeLowering::ConvertCallTargetCheckToHeapConstantCheckAndLowerCall(const TypeAccessor &tacc,
2212 const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall,
2213 uint32_t heapConstantIndex, bool isNoGC)
2214 {
2215 GateRef func = tacc.GetFunc();
2216 GateRef gate = tacc.GetGate();
2217 if (!Uncheck()) {
2218 GateRef frameState = acc_.GetFrameState(gate);
2219 GateRef res = builder_.HeapConstant(heapConstantIndex);
2220 #if DUMP_HEAP_OBJECT_DFX
2221 Label exit(&builder_);
2222 Label notEqual(&builder_);
2223 buidler_.Branch(builder_.Equal(func, res), &exit, ¬Equal,
2224 BranchWeight::ONE_WEIGHT, BranchWeight::ONE_WEIGHT, "isEqualObject");
2225 builder_.Bind(¬Equal);
2226 {
2227 std::vector<GateRef> params;
2228 params.push_back(func);
2229 builder_.CallRuntime(glue_, RTSTUB_ID(DumpHeapObjectAddress), Gate::InvalidGateRef, params, gate);
2230 params.clear();
2231 params.push_back(res);
2232 builder_.CallRuntime(glue_, RTSTUB_ID(DumpHeapObjectAddress), Gate::InvalidGateRef, params, gate);
2233 builder_.Jump(&exit);
2234 }
2235 builder_.Bind(&exit);
2236 #endif
2237 builder_.DeoptCheck(builder_.Equal(func, res), frameState, DeoptType::NOTCALLTARGETHEAPOBJECT);
2238 }
2239 auto *jitCompilationEnv = static_cast<const JitCompilationEnv*>(compilationEnv_);
2240 JSHandle<JSTaggedValue> heapObject = jitCompilationEnv->GetHeapConstantHandle(heapConstantIndex);
2241 JSHandle<JSFunction> jsFunc = JSHandle<JSFunction>::Cast(heapObject);
2242 Method *calleeMethod = Method::Cast(jsFunc->GetMethod(compilationEnv_->GetJSThread()));
2243 ASSERT(calleeMethod->GetMethodLiteral(compilationEnv_->GetJSThread()) != nullptr);
2244 if (calleeMethod->GetMethodLiteral(compilationEnv_->GetJSThread())->IsFastCall()) {
2245 LowerFastCall(gate, func, argsFastCall, isNoGC);
2246 } else {
2247 LowerCall(gate, func, args, isNoGC);
2248 }
2249 }
2250
2251 template<class TypeAccessor>
CheckCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)2252 void TypedBytecodeLowering::CheckCallTargetAndLowerCall(const TypeAccessor &tacc,
2253 const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
2254 {
2255 GateRef func = tacc.GetFunc();
2256 if (IsLoadVtable(func)) {
2257 CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall); // func = a.foo, func()
2258 return;
2259 }
2260 bool isNoGC = tacc.IsNoGC();
2261 auto op = acc_.GetOpCode(func);
2262 if (op == OpCode::JS_BYTECODE && (acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8 ||
2263 acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) {
2264 CheckCallTargetFromDefineFuncAndLowerCall(tacc, args, argsFastCall, isNoGC);
2265 return;
2266 }
2267
2268 if (!tacc.MethodOffsetIsVaild()) {
2269 return;
2270 }
2271 if (!InSameConstPool(tacc)) {
2272 return;
2273 }
2274
2275 auto heapConstantIndex = tacc.TryGetHeapConstantFunctionIndex(tacc.GetMethodId());
2276 if (heapConstantIndex != JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2277 ConvertCallTargetCheckToHeapConstantCheckAndLowerCall(tacc, args, argsFastCall, heapConstantIndex, isNoGC);
2278 return;
2279 }
2280
2281 int methodIndex = tacc.GetMethodIndex();
2282 if (methodIndex == -1) {
2283 return;
2284 }
2285
2286 GateRef gate = tacc.GetGate();
2287 if (tacc.CanFastCall()) {
2288 if (!Uncheck()) {
2289 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL_FAST>(func,
2290 builder_.IntPtr(methodIndex), gate);
2291 }
2292 LowerFastCall(gate, func, argsFastCall, isNoGC);
2293 } else {
2294 if (!Uncheck()) {
2295 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL>(func,
2296 builder_.IntPtr(methodIndex), gate);
2297 }
2298 LowerCall(gate, func, args, isNoGC);
2299 }
2300 }
2301
2302 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedCall(const TypeAccessor & tacc)2303 void TypedBytecodeLowering::LowerTypedCall(const TypeAccessor &tacc)
2304 {
2305 auto heapConstantIndex = tacc.TryGetHeapConstantFunctionIndex(tacc.GetMethodId());
2306 if (!tacc.IsHotnessFunc() &&
2307 heapConstantIndex == JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2308 return;
2309 }
2310 auto methodId = tacc.GetMethodId();
2311 if (methodId == 0) {
2312 return;
2313 }
2314 auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
2315 if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
2316 return;
2317 }
2318 uint32_t argc = tacc.GetArgc();
2319 GateRef gate = tacc.GetGate();
2320 GateRef actualArgc = Circuit::NullGate();
2321 GateRef actualArgv = builder_.IntPtr(0);
2322 switch (Op) {
2323 case EcmaOpcode::CALLARG0_IMM8: {
2324 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2325 EcmaOpcode::CALLARG0_IMM8));
2326 break;
2327 }
2328 case EcmaOpcode::CALLARG1_IMM8_V8: {
2329 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2330 EcmaOpcode::CALLARG1_IMM8_V8));
2331 break;
2332 }
2333 case EcmaOpcode::CALLARGS2_IMM8_V8_V8: {
2334 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2335 EcmaOpcode::CALLARGS2_IMM8_V8_V8));
2336 break;
2337 }
2338 case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8: {
2339 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2340 EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8));
2341 break;
2342 }
2343 case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8: {
2344 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2345 EcmaOpcode::CALLRANGE_IMM8_IMM8_V8));
2346 break;
2347 }
2348 default:
2349 UNREACHABLE();
2350 }
2351 uint32_t len = tacc.GetFunctionTypeLength();
2352 if (len == tacc.INVALID_LEN) {
2353 return;
2354 }
2355 GateRef func = tacc.GetFunc();
2356 GateRef newTarget = builder_.Undefined();
2357 GateRef thisObj = builder_.Undefined();
2358 std::vector<GateRef> argsFastCall { glue_, func, thisObj};
2359 std::vector<GateRef> args { glue_, actualArgc, actualArgv, func, newTarget, thisObj };
2360 for (uint32_t i = 0; i < argc; i++) {
2361 GateRef value = acc_.GetValueIn(gate, i);
2362 argsFastCall.emplace_back(value);
2363 args.emplace_back(value);
2364 }
2365 for (uint32_t i = argc; i < len; i++) {
2366 argsFastCall.emplace_back(builder_.Undefined());
2367 args.emplace_back(builder_.Undefined());
2368 }
2369 if (argc != len) {
2370 return ;
2371 }
2372 AddProfiling(gate);
2373 CheckCallTargetAndLowerCall(tacc, args, argsFastCall);
2374 }
2375
GetCalleePandaFile(GateRef gate)2376 const JSPandaFile* TypedBytecodeLowering::GetCalleePandaFile(GateRef gate)
2377 {
2378 auto profileType = acc_.TryGetPGOType(gate).GetPGOSampleType();
2379 bool haveProfileType = profileType->IsProfileType() && !profileType->IsProfileTypeNone();
2380 if (haveProfileType) {
2381 if (compilationEnv_->IsJitCompiler()) {
2382 return compilationEnv_->GetJSPandaFile();
2383 }
2384 auto abcId = profileType->GetProfileType().GetAbcId();
2385 CString fileDesc;
2386 if (!decoder_->GetAbcNameById(abcId, fileDesc)) {
2387 UNREACHABLE();
2388 }
2389 fileDesc = JSPandaFile::GetNormalizedFileDesc(fileDesc);
2390 return JSPandaFileManager::GetInstance()->FindJSPandaFileByNormalizedName(fileDesc).get();
2391 }
2392 // nullptr if no pgo info
2393 return nullptr;
2394 }
2395
LowerTypedCallArg0(GateRef gate)2396 void TypedBytecodeLowering::LowerTypedCallArg0(GateRef gate)
2397 {
2398 if (GetCalleePandaFile(gate) == nullptr) {
2399 return;
2400 }
2401 CallArg0TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2402 if (!tacc.IsValidCallMethodId()) {
2403 return;
2404 }
2405 LowerTypedCall<EcmaOpcode::CALLARG0_IMM8>(tacc);
2406 }
2407
LowerTypedCallArg1(GateRef gate)2408 void TypedBytecodeLowering::LowerTypedCallArg1(GateRef gate)
2409 {
2410 if (GetCalleePandaFile(gate) == nullptr) {
2411 return;
2412 }
2413 CallArg1TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2414 GateRef func = tacc.GetFunc();
2415 GateRef a0Value = tacc.GetValue();
2416 BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinMethodId();
2417 if (!IS_INVALID_ID(id) && (IS_TYPED_BUILTINS_NUMBER_ID(id) || IS_TYPED_BUILTINS_GLOBAL_ID(id))) {
2418 if (IS_TYPED_INLINE_BUILTINS_ID(id)) {
2419 return;
2420 }
2421 AddProfiling(gate);
2422 if (IsFuncFromGlobal(func)) {
2423 // No need to do CallTargetCheck if func is from LOAD_BUILTIN_OBJECT.
2424 SpeculateCallBuiltinFromGlobal(gate, { a0Value }, id, true);
2425 } else {
2426 SpeculateCallBuiltin(gate, func, { a0Value }, id, true);
2427 }
2428 } else {
2429 if (!tacc.IsValidCallMethodId()) {
2430 return;
2431 }
2432 LowerTypedCall<EcmaOpcode::CALLARG1_IMM8_V8>(tacc);
2433 }
2434 }
2435
LowerTypedCallArg2(GateRef gate)2436 void TypedBytecodeLowering::LowerTypedCallArg2(GateRef gate)
2437 {
2438 if (GetCalleePandaFile(gate) == nullptr) {
2439 return;
2440 }
2441 CallArg2TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2442 if (!tacc.IsValidCallMethodId()) {
2443 return;
2444 }
2445 LowerTypedCall<EcmaOpcode::CALLARGS2_IMM8_V8_V8>(tacc);
2446 }
2447
LowerTypedCallArg3(GateRef gate)2448 void TypedBytecodeLowering::LowerTypedCallArg3(GateRef gate)
2449 {
2450 if (GetCalleePandaFile(gate) == nullptr) {
2451 return;
2452 }
2453 CallArg3TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2454 if (!tacc.IsValidCallMethodId()) {
2455 return;
2456 }
2457 LowerTypedCall<EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8>(tacc);
2458 }
2459
LowerTypedCallrange(GateRef gate)2460 void TypedBytecodeLowering::LowerTypedCallrange(GateRef gate)
2461 {
2462 if (GetCalleePandaFile(gate) == nullptr) {
2463 return;
2464 }
2465 CallRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2466 if (!tacc.IsValidCallMethodId()) {
2467 return;
2468 }
2469 LowerTypedCall<EcmaOpcode::CALLRANGE_IMM8_IMM8_V8>(tacc);
2470 }
2471
IsLoadVtable(GateRef func)2472 bool TypedBytecodeLowering::IsLoadVtable(GateRef func)
2473 {
2474 auto op = acc_.GetOpCode(func);
2475 if (op != OpCode::LOAD_PROPERTY) {
2476 return false;
2477 }
2478 return true;
2479 }
2480
2481 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedThisCall(const TypeAccessor & tacc)2482 void TypedBytecodeLowering::LowerTypedThisCall(const TypeAccessor &tacc)
2483 {
2484 auto methodId = tacc.GetMethodId();
2485 if (methodId == 0) {
2486 return;
2487 }
2488 auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
2489 if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
2490 return;
2491 }
2492 auto heapConstantIndex = tacc.TryGetHeapConstantFunctionIndex(methodId);
2493 if (!tacc.IsHotnessFunc() &&
2494 heapConstantIndex == JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2495 return;
2496 }
2497 uint32_t argc = tacc.GetArgc();
2498 GateRef gate = tacc.GetGate();
2499 GateRef actualArgc = Circuit::NullGate();
2500 GateRef actualArgv = builder_.IntPtr(0);
2501 switch (Op) {
2502 case EcmaOpcode::CALLTHIS0_IMM8_V8: {
2503 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2504 EcmaOpcode::CALLTHIS0_IMM8_V8));
2505 break;
2506 }
2507 case EcmaOpcode::CALLTHIS1_IMM8_V8_V8: {
2508 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2509 EcmaOpcode::CALLTHIS1_IMM8_V8_V8));
2510 break;
2511 }
2512 case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8: {
2513 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2514 EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8));
2515 break;
2516 }
2517 case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8: {
2518 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2519 EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8));
2520 break;
2521 }
2522 case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: {
2523 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2524 EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8));
2525 break;
2526 }
2527 default:
2528 UNREACHABLE();
2529 }
2530
2531 uint32_t len = tacc.GetFunctionTypeLength();
2532 if (len == tacc.INVALID_LEN) {
2533 return;
2534 }
2535 GateRef func = tacc.GetFunc();
2536 GateRef newTarget = builder_.Undefined();
2537 GateRef thisObj = tacc.GetThisObj();
2538 std::vector<GateRef> argsFastCall { glue_, func, thisObj};
2539 std::vector<GateRef> args { glue_, actualArgc, actualArgv, func, newTarget, thisObj };
2540 for (uint32_t i = 0; i < argc; i++) {
2541 GateRef value = acc_.GetValueIn(gate, i + 1);
2542 argsFastCall.emplace_back(value);
2543 args.emplace_back(value);
2544 }
2545 for (uint32_t i = argc; i < len; i++) {
2546 argsFastCall.emplace_back(builder_.Undefined());
2547 args.emplace_back(builder_.Undefined());
2548 }
2549 AddProfiling(gate);
2550 CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall);
2551 }
2552
LowerTypedCallthis0(GateRef gate)2553 void TypedBytecodeLowering::LowerTypedCallthis0(GateRef gate)
2554 {
2555 if (GetCalleePandaFile(gate) == nullptr) {
2556 return;
2557 }
2558 CallThis0TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2559 BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2560 if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS0(pgoFuncId)) {
2561 AddProfiling(gate);
2562 SpeculateCallBuiltin(gate, tacc.GetFunc(), {tacc.GetThisObj()}, pgoFuncId, true);
2563 return;
2564 }
2565 if (!tacc.CanOptimizeAsFastCall()) {
2566 return;
2567 }
2568 LowerTypedThisCall<EcmaOpcode::CALLTHIS0_IMM8_V8>(tacc);
2569 }
2570
LowerTypedCallthis1(GateRef gate)2571 void TypedBytecodeLowering::LowerTypedCallthis1(GateRef gate)
2572 {
2573 if (GetCalleePandaFile(gate) == nullptr) {
2574 return;
2575 }
2576 CallThis1TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2577 BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2578 if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS1(pgoFuncId)) {
2579 AddProfiling(gate);
2580 SpeculateCallBuiltin(gate, tacc.GetFunc(), {tacc.GetArgs()}, pgoFuncId, true);
2581 return;
2582 }
2583 if (!tacc.CanOptimizeAsFastCall()) {
2584 return;
2585 }
2586 LowerTypedThisCall<EcmaOpcode::CALLTHIS1_IMM8_V8_V8>(tacc);
2587 }
2588
LowerTypedCallthis2(GateRef gate)2589 void TypedBytecodeLowering::LowerTypedCallthis2(GateRef gate)
2590 {
2591 if (GetCalleePandaFile(gate) == nullptr) {
2592 return;
2593 }
2594 CallThis2TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2595 BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2596 if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS2(pgoFuncId)) {
2597 AddProfiling(gate);
2598 SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArgs() }, pgoFuncId, true);
2599 return;
2600 }
2601 if (!tacc.CanOptimizeAsFastCall()) {
2602 return;
2603 }
2604 LowerTypedThisCall<EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8>(tacc);
2605 }
2606
LowerTypedCallthis3(GateRef gate)2607 void TypedBytecodeLowering::LowerTypedCallthis3(GateRef gate)
2608 {
2609 if (GetCalleePandaFile(gate) == nullptr) {
2610 return;
2611 }
2612 CallThis3TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2613 BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2614 if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS3(pgoFuncId)) {
2615 AddProfiling(gate);
2616 SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArgs() }, pgoFuncId, true);
2617 return;
2618 }
2619 if (!tacc.CanOptimizeAsFastCall()) {
2620 return;
2621 }
2622 LowerTypedThisCall<EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8>(tacc);
2623 }
2624
LowerTypedCallthisrange(GateRef gate)2625 void TypedBytecodeLowering::LowerTypedCallthisrange(GateRef gate)
2626 {
2627 if (GetCalleePandaFile(gate) == nullptr) {
2628 return;
2629 }
2630 CallThisRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2631 if (!tacc.CanOptimizeAsFastCall()) {
2632 return;
2633 }
2634 LowerTypedThisCall<EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8>(tacc);
2635 }
2636
LowerTypedCallInit(GateRef gate)2637 void TypedBytecodeLowering::LowerTypedCallInit(GateRef gate)
2638 {
2639 // same as callthis0
2640 LowerTypedCallthis0(gate);
2641 }
2642
AddProfiling(GateRef gate)2643 void TypedBytecodeLowering::AddProfiling(GateRef gate)
2644 {
2645 hitTypedOpCount_++;
2646 AddHitBytecodeCount();
2647 if (IsTraceBC()) {
2648 // see stateSplit as a part of JSByteCode if exists
2649 GateRef maybeStateSplit = acc_.GetDep(gate);
2650 GateRef current = Circuit::NullGate();
2651 if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
2652 current = maybeStateSplit;
2653 } else {
2654 current = gate;
2655 }
2656
2657 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
2658 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
2659 GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
2660 GateRef typedPath = builder_.Int32ToTaggedInt(builder_.Int32(1));
2661 GateRef traceGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(current),
2662 { constOpcode, typedPath }, gate);
2663 acc_.SetDep(current, traceGate);
2664 builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: trace or STATE_SPLIT
2665 }
2666
2667 if (IsProfiling()) {
2668 // see stateSplit as a part of JSByteCode if exists
2669 GateRef maybeStateSplit = acc_.GetDep(gate);
2670 GateRef current = Circuit::NullGate();
2671 if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
2672 current = maybeStateSplit;
2673 } else {
2674 current = gate;
2675 }
2676
2677 GateRef func = builder_.Undefined();
2678 if (acc_.HasFrameState(gate)) {
2679 func = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
2680 }
2681
2682 GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate)));
2683 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
2684 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
2685 GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
2686 GateRef mode =
2687 builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::TYPED_PATH)));
2688 GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current),
2689 { func, bcIndex, constOpcode, mode }, gate);
2690 acc_.SetDep(current, profiling);
2691 builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: profiling or STATE_SPLIT
2692 }
2693 }
2694
AddBytecodeCount(EcmaOpcode op)2695 void TypedBytecodeLowering::AddBytecodeCount(EcmaOpcode op)
2696 {
2697 currentOp_ = op;
2698 if (bytecodeMap_.find(op) != bytecodeMap_.end()) {
2699 bytecodeMap_[op]++;
2700 } else {
2701 bytecodeMap_[op] = 1;
2702 }
2703 }
2704
DeleteBytecodeCount(EcmaOpcode op)2705 void TypedBytecodeLowering::DeleteBytecodeCount(EcmaOpcode op)
2706 {
2707 bytecodeMap_.erase(op);
2708 }
2709
AddHitBytecodeCount()2710 void TypedBytecodeLowering::AddHitBytecodeCount()
2711 {
2712 if (bytecodeHitTimeMap_.find(currentOp_) != bytecodeHitTimeMap_.end()) {
2713 bytecodeHitTimeMap_[currentOp_]++;
2714 } else {
2715 bytecodeHitTimeMap_[currentOp_] = 1;
2716 }
2717 }
2718
LowerTypedTypeOf(GateRef gate)2719 void TypedBytecodeLowering::LowerTypedTypeOf(GateRef gate)
2720 {
2721 TypeOfTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
2722 if (tacc.IsIllegalType()) {
2723 return;
2724 }
2725 AddProfiling(gate);
2726 if (!Uncheck()) {
2727 builder_.TypeOfCheck(tacc.GetValue(), tacc.GetParamType());
2728 }
2729 GateRef result = builder_.TypedTypeOf(tacc.GetParamType());
2730 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
2731 }
2732
LowerGetIterator(GateRef gate)2733 void TypedBytecodeLowering::LowerGetIterator(GateRef gate)
2734 {
2735 if (GetCalleePandaFile(gate) == nullptr) {
2736 return;
2737 }
2738 GetIteratorTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2739 BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinMethodId();
2740 if (IS_INVALID_ID(id) || id == BuiltinsStubCSigns::ID::NONE) {
2741 return;
2742 }
2743 AddProfiling(gate);
2744 GateRef obj = tacc.GetCallee();
2745 SpeculateCallBuiltin(gate, obj, { obj }, id, true);
2746 }
2747
LowerTypedTryLdGlobalByName(GateRef gate)2748 void TypedBytecodeLowering::LowerTypedTryLdGlobalByName(GateRef gate)
2749 {
2750 if (!enableLoweringBuiltin_) {
2751 return;
2752 }
2753 LoadGlobalObjByNameTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
2754 JSTaggedValue key = tacc.GetKeyTaggedValue();
2755 if (key.IsUndefined()) {
2756 return;
2757 }
2758
2759 BuiltinIndex& builtin = BuiltinIndex::GetInstance();
2760 auto index = builtin.GetBuiltinIndex(compilationEnv_->GetJSThread(), key);
2761 if (index != builtin.NOT_FOUND) {
2762 AddProfiling(gate);
2763 GateRef result = builder_.LoadBuiltinObject(index);
2764 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
2765 DeleteConstDataIfNoUser(tacc.GetKey());
2766 return;
2767 }
2768
2769 if (compilationEnv_->IsJitCompiler()) {
2770 uint32_t pcOffset = acc_.TryGetPcOffset(gate);
2771 uint32_t methodOffset = acc_.TryGetMethodOffset(gate);
2772 uint32_t heapConstantIndex = static_cast<const JitCompilationEnv*>(compilationEnv_)->
2773 GetLdGlobalByNameBcOffset2HeapConstantIndex(methodOffset, pcOffset);
2774 if (heapConstantIndex == JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2775 return;
2776 }
2777 AddProfiling(gate);
2778 GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
2779 GateRef propertyBoxConst = builder_.HeapConstant(heapConstantIndex);
2780 GateRef boxValue = builder_.LoadConstOffset(
2781 VariableType::JS_ANY(), propertyBoxConst, PropertyBox::VALUE_OFFSET);
2782 builder_.DeoptCheck(builder_.TaggedIsNotHole(boxValue), frameState, DeoptType::PROPERTYBOXINVALID);
2783 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), boxValue);
2784 DeleteConstDataIfNoUser(tacc.GetKey());
2785 }
2786 }
2787
LowerInstanceOf(GateRef gate)2788 void TypedBytecodeLowering::LowerInstanceOf(GateRef gate)
2789 {
2790 InstanceOfTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
2791 if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
2792 return;
2793 }
2794 AddProfiling(gate);
2795 size_t typeCount = tacc.GetTypeCount();
2796 std::vector<GateRef> expectedHCIndexes;
2797 for (size_t i = 0; i < typeCount; ++i) {
2798 GateRef temp = builder_.Int32(tacc.GetExpectedHClassIndex(i));
2799 expectedHCIndexes.emplace_back(temp);
2800 }
2801 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
2802 // RuntimeCheck -
2803 // 1. pgo.hclass == ctor.hclass
2804 // 2. ctor.hclass has a prototype chain up to Function.prototype
2805 GateRef obj = tacc.GetReceiver();
2806 GateRef target = tacc.GetTarget();
2807
2808 builder_.ObjectTypeCheck(false, target, expectedHCIndexes[0]);
2809 builder_.ProtoChangeMarkerCheck(target);
2810
2811 result = builder_.OrdinaryHasInstance(obj, target);
2812 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), *result);
2813 }
2814
LowerCreateEmptyObject(GateRef gate)2815 void TypedBytecodeLowering::LowerCreateEmptyObject(GateRef gate)
2816 {
2817 AddProfiling(gate);
2818 GateRef globalEnv = circuit_->GetGlobalEnvCache();
2819 GateRef hclass = builder_.GetGlobalEnvObjHClass(globalEnv, GlobalEnv::OBJECT_FUNCTION_INDEX);
2820
2821 JSHandle<JSFunction> objectFunc(compilationEnv_->GetGlobalEnv()->GetObjectFunction());
2822 JSTaggedValue protoOrHClass = objectFunc->GetProtoOrHClass(compilationEnv_->GetJSThread());
2823 JSHClass *objectHC = JSHClass::Cast(protoOrHClass.GetTaggedObject());
2824 size_t objectSize = objectHC->GetObjectSize();
2825
2826 GateRef emptyArray = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
2827 GateRef size = builder_.IntPtr(objectHC->GetObjectSize());
2828
2829 builder_.StartAllocate();
2830 GateRef object = builder_.HeapAlloc(glue_, size, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
2831
2832 // initialization
2833 for (size_t offset = JSObject::SIZE; offset < objectSize; offset += JSTaggedValue::TaggedTypeSize()) {
2834 builder_.StoreConstOffset(VariableType::INT64(), object, offset, builder_.Undefined());
2835 }
2836 builder_.StoreHClass(glue_, object, hclass, MemoryAttribute::NeedBarrierAndAtomic());
2837 builder_.StoreConstOffset(VariableType::INT64(), object, JSObject::HASH_OFFSET,
2838 builder_.Int64(JSTaggedValue(0).GetRawData()));
2839 builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::PROPERTIES_OFFSET, emptyArray,
2840 MemoryAttribute::NoBarrier());
2841 builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::ELEMENTS_OFFSET, emptyArray,
2842 MemoryAttribute::NoBarrier());
2843 GateRef result = builder_.FinishAllocate(object);
2844
2845 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
2846 }
2847
LowerTypedStOwnByValue(GateRef gate)2848 void TypedBytecodeLowering::LowerTypedStOwnByValue(GateRef gate)
2849 {
2850 // StOwnByValue is rarely used, so the callruntime solution is used
2851 AddProfiling(gate);
2852 return;
2853 }
2854
LowerCreateObjectWithBuffer(GateRef gate)2855 void TypedBytecodeLowering::LowerCreateObjectWithBuffer(GateRef gate)
2856 {
2857 CreateObjWithBufferTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, recordName_, chunk_);
2858 JSThread *thread = compilationEnv_->GetJSThread();
2859 if (!tacc.CanOptimize(thread)) {
2860 return;
2861 }
2862 JSTaggedValue hclassVal = tacc.GetHClass();
2863 if (hclassVal.IsUndefined()) {
2864 return;
2865 }
2866 JSHClass *newClass = JSHClass::Cast(hclassVal.GetTaggedObject());
2867 GateRef index = tacc.GetIndex();
2868 JSTaggedValue obj = tacc.GetObject();
2869 if (obj.IsUndefined()) {
2870 return;
2871 }
2872 JSObject *objhandle = JSObject::Cast(obj);
2873 std::vector<uint64_t> inlinedProps;
2874 auto layout = LayoutInfo::Cast(newClass->GetLayout(thread).GetTaggedObject());
2875 uint32_t numOfProps = newClass->NumberOfProps();
2876 uint32_t numInlinedProps = newClass->GetInlinedProperties();
2877 for (uint32_t i = 0; i < numOfProps; i++) {
2878 auto attr = layout->GetAttr(thread, i);
2879 JSTaggedValue value = objhandle->GetPropertyInlinedProps(thread, i);
2880 if ((!attr.IsTaggedRep()) || value.IsUndefinedOrNull() ||
2881 value.IsNumber() || value.IsBoolean() || value.IsException()) {
2882 auto converted = JSObject::ConvertValueWithRep(attr, value);
2883 if (!converted.first) {
2884 return;
2885 }
2886 // CanOptimize.GetObject had convert value, just used directly
2887 inlinedProps.emplace_back(value.GetRawData());
2888 } else {
2889 return;
2890 }
2891 }
2892
2893 AddProfiling(gate);
2894 auto size = newClass->GetObjectSize();
2895 std::vector<GateRef> valueIn;
2896 valueIn.emplace_back(builder_.IntPtr(size));
2897 valueIn.emplace_back(index);
2898 valueIn.emplace_back(builder_.Int64(JSTaggedValue(newClass).GetRawData()));
2899 valueIn.emplace_back(acc_.GetValueIn(gate, 1));
2900 for (uint32_t i = 0; i < numOfProps; i++) {
2901 auto attr = layout->GetAttr(thread, i);
2902 GateRef prop;
2903 if (attr.IsIntRep()) {
2904 prop = builder_.Int32(inlinedProps.at(i));
2905 } else if (attr.IsTaggedRep()) {
2906 prop = circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(inlinedProps.at(i)),
2907 MachineType::I64, GateType::AnyType());
2908 } else if (attr.IsDoubleRep()) {
2909 prop = circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(inlinedProps.at(i)),
2910 MachineType::F64, GateType::NJSValue());
2911 } else {
2912 prop = builder_.Int64(inlinedProps.at(i));
2913 }
2914 valueIn.emplace_back(prop);
2915 valueIn.emplace_back(builder_.Int32(newClass->GetInlinedPropertiesOffset(i)));
2916 }
2917 GateRef prop = newClass->IsAOT() ? builder_.Hole() : builder_.Undefined();
2918 for (uint32_t i = numOfProps; i < numInlinedProps; i++) {
2919 valueIn.emplace_back(prop);
2920 valueIn.emplace_back(builder_.Int32(newClass->GetInlinedPropertiesOffset(i)));
2921 }
2922 GateRef ret = builder_.TypedCreateObjWithBuffer(valueIn);
2923 if (compilationEnv_->SupportHeapConstant()) {
2924 auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
2925 JSHandle<JSTaggedValue> jsObjectHandle = jitCompilationEnv->NewJSHandle(obj);
2926 auto methodOffset = acc_.TryGetMethodOffset(gate);
2927 auto objIndex = acc_.GetConstantValue(index);
2928 auto constpool = jitCompilationEnv->GetConstantPoolByMethodOffset(methodOffset);
2929 ASSERT(!constpool.IsUndefined());
2930 auto constpoolId = static_cast<uint32_t>(
2931 ConstantPool::Cast(constpool.GetTaggedObject())->GetSharedConstpoolId().GetInt());
2932 uint32_t indexInConstantTable = jitCompilationEnv->RecordHeapConstant(
2933 { constpoolId, objIndex, JitCompilationEnv::IN_UNSHARED_CONSTANTPOOL }, jsObjectHandle);
2934 jitCompilationEnv->RecordGate2HeapConstantIndex(ret, indexInConstantTable);
2935 }
2936 acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), ret);
2937 }
2938
ReplaceGateWithPendingException(GateRef glue,GateRef gate,GateRef state,GateRef depend,GateRef value)2939 void TypedBytecodeLowering::ReplaceGateWithPendingException(GateRef glue, GateRef gate, GateRef state, GateRef depend,
2940 GateRef value)
2941 {
2942 auto condition = builder_.HasPendingException(glue, compilationEnv_);
2943 GateRef ifBranch = builder_.Branch(state, condition, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
2944 GateRef ifTrue = builder_.IfTrue(ifBranch);
2945 GateRef ifFalse = builder_.IfFalse(ifBranch);
2946 GateRef eDepend = builder_.DependRelay(ifTrue, depend);
2947 GateRef sDepend = builder_.DependRelay(ifFalse, depend);
2948
2949 StateDepend success(ifFalse, sDepend);
2950 StateDepend exception(ifTrue, eDepend);
2951 acc_.ReplaceHirWithIfBranch(gate, success, exception, value);
2952 }
2953
ReplaceHirWithCheckingAccessor(GateRef glue,GateRef hirGate,StateDepend replacement,GateRef value,bool isAccessor)2954 void TypedBytecodeLowering::ReplaceHirWithCheckingAccessor(GateRef glue, GateRef hirGate, StateDepend replacement,
2955 GateRef value, bool isAccessor)
2956 {
2957 if (isAccessor) {
2958 ReplaceGateWithPendingException(glue, hirGate, replacement.State(), replacement.Depend(), value);
2959 } else {
2960 acc_.ReplaceHirAndReplaceDeadIfException(hirGate, replacement, value);
2961 }
2962 }
2963 } // namespace panda::ecmascript
2964