1/*
2 * Copyright (c) 2023 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#ifndef ECMASCRIPT_COMPILER_MCR_CIRCUIT_BUILDER_H
17#define ECMASCRIPT_COMPILER_MCR_CIRCUIT_BUILDER_H
18
19#include "ecmascript/compiler/circuit_builder.h"
20#include "ecmascript/compiler/circuit_builder_helper.h"
21#include "ecmascript/mem/region.h"
22#include "ecmascript/method.h"
23#include "ecmascript/js_function.h"
24
25namespace panda::ecmascript::kungfu {
26
27// bit operation
28
29GateRef CircuitBuilder::TaggedIsInt(GateRef x)
30{
31    x = ChangeTaggedPointerToInt64(x);
32    return Equal(Int64And(x, Int64(JSTaggedValue::TAG_MARK)),
33                 Int64(JSTaggedValue::TAG_INT));
34}
35
36GateRef CircuitBuilder::TaggedIsDouble(GateRef x)
37{
38    x = ChangeTaggedPointerToInt64(x);
39    x = Int64And(x, Int64(JSTaggedValue::TAG_MARK));
40    auto left = NotEqual(x, Int64(JSTaggedValue::TAG_INT));
41    auto right = NotEqual(x, Int64(JSTaggedValue::TAG_OBJECT));
42    return BitAnd(left, right);
43}
44
45GateRef CircuitBuilder::TaggedIsObject(GateRef x)
46{
47    x = ChangeTaggedPointerToInt64(x);
48    return Equal(Int64And(x, Int64(JSTaggedValue::TAG_MARK)),
49                 Int64(JSTaggedValue::TAG_OBJECT));
50}
51
52GateRef CircuitBuilder::TaggedIsNumber(GateRef x)
53{
54    return BoolNot(TaggedIsObject(x));
55}
56
57GateRef CircuitBuilder::TaggedIsNumeric(GateRef x)
58{
59    return LogicOrBuilder(env_).Or(TaggedIsNumber(x)).Or(TaggedIsBigInt(x)).Done();
60}
61
62GateRef CircuitBuilder::TaggedObjectIsString(GateRef obj)
63{
64    GateRef objectType = GetObjectType(LoadHClass(obj));
65    return BitAnd(
66        Int32LessThanOrEqual(objectType, Int32(static_cast<int32_t>(JSType::STRING_LAST))),
67        Int32GreaterThanOrEqual(objectType, Int32(static_cast<int32_t>(JSType::STRING_FIRST))));
68}
69
70GateRef CircuitBuilder::TaggedObjectIsShared(GateRef obj)
71{
72    GateRef bitfield = Load(VariableType::INT32(), LoadHClass(obj), IntPtr(JSHClass::BIT_FIELD_OFFSET));
73    return Int32NotEqual(
74        Int32And(Int32LSR(bitfield, Int32(JSHClass::IsJSSharedBit::START_BIT)),
75                 Int32((1LU << JSHClass::IsJSSharedBit::SIZE) - 1)),
76        Int32(0));
77}
78
79GateRef CircuitBuilder::TaggedObjectIsEcmaObject(GateRef obj)
80{
81    GateRef objectType = GetObjectType(LoadHClass(obj));
82    return BitAnd(
83        Int32LessThanOrEqual(objectType, Int32(static_cast<int32_t>(JSType::ECMA_OBJECT_LAST))),
84        Int32GreaterThanOrEqual(objectType, Int32(static_cast<int32_t>(JSType::ECMA_OBJECT_FIRST))));
85}
86
87GateRef CircuitBuilder::TaggedObjectIsByteArray(GateRef obj)
88{
89    GateRef objectType = GetObjectType(LoadHClass(obj));
90    return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::BYTE_ARRAY)));
91}
92
93GateRef CircuitBuilder::TaggedObjectIsMap(GateRef obj)
94{
95    GateRef objectType = GetObjectType(LoadHClass(obj));
96    return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_MAP)));
97}
98
99GateRef CircuitBuilder::TaggedObjectIsDataView(GateRef obj)
100{
101    GateRef objectType = GetObjectType(LoadHClass(obj));
102    return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_DATA_VIEW)));
103}
104
105GateRef CircuitBuilder::IsSpecialSlicedString(GateRef obj)
106{
107    GateRef objectType = GetObjectType(LoadHClass(obj));
108    GateRef isSlicedString = Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::SLICED_STRING)));
109    Label entry(env_);
110    SubCfgEntry(&entry);
111    Label exit(env_);
112    DEFVALUE(result, env_, VariableType::BOOL(), False());
113    Label isSlicedStr(env_);
114    BRANCH_CIR2(isSlicedString, &isSlicedStr, &exit);
115    Bind(&isSlicedStr);
116    {
117        GateRef hasBackingStore = LoadConstOffset(VariableType::INT32(), obj, SlicedString::BACKING_STORE_FLAG);
118        result = Int32Equal(hasBackingStore, Int32(EcmaString::HAS_BACKING_STORE));
119        Jump(&exit);
120    }
121    Bind(&exit);
122    auto ret = *result;
123    SubCfgExit();
124    return ret;
125}
126
127GateRef CircuitBuilder::TaggedIsBigInt(GateRef obj)
128{
129    Label entry(env_);
130    SubCfgEntry(&entry);
131    Label exit(env_);
132    DEFVALUE(result, env_, VariableType::BOOL(), False());
133    Label isHeapObject(env_);
134    BRANCH_CIR2(TaggedIsHeapObject(obj), &isHeapObject, &exit);
135    Bind(&isHeapObject);
136    {
137        result = Int32Equal(GetObjectType(LoadHClass(obj)),
138                            Int32(static_cast<int32_t>(JSType::BIGINT)));
139        Jump(&exit);
140    }
141    Bind(&exit);
142    auto ret = *result;
143    SubCfgExit();
144    return ret;
145}
146
147GateRef CircuitBuilder::TaggedIsString(GateRef obj)
148{
149    Label entry(env_);
150    SubCfgEntry(&entry);
151    Label exit(env_);
152    DEFVALUE(result, env_, VariableType::BOOL(), False());
153    Label isHeapObject(env_);
154    BRANCH_CIR2(TaggedIsHeapObject(obj), &isHeapObject, &exit);
155    Bind(&isHeapObject);
156    {
157        result = TaggedObjectIsString(obj);
158        Jump(&exit);
159    }
160    Bind(&exit);
161    auto ret = *result;
162    SubCfgExit();
163    return ret;
164}
165
166GateRef CircuitBuilder::TaggedIsStringIterator(GateRef obj)
167{
168    Label entry(env_);
169    SubCfgEntry(&entry);
170    Label exit(env_);
171    DEFVALUE(result, env_, VariableType::BOOL(), False());
172    Label isHeapObject(env_);
173    Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
174    Bind(&isHeapObject);
175    {
176        result = Int32Equal(GetObjectType(LoadHClass(obj)),
177                            Int32(static_cast<int32_t>(JSType::JS_STRING_ITERATOR)));
178        Jump(&exit);
179    }
180    Bind(&exit);
181    auto ret = *result;
182    SubCfgExit();
183    return ret;
184}
185
186GateRef CircuitBuilder::TaggedIsSharedObj(GateRef obj)
187{
188    Label entry(env_);
189    SubCfgEntry(&entry);
190    Label exit(env_);
191    DEFVALUE(result, env_, VariableType::BOOL(), False());
192    Label isHeapObject(env_);
193    BRANCH_CIR2(TaggedIsHeapObject(obj), &isHeapObject, &exit);
194    Bind(&isHeapObject);
195    {
196        result = TaggedObjectIsShared(obj);
197        Jump(&exit);
198    }
199    Bind(&exit);
200    auto ret = *result;
201    SubCfgExit();
202    return ret;
203}
204
205GateRef CircuitBuilder::TaggedIsSymbol(GateRef obj)
206{
207    Label entry(env_);
208    SubCfgEntry(&entry);
209    Label exit(env_);
210    DEFVALUE(result, env_, VariableType::BOOL(), False());
211    Label isHeapObject(env_);
212    BRANCH_CIR2(TaggedIsHeapObject(obj), &isHeapObject, &exit);
213    Bind(&isHeapObject);
214    {
215        GateRef objType = GetObjectType(LoadHClass(obj));
216        result = Equal(objType, Int32(static_cast<int32_t>(JSType::SYMBOL)));
217        Jump(&exit);
218    }
219    Bind(&exit);
220    auto ret = *result;
221    SubCfgExit();
222    return ret;
223}
224
225GateRef CircuitBuilder::TaggedIsStringOrSymbol(GateRef obj)
226{
227    Label entry(env_);
228    SubCfgEntry(&entry);
229    Label exit(env_);
230    DEFVALUE(result, env_, VariableType::BOOL(), False());
231    Label isHeapObject(env_);
232    BRANCH_CIR2(TaggedIsHeapObject(obj), &isHeapObject, &exit);
233    Bind(&isHeapObject);
234    {
235        result = TaggedObjectIsString(obj);
236        Label isString(env_);
237        Label notString(env_);
238        BRANCH_CIR2(*result, &exit, &notString);
239        Bind(&notString);
240        {
241            GateRef objType = GetObjectType(LoadHClass(obj));
242            result = Equal(objType, Int32(static_cast<int32_t>(JSType::SYMBOL)));
243            Jump(&exit);
244        }
245    }
246    Bind(&exit);
247    auto ret = *result;
248    SubCfgExit();
249    return ret;
250}
251
252GateRef CircuitBuilder::TaggedIsProtoChangeMarker(GateRef obj)
253{
254    Label entry(env_);
255    SubCfgEntry(&entry);
256    Label exit(env_);
257    DEFVALUE(result, env_, VariableType::BOOL(), False());
258    Label isHeapObject(env_);
259    BRANCH_CIR2(TaggedIsHeapObject(obj), &isHeapObject, &exit);
260    Bind(&isHeapObject);
261    {
262        GateRef objType = GetObjectType(LoadHClass(obj));
263        result = Equal(objType, Int32(static_cast<int32_t>(JSType::PROTO_CHANGE_MARKER)));
264        Jump(&exit);
265    }
266    Bind(&exit);
267    auto ret = *result;
268    SubCfgExit();
269    return ret;
270}
271
272GateRef CircuitBuilder::TaggedObjectIsJSMap(GateRef obj)
273{
274    GateRef objType = GetObjectType(LoadHClass(obj));
275    return Equal(objType, Int32(static_cast<int32_t>(JSType::JS_MAP)));
276}
277
278GateRef CircuitBuilder::TaggedObjectIsJSSet(GateRef obj)
279{
280    GateRef objType = GetObjectType(LoadHClass(obj));
281    return Equal(objType, Int32(static_cast<int32_t>(JSType::JS_SET)));
282}
283
284GateRef CircuitBuilder::TaggedObjectIsJSDate(GateRef obj)
285{
286    GateRef objType = GetObjectType(LoadHClass(obj));
287    return Equal(objType, Int32(static_cast<int32_t>(JSType::JS_DATE)));
288}
289
290GateRef CircuitBuilder::TaggedObjectIsTypedArray(GateRef obj)
291{
292    GateRef jsType = GetObjectType(LoadHClass(obj));
293    return BitAnd(Int32GreaterThan(jsType, Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY_FIRST))),
294                  Int32GreaterThanOrEqual(Int32(static_cast<int32_t>(JSType::JS_TYPED_ARRAY_LAST)), jsType));
295}
296
297GateRef CircuitBuilder::TaggedObjectIsJSArray(GateRef obj)
298{
299    GateRef objType = GetObjectType(LoadHClass(obj));
300    return Equal(objType, Int32(static_cast<int32_t>(JSType::JS_ARRAY)));
301}
302
303GateRef CircuitBuilder::TaggedIsBoundFunction(GateRef obj)
304{
305    GateRef objType = GetObjectType(LoadHClass(obj));
306    return Equal(objType, Int32(static_cast<int32_t>(JSType::JS_BOUND_FUNCTION)));
307}
308
309inline GateRef CircuitBuilder::JudgeAotAndFastCall(GateRef jsFunc, JudgeMethodType type)
310{
311    GateRef bitFieldOffset = IntPtr(JSFunctionBase::BIT_FIELD_OFFSET);
312    GateRef bitField = Load(VariableType::INT32(), jsFunc, bitFieldOffset);
313    switch (type) {
314        case JudgeMethodType::HAS_AOT: {
315            return Int32NotEqual(
316                Int32And(
317                    Int32LSR(bitField, Int32(JSFunctionBase::IsCompiledCodeBit::START_BIT)),
318                    Int32((1U << JSFunctionBase::IsCompiledCodeBit::SIZE) - 1)),
319                Int32(0));
320        }
321        case JudgeMethodType::HAS_AOT_FASTCALL: {
322            return Int32Equal(
323                Int32And(
324                    bitField,
325                    Int32(JSFunctionBase::COMPILED_CODE_FASTCALL_BITS << JSFunctionBase::IsCompiledCodeBit::START_BIT)),
326                Int32(JSFunctionBase::COMPILED_CODE_FASTCALL_BITS << JSFunctionBase::IsCompiledCodeBit::START_BIT));
327        }
328        case JudgeMethodType::HAS_AOT_NOTFASTCALL: {
329            GateRef fastCallField =
330                Int32And(bitField,
331                    Int32(JSFunctionBase::COMPILED_CODE_FASTCALL_BITS << JSFunctionBase::IsCompiledCodeBit::START_BIT));
332            GateRef hasAot = Int32(1U << JSFunctionBase::IsCompiledCodeBit::START_BIT);
333            return Int32Equal(fastCallField, hasAot);
334        }
335        default:
336            UNREACHABLE();
337    }
338}
339
340GateRef CircuitBuilder::BothAreString(GateRef x, GateRef y)
341{
342    return LogicAndBuilder(env_).And(TaggedIsHeapObject(x)).And(TaggedIsHeapObject(y))
343        .And(TaggedObjectIsString(x)).And(TaggedObjectIsString(y)).Done();
344}
345
346GateRef CircuitBuilder::TaggedIsHole(GateRef x)
347{
348    return Equal(x, HoleConstant());
349}
350
351GateRef CircuitBuilder::TaggedIsNullPtr(GateRef x)
352{
353    return Equal(x, NullPtrConstant());
354}
355
356GateRef CircuitBuilder::IsSpecialHole(GateRef x)
357{
358    return Equal(x, SpecialHoleConstant());
359}
360
361GateRef CircuitBuilder::IsNotSpecialHole(GateRef x)
362{
363    return NotEqual(x, SpecialHoleConstant());
364}
365
366GateRef CircuitBuilder::TaggedIsNotHole(GateRef x)
367{
368    return NotEqual(x, HoleConstant());
369}
370
371GateRef CircuitBuilder::TaggedIsUndefined(GateRef x)
372{
373    return Equal(x, UndefineConstant());
374}
375
376GateRef CircuitBuilder::TaggedIsException(GateRef x)
377{
378    return Equal(x, ExceptionConstant());
379}
380
381GateRef CircuitBuilder::TaggedIsSpecial(GateRef x)
382{
383    return LogicOrBuilder(env_)
384        .Or(TaggedIsHole(x))
385        .Or(Equal(Int64And(ChangeTaggedPointerToInt64(x), Int64(JSTaggedValue::TAG_SPECIAL_MASK)),
386                  Int64(JSTaggedValue::TAG_SPECIAL)))
387        .Done();
388}
389
390GateRef CircuitBuilder::TaggedIsHeapObject(GateRef x)
391{
392    x = ChangeTaggedPointerToInt64(x);
393    auto t = Int64And(x, Int64(JSTaggedValue::TAG_HEAPOBJECT_MASK), GateType::Empty(), "checkHeapObject");
394    return Equal(t, Int64(0), "checkHeapObject");
395}
396
397GateRef CircuitBuilder::TaggedIsAsyncGeneratorObject(GateRef x)
398{
399    return LogicAndBuilder(env_).And(TaggedIsHeapObject(x)).And(IsJsType(x, JSType::JS_ASYNC_GENERATOR_OBJECT)).Done();
400}
401
402GateRef CircuitBuilder::TaggedIsJSGlobalObject(GateRef x)
403{
404    return LogicAndBuilder(env_).And(TaggedIsHeapObject(x)).And(IsJsType(x, JSType::JS_GLOBAL_OBJECT)).Done();
405}
406
407GateRef CircuitBuilder::TaggedIsGeneratorObject(GateRef x)
408{
409    return LogicAndBuilder(env_).And(TaggedIsHeapObject(x)).And(IsJsType(x, JSType::JS_GENERATOR_OBJECT)).Done();
410}
411
412GateRef CircuitBuilder::TaggedIsJSArray(GateRef x)
413{
414    return LogicAndBuilder(env_).And(TaggedIsHeapObject(x)).And(IsJsType(x, JSType::JS_ARRAY)).Done();
415}
416
417GateRef CircuitBuilder::TaggedIsPropertyBox(GateRef x)
418{
419    return LogicAndBuilder(env_).And(TaggedIsHeapObject(x)).And(IsJsType(x, JSType::PROPERTY_BOX)).Done();
420}
421
422GateRef CircuitBuilder::TaggedIsWeak(GateRef x)
423{
424    return LogicAndBuilder(env_)
425        .And(TaggedIsHeapObject(x))
426        .And(Equal(Int64And(ChangeTaggedPointerToInt64(x), Int64(JSTaggedValue::TAG_WEAK)), Int64(1)))
427        .Done();
428}
429
430GateRef CircuitBuilder::TaggedIsPrototypeHandler(GateRef x)
431{
432    return LogicAndBuilder(env_).And(TaggedIsHeapObject(x)).And(IsJsType(x, JSType::PROTOTYPE_HANDLER)).Done();
433}
434
435GateRef CircuitBuilder::TaggedIsTransitionHandler(GateRef x)
436{
437    return LogicAndBuilder(env_).And(TaggedIsHeapObject(x)).And(IsJsType(x, JSType::TRANSITION_HANDLER)).Done();
438}
439
440GateRef CircuitBuilder::TaggedIsStoreTSHandler(GateRef x)
441{
442    return LogicAndBuilder(env_).And(TaggedIsHeapObject(x)).And(IsJsType(x, JSType::STORE_TS_HANDLER)).Done();
443}
444
445GateRef CircuitBuilder::TaggedIsTransWithProtoHandler(GateRef x)
446{
447    return LogicAndBuilder(env_).And(TaggedIsHeapObject(x)).And(IsJsType(x, JSType::TRANS_WITH_PROTO_HANDLER)).Done();
448}
449
450GateRef CircuitBuilder::TaggedIsUndefinedOrNull(GateRef x)
451{
452    x = ChangeTaggedPointerToInt64(x);
453    GateRef heapObjMask = Int64(JSTaggedValue::TAG_HEAPOBJECT_MASK);
454    GateRef tagSpecial = Int64(JSTaggedValue::TAG_SPECIAL);
455    GateRef andGate = Int64And(x, heapObjMask);
456    GateRef result = Equal(andGate, tagSpecial);
457    return result;
458}
459
460GateRef CircuitBuilder::TaggedIsUndefinedOrNullOrHole(GateRef x)
461{
462    return BitOr(TaggedIsHole(x), TaggedIsUndefinedOrNull(x));
463}
464
465GateRef CircuitBuilder::TaggedIsNotUndefinedAndNull(GateRef x)
466{
467    x = ChangeTaggedPointerToInt64(x);
468    GateRef heapObjMask = Int64(JSTaggedValue::TAG_HEAPOBJECT_MASK);
469    GateRef tagSpecial = Int64(JSTaggedValue::TAG_SPECIAL);
470    GateRef andGate = Int64And(x, heapObjMask);
471    GateRef result = NotEqual(andGate, tagSpecial);
472    return result;
473}
474
475GateRef CircuitBuilder::TaggedIsNotUndefinedAndNullAndHole(GateRef x)
476{
477    return BitAnd(TaggedIsNotHole(x), TaggedIsNotUndefinedAndNull(x));
478}
479
480GateRef CircuitBuilder::TaggedIsUndefinedOrHole(GateRef x)
481{
482    GateRef isUndefined = TaggedIsUndefined(x);
483    GateRef isHole = TaggedIsHole(x);
484    GateRef result = BitOr(isHole, isUndefined);
485    return result;
486}
487
488GateRef CircuitBuilder::TaggedTrue()
489{
490    return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_TRUE, GateType::TaggedValue());
491}
492
493GateRef CircuitBuilder::TaggedFalse()
494{
495    return GetCircuit()->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_FALSE, GateType::TaggedValue());
496}
497
498GateRef CircuitBuilder::TaggedIsTrue(GateRef x)
499{
500    return Equal(x, TaggedTrue());
501}
502
503GateRef CircuitBuilder::TaggedIsFalse(GateRef x)
504{
505    return Equal(x, TaggedFalse());
506}
507
508GateRef CircuitBuilder::TaggedIsNull(GateRef x)
509{
510    return Equal(x, NullConstant());
511}
512
513GateRef CircuitBuilder::TaggedIsNotNull(GateRef x)
514{
515    return NotEqual(x, NullConstant());
516}
517
518GateRef CircuitBuilder::TaggedIsBoolean(GateRef x)
519{
520    return BitOr(TaggedIsFalse(x), TaggedIsTrue(x));
521}
522
523GateRef CircuitBuilder::TaggedGetInt(GateRef x)
524{
525    x = ChangeTaggedPointerToInt64(x);
526    return TruncInt64ToInt32(Int64And(x, Int64(~JSTaggedValue::TAG_MARK)));
527}
528
529inline GateRef CircuitBuilder::TypedCallBuiltin(GateRef hirGate, const std::vector<GateRef> &args,
530                                                BuiltinsStubCSigns::ID id, bool isSideEffect)
531{
532    auto currentLabel = env_->GetCurrentLabel();
533    auto currentControl = currentLabel->GetControl();
534    auto currentDepend = currentLabel->GetDepend();
535
536    std::vector<GateRef> inList { currentControl, currentDepend };
537    inList.insert(inList.end(), args.begin(), args.end());
538    inList.push_back(Int16(static_cast<int16_t>(id)));
539    AppendFrameArgs(inList, hirGate);
540
541    auto builtinOp = TypedCallOperator(hirGate, MachineType::I64, inList, isSideEffect);
542    currentLabel->SetControl(builtinOp);
543    currentLabel->SetDepend(builtinOp);
544    return builtinOp;
545}
546
547template<TypedBinOp Op>
548GateRef CircuitBuilder::TypedBinaryOp(GateRef x, GateRef y, ParamType paramType)
549{
550    auto currentLabel = env_->GetCurrentLabel();
551    auto currentControl = currentLabel->GetControl();
552    auto currentDepend = currentLabel->GetDepend();
553    uint64_t value = TypedBinaryAccessor::ToValue(paramType, Op);
554    auto numberBinaryOp = GetCircuit()->NewGate(circuit_->TypedBinaryOp(value),
555        MachineType::I64, {currentControl, currentDepend, x, y}, GateType::AnyType());
556    currentLabel->SetControl(numberBinaryOp);
557    currentLabel->SetDepend(numberBinaryOp);
558    return numberBinaryOp;
559}
560
561template<TypedCallTargetCheckOp Op>
562GateRef CircuitBuilder::JSNoGCCallThisTargetTypeCheck(GateRef func, GateRef methodId, GateRef gate)
563{
564    auto currentLabel = env_->GetCurrentLabel();
565    auto currentControl = currentLabel->GetControl();
566    auto currentDepend = currentLabel->GetDepend();
567    auto frameState = acc_.GetFrameState(gate);
568    uint64_t value = TypedCallTargetCheckAccessor::ToValue(Op);
569    GateRef ret = GetCircuit()->NewGate(circuit_->TypedCallTargetCheckOp(value), MachineType::I1,
570        {currentControl, currentDepend, func, methodId, frameState}, GateType::NJSValue());
571    currentLabel->SetControl(ret);
572    currentLabel->SetDepend(ret);
573    return ret;
574}
575
576template<TypedCallTargetCheckOp Op>
577GateRef CircuitBuilder::JSCallTargetTypeCheck(GateRef func, GateRef methodIndex, GateRef gate)
578{
579    auto currentLabel = env_->GetCurrentLabel();
580    auto currentControl = currentLabel->GetControl();
581    auto currentDepend = currentLabel->GetDepend();
582    auto frameState = acc_.GetFrameState(gate);
583    uint64_t value = TypedCallTargetCheckAccessor::ToValue(Op);
584    GateRef ret = GetCircuit()->NewGate(circuit_->TypedCallTargetCheckOp(value), MachineType::I1,
585        {currentControl, currentDepend, func, methodIndex, frameState}, GateType::NJSValue());
586    currentLabel->SetControl(ret);
587    currentLabel->SetDepend(ret);
588    return ret;
589}
590
591template<TypedUnOp Op>
592GateRef CircuitBuilder::TypedUnaryOp(GateRef x, ParamType paramType)
593{
594    auto currentLabel = env_->GetCurrentLabel();
595    auto currentControl = currentLabel->GetControl();
596    auto currentDepend = currentLabel->GetDepend();
597    uint64_t value = TypedUnaryAccessor::ToValue(paramType, Op);
598    auto numberUnaryOp = GetCircuit()->NewGate(circuit_->TypedUnaryOp(value),
599        MachineType::I64, {currentControl, currentDepend, x}, GateType::AnyType());
600    currentLabel->SetControl(numberUnaryOp);
601    currentLabel->SetDepend(numberUnaryOp);
602    return numberUnaryOp;
603}
604
605template<TypedJumpOp Op>
606GateRef CircuitBuilder::TypedConditionJump(GateRef x, ParamType paramType, uint32_t weight)
607{
608    auto currentLabel = env_->GetCurrentLabel();
609    auto currentControl = currentLabel->GetControl();
610    auto currentDepend = currentLabel->GetDepend();
611    auto machineType = MachineType::NOVALUE;
612    auto jumpOp = TypedConditionJump(machineType, Op, weight, paramType, {currentControl, currentDepend, x});
613    currentLabel->SetControl(jumpOp);
614    currentLabel->SetDepend(jumpOp);
615    return jumpOp;
616}
617
618template <TypedLoadOp Op>
619GateRef CircuitBuilder::LoadElement(GateRef receiver, GateRef index, OnHeapMode onHeap)
620{
621    auto currentLabel = env_->GetCurrentLabel();
622    auto currentControl = currentLabel->GetControl();
623    auto currentDepend = currentLabel->GetDepend();
624    LoadElementAccessor accessor(Op, onHeap);
625    auto ret = GetCircuit()->NewGate(GetCircuit()->LoadElement(accessor.ToValue()), MachineType::I64,
626                                     {currentControl, currentDepend, receiver, index}, GateType::AnyType());
627    currentLabel->SetControl(ret);
628    currentLabel->SetDepend(ret);
629    return ret;
630}
631
632template <TypedStoreOp Op>
633GateRef CircuitBuilder::StoreElement(GateRef receiver, GateRef index, GateRef value, OnHeapMode onHeap)
634{
635    auto currentLabel = env_->GetCurrentLabel();
636    auto currentControl = currentLabel->GetControl();
637    auto currentDepend = currentLabel->GetDepend();
638    StoreElementAccessor accessor(Op, onHeap);
639    auto ret = GetCircuit()->NewGate(GetCircuit()->StoreElement(accessor.ToValue()), MachineType::NOVALUE,
640                                     {currentControl, currentDepend, receiver, index, value}, GateType::AnyType());
641    currentLabel->SetControl(ret);
642    currentLabel->SetDepend(ret);
643    return ret;
644}
645
646GateRef CircuitBuilder::PrimitiveToNumber(GateRef x, ParamType paramType)
647{
648    auto currentLabel = env_->GetCurrentLabel();
649    auto currentControl = currentLabel->GetControl();
650    auto currentDepend = currentLabel->GetDepend();
651
652    auto numberconvert = TypeConvert(MachineType::I64, paramType, GateType::NumberType(),
653                                     {currentControl, currentDepend, x});
654    currentLabel->SetControl(numberconvert);
655    currentLabel->SetDepend(numberconvert);
656    return numberconvert;
657}
658
659GateRef CircuitBuilder::LoadFromTaggedArray(GateRef array, size_t index)
660{
661    auto dataOffset = TaggedArray::DATA_OFFSET + index * JSTaggedValue::TaggedTypeSize();
662    return LoadConstOffset(VariableType::JS_ANY(), array, dataOffset);
663}
664
665GateRef CircuitBuilder::StoreToTaggedArray(GateRef array, size_t index, GateRef value)
666{
667    auto dataOffset = TaggedArray::DATA_OFFSET + index * JSTaggedValue::TaggedTypeSize();
668    return StoreConstOffset(VariableType::JS_ANY(), array, dataOffset, value);
669}
670
671GateRef CircuitBuilder::TreeStringIsFlat(GateRef string)
672{
673    GateRef second = GetSecondFromTreeString(string);
674    GateRef len = GetLengthFromString(second);
675    return Int32Equal(len, Int32(0));
676}
677
678GateRef CircuitBuilder::GetFirstFromTreeString(GateRef string)
679{
680    GateRef offset = IntPtr(TreeEcmaString::FIRST_OFFSET);
681    return Load(VariableType::JS_POINTER(), string, offset);
682}
683
684GateRef CircuitBuilder::GetSecondFromTreeString(GateRef string)
685{
686    GateRef offset = IntPtr(TreeEcmaString::SECOND_OFFSET);
687    return Load(VariableType::JS_POINTER(), string, offset);
688}
689
690GateRef CircuitBuilder::GetValueFromTaggedArray(GateRef array, GateRef index)
691{
692    GateRef offset = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
693    GateRef dataOffset = PtrAdd(offset, IntPtr(TaggedArray::DATA_OFFSET));
694    return Load(VariableType::JS_ANY(), array, dataOffset);
695}
696
697GateRef CircuitBuilder::GetValueFromTaggedArray(VariableType valType, GateRef array, GateRef index)
698{
699    GateRef offset = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
700    GateRef dataOffset = PtrAdd(offset, IntPtr(TaggedArray::DATA_OFFSET));
701    return Load(valType, array, dataOffset);
702}
703
704GateRef CircuitBuilder::GetValueFromJSArrayWithElementsKind(VariableType type, GateRef array, GateRef index)
705{
706    GateRef offset = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
707    GateRef dataOffset = PtrAdd(offset, IntPtr(TaggedArray::DATA_OFFSET));
708    return Load(type, array, dataOffset);
709}
710
711void CircuitBuilder::SetValueToTaggedArray(VariableType valType, GateRef glue,
712                                           GateRef array, GateRef index, GateRef val)
713{
714    GateRef offset = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
715    GateRef dataOffset = PtrAdd(offset, IntPtr(TaggedArray::DATA_OFFSET));
716    Store(valType, glue, array, dataOffset, val);
717}
718}
719
720#endif  // ECMASCRIPT_COMPILER_MCR_CIRCUIT_BUILDER_H
721