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/type_mcr_lowering.h"
17 #include "ecmascript/compiler/builtins_lowering.h"
18 #include "ecmascript/compiler/new_object_stub_builder.h"
19 #include "ecmascript/deoptimizer/deoptimizer.h"
20 #include "ecmascript/js_arraybuffer.h"
21 #include "ecmascript/js_native_pointer.h"
22 #include "ecmascript/subtyping_operator.h"
23 #include "ecmascript/vtable.h"
24 #include "ecmascript/message_string.h"
25 namespace panda::ecmascript::kungfu {
RunTypeMCRLowering()26 void TypeMCRLowering::RunTypeMCRLowering()
27 {
28 std::vector<GateRef> gateList;
29 circuit_->GetAllGates(gateList);
30 for (const auto &gate : gateList) {
31 LowerType(gate);
32 }
33
34 if (IsLogEnabled()) {
35 LOG_COMPILER(INFO) << "";
36 LOG_COMPILER(INFO) << "\033[34m" << "=================="
37 << " After TypeMCRlowering "
38 << "[" << GetMethodName() << "] "
39 << "==================" << "\033[0m";
40 circuit_->PrintAllGatesWithBytecode();
41 LOG_COMPILER(INFO) << "\033[34m" << "=========================== End =========================" << "\033[0m";
42 }
43 }
44
LowerType(GateRef gate)45 void TypeMCRLowering::LowerType(GateRef gate)
46 {
47 GateRef glue = acc_.GetGlueFromArgList();
48 auto op = acc_.GetOpCode(gate);
49 switch (op) {
50 case OpCode::PRIMITIVE_TYPE_CHECK:
51 LowerPrimitiveTypeCheck(gate);
52 break;
53 case OpCode::STABLE_ARRAY_CHECK:
54 LowerStableArrayCheck(gate);
55 break;
56 case OpCode::TYPED_ARRAY_CHECK:
57 LowerTypedArrayCheck(gate);
58 break;
59 case OpCode::LOAD_TYPED_ARRAY_LENGTH:
60 LowerLoadTypedArrayLength(gate);
61 break;
62 case OpCode::OBJECT_TYPE_CHECK:
63 LowerObjectTypeCheck(gate);
64 break;
65 case OpCode::OBJECT_TYPE_COMPARE:
66 LowerObjectTypeCompare(gate);
67 break;
68 case OpCode::INDEX_CHECK:
69 LowerIndexCheck(gate);
70 break;
71 case OpCode::TYPED_CALLTARGETCHECK_OP:
72 LowerJSCallTargetCheck(gate);
73 break;
74 case OpCode::TYPED_CALL_CHECK:
75 LowerCallTargetCheck(gate);
76 break;
77 case OpCode::JSINLINETARGET_TYPE_CHECK:
78 LowerJSInlineTargetTypeCheck(gate);
79 break;
80 case OpCode::TYPE_CONVERT:
81 LowerTypeConvert(gate);
82 break;
83 case OpCode::LOAD_PROPERTY:
84 LowerLoadProperty(gate);
85 break;
86 case OpCode::CALL_GETTER:
87 LowerCallGetter(gate, glue);
88 break;
89 case OpCode::STORE_PROPERTY:
90 case OpCode::STORE_PROPERTY_NO_BARRIER:
91 LowerStoreProperty(gate);
92 break;
93 case OpCode::CALL_SETTER:
94 LowerCallSetter(gate, glue);
95 break;
96 case OpCode::LOAD_ARRAY_LENGTH:
97 LowerLoadArrayLength(gate);
98 break;
99 case OpCode::LOAD_ELEMENT:
100 LowerLoadElement(gate);
101 break;
102 case OpCode::STORE_ELEMENT:
103 LowerStoreElement(gate, glue);
104 break;
105 case OpCode::TYPED_CALL_BUILTIN:
106 LowerTypedCallBuitin(gate);
107 break;
108 case OpCode::TYPED_NEW_ALLOCATE_THIS:
109 LowerTypedNewAllocateThis(gate, glue);
110 break;
111 case OpCode::TYPED_SUPER_ALLOCATE_THIS:
112 LowerTypedSuperAllocateThis(gate, glue);
113 break;
114 case OpCode::GET_SUPER_CONSTRUCTOR:
115 LowerGetSuperConstructor(gate);
116 break;
117 case OpCode::COW_ARRAY_CHECK:
118 LowerCowArrayCheck(gate, glue);
119 break;
120 case OpCode::LOAD_GETTER:
121 LowerLoadGetter(gate);
122 break;
123 case OpCode::LOAD_SETTER:
124 LowerLoadSetter(gate);
125 break;
126 case OpCode::INLINE_ACCESSOR_CHECK:
127 LowerInlineAccessorCheck(gate);
128 break;
129 default:
130 break;
131 }
132 }
133
LowerJSCallTargetCheck(GateRef gate)134 void TypeMCRLowering::LowerJSCallTargetCheck(GateRef gate)
135 {
136 TypedCallTargetCheckOp Op = acc_.GetTypedCallTargetCheckOp(gate);
137 switch (Op) {
138 case TypedCallTargetCheckOp::JSCALL_IMMEDIATE_AFTER_FUNC_DEF: {
139 LowerJSCallTargetFromDefineFuncCheck(gate);
140 break;
141 }
142 case TypedCallTargetCheckOp::JSCALL: {
143 LowerJSCallTargetTypeCheck(gate);
144 break;
145 }
146 case TypedCallTargetCheckOp::JSCALL_FAST: {
147 LowerJSFastCallTargetTypeCheck(gate);
148 break;
149 }
150 case TypedCallTargetCheckOp::JSCALLTHIS: {
151 LowerJSCallThisTargetTypeCheck(gate);
152 break;
153 }
154 case TypedCallTargetCheckOp::JSCALLTHIS_FAST: {
155 LowerJSFastCallThisTargetTypeCheck(gate);
156 break;
157 }
158 case TypedCallTargetCheckOp::JSCALLTHIS_NOGC: {
159 LowerJSNoGCCallThisTargetTypeCheck(gate);
160 break;
161 }
162 case TypedCallTargetCheckOp::JSCALLTHIS_FAST_NOGC: {
163 LowerJSNoGCFastCallThisTargetTypeCheck(gate);
164 break;
165 }
166 default:
167 LOG_ECMA(FATAL) << "this branch is unreachable";
168 UNREACHABLE();
169 }
170 }
171
LowerPrimitiveTypeCheck(GateRef gate)172 void TypeMCRLowering::LowerPrimitiveTypeCheck(GateRef gate)
173 {
174 Environment env(gate, circuit_, &builder_);
175 auto type = acc_.GetParamGateType(gate);
176 if (type.IsIntType()) {
177 LowerIntCheck(gate);
178 } else if (type.IsDoubleType()) {
179 LowerDoubleCheck(gate);
180 } else if (type.IsNumberType()) {
181 LowerNumberCheck(gate);
182 } else if (type.IsBooleanType()) {
183 LowerBooleanCheck(gate);
184 } else {
185 LOG_ECMA(FATAL) << "this branch is unreachable";
186 UNREACHABLE();
187 }
188 }
189
LowerIntCheck(GateRef gate)190 void TypeMCRLowering::LowerIntCheck(GateRef gate)
191 {
192 GateRef frameState = GetFrameState(gate);
193
194 GateRef value = acc_.GetValueIn(gate, 0);
195 GateRef typeCheck = builder_.TaggedIsInt(value);
196 builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTINT);
197
198 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
199 }
200
LowerDoubleCheck(GateRef gate)201 void TypeMCRLowering::LowerDoubleCheck(GateRef gate)
202 {
203 GateRef frameState = GetFrameState(gate);
204
205 GateRef value = acc_.GetValueIn(gate, 0);
206 GateRef typeCheck = builder_.TaggedIsDouble(value);
207 builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTDOUBLE);
208
209 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
210 }
211
LowerNumberCheck(GateRef gate)212 void TypeMCRLowering::LowerNumberCheck(GateRef gate)
213 {
214 GateRef frameState = GetFrameState(gate);
215
216 GateRef value = acc_.GetValueIn(gate, 0);
217 GateRef typeCheck = builder_.TaggedIsNumber(value);
218 builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTNUMBER);
219
220 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
221 }
222
LowerBooleanCheck(GateRef gate)223 void TypeMCRLowering::LowerBooleanCheck(GateRef gate)
224 {
225 GateRef frameState = GetFrameState(gate);
226
227 GateRef value = acc_.GetValueIn(gate, 0);
228 GateRef typeCheck = builder_.TaggedIsBoolean(value);
229 builder_.DeoptCheck(typeCheck, frameState, DeoptType::NOTBOOL);
230
231 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
232 }
233
LowerStableArrayCheck(GateRef gate)234 void TypeMCRLowering::LowerStableArrayCheck(GateRef gate)
235 {
236 Environment env(gate, circuit_, &builder_);
237 GateRef frameState = GetFrameState(gate);
238
239 GateRef receiver = acc_.GetValueIn(gate, 0);
240 builder_.HeapObjectCheck(receiver, frameState);
241
242 GateRef receiverHClass = builder_.LoadConstOffset(
243 VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
244 ArrayMetaDataAccessor accessor = acc_.GetArrayMetaDataAccessor(gate);
245 builder_.HClassStableArrayCheck(receiverHClass, frameState, accessor);
246 builder_.ArrayGuardianCheck(frameState);
247
248 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
249 }
250
SetDeoptTypeInfo(BuiltinTypeId id,DeoptType & type,size_t & funcIndex)251 void TypeMCRLowering::SetDeoptTypeInfo(BuiltinTypeId id, DeoptType &type, size_t &funcIndex)
252 {
253 type = DeoptType::NOTARRAY;
254 switch (id) {
255 case BuiltinTypeId::INT8_ARRAY:
256 funcIndex = GlobalEnv::INT8_ARRAY_FUNCTION_INDEX;
257 break;
258 case BuiltinTypeId::UINT8_ARRAY:
259 funcIndex = GlobalEnv::UINT8_ARRAY_FUNCTION_INDEX;
260 break;
261 case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
262 funcIndex = GlobalEnv::UINT8_CLAMPED_ARRAY_FUNCTION_INDEX;
263 break;
264 case BuiltinTypeId::INT16_ARRAY:
265 funcIndex = GlobalEnv::INT16_ARRAY_FUNCTION_INDEX;
266 break;
267 case BuiltinTypeId::UINT16_ARRAY:
268 funcIndex = GlobalEnv::UINT16_ARRAY_FUNCTION_INDEX;
269 break;
270 case BuiltinTypeId::INT32_ARRAY:
271 funcIndex = GlobalEnv::INT32_ARRAY_FUNCTION_INDEX;
272 break;
273 case BuiltinTypeId::UINT32_ARRAY:
274 funcIndex = GlobalEnv::UINT32_ARRAY_FUNCTION_INDEX;
275 break;
276 case BuiltinTypeId::FLOAT32_ARRAY:
277 funcIndex = GlobalEnv::FLOAT32_ARRAY_FUNCTION_INDEX;
278 break;
279 case BuiltinTypeId::FLOAT64_ARRAY:
280 funcIndex = GlobalEnv::FLOAT64_ARRAY_FUNCTION_INDEX;
281 break;
282 default:
283 LOG_ECMA(FATAL) << "this branch is unreachable";
284 UNREACHABLE();
285 }
286 }
287
LowerTypedArrayCheck(GateRef gate)288 void TypeMCRLowering::LowerTypedArrayCheck(GateRef gate)
289 {
290 Environment env(gate, circuit_, &builder_);
291 auto type = acc_.GetParamGateType(gate);
292 size_t typedArrayFuncIndex = GlobalEnv::TYPED_ARRAY_FUNCTION_INDEX;
293 auto deoptType = DeoptType::NOTCHECK;
294
295 auto builtinTypeId = tsManager_->GetTypedArrayBuiltinId(type);
296 SetDeoptTypeInfo(builtinTypeId, deoptType, typedArrayFuncIndex);
297
298 GateRef frameState = GetFrameState(gate);
299 GateRef glueGlobalEnv = builder_.GetGlobalEnv();
300 GateRef receiver = acc_.GetValueIn(gate, 0);
301 GateRef receiverHClass = builder_.LoadHClass(receiver);
302 GateRef protoOrHclass = builder_.GetGlobalEnvObjHClass(glueGlobalEnv, typedArrayFuncIndex);
303 GateRef check = builder_.Equal(receiverHClass, protoOrHclass);
304 builder_.DeoptCheck(check, frameState, deoptType);
305 GateRef isOnHeap = builder_.LoadConstOffset(VariableType::BOOL(), receiver, JSTypedArray::ON_HEAP_OFFSET);
306 builder_.DeoptCheck(isOnHeap, frameState, DeoptType::NOTONHEAP);
307
308 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
309 }
310
LowerLoadTypedArrayLength(GateRef gate)311 void TypeMCRLowering::LowerLoadTypedArrayLength(GateRef gate)
312 {
313 Environment env(gate, circuit_, &builder_);
314 GateRef receiver = acc_.GetValueIn(gate, 0);
315 GateRef length = builder_.LoadConstOffset(VariableType::INT32(), receiver, JSTypedArray::ARRAY_LENGTH_OFFSET);
316 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), length);
317 }
318
LowerObjectTypeCheck(GateRef gate)319 void TypeMCRLowering::LowerObjectTypeCheck(GateRef gate)
320 {
321 Environment env(gate, circuit_, &builder_);
322 GateType type = acc_.GetObjectTypeAccessor(gate).GetType();
323 if (tsManager_->IsClassInstanceTypeKind(type)) {
324 LowerTSSubtypingCheck(gate);
325 } else if (tsManager_->IsClassTypeKind(type) ||
326 tsManager_->IsObjectTypeKind(type)) {
327 LowerSimpleHClassCheck(gate);
328 } else {
329 LOG_COMPILER(FATAL) << "this branch is unreachable";
330 UNREACHABLE();
331 }
332 }
333
LowerTSSubtypingCheck(GateRef gate)334 void TypeMCRLowering::LowerTSSubtypingCheck(GateRef gate)
335 {
336 GateRef frameState = GetFrameState(gate);
337 Label levelValid(&builder_);
338 Label exit(&builder_);
339 GateRef compare = BuildCompareSubTyping(gate, frameState, &levelValid, &exit);
340 builder_.DeoptCheck(compare, frameState, DeoptType::INCONSISTENTHCLASS);
341 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
342 }
343
LowerSimpleHClassCheck(GateRef gate)344 void TypeMCRLowering::LowerSimpleHClassCheck(GateRef gate)
345 {
346 GateRef frameState = GetFrameState(gate);
347 GateRef compare = BuildCompareHClass(gate, frameState);
348 builder_.DeoptCheck(compare, frameState, DeoptType::INCONSISTENTHCLASS);
349 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
350 }
351
LowerObjectTypeCompare(GateRef gate)352 void TypeMCRLowering::LowerObjectTypeCompare(GateRef gate)
353 {
354 Environment env(gate, circuit_, &builder_);
355 auto type = acc_.GetObjectTypeAccessor(gate).GetType();
356 if (tsManager_->IsClassInstanceTypeKind(type)) {
357 LowerTSSubtypingCompare(gate);
358 } else if (tsManager_->IsClassTypeKind(type) ||
359 tsManager_->IsObjectTypeKind(type)) {
360 LowerSimpleHClassCompare(gate);
361 } else {
362 LOG_COMPILER(FATAL) << "this branch is unreachable";
363 UNREACHABLE();
364 }
365 }
366
LowerSimpleHClassCompare(GateRef gate)367 void TypeMCRLowering::LowerSimpleHClassCompare(GateRef gate)
368 {
369 GateRef frameState = GetFrameState(gate);
370 GateRef compare = BuildCompareHClass(gate, frameState) ;
371 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), compare);
372 }
373
LowerTSSubtypingCompare(GateRef gate)374 void TypeMCRLowering::LowerTSSubtypingCompare(GateRef gate)
375 {
376 GateRef frameState = GetFrameState(gate);
377 Label levelValid(&builder_);
378 Label exit(&builder_);
379 GateRef compare = BuildCompareSubTyping(gate, frameState, &levelValid, &exit);
380 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), compare);
381 }
382
BuildCompareSubTyping(GateRef gate,GateRef frameState,Label * levelValid,Label * exit)383 GateRef TypeMCRLowering::BuildCompareSubTyping(GateRef gate, GateRef frameState, Label *levelValid, Label *exit)
384 {
385 GateRef receiver = acc_.GetValueIn(gate, 0);
386 bool isHeapObject = acc_.GetObjectTypeAccessor(gate).IsHeapObject();
387 if (!isHeapObject) {
388 builder_.HeapObjectCheck(receiver, frameState);
389 }
390
391 GateRef aotHCIndex = acc_.GetValueIn(gate, 1);
392 ArgumentAccessor argAcc(circuit_);
393 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
394 JSTaggedValue aotHC = tsManager_->GetValueFromCache(acc_.TryGetValue(aotHCIndex));
395 ASSERT(aotHC.IsJSHClass());
396
397 int32_t level = JSHClass::Cast(aotHC.GetTaggedObject())->GetLevel();
398 ASSERT(level >= 0);
399
400 GateRef receiverHClass = builder_.LoadConstOffset(
401 VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
402 GateRef supers = LoadSupers(receiverHClass);
403
404 auto hclassIndex = acc_.GetConstantValue(aotHCIndex);
405 GateRef aotHCGate = LoadFromConstPool(jsFunc, hclassIndex);
406
407 if (LIKELY(static_cast<uint32_t>(level) < SubtypingOperator::DEFAULT_SUPERS_CAPACITY)) {
408 return builder_.Equal(aotHCGate, GetValueFromSupers(supers, level));
409 }
410
411 DEFVAlUE(check, (&builder_), VariableType::BOOL(), builder_.False());
412 GateRef levelGate = builder_.Int32(level);
413 GateRef length = GetLengthFromSupers(supers);
414
415 builder_.Branch(builder_.Int32LessThan(levelGate, length), levelValid, exit);
416 builder_.Bind(levelValid);
417 {
418 check = builder_.Equal(aotHCGate, GetValueFromSupers(supers, level));
419 builder_.Jump(exit);
420 }
421 builder_.Bind(exit);
422
423 return *check;
424 }
425
BuildCompareHClass(GateRef gate,GateRef frameState)426 GateRef TypeMCRLowering::BuildCompareHClass(GateRef gate, GateRef frameState)
427 {
428 GateRef receiver = acc_.GetValueIn(gate, 0);
429 bool isHeapObject = acc_.GetObjectTypeAccessor(gate).IsHeapObject();
430 if (!isHeapObject) {
431 builder_.HeapObjectCheck(receiver, frameState);
432 }
433
434 GateRef aotHCIndex = acc_.GetValueIn(gate, 1);
435 auto hclassIndex = acc_.GetConstantValue(aotHCIndex);
436 ArgumentAccessor argAcc(circuit_);
437 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
438 GateRef aotHCGate = LoadFromConstPool(jsFunc, hclassIndex);
439 GateRef receiverHClass = builder_.LoadConstOffset(
440 VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
441 return builder_.Equal(aotHCGate, receiverHClass);
442 }
443
LowerIndexCheck(GateRef gate)444 void TypeMCRLowering::LowerIndexCheck(GateRef gate)
445 {
446 Environment env(gate, circuit_, &builder_);
447 auto deoptType = DeoptType::NOTARRAYIDX;
448
449 GateRef frameState = GetFrameState(gate);
450 GateRef length = acc_.GetValueIn(gate, 0);
451 GateRef index = acc_.GetValueIn(gate, 1);
452 ASSERT(acc_.GetGateType(length).IsNJSValueType());
453 // UnsignedLessThan can check both lower and upper bounds
454 GateRef lengthCheck = builder_.Int32UnsignedLessThan(index, length);
455 builder_.DeoptCheck(lengthCheck, frameState, deoptType);
456 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), index);
457 }
458
LowerCallRuntime(GateRef glue,GateRef hirGate,int index,const std::vector<GateRef> & args,bool useLabel)459 GateRef TypeMCRLowering::LowerCallRuntime(GateRef glue, GateRef hirGate, int index, const std::vector<GateRef> &args,
460 bool useLabel)
461 {
462 if (useLabel) {
463 GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args, hirGate);
464 return result;
465 } else {
466 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
467 GateRef target = builder_.IntPtr(index);
468 GateRef result = builder_.Call(cs, glue, target, dependEntry_, args, hirGate);
469 return result;
470 }
471 }
472
LowerTypeConvert(GateRef gate)473 void TypeMCRLowering::LowerTypeConvert(GateRef gate)
474 {
475 Environment env(gate, circuit_, &builder_);
476 auto leftType = acc_.GetLeftType(gate);
477 auto rightType = acc_.GetRightType(gate);
478 if (rightType.IsNumberType()) {
479 GateRef value = acc_.GetValueIn(gate, 0);
480 if (leftType.IsDigitablePrimitiveType()) {
481 LowerPrimitiveToNumber(gate, value, leftType);
482 }
483 return;
484 }
485 }
486
LowerPrimitiveToNumber(GateRef dst,GateRef src,GateType srcType)487 void TypeMCRLowering::LowerPrimitiveToNumber(GateRef dst, GateRef src, GateType srcType)
488 {
489 DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
490 if (srcType.IsBooleanType()) {
491 Label exit(&builder_);
492 Label isTrue(&builder_);
493 Label isFalse(&builder_);
494 builder_.Branch(builder_.TaggedIsTrue(src), &isTrue, &isFalse);
495 builder_.Bind(&isTrue);
496 {
497 result = IntToTaggedIntPtr(builder_.Int32(1));
498 builder_.Jump(&exit);
499 }
500 builder_.Bind(&isFalse);
501 {
502 result = IntToTaggedIntPtr(builder_.Int32(0));
503 builder_.Jump(&exit);
504 }
505 builder_.Bind(&exit);
506 } else if (srcType.IsUndefinedType()) {
507 result = DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
508 } else if (srcType.IsBigIntType() || srcType.IsNumberType()) {
509 result = src;
510 } else if (srcType.IsNullType()) {
511 result = IntToTaggedIntPtr(builder_.Int32(0));
512 } else {
513 LOG_ECMA(FATAL) << "this branch is unreachable";
514 UNREACHABLE();
515 }
516 acc_.ReplaceGate(dst, builder_.GetState(), builder_.GetDepend(), *result);
517 }
518
LoadFromConstPool(GateRef jsFunc,size_t index)519 GateRef TypeMCRLowering::LoadFromConstPool(GateRef jsFunc, size_t index)
520 {
521 GateRef constPool = builder_.GetConstPool(jsFunc);
522 return builder_.LoadFromTaggedArray(constPool, index);
523 }
524
GetObjectFromConstPool(GateRef jsFunc,GateRef index)525 GateRef TypeMCRLowering::GetObjectFromConstPool(GateRef jsFunc, GateRef index)
526 {
527 GateRef constPool = builder_.GetConstPool(jsFunc);
528 return builder_.GetValueFromTaggedArray(constPool, index);
529 }
530
LowerLoadProperty(GateRef gate)531 void TypeMCRLowering::LowerLoadProperty(GateRef gate)
532 {
533 Environment env(gate, circuit_, &builder_);
534 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: receiver, plr
535 GateRef receiver = acc_.GetValueIn(gate, 0);
536 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
537 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
538 ASSERT(plr.IsLocal() || plr.IsFunction());
539
540 GateRef result = Circuit::NullGate();
541 if (plr.IsNotHole()) {
542 ASSERT(plr.IsLocal());
543 result = builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, plr.GetOffset());
544 } else if (plr.IsLocal()) {
545 result = builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, plr.GetOffset());
546 result = builder_.ConvertHoleAsUndefined(result);
547 } else {
548 result = LoadFromVTable(receiver, plr.GetOffset());
549 }
550
551 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
552 }
553
LowerCallGetter(GateRef gate,GateRef glue)554 void TypeMCRLowering::LowerCallGetter(GateRef gate, GateRef glue)
555 {
556 Environment env(gate, circuit_, &builder_);
557 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: receiver, plr
558 GateRef receiver = acc_.GetValueIn(gate, 0);
559 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
560
561 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
562 ASSERT(plr.IsAccessor());
563 GateRef accessor = LoadFromVTable(receiver, plr.GetOffset());
564 GateRef getter = builder_.LoadConstOffset(VariableType::JS_ANY(), accessor, AccessorData::GETTER_OFFSET);
565
566 DEFVAlUE(result, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
567 Label callGetter(&builder_);
568 Label exit(&builder_);
569 builder_.Branch(builder_.IsSpecial(getter, JSTaggedValue::VALUE_UNDEFINED), &exit, &callGetter);
570 builder_.Bind(&callGetter);
571 {
572 result = CallAccessor(glue, gate, getter, receiver, AccessorMode::GETTER);
573 builder_.Jump(&exit);
574 }
575 builder_.Bind(&exit);
576 ReplaceHirWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), *result);
577 }
578
LowerStoreProperty(GateRef gate)579 void TypeMCRLowering::LowerStoreProperty(GateRef gate)
580 {
581 Environment env(gate, circuit_, &builder_);
582 ASSERT(acc_.GetNumValueIn(gate) == 3); // 3: receiver, plr, value
583 GateRef receiver = acc_.GetValueIn(gate, 0);
584 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
585 GateRef value = acc_.GetValueIn(gate, 2); // 2: value
586 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
587 ASSERT(plr.IsLocal());
588 auto op = OpCode(acc_.GetOpCode(gate));
589 if (op == OpCode::STORE_PROPERTY) {
590 builder_.StoreConstOffset(VariableType::JS_ANY(), receiver, plr.GetOffset(), value);
591 } else if (op == OpCode::STORE_PROPERTY_NO_BARRIER) {
592 builder_.StoreConstOffset(GetVarType(plr), receiver, plr.GetOffset(), value);
593 } else {
594 UNREACHABLE();
595 }
596 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
597 }
598
LowerCallSetter(GateRef gate,GateRef glue)599 void TypeMCRLowering::LowerCallSetter(GateRef gate, GateRef glue)
600 {
601 Environment env(gate, circuit_, &builder_);
602 ASSERT(acc_.GetNumValueIn(gate) == 3); // 3: receiver, plr, value
603 GateRef receiver = acc_.GetValueIn(gate, 0);
604 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
605 GateRef value = acc_.GetValueIn(gate, 2);
606
607 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
608 ASSERT(plr.IsAccessor());
609 GateRef accessor = LoadFromVTable(receiver, plr.GetOffset());
610 GateRef setter = builder_.LoadConstOffset(VariableType::JS_ANY(), accessor, AccessorData::SETTER_OFFSET);
611
612 Label callSetter(&builder_);
613 Label exit(&builder_);
614 builder_.Branch(builder_.IsSpecial(setter, JSTaggedValue::VALUE_UNDEFINED), &exit, &callSetter);
615 builder_.Bind(&callSetter);
616 {
617 CallAccessor(glue, gate, setter, receiver, AccessorMode::SETTER, value);
618 builder_.Jump(&exit);
619 }
620 builder_.Bind(&exit);
621 ReplaceHirWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
622 }
623
LowerLoadArrayLength(GateRef gate)624 void TypeMCRLowering::LowerLoadArrayLength(GateRef gate)
625 {
626 Environment env(gate, circuit_, &builder_);
627 GateRef array = acc_.GetValueIn(gate, 0);
628 GateRef result = builder_.LoadConstOffset(VariableType::INT32(), array, JSArray::LENGTH_OFFSET);
629 acc_.SetGateType(gate, GateType::NJSValue());
630 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
631 }
632
GetElementSize(BuiltinTypeId id)633 GateRef TypeMCRLowering::GetElementSize(BuiltinTypeId id)
634 {
635 GateRef elementSize = Circuit::NullGate();
636 switch (id) {
637 case BuiltinTypeId::INT8_ARRAY:
638 case BuiltinTypeId::UINT8_ARRAY:
639 case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
640 elementSize = builder_.Int32(sizeof(uint8_t));
641 break;
642 case BuiltinTypeId::INT16_ARRAY:
643 case BuiltinTypeId::UINT16_ARRAY:
644 elementSize = builder_.Int32(sizeof(uint16_t));
645 break;
646 case BuiltinTypeId::INT32_ARRAY:
647 case BuiltinTypeId::UINT32_ARRAY:
648 case BuiltinTypeId::FLOAT32_ARRAY:
649 elementSize = builder_.Int32(sizeof(uint32_t));
650 break;
651 case BuiltinTypeId::FLOAT64_ARRAY:
652 elementSize = builder_.Int32(sizeof(double));
653 break;
654 default:
655 LOG_ECMA(FATAL) << "this branch is unreachable";
656 UNREACHABLE();
657 }
658 return elementSize;
659 }
660
GetVariableType(BuiltinTypeId id)661 VariableType TypeMCRLowering::GetVariableType(BuiltinTypeId id)
662 {
663 VariableType type = VariableType::JS_ANY();
664 switch (id) {
665 case BuiltinTypeId::INT8_ARRAY:
666 case BuiltinTypeId::UINT8_ARRAY:
667 case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
668 type = VariableType::INT8();
669 break;
670 case BuiltinTypeId::INT16_ARRAY:
671 case BuiltinTypeId::UINT16_ARRAY:
672 type = VariableType::INT16();
673 break;
674 case BuiltinTypeId::INT32_ARRAY:
675 case BuiltinTypeId::UINT32_ARRAY:
676 type = VariableType::INT32();
677 break;
678 case BuiltinTypeId::FLOAT32_ARRAY:
679 type = VariableType::FLOAT32();
680 break;
681 case BuiltinTypeId::FLOAT64_ARRAY:
682 type = VariableType::FLOAT64();
683 break;
684 default:
685 LOG_ECMA(FATAL) << "this branch is unreachable";
686 UNREACHABLE();
687 }
688 return type;
689 }
690
LowerLoadElement(GateRef gate)691 void TypeMCRLowering::LowerLoadElement(GateRef gate)
692 {
693 Environment env(gate, circuit_, &builder_);
694 auto op = acc_.GetTypedLoadOp(gate);
695 switch (op) {
696 case TypedLoadOp::ARRAY_LOAD_INT_ELEMENT:
697 case TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT:
698 case TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT:
699 case TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT:
700 LowerArrayLoadElement(gate, ArrayState::PACKED);
701 break;
702 case TypedLoadOp::ARRAY_LOAD_HOLE_TAGGED_ELEMENT:
703 LowerArrayLoadElement(gate, ArrayState::HOLEY);
704 break;
705 case TypedLoadOp::INT8ARRAY_LOAD_ELEMENT:
706 LowerTypedArrayLoadElement(gate, BuiltinTypeId::INT8_ARRAY);
707 break;
708 case TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT:
709 LowerTypedArrayLoadElement(gate, BuiltinTypeId::UINT8_ARRAY);
710 break;
711 case TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT:
712 LowerTypedArrayLoadElement(gate, BuiltinTypeId::UINT8_CLAMPED_ARRAY);
713 break;
714 case TypedLoadOp::INT16ARRAY_LOAD_ELEMENT:
715 LowerTypedArrayLoadElement(gate, BuiltinTypeId::INT16_ARRAY);
716 break;
717 case TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT:
718 LowerTypedArrayLoadElement(gate, BuiltinTypeId::UINT16_ARRAY);
719 break;
720 case TypedLoadOp::INT32ARRAY_LOAD_ELEMENT:
721 LowerTypedArrayLoadElement(gate, BuiltinTypeId::INT32_ARRAY);
722 break;
723 case TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT:
724 LowerTypedArrayLoadElement(gate, BuiltinTypeId::UINT32_ARRAY);
725 break;
726 case TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT:
727 LowerTypedArrayLoadElement(gate, BuiltinTypeId::FLOAT32_ARRAY);
728 break;
729 case TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT:
730 LowerTypedArrayLoadElement(gate, BuiltinTypeId::FLOAT64_ARRAY);
731 break;
732 default:
733 LOG_ECMA(FATAL) << "this branch is unreachable";
734 UNREACHABLE();
735 }
736 }
737
LowerCowArrayCheck(GateRef gate,GateRef glue)738 void TypeMCRLowering::LowerCowArrayCheck(GateRef gate, GateRef glue)
739 {
740 Environment env(gate, circuit_, &builder_);
741 GateRef receiver = acc_.GetValueIn(gate, 0);
742 Label notCOWArray(&builder_);
743 Label isCOWArray(&builder_);
744 builder_.Branch(builder_.IsJsCOWArray(receiver), &isCOWArray, ¬COWArray);
745 builder_.Bind(&isCOWArray);
746 {
747 LowerCallRuntime(glue, gate, RTSTUB_ID(CheckAndCopyArray), {receiver}, true);
748 builder_.Jump(¬COWArray);
749 }
750 builder_.Bind(¬COWArray);
751
752 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
753 }
754
755 // for JSArray
LowerArrayLoadElement(GateRef gate,ArrayState arrayState)756 void TypeMCRLowering::LowerArrayLoadElement(GateRef gate, ArrayState arrayState)
757 {
758 Environment env(gate, circuit_, &builder_);
759 GateRef receiver = acc_.GetValueIn(gate, 0);
760 GateRef index = acc_.GetValueIn(gate, 1);
761 GateRef element = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, JSObject::ELEMENTS_OFFSET);
762 GateRef result = builder_.GetValueFromTaggedArray(element, index);
763 if (arrayState == ArrayState::HOLEY) {
764 result = builder_.ConvertHoleAsUndefined(result);
765 }
766 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
767 }
768
LowerTypedArrayLoadElement(GateRef gate,BuiltinTypeId id)769 void TypeMCRLowering::LowerTypedArrayLoadElement(GateRef gate, BuiltinTypeId id)
770 {
771 Environment env(gate, circuit_, &builder_);
772 GateRef receiver = acc_.GetValueIn(gate, 0);
773 GateRef arrbuffer =
774 builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET);
775 GateRef index = acc_.GetValueIn(gate, 1);
776 GateRef elementSize = GetElementSize(id);
777 GateRef offset = builder_.PtrMul(index, elementSize);
778
779 GateRef data = builder_.PtrAdd(arrbuffer, builder_.IntPtr(ByteArray::DATA_OFFSET));
780 auto type = GetVariableType(id);
781 GateRef result = builder_.Load(type, data, offset);
782 switch (id) {
783 case BuiltinTypeId::INT8_ARRAY:
784 result = builder_.SExtInt8ToInt32(result);
785 break;
786 case BuiltinTypeId::UINT8_ARRAY:
787 case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
788 result = builder_.ZExtInt8ToInt32(result);
789 break;
790 case BuiltinTypeId::INT16_ARRAY:
791 result = builder_.SExtInt16ToInt32(result);
792 break;
793 case BuiltinTypeId::UINT16_ARRAY:
794 result = builder_.ZExtInt16ToInt32(result);
795 break;
796 case BuiltinTypeId::FLOAT32_ARRAY:
797 result = builder_.ExtFloat32ToDouble(result);
798 break;
799 default:
800 break;
801 }
802 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
803 }
804
LowerStoreElement(GateRef gate,GateRef glue)805 void TypeMCRLowering::LowerStoreElement(GateRef gate, GateRef glue)
806 {
807 Environment env(gate, circuit_, &builder_);
808 auto op = acc_.GetTypedStoreOp(gate);
809 switch (op) {
810 case TypedStoreOp::ARRAY_STORE_ELEMENT:
811 LowerArrayStoreElement(gate, glue);
812 break;
813 case TypedStoreOp::INT8ARRAY_STORE_ELEMENT:
814 LowerTypedArrayStoreElement(gate, BuiltinTypeId::INT8_ARRAY);
815 break;
816 case TypedStoreOp::UINT8ARRAY_STORE_ELEMENT:
817 LowerTypedArrayStoreElement(gate, BuiltinTypeId::UINT8_ARRAY);
818 break;
819 case TypedStoreOp::UINT8CLAMPEDARRAY_STORE_ELEMENT:
820 LowerUInt8ClampedArrayStoreElement(gate);
821 break;
822 case TypedStoreOp::INT16ARRAY_STORE_ELEMENT:
823 LowerTypedArrayStoreElement(gate, BuiltinTypeId::INT16_ARRAY);
824 break;
825 case TypedStoreOp::UINT16ARRAY_STORE_ELEMENT:
826 LowerTypedArrayStoreElement(gate, BuiltinTypeId::UINT16_ARRAY);
827 break;
828 case TypedStoreOp::INT32ARRAY_STORE_ELEMENT:
829 LowerTypedArrayStoreElement(gate, BuiltinTypeId::INT32_ARRAY);
830 break;
831 case TypedStoreOp::UINT32ARRAY_STORE_ELEMENT:
832 LowerTypedArrayStoreElement(gate, BuiltinTypeId::UINT32_ARRAY);
833 break;
834 case TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT:
835 LowerTypedArrayStoreElement(gate, BuiltinTypeId::FLOAT32_ARRAY);
836 break;
837 case TypedStoreOp::FLOAT64ARRAY_STORE_ELEMENT:
838 LowerTypedArrayStoreElement(gate, BuiltinTypeId::FLOAT64_ARRAY);
839 break;
840 default:
841 LOG_ECMA(FATAL) << "this branch is unreachable";
842 UNREACHABLE();
843 }
844 }
845
846 // for JSArray
LowerArrayStoreElement(GateRef gate,GateRef glue)847 void TypeMCRLowering::LowerArrayStoreElement(GateRef gate, GateRef glue)
848 {
849 Environment env(gate, circuit_, &builder_);
850 GateRef receiver = acc_.GetValueIn(gate, 0); // 0: receiver
851 GateRef index = acc_.GetValueIn(gate, 1); // 1: index
852 GateRef value = acc_.GetValueIn(gate, 2); // 2: value
853
854 GateRef element = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, JSObject::ELEMENTS_OFFSET);
855 builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue, element, index, value);
856
857 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
858 }
859
860 // for JSTypedArray
LowerTypedArrayStoreElement(GateRef gate,BuiltinTypeId id)861 void TypeMCRLowering::LowerTypedArrayStoreElement(GateRef gate, BuiltinTypeId id)
862 {
863 Environment env(gate, circuit_, &builder_);
864 GateRef receiver = acc_.GetValueIn(gate, 0);
865 GateRef index = acc_.GetValueIn(gate, 1);
866 GateRef value = acc_.GetValueIn(gate, 2);
867
868 GateRef elementSize = GetElementSize(id);
869 GateRef offset = builder_.PtrMul(index, elementSize);
870 switch (id) {
871 case BuiltinTypeId::INT8_ARRAY:
872 case BuiltinTypeId::UINT8_ARRAY:
873 value = builder_.TruncInt32ToInt8(value);
874 break;
875 case BuiltinTypeId::INT16_ARRAY:
876 case BuiltinTypeId::UINT16_ARRAY:
877 value = builder_.TruncInt32ToInt16(value);
878 break;
879 case BuiltinTypeId::FLOAT32_ARRAY:
880 value = builder_.TruncDoubleToFloat32(value);
881 break;
882 default:
883 break;
884 }
885 GateRef arrbuffer = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver,
886 JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET);
887 GateRef data = builder_.PtrAdd(arrbuffer, builder_.IntPtr(ByteArray::DATA_OFFSET));
888
889 builder_.StoreMemory(MemoryType::ELEMENT_TYPE, VariableType::VOID(), data, offset, value);
890 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
891 }
892
893 // for UInt8ClampedArray
LowerUInt8ClampedArrayStoreElement(GateRef gate)894 void TypeMCRLowering::LowerUInt8ClampedArrayStoreElement(GateRef gate)
895 {
896 Environment env(gate, circuit_, &builder_);
897
898 GateRef receiver = acc_.GetValueIn(gate, 0);
899 GateRef index = acc_.GetValueIn(gate, 1);
900 GateRef elementSize = builder_.Int32(sizeof(uint8_t));
901 GateRef offset = builder_.PtrMul(index, elementSize);
902 GateRef value = acc_.GetValueIn(gate, 2);
903
904 DEFVAlUE(result, (&builder_), VariableType::INT32(), value);
905 GateRef topValue = builder_.Int32(static_cast<uint32_t>(UINT8_MAX));
906 GateRef bottomValue = builder_.Int32(static_cast<uint32_t>(0));
907 Label isOverFlow(&builder_);
908 Label notOverFlow(&builder_);
909 Label exit(&builder_);
910 builder_.Branch(builder_.Int32GreaterThan(value, topValue), &isOverFlow, ¬OverFlow);
911 builder_.Bind(&isOverFlow);
912 {
913 result = topValue;
914 builder_.Jump(&exit);
915 }
916 builder_.Bind(¬OverFlow);
917 {
918 Label isUnderSpill(&builder_);
919 builder_.Branch(builder_.Int32LessThan(value, bottomValue), &isUnderSpill, &exit);
920 builder_.Bind(&isUnderSpill);
921 {
922 result = bottomValue;
923 builder_.Jump(&exit);
924 }
925 }
926 builder_.Bind(&exit);
927 value = builder_.TruncInt32ToInt8(*result);
928
929 GateRef arrbuffer = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver,
930 JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET);
931
932 GateRef data = builder_.PtrAdd(arrbuffer, builder_.IntPtr(ByteArray::DATA_OFFSET));
933
934 builder_.StoreMemory(MemoryType::ELEMENT_TYPE, VariableType::VOID(), data, offset, value);
935 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
936 }
937
DoubleToTaggedDoublePtr(GateRef gate)938 GateRef TypeMCRLowering::DoubleToTaggedDoublePtr(GateRef gate)
939 {
940 return builder_.DoubleToTaggedDoublePtr(gate);
941 }
942
ChangeInt32ToFloat64(GateRef gate)943 GateRef TypeMCRLowering::ChangeInt32ToFloat64(GateRef gate)
944 {
945 return builder_.ChangeInt32ToFloat64(gate);
946 }
947
TruncDoubleToInt(GateRef gate)948 GateRef TypeMCRLowering::TruncDoubleToInt(GateRef gate)
949 {
950 return builder_.TruncInt64ToInt32(builder_.TruncFloatToInt64(gate));
951 }
952
IntToTaggedIntPtr(GateRef x)953 GateRef TypeMCRLowering::IntToTaggedIntPtr(GateRef x)
954 {
955 GateRef val = builder_.SExtInt32ToInt64(x);
956 return builder_.ToTaggedIntPtr(val);
957 }
958
LowerTypedCallBuitin(GateRef gate)959 void TypeMCRLowering::LowerTypedCallBuitin(GateRef gate)
960 {
961 BuiltinLowering lowering(circuit_);
962 lowering.LowerTypedCallBuitin(gate);
963 }
964
LowerJSCallTargetFromDefineFuncCheck(GateRef gate)965 void TypeMCRLowering::LowerJSCallTargetFromDefineFuncCheck(GateRef gate)
966 {
967 Environment env(gate, circuit_, &builder_);
968 auto type = acc_.GetParamGateType(gate);
969 if (tsManager_->IsFunctionTypeKind(type)) {
970 GateRef frameState = GetFrameState(gate);
971 auto func = acc_.GetValueIn(gate, 0);
972 GateRef check = builder_.IsOptimized(func);
973 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT);
974 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
975 } else {
976 LOG_COMPILER(FATAL) << "this branch is unreachable";
977 UNREACHABLE();
978 }
979 }
980
LowerJSCallTargetTypeCheck(GateRef gate)981 void TypeMCRLowering::LowerJSCallTargetTypeCheck(GateRef gate)
982 {
983 Environment env(gate, circuit_, &builder_);
984 auto type = acc_.GetParamGateType(gate);
985 if (tsManager_->IsFunctionTypeKind(type)) {
986 ArgumentAccessor argAcc(circuit_);
987 GateRef frameState = GetFrameState(gate);
988 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
989 auto func = acc_.GetValueIn(gate, 0);
990 auto methodIndex = acc_.GetValueIn(gate, 1);
991 GateRef isObj = builder_.TaggedIsHeapObject(func);
992 GateRef isOptimized = builder_.IsOptimized(func);
993 GateRef funcMethodTarget = builder_.GetMethodFromFunction(func);
994 GateRef checkFunc = builder_.BoolAnd(isObj, isOptimized);
995 GateRef methodTarget = GetObjectFromConstPool(jsFunc, methodIndex);
996 GateRef check = builder_.BoolAnd(checkFunc, builder_.Equal(funcMethodTarget, methodTarget));
997 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT);
998 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
999 } else {
1000 LOG_COMPILER(FATAL) << "this branch is unreachable";
1001 UNREACHABLE();
1002 }
1003 }
1004
LowerJSFastCallTargetTypeCheck(GateRef gate)1005 void TypeMCRLowering::LowerJSFastCallTargetTypeCheck(GateRef gate)
1006 {
1007 Environment env(gate, circuit_, &builder_);
1008 auto type = acc_.GetParamGateType(gate);
1009 if (tsManager_->IsFunctionTypeKind(type)) {
1010 ArgumentAccessor argAcc(circuit_);
1011 GateRef frameState = GetFrameState(gate);
1012 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
1013 auto func = acc_.GetValueIn(gate, 0);
1014 auto methodIndex = acc_.GetValueIn(gate, 1);
1015 GateRef isObj = builder_.TaggedIsHeapObject(func);
1016 GateRef canFastCall = builder_.CanFastCall(func);
1017 GateRef funcMethodTarget = builder_.GetMethodFromFunction(func);
1018 GateRef checkFunc = builder_.BoolAnd(isObj, canFastCall);
1019 GateRef methodTarget = GetObjectFromConstPool(jsFunc, methodIndex);
1020 GateRef check = builder_.BoolAnd(checkFunc, builder_.Equal(funcMethodTarget, methodTarget));
1021 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT);
1022 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1023 } else {
1024 LOG_COMPILER(FATAL) << "this branch is unreachable";
1025 UNREACHABLE();
1026 }
1027 }
1028
LowerJSCallThisTargetTypeCheck(GateRef gate)1029 void TypeMCRLowering::LowerJSCallThisTargetTypeCheck(GateRef gate)
1030 {
1031 Environment env(gate, circuit_, &builder_);
1032 auto type = acc_.GetParamGateType(gate);
1033 if (tsManager_->IsFunctionTypeKind(type)) {
1034 GateRef frameState = GetFrameState(gate);
1035 auto func = acc_.GetValueIn(gate, 0);
1036 GateRef isObj = builder_.TaggedIsHeapObject(func);
1037 GateRef isOptimized = builder_.IsOptimizedAndNotFastCall(func);
1038 GateRef check = builder_.BoolAnd(isObj, isOptimized);
1039 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT);
1040 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1041 } else {
1042 LOG_COMPILER(FATAL) << "this branch is unreachable";
1043 UNREACHABLE();
1044 }
1045 }
1046
LowerJSNoGCCallThisTargetTypeCheck(GateRef gate)1047 void TypeMCRLowering::LowerJSNoGCCallThisTargetTypeCheck(GateRef gate)
1048 {
1049 Environment env(gate, circuit_, &builder_);
1050 auto type = acc_.GetParamGateType(gate);
1051 if (tsManager_->IsFunctionTypeKind(type)) {
1052 GateRef frameState = GetFrameState(gate);
1053 auto func = acc_.GetValueIn(gate, 0);
1054 GateRef isObj = builder_.TaggedIsHeapObject(func);
1055 GateRef isOptimized = builder_.IsOptimizedAndNotFastCall(func);
1056 GateRef methodId = builder_.GetMethodId(func);
1057 GateRef checkOptimized = builder_.BoolAnd(isObj, isOptimized);
1058 GateRef check = builder_.BoolAnd(checkOptimized, builder_.Equal(methodId, acc_.GetValueIn(gate, 1)));
1059 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT);
1060 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1061 } else {
1062 LOG_COMPILER(FATAL) << "this branch is unreachable";
1063 UNREACHABLE();
1064 }
1065 }
1066
LowerJSFastCallThisTargetTypeCheck(GateRef gate)1067 void TypeMCRLowering::LowerJSFastCallThisTargetTypeCheck(GateRef gate)
1068 {
1069 Environment env(gate, circuit_, &builder_);
1070 auto type = acc_.GetParamGateType(gate);
1071 if (tsManager_->IsFunctionTypeKind(type)) {
1072 GateRef frameState = GetFrameState(gate);
1073 auto func = acc_.GetValueIn(gate, 0);
1074 GateRef isObj = builder_.TaggedIsHeapObject(func);
1075 GateRef canFastCall = builder_.CanFastCall(func);
1076 GateRef check = builder_.BoolAnd(isObj, canFastCall);
1077 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT);
1078 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1079 } else {
1080 LOG_COMPILER(FATAL) << "this branch is unreachable";
1081 UNREACHABLE();
1082 }
1083 }
1084
LowerJSNoGCFastCallThisTargetTypeCheck(GateRef gate)1085 void TypeMCRLowering::LowerJSNoGCFastCallThisTargetTypeCheck(GateRef gate)
1086 {
1087 Environment env(gate, circuit_, &builder_);
1088 auto type = acc_.GetParamGateType(gate);
1089 if (tsManager_->IsFunctionTypeKind(type)) {
1090 GateRef frameState = GetFrameState(gate);
1091 auto func = acc_.GetValueIn(gate, 0);
1092 GateRef isObj = builder_.TaggedIsHeapObject(func);
1093 GateRef canFastCall = builder_.CanFastCall(func);
1094 GateRef methodId = builder_.GetMethodId(func);
1095 GateRef checkOptimized = builder_.BoolAnd(isObj, canFastCall);
1096 GateRef check = builder_.BoolAnd(checkOptimized, builder_.Equal(methodId, acc_.GetValueIn(gate, 1)));
1097 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT);
1098 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1099 } else {
1100 LOG_COMPILER(FATAL) << "this branch is unreachable";
1101 UNREACHABLE();
1102 }
1103 }
1104
LowerCallTargetCheck(GateRef gate)1105 void TypeMCRLowering::LowerCallTargetCheck(GateRef gate)
1106 {
1107 Environment env(gate, circuit_, &builder_);
1108 GateRef frameState = GetFrameState(gate);
1109
1110 BuiltinLowering lowering(circuit_);
1111 GateRef funcheck = lowering.LowerCallTargetCheck(&env, gate);
1112 GateRef check = lowering.CheckPara(gate, funcheck);
1113 builder_.DeoptCheck(check, frameState, DeoptType::NOTCALLTGT);
1114
1115 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1116 }
1117
LowerJSInlineTargetTypeCheck(GateRef gate)1118 void TypeMCRLowering::LowerJSInlineTargetTypeCheck(GateRef gate)
1119 {
1120 Environment env(gate, circuit_, &builder_);
1121 GateRef frameState = GetFrameState(gate);
1122 auto func = acc_.GetValueIn(gate, 0);
1123 GateRef isObj = builder_.TaggedIsHeapObject(func);
1124 GateRef isJsFunc = builder_.IsJSFunction(func);
1125 GateRef checkFunc = builder_.BoolAnd(isObj, isJsFunc);
1126 GateRef GetMethodId = builder_.GetMethodId(func);
1127 GateRef check = builder_.BoolAnd(checkFunc, builder_.Equal(GetMethodId, acc_.GetValueIn(gate, 1)));
1128 builder_.DeoptCheck(check, frameState, DeoptType::INLINEFAIL);
1129 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1130 }
1131
LowerTypedNewAllocateThis(GateRef gate,GateRef glue)1132 void TypeMCRLowering::LowerTypedNewAllocateThis(GateRef gate, GateRef glue)
1133 {
1134 Environment env(gate, circuit_, &builder_);
1135 ArgumentAccessor argAcc(circuit_);
1136 GateRef frameState = GetFrameState(gate);
1137 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
1138
1139 GateRef ctor = acc_.GetValueIn(gate, 0);
1140
1141 DEFVAlUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1142 Label allocate(&builder_);
1143 Label exit(&builder_);
1144
1145 GateRef isBase = builder_.IsBase(ctor);
1146 builder_.Branch(isBase, &allocate, &exit);
1147 builder_.Bind(&allocate);
1148 {
1149 // add typecheck to detect protoOrHclass is equal with ihclass,
1150 // if pass typecheck: 1.no need to check whether hclass is valid 2.no need to check return result
1151 GateRef protoOrHclass = builder_.LoadConstOffset(VariableType::JS_ANY(), ctor,
1152 JSFunction::PROTO_OR_DYNCLASS_OFFSET);
1153 GateRef ihclassIndex = acc_.GetValueIn(gate, 1);
1154 GateRef ihclass = GetObjectFromConstPool(jsFunc, ihclassIndex);
1155 GateRef check = builder_.Equal(protoOrHclass, ihclass);
1156 builder_.DeoptCheck(check, frameState, DeoptType::NOTNEWOBJ);
1157
1158 thisObj = builder_.CallStub(glue, gate, CommonStubCSigns::NewJSObject, { glue, protoOrHclass });
1159 builder_.Jump(&exit);
1160 }
1161 builder_.Bind(&exit);
1162 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *thisObj);
1163 }
1164
LowerTypedSuperAllocateThis(GateRef gate,GateRef glue)1165 void TypeMCRLowering::LowerTypedSuperAllocateThis(GateRef gate, GateRef glue)
1166 {
1167 Environment env(gate, circuit_, &builder_);
1168 GateRef superCtor = acc_.GetValueIn(gate, 0);
1169 GateRef newTarget = acc_.GetValueIn(gate, 1);
1170
1171 DEFVAlUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1172 Label allocate(&builder_);
1173 Label exit(&builder_);
1174
1175 GateRef isBase = builder_.IsBase(superCtor);
1176 builder_.Branch(isBase, &allocate, &exit);
1177 builder_.Bind(&allocate);
1178 {
1179 GateRef protoOrHclass = builder_.LoadConstOffset(VariableType::JS_ANY(), newTarget,
1180 JSFunction::PROTO_OR_DYNCLASS_OFFSET);
1181 GateRef check = builder_.IsJSHClass(protoOrHclass);
1182 GateRef frameState = GetFrameState(gate);
1183 builder_.DeoptCheck(check, frameState, DeoptType::NOTNEWOBJ);
1184
1185 thisObj = builder_.CallStub(glue, gate, CommonStubCSigns::NewJSObject, { glue, protoOrHclass });
1186 builder_.Jump(&exit);
1187 }
1188 builder_.Bind(&exit);
1189 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *thisObj);
1190 }
1191
LowerGetSuperConstructor(GateRef gate)1192 void TypeMCRLowering::LowerGetSuperConstructor(GateRef gate)
1193 {
1194 Environment env(gate, circuit_, &builder_);
1195 GateRef ctor = acc_.GetValueIn(gate, 0);
1196 GateRef hclass = builder_.LoadHClass(ctor);
1197 GateRef superCtor = builder_.LoadConstOffset(VariableType::JS_ANY(), hclass, JSHClass::PROTOTYPE_OFFSET);
1198 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), superCtor);
1199 }
1200
LoadFromVTable(GateRef receiver,size_t index)1201 GateRef TypeMCRLowering::LoadFromVTable(GateRef receiver, size_t index)
1202 {
1203 GateRef hclass = builder_.LoadConstOffset(
1204 VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
1205 GateRef vtable = builder_.LoadConstOffset(VariableType::JS_ANY(),
1206 hclass, JSHClass::VTABLE_OFFSET);
1207
1208 GateRef itemOwner = builder_.LoadFromTaggedArray(vtable, VTable::TupleItem::OWNER + index);
1209 GateRef itemOffset = builder_.LoadFromTaggedArray(vtable, VTable::TupleItem::OFFSET + index);
1210 return builder_.Load(VariableType::JS_ANY(), itemOwner, builder_.TaggedGetInt(itemOffset));
1211 }
1212
GetVarType(PropertyLookupResult plr)1213 VariableType TypeMCRLowering::GetVarType(PropertyLookupResult plr)
1214 {
1215 if (plr.GetRepresentation() == Representation::DOUBLE) {
1216 return kungfu::VariableType::FLOAT64();
1217 } else if (plr.GetRepresentation() == Representation::INT) {
1218 return kungfu::VariableType::INT32();
1219 } else {
1220 return kungfu::VariableType::INT64();
1221 }
1222 }
1223
LoadSupers(GateRef hclass)1224 GateRef TypeMCRLowering::LoadSupers(GateRef hclass)
1225 {
1226 return builder_.LoadConstOffset(VariableType::JS_ANY(), hclass, JSHClass::SUPERS_OFFSET);
1227 }
1228
GetLengthFromSupers(GateRef supers)1229 GateRef TypeMCRLowering::GetLengthFromSupers(GateRef supers)
1230 {
1231 return builder_.LoadConstOffset(VariableType::INT32(), supers, TaggedArray::EXTRACT_LENGTH_OFFSET);
1232 }
1233
GetValueFromSupers(GateRef supers,size_t index)1234 GateRef TypeMCRLowering::GetValueFromSupers(GateRef supers, size_t index)
1235 {
1236 GateRef val = builder_.LoadFromTaggedArray(supers, index);
1237 return builder_.LoadObjectFromWeakRef(val);
1238 }
1239
CallAccessor(GateRef glue,GateRef gate,GateRef function,GateRef receiver,AccessorMode mode,GateRef value)1240 GateRef TypeMCRLowering::CallAccessor(GateRef glue, GateRef gate, GateRef function, GateRef receiver,
1241 AccessorMode mode, GateRef value)
1242 {
1243 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCall));
1244 GateRef target = builder_.IntPtr(RTSTUB_ID(JSCall));
1245 GateRef newTarget = builder_.Undefined();
1246 GateRef argc = builder_.Int64(NUM_MANDATORY_JSFUNC_ARGS + (mode == AccessorMode::SETTER ? 1 : 0)); // 1: value
1247 std::vector<GateRef> args { glue, argc, function, newTarget, receiver };
1248 if (mode == AccessorMode::SETTER) {
1249 args.emplace_back(value);
1250 }
1251
1252 return builder_.Call(cs, glue, target, builder_.GetDepend(), args, gate);
1253 }
1254
ReplaceHirWithPendingException(GateRef hirGate,GateRef glue,GateRef state,GateRef depend,GateRef value)1255 void TypeMCRLowering::ReplaceHirWithPendingException(GateRef hirGate, GateRef glue, GateRef state, GateRef depend,
1256 GateRef value)
1257 {
1258 auto condition = builder_.HasPendingException(glue);
1259 GateRef ifBranch = builder_.Branch(state, condition);
1260 GateRef ifTrue = builder_.IfTrue(ifBranch);
1261 GateRef ifFalse = builder_.IfFalse(ifBranch);
1262 GateRef eDepend = builder_.DependRelay(ifTrue, depend);
1263 GateRef sDepend = builder_.DependRelay(ifFalse, depend);
1264
1265 StateDepend success(ifFalse, sDepend);
1266 StateDepend exception(ifTrue, eDepend);
1267 acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
1268 }
1269
LowerLoadGetter(GateRef gate)1270 void TypeMCRLowering::LowerLoadGetter(GateRef gate)
1271 {
1272 Environment env(gate, circuit_, &builder_);
1273 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: receiver, plr
1274 GateRef receiver = acc_.GetValueIn(gate, 0);
1275 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
1276
1277 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
1278 ASSERT(plr.IsAccessor());
1279 GateRef accessor = LoadFromVTable(receiver, plr.GetOffset());
1280 GateRef getter = builder_.Load(VariableType::JS_ANY(), accessor,
1281 builder_.IntPtr(AccessorData::GETTER_OFFSET));
1282 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), getter);
1283 }
1284
LowerLoadSetter(GateRef gate)1285 void TypeMCRLowering::LowerLoadSetter(GateRef gate)
1286 {
1287 Environment env(gate, circuit_, &builder_);
1288 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: receiver, plr
1289 GateRef receiver = acc_.GetValueIn(gate, 0);
1290 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
1291
1292 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
1293 ASSERT(plr.IsAccessor());
1294 GateRef accessor = LoadFromVTable(receiver, plr.GetOffset());
1295 GateRef setter = builder_.Load(VariableType::JS_ANY(),
1296 accessor, builder_.IntPtr(AccessorData::SETTER_OFFSET));
1297 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), setter);
1298 }
1299
1300 // subtyping check and hclss check
LowerInlineAccessorCheck(GateRef gate)1301 void TypeMCRLowering::LowerInlineAccessorCheck(GateRef gate)
1302 {
1303 Environment env(gate, circuit_, &builder_);
1304 GateRef receiver = acc_.GetValueIn(gate, 0);
1305 GateRef frameState = acc_.GetFrameState(gate);
1306 builder_.HeapObjectCheck(receiver, frameState);
1307
1308 GateRef aotHCIndex = acc_.GetValueIn(gate, 1);
1309 ArgumentAccessor argAcc(circuit_);
1310 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
1311 JSTaggedValue aotHC = tsManager_->GetValueFromCache(acc_.TryGetValue(aotHCIndex));
1312 ASSERT(aotHC.IsJSHClass());
1313
1314 int32_t level = JSHClass::Cast(aotHC.GetTaggedObject())->GetLevel();
1315 ASSERT(level >= 0);
1316
1317 GateRef receiverHClass = builder_.LoadConstOffset(
1318 VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
1319 GateRef supers = LoadSupers(receiverHClass);
1320
1321 auto hclassIndex = acc_.GetConstantValue(aotHCIndex);
1322 GateRef aotHCGate = LoadFromConstPool(jsFunc, hclassIndex);
1323 GateRef hclassCompare = builder_.Equal(aotHCGate, receiverHClass);
1324 if (LIKELY(static_cast<uint32_t>(level) < SubtypingOperator::DEFAULT_SUPERS_CAPACITY)) {
1325 GateRef subtypingCompare = builder_.Equal(aotHCGate, GetValueFromSupers(supers, level));
1326 GateRef compare = builder_.BoolAnd(hclassCompare, subtypingCompare);
1327 builder_.DeoptCheck(compare, frameState, DeoptType::INCONSISTENTHCLASS);
1328 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1329 return;
1330 }
1331
1332 Label levelValid(&builder_);
1333 Label exit(&builder_);
1334 DEFVAlUE(check, (&builder_), VariableType::BOOL(), builder_.False());
1335 GateRef levelGate = builder_.Int32(level);
1336 GateRef length = GetLengthFromSupers(supers);
1337
1338 builder_.Branch(builder_.Int32LessThan(levelGate, length), &levelValid, &exit);
1339 builder_.Bind(&levelValid);
1340 {
1341 check = builder_.Equal(aotHCGate, GetValueFromSupers(supers, level));
1342 builder_.Jump(&exit);
1343 }
1344 builder_.Bind(&exit);
1345
1346 GateRef compare = builder_.BoolAnd(hclassCompare, *check);
1347 builder_.DeoptCheck(compare, frameState, DeoptType::INCONSISTENTHCLASS);
1348 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1349 }
1350 } // namespace panda::ecmascript::kungfu
1351