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