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 Environment env(gate, circuit_, &builder_);
740 GateRef receiver = acc_.GetValueIn(gate, 0);
741 Label notCOWArray(&builder_);
742 Label isCOWArray(&builder_);
743 builder_.Branch(builder_.IsJsCOWArray(receiver), &isCOWArray, ¬COWArray);
744 builder_.Bind(&isCOWArray);
745 {
746 LowerCallRuntime(glue, gate, RTSTUB_ID(CheckAndCopyArray), {receiver}, true);
747 builder_.Jump(¬COWArray);
748 }
749 builder_.Bind(¬COWArray);
750
751 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
752 }
753
754 // for JSArray
LowerArrayLoadElement(GateRef gate,ArrayState arrayState)755 void TypeMCRLowering::LowerArrayLoadElement(GateRef gate, ArrayState arrayState)
756 {
757 Environment env(gate, circuit_, &builder_);
758 GateRef receiver = acc_.GetValueIn(gate, 0);
759 GateRef index = acc_.GetValueIn(gate, 1);
760 GateRef element = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, JSObject::ELEMENTS_OFFSET);
761 GateRef result = builder_.GetValueFromTaggedArray(element, index);
762 if (arrayState == ArrayState::HOLEY) {
763 result = builder_.ConvertHoleAsUndefined(result);
764 }
765 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
766 }
767
LowerTypedArrayLoadElement(GateRef gate,BuiltinTypeId id)768 void TypeMCRLowering::LowerTypedArrayLoadElement(GateRef gate, BuiltinTypeId id)
769 {
770 Environment env(gate, circuit_, &builder_);
771 GateRef receiver = acc_.GetValueIn(gate, 0);
772 GateRef arrbuffer =
773 builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET);
774 GateRef index = acc_.GetValueIn(gate, 1);
775 GateRef elementSize = GetElementSize(id);
776 GateRef offset = builder_.PtrMul(index, elementSize);
777
778 GateRef data = builder_.PtrAdd(arrbuffer, builder_.IntPtr(ByteArray::DATA_OFFSET));
779 auto type = GetVariableType(id);
780 GateRef result = builder_.Load(type, data, offset);
781 switch (id) {
782 case BuiltinTypeId::INT8_ARRAY:
783 result = builder_.SExtInt8ToInt32(result);
784 break;
785 case BuiltinTypeId::UINT8_ARRAY:
786 case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
787 result = builder_.ZExtInt8ToInt32(result);
788 break;
789 case BuiltinTypeId::INT16_ARRAY:
790 result = builder_.SExtInt16ToInt32(result);
791 break;
792 case BuiltinTypeId::UINT16_ARRAY:
793 result = builder_.ZExtInt16ToInt32(result);
794 break;
795 case BuiltinTypeId::FLOAT32_ARRAY:
796 result = builder_.ExtFloat32ToDouble(result);
797 break;
798 default:
799 break;
800 }
801 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
802 }
803
LowerStoreElement(GateRef gate,GateRef glue)804 void TypeMCRLowering::LowerStoreElement(GateRef gate, GateRef glue)
805 {
806 Environment env(gate, circuit_, &builder_);
807 auto op = acc_.GetTypedStoreOp(gate);
808 switch (op) {
809 case TypedStoreOp::ARRAY_STORE_ELEMENT:
810 LowerArrayStoreElement(gate, glue);
811 break;
812 case TypedStoreOp::INT8ARRAY_STORE_ELEMENT:
813 LowerTypedArrayStoreElement(gate, BuiltinTypeId::INT8_ARRAY);
814 break;
815 case TypedStoreOp::UINT8ARRAY_STORE_ELEMENT:
816 LowerTypedArrayStoreElement(gate, BuiltinTypeId::UINT8_ARRAY);
817 break;
818 case TypedStoreOp::UINT8CLAMPEDARRAY_STORE_ELEMENT:
819 LowerUInt8ClampedArrayStoreElement(gate);
820 break;
821 case TypedStoreOp::INT16ARRAY_STORE_ELEMENT:
822 LowerTypedArrayStoreElement(gate, BuiltinTypeId::INT16_ARRAY);
823 break;
824 case TypedStoreOp::UINT16ARRAY_STORE_ELEMENT:
825 LowerTypedArrayStoreElement(gate, BuiltinTypeId::UINT16_ARRAY);
826 break;
827 case TypedStoreOp::INT32ARRAY_STORE_ELEMENT:
828 LowerTypedArrayStoreElement(gate, BuiltinTypeId::INT32_ARRAY);
829 break;
830 case TypedStoreOp::UINT32ARRAY_STORE_ELEMENT:
831 LowerTypedArrayStoreElement(gate, BuiltinTypeId::UINT32_ARRAY);
832 break;
833 case TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT:
834 LowerTypedArrayStoreElement(gate, BuiltinTypeId::FLOAT32_ARRAY);
835 break;
836 case TypedStoreOp::FLOAT64ARRAY_STORE_ELEMENT:
837 LowerTypedArrayStoreElement(gate, BuiltinTypeId::FLOAT64_ARRAY);
838 break;
839 default:
840 LOG_ECMA(FATAL) << "this branch is unreachable";
841 UNREACHABLE();
842 }
843 }
844
845 // for JSArray
LowerArrayStoreElement(GateRef gate,GateRef glue)846 void TypeMCRLowering::LowerArrayStoreElement(GateRef gate, GateRef glue)
847 {
848 Environment env(gate, circuit_, &builder_);
849 GateRef receiver = acc_.GetValueIn(gate, 0); // 0: receiver
850 GateRef index = acc_.GetValueIn(gate, 1); // 1: index
851 GateRef value = acc_.GetValueIn(gate, 2); // 2: value
852
853 GateRef element = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, JSObject::ELEMENTS_OFFSET);
854 builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue, element, index, value);
855
856 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
857 }
858
859 // for JSTypedArray
LowerTypedArrayStoreElement(GateRef gate,BuiltinTypeId id)860 void TypeMCRLowering::LowerTypedArrayStoreElement(GateRef gate, BuiltinTypeId id)
861 {
862 Environment env(gate, circuit_, &builder_);
863 GateRef receiver = acc_.GetValueIn(gate, 0);
864 GateRef index = acc_.GetValueIn(gate, 1);
865 GateRef value = acc_.GetValueIn(gate, 2);
866
867 GateRef elementSize = GetElementSize(id);
868 GateRef offset = builder_.PtrMul(index, elementSize);
869 switch (id) {
870 case BuiltinTypeId::INT8_ARRAY:
871 case BuiltinTypeId::UINT8_ARRAY:
872 value = builder_.TruncInt32ToInt8(value);
873 break;
874 case BuiltinTypeId::INT16_ARRAY:
875 case BuiltinTypeId::UINT16_ARRAY:
876 value = builder_.TruncInt32ToInt16(value);
877 break;
878 case BuiltinTypeId::FLOAT32_ARRAY:
879 value = builder_.TruncDoubleToFloat32(value);
880 break;
881 default:
882 break;
883 }
884 GateRef arrbuffer = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver,
885 JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET);
886 GateRef data = builder_.PtrAdd(arrbuffer, builder_.IntPtr(ByteArray::DATA_OFFSET));
887
888 builder_.StoreMemory(MemoryType::ELEMENT_TYPE, VariableType::VOID(), data, offset, value);
889 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
890 }
891
892 // for UInt8ClampedArray
LowerUInt8ClampedArrayStoreElement(GateRef gate)893 void TypeMCRLowering::LowerUInt8ClampedArrayStoreElement(GateRef gate)
894 {
895 Environment env(gate, circuit_, &builder_);
896
897 GateRef receiver = acc_.GetValueIn(gate, 0);
898 GateRef index = acc_.GetValueIn(gate, 1);
899 GateRef elementSize = builder_.Int32(sizeof(uint8_t));
900 GateRef offset = builder_.PtrMul(index, elementSize);
901 GateRef value = acc_.GetValueIn(gate, 2);
902
903 DEFVAlUE(result, (&builder_), VariableType::INT32(), value);
904 GateRef topValue = builder_.Int32(static_cast<uint32_t>(UINT8_MAX));
905 GateRef bottomValue = builder_.Int32(static_cast<uint32_t>(0));
906 Label isOverFlow(&builder_);
907 Label notOverFlow(&builder_);
908 Label exit(&builder_);
909 builder_.Branch(builder_.Int32GreaterThan(value, topValue), &isOverFlow, ¬OverFlow);
910 builder_.Bind(&isOverFlow);
911 {
912 result = topValue;
913 builder_.Jump(&exit);
914 }
915 builder_.Bind(¬OverFlow);
916 {
917 Label isUnderSpill(&builder_);
918 builder_.Branch(builder_.Int32LessThan(value, bottomValue), &isUnderSpill, &exit);
919 builder_.Bind(&isUnderSpill);
920 {
921 result = bottomValue;
922 builder_.Jump(&exit);
923 }
924 }
925 builder_.Bind(&exit);
926 value = builder_.TruncInt32ToInt8(*result);
927
928 GateRef arrbuffer = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver,
929 JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET);
930
931 GateRef data = builder_.PtrAdd(arrbuffer, builder_.IntPtr(ByteArray::DATA_OFFSET));
932
933 builder_.StoreMemory(MemoryType::ELEMENT_TYPE, VariableType::VOID(), data, offset, value);
934 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
935 }
936
DoubleToTaggedDoublePtr(GateRef gate)937 GateRef TypeMCRLowering::DoubleToTaggedDoublePtr(GateRef gate)
938 {
939 return builder_.DoubleToTaggedDoublePtr(gate);
940 }
941
ChangeInt32ToFloat64(GateRef gate)942 GateRef TypeMCRLowering::ChangeInt32ToFloat64(GateRef gate)
943 {
944 return builder_.ChangeInt32ToFloat64(gate);
945 }
946
TruncDoubleToInt(GateRef gate)947 GateRef TypeMCRLowering::TruncDoubleToInt(GateRef gate)
948 {
949 return builder_.TruncInt64ToInt32(builder_.TruncFloatToInt64(gate));
950 }
951
IntToTaggedIntPtr(GateRef x)952 GateRef TypeMCRLowering::IntToTaggedIntPtr(GateRef x)
953 {
954 GateRef val = builder_.SExtInt32ToInt64(x);
955 return builder_.ToTaggedIntPtr(val);
956 }
957
LowerTypedCallBuitin(GateRef gate)958 void TypeMCRLowering::LowerTypedCallBuitin(GateRef gate)
959 {
960 BuiltinLowering lowering(circuit_);
961 lowering.LowerTypedCallBuitin(gate);
962 }
963
LowerJSCallTargetFromDefineFuncCheck(GateRef gate)964 void TypeMCRLowering::LowerJSCallTargetFromDefineFuncCheck(GateRef gate)
965 {
966 Environment env(gate, circuit_, &builder_);
967 auto type = acc_.GetParamGateType(gate);
968 if (tsManager_->IsFunctionTypeKind(type)) {
969 GateRef frameState = GetFrameState(gate);
970 auto func = acc_.GetValueIn(gate, 0);
971 GateRef check = builder_.IsOptimized(func);
972 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT);
973 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
974 } else {
975 LOG_COMPILER(FATAL) << "this branch is unreachable";
976 UNREACHABLE();
977 }
978 }
979
LowerJSCallTargetTypeCheck(GateRef gate)980 void TypeMCRLowering::LowerJSCallTargetTypeCheck(GateRef gate)
981 {
982 Environment env(gate, circuit_, &builder_);
983 auto type = acc_.GetParamGateType(gate);
984 if (tsManager_->IsFunctionTypeKind(type)) {
985 ArgumentAccessor argAcc(circuit_);
986 GateRef frameState = GetFrameState(gate);
987 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
988 auto func = acc_.GetValueIn(gate, 0);
989 auto methodIndex = acc_.GetValueIn(gate, 1);
990 GateRef isObj = builder_.TaggedIsHeapObject(func);
991 GateRef isOptimized = builder_.IsOptimized(func);
992 GateRef funcMethodTarget = builder_.GetMethodFromFunction(func);
993 GateRef checkFunc = builder_.BoolAnd(isObj, isOptimized);
994 GateRef methodTarget = GetObjectFromConstPool(jsFunc, methodIndex);
995 GateRef check = builder_.BoolAnd(checkFunc, builder_.Equal(funcMethodTarget, methodTarget));
996 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT);
997 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
998 } else {
999 LOG_COMPILER(FATAL) << "this branch is unreachable";
1000 UNREACHABLE();
1001 }
1002 }
1003
LowerJSFastCallTargetTypeCheck(GateRef gate)1004 void TypeMCRLowering::LowerJSFastCallTargetTypeCheck(GateRef gate)
1005 {
1006 Environment env(gate, circuit_, &builder_);
1007 auto type = acc_.GetParamGateType(gate);
1008 if (tsManager_->IsFunctionTypeKind(type)) {
1009 ArgumentAccessor argAcc(circuit_);
1010 GateRef frameState = GetFrameState(gate);
1011 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
1012 auto func = acc_.GetValueIn(gate, 0);
1013 auto methodIndex = acc_.GetValueIn(gate, 1);
1014 GateRef isObj = builder_.TaggedIsHeapObject(func);
1015 GateRef canFastCall = builder_.CanFastCall(func);
1016 GateRef funcMethodTarget = builder_.GetMethodFromFunction(func);
1017 GateRef checkFunc = builder_.BoolAnd(isObj, canFastCall);
1018 GateRef methodTarget = GetObjectFromConstPool(jsFunc, methodIndex);
1019 GateRef check = builder_.BoolAnd(checkFunc, builder_.Equal(funcMethodTarget, methodTarget));
1020 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT);
1021 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1022 } else {
1023 LOG_COMPILER(FATAL) << "this branch is unreachable";
1024 UNREACHABLE();
1025 }
1026 }
1027
LowerJSCallThisTargetTypeCheck(GateRef gate)1028 void TypeMCRLowering::LowerJSCallThisTargetTypeCheck(GateRef gate)
1029 {
1030 Environment env(gate, circuit_, &builder_);
1031 auto type = acc_.GetParamGateType(gate);
1032 if (tsManager_->IsFunctionTypeKind(type)) {
1033 GateRef frameState = GetFrameState(gate);
1034 auto func = acc_.GetValueIn(gate, 0);
1035 GateRef isObj = builder_.TaggedIsHeapObject(func);
1036 GateRef isOptimized = builder_.IsOptimizedAndNotFastCall(func);
1037 GateRef check = builder_.BoolAnd(isObj, isOptimized);
1038 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT);
1039 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1040 } else {
1041 LOG_COMPILER(FATAL) << "this branch is unreachable";
1042 UNREACHABLE();
1043 }
1044 }
1045
LowerJSNoGCCallThisTargetTypeCheck(GateRef gate)1046 void TypeMCRLowering::LowerJSNoGCCallThisTargetTypeCheck(GateRef gate)
1047 {
1048 Environment env(gate, circuit_, &builder_);
1049 auto type = acc_.GetParamGateType(gate);
1050 if (tsManager_->IsFunctionTypeKind(type)) {
1051 GateRef frameState = GetFrameState(gate);
1052 auto func = acc_.GetValueIn(gate, 0);
1053 GateRef isObj = builder_.TaggedIsHeapObject(func);
1054 GateRef isOptimized = builder_.IsOptimizedAndNotFastCall(func);
1055 GateRef methodId = builder_.GetMethodId(func);
1056 GateRef checkOptimized = builder_.BoolAnd(isObj, isOptimized);
1057 GateRef check = builder_.BoolAnd(checkOptimized, builder_.Equal(methodId, acc_.GetValueIn(gate, 1)));
1058 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT);
1059 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1060 } else {
1061 LOG_COMPILER(FATAL) << "this branch is unreachable";
1062 UNREACHABLE();
1063 }
1064 }
1065
LowerJSFastCallThisTargetTypeCheck(GateRef gate)1066 void TypeMCRLowering::LowerJSFastCallThisTargetTypeCheck(GateRef gate)
1067 {
1068 Environment env(gate, circuit_, &builder_);
1069 auto type = acc_.GetParamGateType(gate);
1070 if (tsManager_->IsFunctionTypeKind(type)) {
1071 GateRef frameState = GetFrameState(gate);
1072 auto func = acc_.GetValueIn(gate, 0);
1073 GateRef isObj = builder_.TaggedIsHeapObject(func);
1074 GateRef canFastCall = builder_.CanFastCall(func);
1075 GateRef check = builder_.BoolAnd(isObj, canFastCall);
1076 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT);
1077 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1078 } else {
1079 LOG_COMPILER(FATAL) << "this branch is unreachable";
1080 UNREACHABLE();
1081 }
1082 }
1083
LowerJSNoGCFastCallThisTargetTypeCheck(GateRef gate)1084 void TypeMCRLowering::LowerJSNoGCFastCallThisTargetTypeCheck(GateRef gate)
1085 {
1086 Environment env(gate, circuit_, &builder_);
1087 auto type = acc_.GetParamGateType(gate);
1088 if (tsManager_->IsFunctionTypeKind(type)) {
1089 GateRef frameState = GetFrameState(gate);
1090 auto func = acc_.GetValueIn(gate, 0);
1091 GateRef isObj = builder_.TaggedIsHeapObject(func);
1092 GateRef canFastCall = builder_.CanFastCall(func);
1093 GateRef methodId = builder_.GetMethodId(func);
1094 GateRef checkOptimized = builder_.BoolAnd(isObj, canFastCall);
1095 GateRef check = builder_.BoolAnd(checkOptimized, builder_.Equal(methodId, acc_.GetValueIn(gate, 1)));
1096 builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT);
1097 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1098 } else {
1099 LOG_COMPILER(FATAL) << "this branch is unreachable";
1100 UNREACHABLE();
1101 }
1102 }
1103
LowerCallTargetCheck(GateRef gate)1104 void TypeMCRLowering::LowerCallTargetCheck(GateRef gate)
1105 {
1106 Environment env(gate, circuit_, &builder_);
1107 GateRef frameState = GetFrameState(gate);
1108
1109 BuiltinLowering lowering(circuit_);
1110 GateRef funcheck = lowering.LowerCallTargetCheck(&env, gate);
1111 GateRef check = lowering.CheckPara(gate, funcheck);
1112 builder_.DeoptCheck(check, frameState, DeoptType::NOTCALLTGT);
1113
1114 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1115 }
1116
LowerJSInlineTargetTypeCheck(GateRef gate)1117 void TypeMCRLowering::LowerJSInlineTargetTypeCheck(GateRef gate)
1118 {
1119 Environment env(gate, circuit_, &builder_);
1120 GateRef frameState = GetFrameState(gate);
1121 auto func = acc_.GetValueIn(gate, 0);
1122 GateRef isObj = builder_.TaggedIsHeapObject(func);
1123 GateRef isJsFunc = builder_.IsJSFunction(func);
1124 GateRef checkFunc = builder_.BoolAnd(isObj, isJsFunc);
1125 GateRef GetMethodId = builder_.GetMethodId(func);
1126 GateRef check = builder_.BoolAnd(checkFunc, builder_.Equal(GetMethodId, acc_.GetValueIn(gate, 1)));
1127 builder_.DeoptCheck(check, frameState, DeoptType::INLINEFAIL);
1128 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1129 }
1130
LowerTypedNewAllocateThis(GateRef gate,GateRef glue)1131 void TypeMCRLowering::LowerTypedNewAllocateThis(GateRef gate, GateRef glue)
1132 {
1133 Environment env(gate, circuit_, &builder_);
1134 ArgumentAccessor argAcc(circuit_);
1135 GateRef frameState = GetFrameState(gate);
1136 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
1137
1138 GateRef ctor = acc_.GetValueIn(gate, 0);
1139
1140 DEFVAlUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1141 Label allocate(&builder_);
1142 Label exit(&builder_);
1143
1144 GateRef isBase = builder_.IsBase(ctor);
1145 builder_.Branch(isBase, &allocate, &exit);
1146 builder_.Bind(&allocate);
1147 {
1148 // add typecheck to detect protoOrHclass is equal with ihclass,
1149 // if pass typecheck: 1.no need to check whether hclass is valid 2.no need to check return result
1150 GateRef protoOrHclass = builder_.LoadConstOffset(VariableType::JS_ANY(), ctor,
1151 JSFunction::PROTO_OR_DYNCLASS_OFFSET);
1152 GateRef ihclassIndex = acc_.GetValueIn(gate, 1);
1153 GateRef ihclass = GetObjectFromConstPool(jsFunc, ihclassIndex);
1154 GateRef check = builder_.Equal(protoOrHclass, ihclass);
1155 builder_.DeoptCheck(check, frameState, DeoptType::NOTNEWOBJ);
1156
1157 thisObj = builder_.CallStub(glue, gate, CommonStubCSigns::NewJSObject, { glue, protoOrHclass });
1158 builder_.Jump(&exit);
1159 }
1160 builder_.Bind(&exit);
1161 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *thisObj);
1162 }
1163
LowerTypedSuperAllocateThis(GateRef gate,GateRef glue)1164 void TypeMCRLowering::LowerTypedSuperAllocateThis(GateRef gate, GateRef glue)
1165 {
1166 Environment env(gate, circuit_, &builder_);
1167 GateRef superCtor = acc_.GetValueIn(gate, 0);
1168 GateRef newTarget = acc_.GetValueIn(gate, 1);
1169
1170 DEFVAlUE(thisObj, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1171 Label allocate(&builder_);
1172 Label exit(&builder_);
1173
1174 GateRef isBase = builder_.IsBase(superCtor);
1175 builder_.Branch(isBase, &allocate, &exit);
1176 builder_.Bind(&allocate);
1177 {
1178 GateRef protoOrHclass = builder_.LoadConstOffset(VariableType::JS_ANY(), newTarget,
1179 JSFunction::PROTO_OR_DYNCLASS_OFFSET);
1180 GateRef check = builder_.IsJSHClass(protoOrHclass);
1181 GateRef frameState = GetFrameState(gate);
1182 builder_.DeoptCheck(check, frameState, DeoptType::NOTNEWOBJ);
1183
1184 thisObj = builder_.CallStub(glue, gate, CommonStubCSigns::NewJSObject, { glue, protoOrHclass });
1185 builder_.Jump(&exit);
1186 }
1187 builder_.Bind(&exit);
1188 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *thisObj);
1189 }
1190
LowerGetSuperConstructor(GateRef gate)1191 void TypeMCRLowering::LowerGetSuperConstructor(GateRef gate)
1192 {
1193 Environment env(gate, circuit_, &builder_);
1194 GateRef ctor = acc_.GetValueIn(gate, 0);
1195 GateRef hclass = builder_.LoadHClass(ctor);
1196 GateRef superCtor = builder_.LoadConstOffset(VariableType::JS_ANY(), hclass, JSHClass::PROTOTYPE_OFFSET);
1197 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), superCtor);
1198 }
1199
LoadFromVTable(GateRef receiver,size_t index)1200 GateRef TypeMCRLowering::LoadFromVTable(GateRef receiver, size_t index)
1201 {
1202 GateRef hclass = builder_.LoadConstOffset(
1203 VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
1204 GateRef vtable = builder_.LoadConstOffset(VariableType::JS_ANY(),
1205 hclass, JSHClass::VTABLE_OFFSET);
1206
1207 GateRef itemOwner = builder_.LoadFromTaggedArray(vtable, VTable::TupleItem::OWNER + index);
1208 GateRef itemOffset = builder_.LoadFromTaggedArray(vtable, VTable::TupleItem::OFFSET + index);
1209 return builder_.Load(VariableType::JS_ANY(), itemOwner, builder_.TaggedGetInt(itemOffset));
1210 }
1211
GetVarType(PropertyLookupResult plr)1212 VariableType TypeMCRLowering::GetVarType(PropertyLookupResult plr)
1213 {
1214 if (plr.GetRepresentation() == Representation::DOUBLE) {
1215 return kungfu::VariableType::FLOAT64();
1216 } else if (plr.GetRepresentation() == Representation::INT) {
1217 return kungfu::VariableType::INT32();
1218 } else {
1219 return kungfu::VariableType::INT64();
1220 }
1221 }
1222
LoadSupers(GateRef hclass)1223 GateRef TypeMCRLowering::LoadSupers(GateRef hclass)
1224 {
1225 return builder_.LoadConstOffset(VariableType::JS_ANY(), hclass, JSHClass::SUPERS_OFFSET);
1226 }
1227
GetLengthFromSupers(GateRef supers)1228 GateRef TypeMCRLowering::GetLengthFromSupers(GateRef supers)
1229 {
1230 return builder_.LoadConstOffset(VariableType::INT32(), supers, TaggedArray::EXTRACT_LENGTH_OFFSET);
1231 }
1232
GetValueFromSupers(GateRef supers,size_t index)1233 GateRef TypeMCRLowering::GetValueFromSupers(GateRef supers, size_t index)
1234 {
1235 GateRef val = builder_.LoadFromTaggedArray(supers, index);
1236 return builder_.LoadObjectFromWeakRef(val);
1237 }
1238
CallAccessor(GateRef glue,GateRef gate,GateRef function,GateRef receiver,AccessorMode mode,GateRef value)1239 GateRef TypeMCRLowering::CallAccessor(GateRef glue, GateRef gate, GateRef function, GateRef receiver,
1240 AccessorMode mode, GateRef value)
1241 {
1242 const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(JSCall));
1243 GateRef target = builder_.IntPtr(RTSTUB_ID(JSCall));
1244 GateRef newTarget = builder_.Undefined();
1245 GateRef argc = builder_.Int64(NUM_MANDATORY_JSFUNC_ARGS + (mode == AccessorMode::SETTER ? 1 : 0)); // 1: value
1246 std::vector<GateRef> args { glue, argc, function, newTarget, receiver };
1247 if (mode == AccessorMode::SETTER) {
1248 args.emplace_back(value);
1249 }
1250
1251 return builder_.Call(cs, glue, target, builder_.GetDepend(), args, gate);
1252 }
1253
ReplaceHirWithPendingException(GateRef hirGate,GateRef glue,GateRef state,GateRef depend,GateRef value)1254 void TypeMCRLowering::ReplaceHirWithPendingException(GateRef hirGate, GateRef glue, GateRef state, GateRef depend,
1255 GateRef value)
1256 {
1257 auto condition = builder_.HasPendingException(glue);
1258 GateRef ifBranch = builder_.Branch(state, condition);
1259 GateRef ifTrue = builder_.IfTrue(ifBranch);
1260 GateRef ifFalse = builder_.IfFalse(ifBranch);
1261 GateRef eDepend = builder_.DependRelay(ifTrue, depend);
1262 GateRef sDepend = builder_.DependRelay(ifFalse, depend);
1263
1264 StateDepend success(ifFalse, sDepend);
1265 StateDepend exception(ifTrue, eDepend);
1266 acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
1267 }
1268
LowerLoadGetter(GateRef gate)1269 void TypeMCRLowering::LowerLoadGetter(GateRef gate)
1270 {
1271 Environment env(gate, circuit_, &builder_);
1272 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: receiver, plr
1273 GateRef receiver = acc_.GetValueIn(gate, 0);
1274 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
1275
1276 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
1277 ASSERT(plr.IsAccessor());
1278 GateRef accessor = LoadFromVTable(receiver, plr.GetOffset());
1279 GateRef getter = builder_.Load(VariableType::JS_ANY(), accessor,
1280 builder_.IntPtr(AccessorData::GETTER_OFFSET));
1281 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), getter);
1282 }
1283
LowerLoadSetter(GateRef gate)1284 void TypeMCRLowering::LowerLoadSetter(GateRef gate)
1285 {
1286 Environment env(gate, circuit_, &builder_);
1287 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: receiver, plr
1288 GateRef receiver = acc_.GetValueIn(gate, 0);
1289 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
1290
1291 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
1292 ASSERT(plr.IsAccessor());
1293 GateRef accessor = LoadFromVTable(receiver, plr.GetOffset());
1294 GateRef setter = builder_.Load(VariableType::JS_ANY(),
1295 accessor, builder_.IntPtr(AccessorData::SETTER_OFFSET));
1296 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), setter);
1297 }
1298
1299 // subtyping check and hclss check
LowerInlineAccessorCheck(GateRef gate)1300 void TypeMCRLowering::LowerInlineAccessorCheck(GateRef gate)
1301 {
1302 Environment env(gate, circuit_, &builder_);
1303 GateRef receiver = acc_.GetValueIn(gate, 0);
1304 GateRef frameState = acc_.GetFrameState(gate);
1305 builder_.HeapObjectCheck(receiver, frameState);
1306
1307 GateRef aotHCIndex = acc_.GetValueIn(gate, 1);
1308 ArgumentAccessor argAcc(circuit_);
1309 GateRef jsFunc = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::FUNC);
1310 JSTaggedValue aotHC = tsManager_->GetValueFromCache(acc_.TryGetValue(aotHCIndex));
1311 ASSERT(aotHC.IsJSHClass());
1312
1313 int32_t level = JSHClass::Cast(aotHC.GetTaggedObject())->GetLevel();
1314 ASSERT(level >= 0);
1315
1316 GateRef receiverHClass = builder_.LoadConstOffset(
1317 VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
1318 GateRef supers = LoadSupers(receiverHClass);
1319
1320 auto hclassIndex = acc_.GetConstantValue(aotHCIndex);
1321 GateRef aotHCGate = LoadFromConstPool(jsFunc, hclassIndex);
1322 GateRef hclassCompare = builder_.Equal(aotHCGate, receiverHClass);
1323 if (LIKELY(static_cast<uint32_t>(level) < SubtypingOperator::DEFAULT_SUPERS_CAPACITY)) {
1324 GateRef subtypingCompare = builder_.Equal(aotHCGate, GetValueFromSupers(supers, level));
1325 GateRef compare = builder_.BoolAnd(hclassCompare, subtypingCompare);
1326 builder_.DeoptCheck(compare, frameState, DeoptType::INCONSISTENTHCLASS);
1327 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1328 return;
1329 }
1330
1331 Label levelValid(&builder_);
1332 Label exit(&builder_);
1333 DEFVAlUE(check, (&builder_), VariableType::BOOL(), builder_.False());
1334 GateRef levelGate = builder_.Int32(level);
1335 GateRef length = GetLengthFromSupers(supers);
1336
1337 builder_.Branch(builder_.Int32LessThan(levelGate, length), &levelValid, &exit);
1338 builder_.Bind(&levelValid);
1339 {
1340 check = builder_.Equal(aotHCGate, GetValueFromSupers(supers, level));
1341 builder_.Jump(&exit);
1342 }
1343 builder_.Bind(&exit);
1344
1345 GateRef compare = builder_.BoolAnd(hclassCompare, *check);
1346 builder_.DeoptCheck(compare, frameState, DeoptType::INCONSISTENTHCLASS);
1347 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
1348 }
1349 } // namespace panda::ecmascript::kungfu
1350