1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/compiler/typed_bytecode_lowering.h"
17 #include "ecmascript/builtin_entries.h"
18 #include "ecmascript/compiler/builtins_lowering.h"
19 #include "ecmascript/compiler/bytecodes.h"
20 #include "ecmascript/compiler/circuit.h"
21 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
22 #include "ecmascript/enum_conversion.h"
23 #include "ecmascript/js_tagged_value.h"
24 #include "ecmascript/jspandafile/program_object.h"
25 #include "ecmascript/stackmap/llvm_stackmap_parser.h"
26
27 namespace panda::ecmascript::kungfu {
RunTypedBytecodeLowering()28 bool TypedBytecodeLowering::RunTypedBytecodeLowering()
29 {
30 std::vector<GateRef> gateList;
31 circuit_->GetAllGates(gateList);
32 for (const auto &gate : gateList) {
33 auto op = acc_.GetOpCode(gate);
34 if (op == OpCode::JS_BYTECODE) {
35 Lower(gate);
36 allJSBcCount_++;
37 }
38 }
39
40 bool success = true;
41 double typeHitRate = 0.0;
42 auto allTypedOpCount = allJSBcCount_ - allNonTypedOpCount_;
43 if (allTypedOpCount != 0) {
44 typeHitRate = static_cast<double>(hitTypedOpCount_) / static_cast<double>(allTypedOpCount);
45 auto typeThreshold = tsManager_->GetTypeThreshold();
46 if (typeHitRate <= typeThreshold) {
47 success = false;
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 circuit_->PrintAllGatesWithBytecode();
64 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End typeHitRate: "
65 << std::to_string(typeHitRate)
66 << " ===========================" << "\033[0m";
67 for (auto a : bytecodeMap_) {
68 if (bytecodeHitTimeMap_.find(a.first) != bytecodeHitTimeMap_.end()) {
69 double rate = static_cast<double>(bytecodeHitTimeMap_[a.first]) / static_cast<double>(a.second);
70 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
71 << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(rate)
72 << "(" << std::to_string(bytecodeHitTimeMap_[a.first])
73 << " / " << std::to_string(a.second) << ")"
74 << " ===========================" << "\033[0m";
75 } else {
76 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
77 << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(0)
78 << "(" << std::to_string(0)
79 << " / " << std::to_string(a.second) << ")"
80 << " ===========================" << "\033[0m";
81 }
82 }
83 }
84
85 return success;
86 }
87
Lower(GateRef gate)88 void TypedBytecodeLowering::Lower(GateRef gate)
89 {
90 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
91 // initialize label manager
92 Environment env(gate, circuit_, &builder_);
93 AddBytecodeCount(ecmaOpcode);
94 switch (ecmaOpcode) {
95 case EcmaOpcode::ADD2_IMM8_V8:
96 LowerTypedBinOp<TypedBinOp::TYPED_ADD>(gate);
97 break;
98 case EcmaOpcode::SUB2_IMM8_V8:
99 LowerTypedBinOp<TypedBinOp::TYPED_SUB>(gate);
100 break;
101 case EcmaOpcode::MUL2_IMM8_V8:
102 LowerTypedBinOp<TypedBinOp::TYPED_MUL>(gate);
103 break;
104 case EcmaOpcode::DIV2_IMM8_V8:
105 LowerTypedBinOp<TypedBinOp::TYPED_DIV>(gate);
106 break;
107 case EcmaOpcode::MOD2_IMM8_V8:
108 LowerTypedBinOp<TypedBinOp::TYPED_MOD>(gate);
109 break;
110 case EcmaOpcode::LESS_IMM8_V8:
111 LowerTypedBinOp<TypedBinOp::TYPED_LESS>(gate);
112 break;
113 case EcmaOpcode::LESSEQ_IMM8_V8:
114 LowerTypedBinOp<TypedBinOp::TYPED_LESSEQ>(gate);
115 break;
116 case EcmaOpcode::GREATER_IMM8_V8:
117 LowerTypedBinOp<TypedBinOp::TYPED_GREATER>(gate);
118 break;
119 case EcmaOpcode::GREATEREQ_IMM8_V8:
120 LowerTypedBinOp<TypedBinOp::TYPED_GREATEREQ>(gate);
121 break;
122 case EcmaOpcode::EQ_IMM8_V8:
123 LowerTypedEqOrNotEq<TypedBinOp::TYPED_EQ>(gate);
124 break;
125 case EcmaOpcode::STRICTEQ_IMM8_V8:
126 LowerTypedEqOrNotEq<TypedBinOp::TYPED_STRICTEQ>(gate);
127 break;
128 case EcmaOpcode::NOTEQ_IMM8_V8:
129 LowerTypedEqOrNotEq<TypedBinOp::TYPED_NOTEQ>(gate);
130 break;
131 case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
132 LowerTypedEqOrNotEq<TypedBinOp::TYPED_STRICTNOTEQ>(gate);
133 break;
134 case EcmaOpcode::SHL2_IMM8_V8:
135 LowerTypedBinOp<TypedBinOp::TYPED_SHL>(gate);
136 break;
137 case EcmaOpcode::SHR2_IMM8_V8:
138 LowerTypedBinOp<TypedBinOp::TYPED_SHR>(gate);
139 break;
140 case EcmaOpcode::ASHR2_IMM8_V8:
141 LowerTypedBinOp<TypedBinOp::TYPED_ASHR>(gate);
142 break;
143 case EcmaOpcode::AND2_IMM8_V8:
144 LowerTypedBinOp<TypedBinOp::TYPED_AND>(gate);
145 break;
146 case EcmaOpcode::OR2_IMM8_V8:
147 LowerTypedBinOp<TypedBinOp::TYPED_OR>(gate);
148 break;
149 case EcmaOpcode::XOR2_IMM8_V8:
150 LowerTypedBinOp<TypedBinOp::TYPED_XOR>(gate);
151 break;
152 case EcmaOpcode::TONUMERIC_IMM8:
153 LowerTypeToNumeric(gate);
154 break;
155 case EcmaOpcode::NEG_IMM8:
156 LowerTypedUnOp<TypedUnOp::TYPED_NEG>(gate);
157 break;
158 case EcmaOpcode::NOT_IMM8:
159 LowerTypedUnOp<TypedUnOp::TYPED_NOT>(gate);
160 break;
161 case EcmaOpcode::INC_IMM8:
162 LowerTypedUnOp<TypedUnOp::TYPED_INC>(gate);
163 break;
164 case EcmaOpcode::DEC_IMM8:
165 LowerTypedUnOp<TypedUnOp::TYPED_DEC>(gate);
166 break;
167 case EcmaOpcode::ISTRUE:
168 LowerTypedIsTrueOrFalse(gate, true);
169 break;
170 case EcmaOpcode::ISFALSE:
171 LowerTypedIsTrueOrFalse(gate, false);
172 break;
173 case EcmaOpcode::JEQZ_IMM8:
174 case EcmaOpcode::JEQZ_IMM16:
175 case EcmaOpcode::JEQZ_IMM32:
176 LowerConditionJump(gate, false);
177 break;
178 case EcmaOpcode::JNEZ_IMM8:
179 case EcmaOpcode::JNEZ_IMM16:
180 case EcmaOpcode::JNEZ_IMM32:
181 LowerConditionJump(gate, true);
182 break;
183 case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
184 case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
185 case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
186 case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
187 LowerTypedLdObjByName(gate);
188 break;
189 case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
190 case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
191 case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
192 case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
193 case EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8:
194 LowerTypedStObjByName(gate);
195 break;
196 case EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8:
197 case EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8:
198 LowerTypedStOwnByName(gate);
199 break;
200 case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
201 case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
202 case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
203 LowerTypedLdObjByIndex(gate);
204 break;
205 case EcmaOpcode::STOBJBYINDEX_IMM8_V8_IMM16:
206 case EcmaOpcode::STOBJBYINDEX_IMM16_V8_IMM16:
207 case EcmaOpcode::WIDE_STOBJBYINDEX_PREF_V8_IMM32:
208 LowerTypedStObjByIndex(gate);
209 break;
210 case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
211 case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
212 case EcmaOpcode::LDTHISBYVALUE_IMM8:
213 case EcmaOpcode::LDTHISBYVALUE_IMM16:
214 LowerTypedLdObjByValue(gate);
215 break;
216 case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
217 case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
218 LowerTypedStObjByValue(gate);
219 break;
220 case EcmaOpcode::STOWNBYVALUE_IMM8_V8_V8:
221 case EcmaOpcode::STOWNBYVALUE_IMM16_V8_V8:
222 LowerTypedStOwnByValue(gate);
223 break;
224 case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
225 case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
226 case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
227 LowerTypedNewObjRange(gate);
228 break;
229 case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
230 case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
231 LowerTypedSuperCall(gate);
232 break;
233 case EcmaOpcode::CALLARG0_IMM8:
234 LowerTypedCallArg0(gate);
235 break;
236 case EcmaOpcode::CALLARG1_IMM8_V8:
237 LowerTypedCallArg1(gate);
238 break;
239 case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
240 LowerTypedCallArg2(gate);
241 break;
242 case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
243 LowerTypedCallArg3(gate);
244 break;
245 case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
246 LowerTypedCallrange(gate);
247 break;
248 case EcmaOpcode::CALLTHIS0_IMM8_V8:
249 LowerTypedCallthis0(gate);
250 break;
251 case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
252 LowerTypedCallthis1(gate);
253 break;
254 case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
255 LowerTypedCallthis2(gate);
256 break;
257 case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
258 LowerTypedCallthis3(gate);
259 break;
260 case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
261 LowerTypedCallthisrange(gate);
262 break;
263 case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8:
264 LowerTypedCallInit(gate);
265 break;
266 case EcmaOpcode::TYPEOF_IMM8:
267 case EcmaOpcode::TYPEOF_IMM16:
268 LowerTypedTypeOf(gate);
269 break;
270 case EcmaOpcode::GETITERATOR_IMM8:
271 case EcmaOpcode::GETITERATOR_IMM16:
272 LowerGetIterator(gate);
273 break;
274 case EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16:
275 case EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16:
276 LowerTypedTryLdGlobalByName(gate);
277 break;
278 case EcmaOpcode::INSTANCEOF_IMM8_V8:
279 LowerInstanceOf(gate);
280 break;
281 case EcmaOpcode::CREATEEMPTYOBJECT:
282 LowerCreateEmptyObject(gate);
283 break;
284 case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
285 case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM16_ID16:
286 LowerCreateObjectWithBuffer(gate);
287 break;
288 default:
289 DeleteBytecodeCount(ecmaOpcode);
290 allNonTypedOpCount_++;
291 break;
292 }
293 }
294
295 template<TypedBinOp Op>
LowerTypedBinOp(GateRef gate,bool convertNumberType)296 void TypedBytecodeLowering::LowerTypedBinOp(GateRef gate, bool convertNumberType)
297 {
298 BinOpTypeInfoAccessor tacc(thread_, circuit_, gate, convertNumberType);
299 if (tacc.HasNumberType()) {
300 SpeculateNumbers<Op>(gate);
301 } else if (tacc.HasStringType()) {
302 SpeculateStrings<Op>(gate);
303 }
304 }
305
306 template<TypedUnOp Op>
LowerTypedUnOp(GateRef gate)307 void TypedBytecodeLowering::LowerTypedUnOp(GateRef gate)
308 {
309 UnOpTypeInfoAccessor tacc(thread_, circuit_, gate);
310 if (tacc.ValueIsNumberType()) {
311 SpeculateNumber<Op>(gate);
312 }
313 }
314
315 template<TypedBinOp Op>
LowerTypedEqOrNotEq(GateRef gate)316 void TypedBytecodeLowering::LowerTypedEqOrNotEq(GateRef gate)
317 {
318 GateRef left = acc_.GetValueIn(gate, 0);
319 GateRef right = acc_.GetValueIn(gate, 1);
320 GateType leftType = acc_.GetGateType(left);
321 GateType rightType = acc_.GetGateType(right);
322 GateType gateType = acc_.GetGateType(gate);
323 PGOTypeRef pgoType = acc_.TryGetPGOType(gate);
324
325 BinOpTypeInfoAccessor tacc(thread_, circuit_, gate);
326 if (tacc.LeftOrRightIsUndefinedOrNull() || tacc.HasNumberType()) {
327 AddProfiling(gate);
328 GateRef result = builder_.TypedBinaryOp<Op>(
329 left, right, leftType, rightType, gateType, pgoType);
330 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
331 } else if (tacc.HasStringType()) {
332 SpeculateStrings<Op>(gate);
333 }
334 }
335
336 template<TypedBinOp Op>
SpeculateStrings(GateRef gate)337 void TypedBytecodeLowering::SpeculateStrings(GateRef gate)
338 {
339 if (Op == TypedBinOp::TYPED_EQ || Op == TypedBinOp::TYPED_ADD) {
340 AddProfiling(gate);
341 GateRef left = acc_.GetValueIn(gate, 0);
342 GateRef right = acc_.GetValueIn(gate, 1);
343 if (!TypeInfoAccessor::IsTrustedStringType(thread_, circuit_, chunk_, acc_, left)) {
344 builder_.EcmaStringCheck(left);
345 }
346 if (!TypeInfoAccessor::IsTrustedStringType(thread_, circuit_, chunk_, acc_, right)) {
347 builder_.EcmaStringCheck(right);
348 }
349 GateType leftType = acc_.GetGateType(left);
350 GateType rightType = acc_.GetGateType(right);
351 GateType gateType = acc_.GetGateType(gate);
352 PGOTypeRef pgoType = acc_.TryGetPGOType(gate);
353 pgoTypeLog_.CollectGateTypeLogInfo(gate, true);
354
355 GateRef result = builder_.TypedBinaryOp<Op>(left, right, leftType, rightType, gateType, pgoType);
356 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
357 }
358 }
359
360 template<TypedBinOp Op>
SpeculateNumbers(GateRef gate)361 void TypedBytecodeLowering::SpeculateNumbers(GateRef gate)
362 {
363 AddProfiling(gate);
364 GateRef left = acc_.GetValueIn(gate, 0);
365 GateRef right = acc_.GetValueIn(gate, 1);
366 GateType leftType = acc_.GetGateType(left);
367 GateType rightType = acc_.GetGateType(right);
368 GateType gateType = acc_.GetGateType(gate);
369 PGOTypeRef pgoType = acc_.TryGetPGOType(gate);
370 pgoTypeLog_.CollectGateTypeLogInfo(gate, true);
371
372 GateRef result = builder_.TypedBinaryOp<Op>(left, right, leftType, rightType, gateType, pgoType);
373 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
374 }
375
376 template<TypedUnOp Op>
SpeculateNumber(GateRef gate)377 void TypedBytecodeLowering::SpeculateNumber(GateRef gate)
378 {
379 AddProfiling(gate);
380 GateRef value = acc_.GetValueIn(gate, 0);
381 GateType valueType = acc_.GetGateType(value);
382 GateType gateType = acc_.GetGateType(gate);
383 pgoTypeLog_.CollectGateTypeLogInfo(gate, false);
384
385 const PGOSampleType *sampleType = acc_.TryGetPGOType(gate).GetPGOSampleType();
386 if (sampleType->IsNumber()) {
387 if (sampleType->IsInt()) {
388 gateType = GateType::IntType();
389 } else if (sampleType->IsDouble()) {
390 gateType = GateType::DoubleType();
391 } else {
392 gateType = GateType::NumberType();
393 }
394 valueType = gateType;
395 }
396
397 GateRef result = builder_.TypedUnaryOp<Op>(value, valueType, gateType);
398
399 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
400 }
401
LowerTypeToNumeric(GateRef gate)402 void TypedBytecodeLowering::LowerTypeToNumeric(GateRef gate)
403 {
404 UnOpTypeInfoAccessor tacc(thread_, circuit_, gate);
405 if (tacc.ValueIsNumberType()) {
406 AddProfiling(gate);
407 LowerPrimitiveTypeToNumber(tacc);
408 }
409 }
410
LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor & tacc)411 void TypedBytecodeLowering::LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor &tacc)
412 {
413 GateRef result = builder_.PrimitiveToNumber(tacc.GetValue(),
414 VariableType(MachineType::I64, tacc.GetValueGateType()));
415 acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
416 }
417
LowerConditionJump(GateRef gate,bool flag)418 void TypedBytecodeLowering::LowerConditionJump(GateRef gate, bool flag)
419 {
420 ConditionJumpTypeInfoAccessor tacc(thread_, circuit_, gate);
421 if (tacc.ValueIsBooleanType() && TypeInfoAccessor::IsTrustedType(acc_, tacc.GetValue())) {
422 AddProfiling(gate);
423 SpeculateConditionJump(tacc, flag);
424 }
425 }
426
SpeculateConditionJump(const ConditionJumpTypeInfoAccessor & tacc,bool flag)427 void TypedBytecodeLowering::SpeculateConditionJump(const ConditionJumpTypeInfoAccessor &tacc, bool flag)
428 {
429 GateRef value = tacc.GetValue();
430 GateType valueType = tacc.GetValueGateType();
431 uint32_t weight = tacc.GetBranchWeight();
432 GateRef jump = Circuit::NullGate();
433 if (flag) {
434 jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JNEZ>(value, valueType, weight);
435 } else {
436 jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JEQZ>(value, valueType, weight);
437 }
438 acc_.ReplaceGate(tacc.GetGate(), jump, jump, Circuit::NullGate());
439 }
440
DeleteConstDataIfNoUser(GateRef gate)441 void TypedBytecodeLowering::DeleteConstDataIfNoUser(GateRef gate)
442 {
443 auto uses = acc_.Uses(gate);
444 if (uses.begin() == uses.end()) {
445 builder_.ClearConstantCache(gate);
446 acc_.DeleteGate(gate);
447 }
448 }
449
LowerTypedLdObjByName(GateRef gate)450 void TypedBytecodeLowering::LowerTypedLdObjByName(GateRef gate)
451 {
452 DISALLOW_GARBAGE_COLLECTION;
453 LoadObjByNameTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
454
455 if (TryLowerTypedLdobjBynameFromGloablBuiltin(gate)) {
456 return;
457 }
458 if (TryLowerTypedLdObjByNameForBuiltin(gate)) {
459 return;
460 }
461 if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
462 return;
463 }
464
465 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
466 size_t typeCount = tacc.GetTypeCount();
467 std::vector<Label> loaders;
468 std::vector<Label> fails;
469 for (size_t i = 0; i < typeCount - 1; ++i) {
470 loaders.emplace_back(Label(&builder_));
471 fails.emplace_back(Label(&builder_));
472 }
473 Label exit(&builder_);
474 AddProfiling(gate);
475 GateRef frameState = acc_.GetFrameState(gate);
476 if (tacc.IsMono()) {
477 GateRef receiver = tacc.GetReceiver();
478 builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, receiver,
479 builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
480 if (tacc.IsReceiverEqHolder(0)) {
481 result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
482 } else {
483 builder_.ProtoChangeMarkerCheck(receiver, frameState);
484 PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
485 GateRef plrGate = builder_.Int32(plr.GetData());
486 GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
487 size_t holderHClassIndex = tacc.GetAccessInfo(0).HClassIndex();
488 if (LIKELY(!plr.IsAccessor())) {
489 result = builder_.MonoLoadPropertyOnProto(receiver, plrGate, jsFunc, holderHClassIndex);
490 } else {
491 result = builder_.MonoCallGetterOnProto(gate, receiver, plrGate, jsFunc, holderHClassIndex);
492 }
493 }
494 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
495 DeleteConstDataIfNoUser(tacc.GetKey());
496 return;
497 }
498 auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), tacc.GetReceiver(),
499 TaggedObject::HCLASS_OFFSET);
500 for (size_t i = 0; i < typeCount; ++i) {
501 auto expected = builder_.GetHClassGateFromIndex(gate, tacc.GetExpectedHClassIndex(i));
502 if (i != typeCount - 1) {
503 builder_.Branch(builder_.Equal(receiverHC, expected), &loaders[i], &fails[i]);
504 builder_.Bind(&loaders[i]);
505 } else {
506 // Deopt if fails at last hclass compare
507 builder_.DeoptCheck(builder_.Equal(receiverHC, expected), frameState, DeoptType::INCONSISTENTHCLASS1);
508 }
509
510 if (tacc.IsReceiverEqHolder(i)) {
511 result = BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
512 tacc.GetAccessInfo(i).Plr());
513 builder_.Jump(&exit);
514 } else {
515 // prototype change marker check
516 builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
517 // lookup from receiver for holder
518 auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
519 // lookup from receiver for holder
520 ObjectAccessTypeInfoAccessor::ObjectAccessInfo info = tacc.GetAccessInfo(i);
521 auto holderHC = builder_.GetHClassGateFromIndex(gate, info.HClassIndex());
522 DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
523 Label loopHead(&builder_);
524 Label loadHolder(&builder_);
525 Label lookUpProto(&builder_);
526 builder_.Jump(&loopHead);
527
528 builder_.LoopBegin(&loopHead);
529 builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS2);
530 auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET);
531 builder_.Branch(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
532
533 builder_.Bind(&lookUpProto);
534 current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
535 builder_.LoopEnd(&loopHead);
536
537 builder_.Bind(&loadHolder);
538 result = BuildNamedPropertyAccess(gate, tacc.GetReceiver(), *current, tacc.GetAccessInfo(i).Plr());
539 builder_.Jump(&exit);
540 }
541 if (i != typeCount - 1) {
542 builder_.Bind(&fails[i]);
543 }
544 }
545 builder_.Bind(&exit);
546 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
547 DeleteConstDataIfNoUser(tacc.GetKey());
548 }
549
LowerTypedStObjByName(GateRef gate)550 void TypedBytecodeLowering::LowerTypedStObjByName(GateRef gate)
551 {
552 DISALLOW_GARBAGE_COLLECTION;
553 StoreObjByNameTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
554 if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
555 return;
556 }
557 size_t typeCount = tacc.GetTypeCount();
558 std::vector<Label> loaders;
559 std::vector<Label> fails;
560 for (size_t i = 0; i < typeCount - 1; ++i) {
561 loaders.emplace_back(Label(&builder_));
562 fails.emplace_back(Label(&builder_));
563 }
564 Label exit(&builder_);
565 AddProfiling(gate);
566 GateRef frameState = Circuit::NullGate();
567 auto opcode = acc_.GetByteCodeOpcode(gate);
568
569 // The framestate of Call and Accessor related instructions directives is placed on IR. Using the depend edge to
570 // climb up and find the nearest framestate for other instructions
571 if (opcode == EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8 ||
572 opcode == EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8 ||
573 opcode == EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8) {
574 frameState = acc_.FindNearestFrameState(builder_.GetDepend());
575 } else if (opcode == EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8 ||
576 opcode == EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8 ||
577 opcode == EcmaOpcode::STTHISBYNAME_IMM8_ID16 ||
578 opcode == EcmaOpcode::STTHISBYNAME_IMM16_ID16) {
579 frameState = acc_.GetFrameState(gate);
580 } else {
581 UNREACHABLE();
582 }
583
584 if (tacc.IsMono()) {
585 GateRef receiver = tacc.GetReceiver();
586 builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, receiver,
587 builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
588 if (tacc.IsReceiverNoEqNewHolder(0)) {
589 builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
590 PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
591 GateRef plrGate = builder_.Int32(plr.GetData());
592 GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
593 size_t holderHClassIndex = tacc.GetAccessInfo(0).HClassIndex();
594 GateRef value = tacc.GetValue();
595 if (tacc.IsHolderEqNewHolder(0)) {
596 builder_.MonoStorePropertyLookUpProto(tacc.GetReceiver(), plrGate, jsFunc, holderHClassIndex, value);
597 } else {
598 auto propKey = builder_.LoadObjectFromConstPool(argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC),
599 tacc.GetKey());
600 builder_.MonoStoreProperty(tacc.GetReceiver(), plrGate, jsFunc, holderHClassIndex, value,
601 propKey);
602 }
603 } else if (tacc.IsReceiverEqHolder(0)) {
604 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
605 tacc.GetValue(), tacc.GetAccessInfo(0).Plr(), tacc.GetExpectedHClassIndex(0));
606 }
607 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
608 DeleteConstDataIfNoUser(tacc.GetKey());
609 return;
610 }
611
612 auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), tacc.GetReceiver(),
613 TaggedObject::HCLASS_OFFSET);
614 for (size_t i = 0; i < typeCount; ++i) {
615 auto expected = builder_.GetHClassGateFromIndex(gate, tacc.GetExpectedHClassIndex(i));
616 if (i != typeCount - 1) {
617 builder_.Branch(builder_.Equal(receiverHC, expected),
618 &loaders[i], &fails[i]);
619 builder_.Bind(&loaders[i]);
620 } else {
621 builder_.DeoptCheck(builder_.Equal(receiverHC, expected), frameState, DeoptType::INCONSISTENTHCLASS3);
622 }
623 if (tacc.IsReceiverNoEqNewHolder(i)) {
624 builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
625 auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
626 if (tacc.IsHolderEqNewHolder(i)) {
627 // lookup from receiver for holder
628 auto holderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
629 DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
630 Label loopHead(&builder_);
631 Label loadHolder(&builder_);
632 Label lookUpProto(&builder_);
633 builder_.Jump(&loopHead);
634
635 builder_.LoopBegin(&loopHead);
636 builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS4);
637 auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current,
638 TaggedObject::HCLASS_OFFSET);
639 builder_.Branch(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
640
641 builder_.Bind(&lookUpProto);
642 current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
643 builder_.LoopEnd(&loopHead);
644
645 builder_.Bind(&loadHolder);
646 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), *current, tacc.GetValue(),
647 tacc.GetAccessInfo(i).Plr());
648 builder_.Jump(&exit);
649 } else {
650 // transition happened
651 Label notProto(&builder_);
652 Label isProto(&builder_);
653 auto newHolderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
654 builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype);
655 builder_.Branch(builder_.IsProtoTypeHClass(receiverHC), &isProto, ¬Proto,
656 BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT);
657 builder_.Bind(&isProto);
658 auto propKey = builder_.LoadObjectFromConstPool(argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC),
659 tacc.GetKey());
660 builder_.CallRuntime(glue_, RTSTUB_ID(UpdateAOTHClass), Gate::InvalidGateRef,
661 { receiverHC, newHolderHC, propKey }, gate);
662 builder_.Jump(¬Proto);
663 builder_.Bind(¬Proto);
664 MemoryOrder order = MemoryOrder::Create(MemoryOrder::MEMORY_ORDER_RELEASE);
665 builder_.StoreConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(),
666 TaggedObject::HCLASS_OFFSET, newHolderHC, order);
667 if (!tacc.GetAccessInfo(i).Plr().IsInlinedProps()) {
668 auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(),
669 JSObject::PROPERTIES_OFFSET);
670 auto capacity =
671 builder_.LoadConstOffset(VariableType::INT32(), properties, TaggedArray::LENGTH_OFFSET);
672 auto index = builder_.Int32(tacc.GetAccessInfo(i).Plr().GetOffset());
673 Label needExtend(&builder_);
674 Label notExtend(&builder_);
675 builder_.Branch(builder_.Int32UnsignedLessThan(index, capacity), ¬Extend, &needExtend);
676 builder_.Bind(¬Extend);
677 {
678 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
679 tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
680 builder_.Jump(&exit);
681 }
682 builder_.Bind(&needExtend);
683 {
684 builder_.CallRuntime(glue_,
685 RTSTUB_ID(PropertiesSetValue),
686 Gate::InvalidGateRef,
687 { tacc.GetReceiver(), tacc.GetValue(), properties, builder_.Int32ToTaggedInt(capacity),
688 builder_.Int32ToTaggedInt(index) }, gate);
689 builder_.Jump(&exit);
690 }
691 } else {
692 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
693 tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
694 builder_.Jump(&exit);
695 }
696 }
697 } else if (tacc.IsReceiverEqHolder(i)) {
698 // Local
699 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
700 tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
701 builder_.Jump(&exit);
702 } else {
703 // find in prototype, same as transition
704 UNREACHABLE();
705 return;
706 }
707 if (i != typeCount - 1) {
708 // process fastpath for next type
709 builder_.Bind(&fails[i]);
710 }
711 }
712
713 builder_.Bind(&exit);
714 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
715 DeleteConstDataIfNoUser(tacc.GetKey());
716 }
717
LowerTypedStOwnByName(GateRef gate)718 void TypedBytecodeLowering::LowerTypedStOwnByName(GateRef gate)
719 {
720 LowerTypedStObjByName(gate);
721 }
722
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,PropertyLookupResult plr)723 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
724 GateRef hir, GateRef receiver, GateRef holder, PropertyLookupResult plr)
725 {
726 GateRef plrGate = builder_.Int32(plr.GetData());
727 GateRef result = Circuit::NullGate();
728 if (LIKELY(!plr.IsAccessor())) {
729 result = builder_.LoadProperty(holder, plrGate, plr.IsFunction());
730 } else {
731 result = builder_.CallGetter(hir, receiver, holder, plrGate);
732 }
733 return result;
734 }
735
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,GateRef value,PropertyLookupResult plr,uint32_t receiverHClassIndex)736 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
737 GateRef hir, GateRef receiver, GateRef holder, GateRef value, PropertyLookupResult plr,
738 uint32_t receiverHClassIndex)
739 {
740 GateRef plrGate = builder_.Int32(plr.GetData());
741 GateRef result = Circuit::NullGate();
742 if (LIKELY(!plr.IsAccessor())) {
743 builder_.StoreProperty(receiver, plrGate, value, receiverHClassIndex);
744 } else {
745 builder_.CallSetter(hir, receiver, holder, plrGate, value);
746 }
747 return result;
748 }
749
TryLowerTypedLdObjByNameForBuiltin(GateRef gate)750 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate)
751 {
752 LoadBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
753 // Just supported mono.
754 if (tacc.IsMono()) {
755 if (tacc.IsBuiltinsString()) {
756 return TryLowerTypedLdObjByNameForBuiltin(tacc, BuiltinTypeId::STRING);
757 }
758 if (tacc.IsBuiltinsArray()) {
759 return TryLowerTypedLdObjByNameForBuiltin(tacc, BuiltinTypeId::ARRAY);
760 }
761 }
762
763 // String: primitive string type only
764 /* e.g. let s1 = "ABC"; -> OK
765 * e.g. let s2 = new String("DEF"); -> Not included, whose type is JSType::JS_PRIMITIVE_REF */
766 if (tacc.IsStringType()) {
767 return TryLowerTypedLdObjByNameForBuiltin(tacc, BuiltinTypeId::STRING);
768 }
769 // Array: created via either array literal or new Array(...)
770 /* e.g. let a1 = [1, 2, 3]; -> OK
771 * e.g. let a2 = new Array(1, 2, 3); -> OK */
772 if (tacc.IsArrayType()) {
773 return TryLowerTypedLdObjByNameForBuiltin(tacc, BuiltinTypeId::ARRAY);
774 }
775 // Other valid types: let x = new X(...);
776 const auto hclassEntries = thread_->GetBuiltinHClassEntries();
777 for (BuiltinTypeId type: BuiltinHClassEntries::BUILTIN_TYPES) {
778 if (type == BuiltinTypeId::ARRAY || type == BuiltinTypeId::STRING || !hclassEntries.EntryIsValid(type)) {
779 continue; // Checked before or invalid
780 }
781 if (!tacc.IsBuiltinInstanceType(type)) {
782 continue; // Type mismatch
783 }
784 return TryLowerTypedLdObjByNameForBuiltin(tacc, type);
785 }
786 return false; // No lowering performed
787 }
788
TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor & tacc,BuiltinTypeId type)789 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor &tacc,
790 BuiltinTypeId type)
791 {
792 EcmaString *propString = EcmaString::Cast(tacc.GetKeyTaggedValue().GetTaggedObject());
793 // (1) get length
794 EcmaString *lengthString = EcmaString::Cast(thread_->GlobalConstants()->GetLengthString().GetTaggedObject());
795 if (propString == lengthString) {
796 if (type == BuiltinTypeId::ARRAY) {
797 LowerTypedLdArrayLength(tacc);
798 return true;
799 }
800 if (type == BuiltinTypeId::STRING) {
801 LowerTypedLdStringLength(tacc);
802 return true;
803 }
804 if (IsTypedArrayType(type)) {
805 LowerTypedLdTypedArrayLength(tacc);
806 return true;
807 }
808 }
809 // (2) other functions
810 return false;
811 }
812
TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)813 bool TypedBytecodeLowering::TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)
814 {
815 LoadBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
816 GateRef receiver = tacc.GetReceiver();
817 if (acc_.GetOpCode(receiver) != OpCode::LOAD_BUILTIN_OBJECT) {
818 return false;
819 }
820 JSHandle<GlobalEnv> globalEnv = thread_->GetEcmaVM()->GetGlobalEnv();
821 uint64_t index = acc_.TryGetValue(receiver);
822 BuiltinType type = static_cast<BuiltinType>(index);
823 if (type == BuiltinType::BT_MATH) {
824 auto math = globalEnv->GetMathFunction();
825 JSHClass *hclass = math.GetTaggedValue().GetTaggedObject()->GetClass();
826 JSTaggedValue key = tacc.GetKeyTaggedValue();
827 PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(thread_, hclass, key);
828 if (!plr.IsFound() || plr.IsAccessor()) {
829 return false;
830 }
831 AddProfiling(gate);
832 GateRef plrGate = builder_.Int32(plr.GetData());
833 GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
834 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
835 DeleteConstDataIfNoUser(tacc.GetKey());
836 return true;
837 }
838 return false;
839 }
840
LowerTypedLdArrayLength(const LoadBulitinObjTypeInfoAccessor & tacc)841 void TypedBytecodeLowering::LowerTypedLdArrayLength(const LoadBulitinObjTypeInfoAccessor &tacc)
842 {
843 GateRef gate = tacc.GetGate();
844 GateRef array = tacc.GetReceiver();
845 AddProfiling(gate);
846 if (!Uncheck()) {
847 ElementsKind kind = acc_.TryGetElementsKind(gate);
848 if (!acc_.IsCreateArray(array)) {
849 builder_.StableArrayCheck(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
850 }
851 }
852
853 GateRef result = builder_.LoadArrayLength(array);
854 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
855 }
856
LowerTypedLdTypedArrayLength(const LoadBulitinObjTypeInfoAccessor & tacc)857 void TypedBytecodeLowering::LowerTypedLdTypedArrayLength(const LoadBulitinObjTypeInfoAccessor &tacc)
858 {
859 GateRef gate = tacc.GetGate();
860 GateRef array = tacc.GetReceiver();
861 AddProfiling(gate);
862 GateType arrayType = tacc.GetReceiverGateType();
863 OnHeapMode onHeap = acc_.TryGetOnHeapMode(gate);
864 if (!Uncheck()) {
865 builder_.TypedArrayCheck(array, arrayType, TypedArrayMetaDateAccessor::Mode::LOAD_LENGTH, onHeap);
866 }
867 GateRef result = builder_.LoadTypedArrayLength(array, arrayType, onHeap);
868 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
869 }
870
LowerTypedLdStringLength(const LoadBulitinObjTypeInfoAccessor & tacc)871 void TypedBytecodeLowering::LowerTypedLdStringLength(const LoadBulitinObjTypeInfoAccessor &tacc)
872 {
873 GateRef gate = tacc.GetGate();
874 GateRef str = tacc.GetReceiver();
875 AddProfiling(gate);
876 if (!Uncheck()) {
877 builder_.EcmaStringCheck(str);
878 }
879 GateRef result = builder_.LoadStringLength(str);
880 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
881 }
882
TryLowerTypedLdObjByNameForBuiltinMethod(GateRef gate,JSTaggedValue key,BuiltinTypeId type)883 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltinMethod(
884 GateRef gate, JSTaggedValue key, BuiltinTypeId type)
885 {
886 AddProfiling(gate);
887 std::optional<GlobalEnvField> protoField = ToGlobelEnvPrototypeField(type);
888 if (!protoField.has_value()) {
889 return false;
890 }
891 size_t protoFieldIndex = static_cast<size_t>(*protoField);
892 JSHandle<GlobalEnv> globalEnv = thread_->GetEcmaVM()->GetGlobalEnv();
893 JSHClass *prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass();
894 PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(thread_, prototypeHClass, key);
895 // Unable to handle accessor at the moment
896 if (!plr.IsFound() || plr.IsAccessor()) {
897 return false;
898 }
899 GateRef receiver = acc_.GetValueIn(gate, 2);
900 if (!Uncheck()) {
901 // For Array type only: array stability shall be ensured.
902 if (type == BuiltinTypeId::ARRAY) {
903 builder_.StableArrayCheck(receiver, ElementsKind::GENERIC, ArrayMetaDataAccessor::CALL_BUILTIN_METHOD);
904 }
905 // This check is not required by String, since string is a primitive type.
906 if (type != BuiltinTypeId::STRING) {
907 builder_.BuiltinPrototypeHClassCheck(receiver, type);
908 }
909 }
910 // Successfully goes to typed path
911 GateRef plrGate = builder_.Int32(plr.GetData());
912 GateRef prototype = builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), static_cast<size_t>(*protoField));
913 GateRef result = builder_.LoadProperty(prototype, plrGate, plr.IsFunction());
914 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
915 return true;
916 }
917
TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)918 bool TypedBytecodeLowering::TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)
919 {
920 LoadBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
921 GateRef result = Circuit::NullGate();
922 if (tacc.IsValidTypedArrayType()) {
923 AddProfiling(gate);
924 result = LoadTypedArrayByIndex(tacc);
925 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
926 return true;
927 }
928 return false;
929 }
930
LowerTypedLdObjByIndex(GateRef gate)931 void TypedBytecodeLowering::LowerTypedLdObjByIndex(GateRef gate)
932 {
933 if (TryLowerTypedLdObjByIndexForBuiltin(gate)) {
934 return;
935 }
936 }
937
TryLowerTypedStObjByIndexForBuiltin(GateRef gate)938 bool TypedBytecodeLowering::TryLowerTypedStObjByIndexForBuiltin(GateRef gate)
939 {
940 StoreBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
941 if (!tacc.IsBuiltinInstanceType(BuiltinTypeId::FLOAT32_ARRAY) ||
942 !tacc.ValueIsNumberType()) {
943 return false;
944 }
945 AddProfiling(gate);
946 GateRef receiver = tacc.GetReceiver();
947 GateType receiverType = tacc.GetReceiverGateType();
948 if (!Uncheck()) {
949 OnHeapMode onHeap = tacc.TryGetHeapMode();
950 builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDateAccessor::Mode::ACCESS_ELEMENT, onHeap);
951 }
952 GateRef index = builder_.Int32(tacc.TryConvertKeyToInt());
953 GateRef value = tacc.GetValue();
954 OnHeapMode onHeap = tacc.TryGetHeapMode();
955 auto length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
956 if (!Uncheck()) {
957 builder_.IndexCheck(length, index);
958 }
959 builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, index, value, onHeap);
960 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
961 return true;
962 }
963
LowerTypedStObjByIndex(GateRef gate)964 void TypedBytecodeLowering::LowerTypedStObjByIndex(GateRef gate)
965 {
966 if (TryLowerTypedStObjByIndexForBuiltin(gate)) {
967 return;
968 }
969 }
970
TryLowerTypedLdObjByValueForBuiltin(GateRef gate)971 bool TypedBytecodeLowering::TryLowerTypedLdObjByValueForBuiltin(GateRef gate)
972 {
973 LoadBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
974 GateRef result = Circuit::NullGate();
975 // Just supported mono.
976 if (tacc.IsMono()) {
977 if (tacc.IsBuiltinsString()) {
978 AddProfiling(gate);
979 result = LoadStringByIndex(tacc);
980 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
981 return true;
982 } else if (tacc.IsBuiltinsArray()) {
983 AddProfiling(gate);
984 result = LoadJSArrayByIndex(tacc);
985 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
986 return true;
987 }
988 }
989
990 if (!tacc.KeyIsNumberType()) {
991 return false;
992 }
993 if (tacc.IsValidTypedArrayType()) {
994 AddProfiling(gate);
995 result = LoadTypedArrayByIndex(tacc);
996 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
997 return true;
998 }
999 return false;
1000 }
1001
LowerTypedLdObjByValue(GateRef gate)1002 void TypedBytecodeLowering::LowerTypedLdObjByValue(GateRef gate)
1003 {
1004 if (TryLowerTypedLdObjByValueForBuiltin(gate)) {
1005 return;
1006 }
1007 }
1008
LoadStringByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1009 GateRef TypedBytecodeLowering::LoadStringByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1010 {
1011 GateRef receiver = tacc.GetReceiver();
1012 GateRef propKey = tacc.GetKey();
1013 acc_.SetGateType(propKey, GateType::NumberType());
1014 if (!Uncheck()) {
1015 builder_.EcmaStringCheck(receiver);
1016 GateRef length = builder_.LoadStringLength(receiver);
1017 propKey = builder_.IndexCheck(length, propKey);
1018 receiver = builder_.FlattenTreeStringCheck(receiver);
1019 }
1020 return builder_.LoadElement<TypedLoadOp::STRING_LOAD_ELEMENT>(receiver, propKey);
1021 }
1022
LoadJSArrayByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1023 GateRef TypedBytecodeLowering::LoadJSArrayByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1024 {
1025 GateRef receiver = tacc.GetReceiver();
1026 GateRef propKey = tacc.GetKey();
1027 acc_.SetGateType(propKey, GateType::NumberType());
1028 ElementsKind kind = tacc.TryGetArrayElementsKind();
1029 if (!Uncheck()) {
1030 if (!acc_.IsCreateArray(receiver)) {
1031 builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
1032 }
1033 GateRef length = builder_.LoadArrayLength(receiver);
1034 propKey = builder_.IndexCheck(length, propKey);
1035 }
1036
1037 GateRef result = Circuit::NullGate();
1038 if (Elements::IsInt(kind)) {
1039 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_INT_ELEMENT>(receiver, propKey);
1040 } else if (Elements::IsNumber(kind)) {
1041 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT>(receiver, propKey);
1042 } else if (Elements::IsObject(kind)) {
1043 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT>(receiver, propKey);
1044 } else if (!Elements::IsHole(kind)) {
1045 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT>(receiver, propKey);
1046 } else {
1047 result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_HOLE_TAGGED_ELEMENT>(receiver, propKey);
1048 }
1049 return result;
1050 }
1051
LoadTypedArrayByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1052 GateRef TypedBytecodeLowering::LoadTypedArrayByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1053 {
1054 GateRef receiver = tacc.GetReceiver();
1055 GateType receiverType = tacc.GetReceiverGateType();
1056 GateRef propKey = tacc.GetKey();
1057 OnHeapMode onHeap = tacc.TryGetHeapMode();
1058 BuiltinTypeId builtinTypeId = tacc.GetTypedArrayBuiltinId();
1059 if (!Uncheck()) {
1060 builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDateAccessor::Mode::ACCESS_ELEMENT, onHeap);
1061 GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1062 propKey = builder_.IndexCheck(length, propKey);
1063 }
1064 switch (builtinTypeId) {
1065 case BuiltinTypeId::INT8_ARRAY:
1066 return builder_.LoadElement<TypedLoadOp::INT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1067 case BuiltinTypeId::UINT8_ARRAY:
1068 return builder_.LoadElement<TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1069 case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
1070 return builder_.LoadElement<TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1071 case BuiltinTypeId::INT16_ARRAY:
1072 return builder_.LoadElement<TypedLoadOp::INT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1073 case BuiltinTypeId::UINT16_ARRAY:
1074 return builder_.LoadElement<TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1075 case BuiltinTypeId::INT32_ARRAY:
1076 return builder_.LoadElement<TypedLoadOp::INT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1077 case BuiltinTypeId::UINT32_ARRAY:
1078 return builder_.LoadElement<TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1079 case BuiltinTypeId::FLOAT32_ARRAY:
1080 return builder_.LoadElement<TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1081 case BuiltinTypeId::FLOAT64_ARRAY:
1082 return builder_.LoadElement<TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1083 default:
1084 LOG_ECMA(FATAL) << "this branch is unreachable";
1085 UNREACHABLE();
1086 }
1087
1088 return Circuit::NullGate();
1089 }
1090
StoreJSArrayByIndex(const StoreBulitinObjTypeInfoAccessor & tacc)1091 void TypedBytecodeLowering::StoreJSArrayByIndex(const StoreBulitinObjTypeInfoAccessor &tacc)
1092 {
1093 GateRef receiver = tacc.GetReceiver();
1094 GateRef propKey = tacc.GetKey();
1095 GateRef value = tacc.GetValue();
1096 ElementsKind kind = tacc.TryGetArrayElementsKind();
1097 if (!Uncheck()) {
1098 if (!acc_.IsCreateArray(receiver)) {
1099 builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::STORE_ELEMENT);
1100 }
1101 GateRef length = builder_.LoadArrayLength(receiver);
1102 builder_.IndexCheck(length, propKey);
1103 builder_.COWArrayCheck(receiver);
1104
1105 if (Elements::IsObject(kind)) {
1106 GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
1107 builder_.HeapObjectCheck(value, frameState);
1108 }
1109 }
1110 builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, propKey, value);
1111 }
1112
StoreTypedArrayByIndex(const StoreBulitinObjTypeInfoAccessor & tacc)1113 void TypedBytecodeLowering::StoreTypedArrayByIndex(const StoreBulitinObjTypeInfoAccessor &tacc)
1114 {
1115 GateRef receiver = tacc.GetReceiver();
1116 GateType receiverType = tacc.GetReceiverGateType();
1117 GateRef propKey = tacc.GetKey();
1118 GateRef value = tacc.GetValue();
1119 OnHeapMode onHeap = tacc.TryGetHeapMode();
1120 if (!Uncheck()) {
1121 builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDateAccessor::Mode::ACCESS_ELEMENT, onHeap);
1122 GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1123 propKey = builder_.IndexCheck(length, propKey);
1124 }
1125
1126 auto builtinTypeId = tsManager_->GetTypedArrayBuiltinId(receiverType);
1127 switch (builtinTypeId) {
1128 case BuiltinTypeId::INT8_ARRAY:
1129 builder_.StoreElement<TypedStoreOp::INT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1130 break;
1131 case BuiltinTypeId::UINT8_ARRAY:
1132 builder_.StoreElement<TypedStoreOp::UINT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1133 break;
1134 case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
1135 builder_.StoreElement<TypedStoreOp::UINT8CLAMPEDARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1136 break;
1137 case BuiltinTypeId::INT16_ARRAY:
1138 builder_.StoreElement<TypedStoreOp::INT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1139 break;
1140 case BuiltinTypeId::UINT16_ARRAY:
1141 builder_.StoreElement<TypedStoreOp::UINT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1142 break;
1143 case BuiltinTypeId::INT32_ARRAY:
1144 builder_.StoreElement<TypedStoreOp::INT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1145 break;
1146 case BuiltinTypeId::UINT32_ARRAY:
1147 builder_.StoreElement<TypedStoreOp::UINT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1148 break;
1149 case BuiltinTypeId::FLOAT32_ARRAY:
1150 builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1151 break;
1152 case BuiltinTypeId::FLOAT64_ARRAY:
1153 builder_.StoreElement<TypedStoreOp::FLOAT64ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1154 break;
1155 default:
1156 LOG_ECMA(FATAL) << "this branch is unreachable";
1157 UNREACHABLE();
1158 }
1159 }
1160
TryLowerTypedStObjByValueForBuiltin(GateRef gate)1161 bool TypedBytecodeLowering::TryLowerTypedStObjByValueForBuiltin(GateRef gate)
1162 {
1163 StoreBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
1164 // Just supported mono.
1165 if (tacc.IsMono()) {
1166 if (tacc.IsBuiltinsArray()) {
1167 AddProfiling(gate);
1168 StoreJSArrayByIndex(tacc);
1169 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1170 return true;
1171 }
1172 }
1173
1174 if (!tacc.KeyIsNumberType()) {
1175 return false;
1176 }
1177
1178 if (tacc.IsValidTypedArrayType()) {
1179 AddProfiling(gate);
1180 StoreTypedArrayByIndex(tacc);
1181 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1182 return true;
1183 }
1184
1185 return false;
1186 }
1187
LowerTypedStObjByValue(GateRef gate)1188 void TypedBytecodeLowering::LowerTypedStObjByValue(GateRef gate)
1189 {
1190 if (TryLowerTypedStObjByValueForBuiltin(gate)) {
1191 return;
1192 }
1193 }
1194
LowerTypedIsTrueOrFalse(GateRef gate,bool flag)1195 void TypedBytecodeLowering::LowerTypedIsTrueOrFalse(GateRef gate, bool flag)
1196 {
1197 UnOpTypeInfoAccessor tacc(thread_, circuit_, gate);
1198 if (!tacc.ValueIsPrimitiveNumberType() && !tacc.ValueIsBooleanType()) {
1199 return;
1200 }
1201 AddProfiling(gate);
1202 GateRef value = tacc.GetValue();
1203 GateType valueType = tacc.GetValueGateType();
1204 GateRef result;
1205 if (!flag) {
1206 result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISFALSE>(value, valueType, GateType::TaggedValue());
1207 } else {
1208 result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISTRUE>(value, valueType, GateType::TaggedValue());
1209 }
1210
1211 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1212 }
1213
LowerTypedNewObjRange(GateRef gate)1214 void TypedBytecodeLowering::LowerTypedNewObjRange(GateRef gate)
1215 {
1216 if (TryLowerNewBuiltinConstructor(gate)) {
1217 return;
1218 }
1219 NewObjRangeTypeInfoAccessor tacc(thread_, circuit_, gate);
1220 if (!tacc.FindHClass()) {
1221 return;
1222 }
1223 AddProfiling(gate);
1224 GateRef hclassIndex = builder_.IntPtr(tacc.GetHClassIndex());
1225 GateRef ctor = tacc.GetValue();
1226
1227 GateRef stateSplit = acc_.GetDep(gate);
1228 GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1229 GateRef thisObj = builder_.TypedNewAllocateThis(ctor, hclassIndex, frameState);
1230
1231 // call constructor
1232 size_t range = acc_.GetNumValueIn(gate);
1233 GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(range,
1234 EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
1235 std::vector<GateRef> args { glue_, actualArgc, ctor, ctor, thisObj };
1236 for (size_t i = 1; i < range; ++i) { // 1:skip ctor
1237 args.emplace_back(acc_.GetValueIn(gate, i));
1238 }
1239 GateRef constructGate = builder_.Construct(gate, args);
1240 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
1241 }
1242
TryLowerNewBuiltinConstructor(GateRef gate)1243 bool TypedBytecodeLowering::TryLowerNewBuiltinConstructor(GateRef gate)
1244 {
1245 NewBuiltinCtorTypeInfoAccessor tacc(thread_, circuit_, gate);
1246 if (!tacc.IsBuiltinModule()) {
1247 return false;
1248 }
1249 GateRef ctor = tacc.GetValue();
1250 GateRef constructGate = Circuit::NullGate();
1251 if (tacc.IsBuiltinConstructor(BuiltinTypeId::ARRAY)) {
1252 if (acc_.GetNumValueIn(gate) <= 2) { // 2: ctor and first arg
1253 AddProfiling(gate);
1254 if (!Uncheck()) {
1255 builder_.ArrayConstructorCheck(ctor);
1256 }
1257 constructGate = builder_.BuiltinConstructor(BuiltinTypeId::ARRAY, gate);
1258 }
1259 } else if (tacc.IsBuiltinConstructor(BuiltinTypeId::OBJECT)) {
1260 AddProfiling(gate);
1261 if (!Uncheck()) {
1262 builder_.ObjectConstructorCheck(ctor);
1263 }
1264 constructGate = builder_.BuiltinConstructor(BuiltinTypeId::OBJECT, gate);
1265 }
1266 if (constructGate == Circuit::NullGate()) {
1267 return false;
1268 }
1269 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
1270 return true;
1271 }
1272
LowerTypedSuperCall(GateRef gate)1273 void TypedBytecodeLowering::LowerTypedSuperCall(GateRef gate)
1274 {
1275 SuperCallTypeInfoAccessor tacc(thread_, circuit_, gate);
1276 if (!tacc.IsClassTypeKind() && !tacc.IsFunctionTypeKind()) {
1277 return;
1278 }
1279 AddProfiling(gate);
1280
1281 GateRef ctor = tacc.GetCtor();
1282 // stateSplit maybe not a STATE_SPLIT
1283 GateRef stateSplit = acc_.GetDep(gate);
1284
1285 GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1286 GateRef superCtor = builder_.GetSuperConstructor(ctor);
1287 GateRef newTarget = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
1288 GateRef thisObj = builder_.TypedSuperAllocateThis(superCtor, newTarget, frameState);
1289
1290 // call constructor
1291 size_t range = acc_.GetNumValueIn(gate);
1292 GateRef actualArgc = builder_.Int64(range + 3); // 3: ctor, newTaget, this
1293 std::vector<GateRef> args { glue_, actualArgc, superCtor, newTarget, thisObj };
1294 for (size_t i = 0; i < range; ++i) {
1295 args.emplace_back(acc_.GetValueIn(gate, i));
1296 }
1297
1298 GateRef constructGate = builder_.Construct(gate, args);
1299 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
1300 }
1301
SpeculateCallBuiltin(GateRef gate,GateRef func,const std::vector<GateRef> & args,BuiltinsStubCSigns::ID id,bool isThrow)1302 void TypedBytecodeLowering::SpeculateCallBuiltin(GateRef gate, GateRef func, const std::vector<GateRef> &args,
1303 BuiltinsStubCSigns::ID id, bool isThrow)
1304 {
1305 if (!Uncheck()) {
1306 builder_.CallTargetCheck(gate, func, builder_.IntPtr(static_cast<int64_t>(id)), args[0]);
1307 }
1308
1309 GateRef result = builder_.TypedCallBuiltin(gate, args, id);
1310
1311 if (isThrow) {
1312 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1313 } else {
1314 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1315 }
1316 }
1317
LowerFastCall(GateRef gate,GateRef func,const std::vector<GateRef> & argsFastCall,bool isNoGC)1318 void TypedBytecodeLowering::LowerFastCall(GateRef gate, GateRef func,
1319 const std::vector<GateRef> &argsFastCall, bool isNoGC)
1320 {
1321 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1322 GateRef result = builder_.TypedFastCall(gate, argsFastCall, isNoGC);
1323 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1324 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1325 }
1326
LowerCall(GateRef gate,GateRef func,const std::vector<GateRef> & args,bool isNoGC)1327 void TypedBytecodeLowering::LowerCall(GateRef gate, GateRef func,
1328 const std::vector<GateRef> &args, bool isNoGC)
1329 {
1330 builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1331 GateRef result = builder_.TypedCall(gate, args, isNoGC);
1332 builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1333 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1334 }
1335
1336 template<class TypeAccessor>
CheckFastCallThisCallTarget(const TypeAccessor & tacc)1337 void TypedBytecodeLowering::CheckFastCallThisCallTarget(const TypeAccessor &tacc)
1338 {
1339 if (noCheck_) {
1340 return;
1341 }
1342 GateRef func = tacc.GetFunc();
1343 GateRef gate = tacc.GetGate();
1344 GateType funcType = tacc.GetFuncGateType();
1345 if (tacc.IsNoGC()) {
1346 uint32_t methodOffset = tacc.GetFuncMethodOffset();
1347 builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST_NOGC>(funcType,
1348 func, builder_.IntPtr(methodOffset), gate);
1349 } else {
1350 builder_.JSCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST>(funcType,
1351 func, gate);
1352 }
1353 }
1354
1355 template<class TypeAccessor>
CheckCallThisCallTarget(const TypeAccessor & tacc)1356 void TypedBytecodeLowering::CheckCallThisCallTarget(const TypeAccessor &tacc)
1357 {
1358 if (noCheck_) {
1359 return;
1360 }
1361 GateRef func = tacc.GetFunc();
1362 GateRef gate = tacc.GetGate();
1363 GateType funcType = tacc.GetFuncGateType();
1364 if (tacc.IsNoGC()) {
1365 auto methodOffset = tacc.GetFuncMethodOffset();
1366 builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_NOGC>(funcType,
1367 func, builder_.IntPtr(methodOffset), gate);
1368 } else {
1369 builder_.JSCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS>(funcType,
1370 func, gate);
1371 }
1372 }
1373
1374 template<class TypeAccessor>
CheckThisCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1375 void TypedBytecodeLowering::CheckThisCallTargetAndLowerCall(const TypeAccessor &tacc,
1376 const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1377 {
1378 if (!tacc.FastCallFlagIsVaild()) {
1379 return;
1380 }
1381 GateRef func = tacc.GetFunc();
1382 GateRef gate = tacc.GetGate();
1383 bool isNoGC = tacc.IsNoGC();
1384 if (tacc.CanFastCall()) {
1385 CheckFastCallThisCallTarget(tacc);
1386 LowerFastCall(gate, func, argsFastCall, isNoGC);
1387 } else {
1388 CheckCallThisCallTarget(tacc);
1389 LowerCall(gate, func, args, isNoGC);
1390 }
1391 }
1392
1393 template<class TypeAccessor>
CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,bool isNoGC)1394 void TypedBytecodeLowering::CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor &tacc,
1395 const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall, bool isNoGC)
1396 {
1397 GateRef func = tacc.GetFunc();
1398 GateRef gate = tacc.GetGate();
1399 GateType funcType = tacc.GetFuncGateType();
1400 if (!Uncheck()) {
1401 builder_.JSCallTargetFromDefineFuncCheck(funcType, func, gate);
1402 }
1403 if (tacc.CanFastCall()) {
1404 LowerFastCall(gate, func, argsFastCall, isNoGC);
1405 } else {
1406 LowerCall(gate, func, args, isNoGC);
1407 }
1408 }
1409
1410 template<class TypeAccessor>
CheckCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1411 void TypedBytecodeLowering::CheckCallTargetAndLowerCall(const TypeAccessor &tacc,
1412 const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1413 {
1414 GateRef func = tacc.GetFunc();
1415 if (IsLoadVtable(func)) {
1416 CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall); // func = a.foo, func()
1417 } else {
1418 bool isNoGC = tacc.IsNoGC();
1419 auto op = acc_.GetOpCode(func);
1420 if (!tacc.FastCallFlagIsVaild()) {
1421 return;
1422 }
1423 if (op == OpCode::JS_BYTECODE && (acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8 ||
1424 acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) {
1425 CheckCallTargetFromDefineFuncAndLowerCall(tacc, args, argsFastCall, isNoGC);
1426 return;
1427 }
1428 int methodIndex = tacc.GetMethodIndex();
1429 if (!tacc.MethodOffsetIsVaild() || methodIndex == -1) {
1430 return;
1431 }
1432
1433 GateRef gate = tacc.GetGate();
1434 GateType funcType = tacc.GetFuncGateType();
1435 if (tacc.CanFastCall()) {
1436 if (!Uncheck()) {
1437 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL_FAST>(funcType,
1438 func, builder_.IntPtr(methodIndex), gate);
1439 }
1440 LowerFastCall(gate, func, argsFastCall, isNoGC);
1441 } else {
1442 if (!Uncheck()) {
1443 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL>(funcType,
1444 func, builder_.IntPtr(methodIndex), gate);
1445 }
1446 LowerCall(gate, func, args, isNoGC);
1447 }
1448 }
1449 }
1450
1451 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedCall(const TypeAccessor & tacc)1452 void TypedBytecodeLowering::LowerTypedCall(const TypeAccessor &tacc)
1453 {
1454 uint32_t argc = tacc.GetArgc();
1455 GateRef gate = tacc.GetGate();
1456 GateRef actualArgc = Circuit::NullGate();
1457 switch (Op) {
1458 case EcmaOpcode::CALLARG0_IMM8: {
1459 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1460 EcmaOpcode::CALLARG0_IMM8));
1461 break;
1462 }
1463 case EcmaOpcode::CALLARG1_IMM8_V8: {
1464 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1465 EcmaOpcode::CALLARG1_IMM8_V8));
1466 break;
1467 }
1468 case EcmaOpcode::CALLARGS2_IMM8_V8_V8: {
1469 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1470 EcmaOpcode::CALLARGS2_IMM8_V8_V8));
1471 break;
1472 }
1473 case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8: {
1474 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1475 EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8));
1476 break;
1477 }
1478 case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8: {
1479 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1480 EcmaOpcode::CALLRANGE_IMM8_IMM8_V8));
1481 break;
1482 }
1483 default:
1484 UNREACHABLE();
1485 }
1486 if (!tacc.IsHotnessFunc()) {
1487 return;
1488 }
1489 uint32_t len = tacc.GetFunctionTypeLength();
1490 GateRef func = tacc.GetFunc();
1491 GateRef newTarget = builder_.Undefined();
1492 GateRef thisObj = builder_.Undefined();
1493 std::vector<GateRef> argsFastCall { glue_, func, thisObj};
1494 std::vector<GateRef> args { glue_, actualArgc, func, newTarget, thisObj };
1495 for (uint32_t i = 0; i < argc; i++) {
1496 GateRef value = acc_.GetValueIn(gate, i);
1497 argsFastCall.emplace_back(value);
1498 args.emplace_back(value);
1499 }
1500 for (uint32_t i = argc; i < len; i++) {
1501 argsFastCall.emplace_back(builder_.Undefined());
1502 args.emplace_back(builder_.Undefined());
1503 }
1504 CheckCallTargetAndLowerCall(tacc, args, argsFastCall);
1505 }
1506
LowerTypedCallArg0(GateRef gate)1507 void TypedBytecodeLowering::LowerTypedCallArg0(GateRef gate)
1508 {
1509 CallArg0TypeInfoAccessor tacc(thread_, circuit_, gate);
1510 if (!tacc.IsFunctionTypeKind()) {
1511 return;
1512 }
1513 LowerTypedCall<EcmaOpcode::CALLARG0_IMM8>(tacc);
1514 }
1515
LowerTypedCallArg1(GateRef gate)1516 void TypedBytecodeLowering::LowerTypedCallArg1(GateRef gate)
1517 {
1518 CallArg1TypeInfoAccessor tacc(thread_, circuit_, gate);
1519 GateRef func = tacc.GetFunc();
1520 GateRef a0Value = tacc.GetValue();
1521 GateType a0Type = tacc.GetValueGateType();
1522 BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinId();
1523 if ((IS_TYPED_BUILTINS_MATH_ID(id) && a0Type.IsNumberType())) {
1524 AddProfiling(gate);
1525 SpeculateCallBuiltin(gate, func, { a0Value }, id, false);
1526 } else if (IS_TYPED_BUILTINS_NUMBER_ID(id)) {
1527 AddProfiling(gate);
1528 SpeculateCallBuiltin(gate, func, { a0Value }, id, true);
1529 } else {
1530 if (!tacc.IsFunctionTypeKind()) {
1531 return;
1532 }
1533 LowerTypedCall<EcmaOpcode::CALLARG1_IMM8_V8>(tacc);
1534 }
1535 }
1536
LowerTypedCallArg2(GateRef gate)1537 void TypedBytecodeLowering::LowerTypedCallArg2(GateRef gate)
1538 {
1539 CallArg2TypeInfoAccessor tacc(thread_, circuit_, gate);
1540 if (!tacc.IsFunctionTypeKind()) {
1541 return;
1542 }
1543 LowerTypedCall<EcmaOpcode::CALLARGS2_IMM8_V8_V8>(tacc);
1544 }
1545
LowerTypedCallArg3(GateRef gate)1546 void TypedBytecodeLowering::LowerTypedCallArg3(GateRef gate)
1547 {
1548 CallArg3TypeInfoAccessor tacc(thread_, circuit_, gate);
1549 if (!tacc.IsFunctionTypeKind()) {
1550 return;
1551 }
1552 LowerTypedCall<EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8>(tacc);
1553 }
1554
LowerTypedCallrange(GateRef gate)1555 void TypedBytecodeLowering::LowerTypedCallrange(GateRef gate)
1556 {
1557 CallRangeTypeInfoAccessor tacc(thread_, circuit_, gate);
1558 if (!tacc.IsFunctionTypeKind()) {
1559 return;
1560 }
1561 LowerTypedCall<EcmaOpcode::CALLRANGE_IMM8_IMM8_V8>(tacc);
1562 }
1563
IsLoadVtable(GateRef func)1564 bool TypedBytecodeLowering::IsLoadVtable(GateRef func)
1565 {
1566 auto op = acc_.GetOpCode(func);
1567 if (op != OpCode::LOAD_PROPERTY || !acc_.IsVtable(func)) {
1568 return false;
1569 }
1570 return true;
1571 }
1572
1573 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedThisCall(const TypeAccessor & tacc)1574 void TypedBytecodeLowering::LowerTypedThisCall(const TypeAccessor &tacc)
1575 {
1576 uint32_t argc = tacc.GetArgc();
1577 GateRef gate = tacc.GetGate();
1578 GateRef actualArgc = Circuit::NullGate();
1579 switch (Op) {
1580 case EcmaOpcode::CALLTHIS0_IMM8_V8: {
1581 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1582 EcmaOpcode::CALLTHIS0_IMM8_V8));
1583 break;
1584 }
1585 case EcmaOpcode::CALLTHIS1_IMM8_V8_V8: {
1586 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1587 EcmaOpcode::CALLTHIS1_IMM8_V8_V8));
1588 break;
1589 }
1590 case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8: {
1591 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1592 EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8));
1593 break;
1594 }
1595 case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8: {
1596 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1597 EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8));
1598 break;
1599 }
1600 case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: {
1601 actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1602 EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8));
1603 break;
1604 }
1605 default:
1606 UNREACHABLE();
1607 }
1608
1609 uint32_t len = tacc.GetFunctionTypeLength();
1610 GateRef func = tacc.GetFunc();
1611 GateRef newTarget = builder_.Undefined();
1612 GateRef thisObj = tacc.GetThisObj();
1613 std::vector<GateRef> argsFastCall { glue_, func, thisObj};
1614 std::vector<GateRef> args { glue_, actualArgc, func, newTarget, thisObj };
1615 for (uint32_t i = 0; i < argc; i++) {
1616 GateRef value = acc_.GetValueIn(gate, i + 1);
1617 argsFastCall.emplace_back(value);
1618 args.emplace_back(value);
1619 }
1620 for (uint32_t i = argc; i < len; i++) {
1621 argsFastCall.emplace_back(builder_.Undefined());
1622 args.emplace_back(builder_.Undefined());
1623 }
1624 CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall);
1625 }
1626
LowerTypedCallthis0(GateRef gate)1627 void TypedBytecodeLowering::LowerTypedCallthis0(GateRef gate)
1628 {
1629 CallThis0TypeInfoAccessor tacc(thread_, circuit_, gate);
1630 BuiltinsStubCSigns::ID id = tacc.TryGetBuiltinId(BuiltinTypeId::ARRAY);
1631 if (id == BuiltinsStubCSigns::ID::SORT) {
1632 AddProfiling(gate);
1633 SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetThisObj() }, id, true);
1634 return;
1635 }
1636 BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinId();
1637 if (IS_TYPED_BUILTINS_ID_CALL_THIS0(pgoFuncId)) {
1638 AddProfiling(gate);
1639 SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetThisObj() }, pgoFuncId, true);
1640 return;
1641 }
1642 if (!tacc.CanOptimizeAsFastCall()) {
1643 return;
1644 }
1645 LowerTypedThisCall<EcmaOpcode::CALLTHIS0_IMM8_V8>(tacc);
1646 }
1647
LowerTypedCallthis1(GateRef gate)1648 void TypedBytecodeLowering::LowerTypedCallthis1(GateRef gate)
1649 {
1650 CallThis1TypeInfoAccessor tacc(thread_, circuit_, gate);
1651 BuiltinsStubCSigns::ID id = tacc.TryGetBuiltinId(BuiltinTypeId::MATH);
1652 if (id == BuiltinsStubCSigns::ID::NONE) {
1653 id = tacc.TryGetBuiltinId(BuiltinTypeId::JSON);
1654 if (id != BuiltinsStubCSigns::ID::NONE) {
1655 AddProfiling(gate);
1656 SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArg0() }, id, true);
1657 return;
1658 }
1659 } else if (tacc.Arg0IsNumberType()) {
1660 AddProfiling(gate);
1661 SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArg0() }, id, false);
1662 return;
1663 }
1664 if (!tacc.CanOptimizeAsFastCall()) {
1665 return;
1666 }
1667 LowerTypedThisCall<EcmaOpcode::CALLTHIS1_IMM8_V8_V8>(tacc);
1668 }
1669
LowerTypedCallthis2(GateRef gate)1670 void TypedBytecodeLowering::LowerTypedCallthis2(GateRef gate)
1671 {
1672 CallThis2TypeInfoAccessor tacc(thread_, circuit_, gate);
1673 if (!tacc.CanOptimizeAsFastCall()) {
1674 return;
1675 }
1676 LowerTypedThisCall<EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8>(tacc);
1677 }
1678
LowerTypedCallthis3(GateRef gate)1679 void TypedBytecodeLowering::LowerTypedCallthis3(GateRef gate)
1680 {
1681 CallThis3TypeInfoAccessor tacc(thread_, circuit_, gate);
1682 BuiltinsStubCSigns::ID id = tacc.TryGetBuiltinId(BuiltinTypeId::STRING);
1683 if (IS_TYPED_BUILTINS_ID_CALL_THIS3(id)) {
1684 AddProfiling(gate);
1685 SpeculateCallBuiltin(gate, tacc.GetFunc(), tacc.GetArgs(), id, true);
1686 return;
1687 }
1688 if (!tacc.CanOptimizeAsFastCall()) {
1689 return;
1690 }
1691 LowerTypedThisCall<EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8>(tacc);
1692 }
1693
LowerTypedCallthisrange(GateRef gate)1694 void TypedBytecodeLowering::LowerTypedCallthisrange(GateRef gate)
1695 {
1696 CallThisRangeTypeInfoAccessor tacc(thread_, circuit_, gate);
1697 if (!tacc.CanOptimizeAsFastCall()) {
1698 return;
1699 }
1700 LowerTypedThisCall<EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8>(tacc);
1701 }
1702
LowerTypedCallInit(GateRef gate)1703 void TypedBytecodeLowering::LowerTypedCallInit(GateRef gate)
1704 {
1705 // same as callthis0
1706 LowerTypedCallthis0(gate);
1707 }
1708
AddProfiling(GateRef gate)1709 void TypedBytecodeLowering::AddProfiling(GateRef gate)
1710 {
1711 hitTypedOpCount_++;
1712 AddHitBytecodeCount();
1713 if (IsTraceBC()) {
1714 // see stateSplit as a part of JSByteCode if exists
1715 GateRef maybeStateSplit = acc_.GetDep(gate);
1716 GateRef current = Circuit::NullGate();
1717 if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
1718 current = maybeStateSplit;
1719 } else {
1720 current = gate;
1721 }
1722
1723 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
1724 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
1725 GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
1726 GateRef typedPath = builder_.Int32ToTaggedInt(builder_.Int32(1));
1727 GateRef traceGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(current),
1728 { constOpcode, typedPath }, gate);
1729 acc_.SetDep(current, traceGate);
1730 builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: trace or STATE_SPLIT
1731 }
1732
1733 if (IsProfiling()) {
1734 // see stateSplit as a part of JSByteCode if exists
1735 GateRef maybeStateSplit = acc_.GetDep(gate);
1736 GateRef current = Circuit::NullGate();
1737 if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
1738 current = maybeStateSplit;
1739 } else {
1740 current = gate;
1741 }
1742
1743 if (acc_.HasFrameState(gate)) {
1744 // func, pcoffset, opcode, mode
1745 GateRef func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1746 GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate)));
1747 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
1748 auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
1749 GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
1750 GateRef mode =
1751 builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::TYPED_PATH)));
1752 GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current),
1753 { func, bcIndex, constOpcode, mode }, gate);
1754 acc_.SetDep(current, profiling);
1755 builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: profiling or STATE_SPLIT
1756 }
1757 }
1758 }
1759
AddBytecodeCount(EcmaOpcode op)1760 void TypedBytecodeLowering::AddBytecodeCount(EcmaOpcode op)
1761 {
1762 currentOp_ = op;
1763 if (bytecodeMap_.find(op) != bytecodeMap_.end()) {
1764 bytecodeMap_[op]++;
1765 } else {
1766 bytecodeMap_[op] = 1;
1767 }
1768 }
1769
DeleteBytecodeCount(EcmaOpcode op)1770 void TypedBytecodeLowering::DeleteBytecodeCount(EcmaOpcode op)
1771 {
1772 bytecodeMap_.erase(op);
1773 }
1774
AddHitBytecodeCount()1775 void TypedBytecodeLowering::AddHitBytecodeCount()
1776 {
1777 if (bytecodeHitTimeMap_.find(currentOp_) != bytecodeHitTimeMap_.end()) {
1778 bytecodeHitTimeMap_[currentOp_]++;
1779 } else {
1780 bytecodeHitTimeMap_[currentOp_] = 1;
1781 }
1782 }
1783
LowerTypedTypeOf(GateRef gate)1784 void TypedBytecodeLowering::LowerTypedTypeOf(GateRef gate)
1785 {
1786 // 1: number of value inputs
1787 TypeOfTypeInfoAccessor tacc(thread_, circuit_, gate);
1788 if (tacc.IsIllegalType()) {
1789 return;
1790 }
1791 AddProfiling(gate);
1792 if (!Uncheck()) {
1793 builder_.TypeOfCheck(tacc.GetValue(), tacc.GetValueGateType());
1794 }
1795 GateRef result = builder_.TypedTypeOf(tacc.GetValueGateType());
1796 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1797 }
1798
LowerGetIterator(GateRef gate)1799 void TypedBytecodeLowering::LowerGetIterator(GateRef gate)
1800 {
1801 GetIteratorTypeInfoAccessor tacc(thread_, circuit_, gate);
1802 BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinId();
1803 if (id == BuiltinsStubCSigns::ID::NONE) {
1804 return;
1805 }
1806 AddProfiling(gate);
1807 GateRef obj = tacc.GetCallee();
1808 SpeculateCallBuiltin(gate, obj, { obj }, id, true);
1809 }
1810
LowerTypedTryLdGlobalByName(GateRef gate)1811 void TypedBytecodeLowering::LowerTypedTryLdGlobalByName(GateRef gate)
1812 {
1813 if (!enableLoweringBuiltin_) {
1814 return;
1815 }
1816 DISALLOW_GARBAGE_COLLECTION;
1817 LoadGlobalObjByNameTypeInfoAccessor tacc(thread_, circuit_, gate);
1818 JSTaggedValue key = tacc.GetKeyTaggedValue();
1819
1820 BuiltinIndex& builtin = BuiltinIndex::GetInstance();
1821 auto index = builtin.GetBuiltinIndex(key);
1822 if (index == builtin.NOT_FOUND) {
1823 return;
1824 }
1825 AddProfiling(gate);
1826 GateRef result = builder_.LoadBuiltinObject(index);
1827 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1828 DeleteConstDataIfNoUser(tacc.GetKey());
1829 }
1830
LowerInstanceOf(GateRef gate)1831 void TypedBytecodeLowering::LowerInstanceOf(GateRef gate)
1832 {
1833 InstanceOfTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
1834 if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
1835 return;
1836 }
1837 AddProfiling(gate);
1838 size_t typeCount = tacc.GetTypeCount();
1839 std::vector<GateRef> expectedHCIndexes;
1840 for (size_t i = 0; i < typeCount; ++i) {
1841 GateRef temp = builder_.Int32(tacc.GetExpectedHClassIndex(i));
1842 expectedHCIndexes.emplace_back(temp);
1843 }
1844 DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
1845 // RuntimeCheck -
1846 // 1. pgo.hclass == ctor.hclass
1847 // 2. ctor.hclass has a prototype chain up to Function.prototype
1848 GateRef obj = tacc.GetReceiver();
1849 GateRef target = tacc.GetTarget();
1850
1851 builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, target, expectedHCIndexes[0]);
1852 builder_.ProtoChangeMarkerCheck(target);
1853
1854 result = builder_.OrdinaryHasInstance(obj, target);
1855 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
1856 }
1857
LowerCreateEmptyObject(GateRef gate)1858 void TypedBytecodeLowering::LowerCreateEmptyObject(GateRef gate)
1859 {
1860 AddProfiling(gate);
1861 GateRef globalEnv = builder_.GetGlobalEnv();
1862 GateRef hclass = builder_.GetGlobalEnvObjHClass(globalEnv, GlobalEnv::OBJECT_FUNCTION_INDEX);
1863
1864 JSHandle<JSFunction> objectFunc(tsManager_->GetEcmaVM()->GetGlobalEnv()->GetObjectFunction());
1865 JSTaggedValue protoOrHClass = objectFunc->GetProtoOrHClass();
1866 JSHClass *objectHC = JSHClass::Cast(protoOrHClass.GetTaggedObject());
1867 size_t objectSize = objectHC->GetObjectSize();
1868
1869 GateRef emptyArray = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
1870 GateRef size = builder_.IntPtr(objectHC->GetObjectSize());
1871
1872 builder_.StartAllocate();
1873 GateRef object = builder_.HeapAlloc(size, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
1874
1875 // initialization
1876 for (size_t offset = JSObject::SIZE; offset < objectSize; offset += JSTaggedValue::TaggedTypeSize()) {
1877 builder_.StoreConstOffset(VariableType::INT64(), object, offset, builder_.Undefined());
1878 }
1879 builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::HCLASS_OFFSET, hclass);
1880 builder_.StoreConstOffset(VariableType::INT64(), object, JSObject::HASH_OFFSET,
1881 builder_.Int64(JSTaggedValue(0).GetRawData()));
1882 builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::PROPERTIES_OFFSET, emptyArray);
1883 builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::ELEMENTS_OFFSET, emptyArray);
1884 builder_.FinishAllocate(object);
1885
1886 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), object);
1887 }
1888
LowerTypedStOwnByValue(GateRef gate)1889 void TypedBytecodeLowering::LowerTypedStOwnByValue(GateRef gate)
1890 {
1891 // StOwnByValue is rarely used, so the callruntime solution is used
1892 AddProfiling(gate);
1893 return;
1894 }
1895
LowerCreateObjectWithBuffer(GateRef gate)1896 void TypedBytecodeLowering::LowerCreateObjectWithBuffer(GateRef gate)
1897 {
1898 CreateObjWithBufferTypeInfoAccessor tacc(thread_, circuit_, gate, recordName_);
1899 if (!tacc.CanOptimize()) {
1900 return;
1901 }
1902 JSTaggedValue hclassVal = tacc.GetHClass();
1903 if (hclassVal.IsUndefined()) {
1904 return;
1905 }
1906 JSHandle<JSHClass> newClass(thread_, hclassVal);
1907 GateRef index = tacc.GetIndex();
1908 JSHandle<JSObject> objhandle = tacc.GetObjHandle();
1909 std::vector<uint64_t> inlinedProps;
1910 auto layout = LayoutInfo::Cast(newClass->GetLayout().GetTaggedObject());
1911 for (uint32_t i = 0; i < newClass->GetInlinedProperties(); i++) {
1912 auto attr = layout->GetAttr(i);
1913 JSTaggedValue value = objhandle->GetPropertyInlinedProps(i);
1914 if ((!attr.IsTaggedRep()) || value.IsUndefinedOrNull() ||
1915 value.IsNumber() || value.IsBoolean() || value.IsException()) {
1916 auto converted = JSObject::ConvertValueWithRep(attr, value);
1917 if (!converted.first) {
1918 return;
1919 }
1920 inlinedProps.emplace_back(converted.second.GetRawData());
1921 } else {
1922 return;
1923 }
1924 }
1925
1926 AddProfiling(gate);
1927 GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1928 auto size = newClass->GetObjectSize();
1929 std::vector<GateRef> valueIn;
1930 valueIn.emplace_back(jsFunc);
1931 valueIn.emplace_back(builder_.IntPtr(size));
1932 valueIn.emplace_back(index);
1933 valueIn.emplace_back(builder_.Int64(newClass.GetTaggedValue().GetRawData()));
1934 valueIn.emplace_back(acc_.GetValueIn(gate, 1));
1935 for (uint32_t i = 0; i < newClass->GetInlinedProperties(); i++) {
1936 valueIn.emplace_back(builder_.Int64(inlinedProps.at(i)));
1937 valueIn.emplace_back(builder_.Int32(newClass->GetInlinedPropertiesOffset(i)));
1938 }
1939 GateRef ret = builder_.TypedCreateObjWithBuffer(valueIn);
1940 acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret);
1941 }
1942 } // namespace panda::ecmascript
1943