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_HCR_CIRCUIT_BUILDER_H
17#define ECMASCRIPT_COMPILER_HCR_CIRCUIT_BUILDER_H
18
19#include "ecmascript/compiler/circuit_builder_helper.h"
20#include "ecmascript/mem/region.h"
21#include "ecmascript/js_function.h"
22
23namespace panda::ecmascript::kungfu {
24
25GateRef CircuitBuilder::IsSpecial(GateRef x, JSTaggedType type)
26{
27    auto specialValue = circuit_->GetConstantGate(
28        MachineType::I64, type, GateType::TaggedValue());
29
30    return Equal(x, specialValue);
31}
32
33inline GateRef CircuitBuilder::IsJSHClass(GateRef obj)
34{
35    return Int32Equal(GetObjectType(LoadHClass(obj)), Int32(static_cast<int32_t>(JSType::HCLASS)));
36}
37
38inline GateRef CircuitBuilder::IsJSFunction(GateRef obj)
39{
40    GateRef objectType = GetObjectType(LoadHClass(obj));
41    GateRef greater = Int32GreaterThanOrEqual(objectType,
42        Int32(static_cast<int32_t>(JSType::JS_FUNCTION_FIRST)));
43    GateRef less = Int32LessThanOrEqual(objectType,
44        Int32(static_cast<int32_t>(JSType::JS_FUNCTION_LAST)));
45    return BitAnd(greater, less);
46}
47
48GateRef CircuitBuilder::IsJsType(GateRef obj, JSType type)
49{
50    GateRef objectType = GetObjectType(LoadHClass(obj));
51    return Equal(objectType, Int32(static_cast<int32_t>(type)));
52}
53
54GateRef CircuitBuilder::IsJSObject(GateRef obj)
55{
56    Label entryPass(env_);
57    SubCfgEntry(&entryPass);
58    DEFVALUE(result, env_, VariableType::BOOL(), False());
59    Label heapObj(env_);
60    Label exit(env_);
61    GateRef isHeapObject = TaggedIsHeapObject(obj);
62    BRANCH_CIR2(isHeapObject, &heapObj, &exit);
63    Bind(&heapObj);
64    {
65        GateRef objectType = GetObjectType(LoadHClass(obj));
66        result = BitAnd(
67            Int32LessThanOrEqual(objectType, Int32(static_cast<int32_t>(JSType::JS_OBJECT_LAST))),
68            Int32GreaterThanOrEqual(objectType, Int32(static_cast<int32_t>(JSType::JS_OBJECT_FIRST))));
69        Jump(&exit);
70    }
71    Bind(&exit);
72    auto ret = *result;
73    SubCfgExit();
74    return ret;
75}
76
77GateRef CircuitBuilder::IsCallableFromBitField(GateRef bitfield)
78{
79    return NotEqual(
80        Int32And(Int32LSR(bitfield, Int32(JSHClass::CallableBit::START_BIT)),
81            Int32((1LU << JSHClass::CallableBit::SIZE) - 1)),
82        Int32(0));
83}
84
85GateRef CircuitBuilder::IsCallable(GateRef obj)
86{
87    GateRef hClass = LoadHClass(obj);
88    GateRef bitfieldOffset = IntPtr(JSHClass::BIT_FIELD_OFFSET);
89    GateRef bitfield = Load(VariableType::INT32(), hClass, bitfieldOffset);
90    return IsCallableFromBitField(bitfield);
91}
92
93GateRef CircuitBuilder::IsProtoTypeHClass(GateRef hClass)
94{
95    GateRef bitfield = LoadConstOffset(VariableType::INT32(), hClass, JSHClass::BIT_FIELD_OFFSET);
96    return TruncInt32ToInt1(Int32And(Int32LSR(bitfield,
97        Int32(JSHClass::IsPrototypeBit::START_BIT)),
98        Int32((1LU << JSHClass::IsPrototypeBit::SIZE) - 1)));
99}
100
101GateRef CircuitBuilder::IsJsProxy(GateRef obj)
102{
103    GateRef objectType = GetObjectType(LoadHClass(obj));
104    return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_PROXY)));
105}
106
107GateRef CircuitBuilder::IsTreeString(GateRef obj)
108{
109    GateRef objectType = GetObjectType(LoadHClass(obj));
110    return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::TREE_STRING)));
111}
112
113GateRef CircuitBuilder::IsSlicedString(GateRef obj)
114{
115    GateRef objectType = GetObjectType(LoadHClass(obj));
116    return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::SLICED_STRING)));
117}
118
119GateRef CircuitBuilder::IsLineString(GateRef obj)
120{
121    GateRef objectType = GetObjectType(LoadHClass(obj));
122    return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::LINE_STRING)));
123}
124
125GateRef CircuitBuilder::IsConstantString(GateRef obj)
126{
127    GateRef objectType = GetObjectType(LoadHClass(obj));
128    return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::CONSTANT_STRING)));
129}
130
131GateRef CircuitBuilder::ComputeSizeUtf8(GateRef length)
132{
133    return PtrAdd(IntPtr(LineEcmaString::DATA_OFFSET), length);
134}
135
136GateRef CircuitBuilder::ComputeSizeUtf16(GateRef length)
137{
138    return PtrAdd(IntPtr(LineEcmaString::DATA_OFFSET), PtrMul(length, IntPtr(sizeof(uint16_t))));
139}
140
141GateRef CircuitBuilder::AlignUp(GateRef x, GateRef alignment)
142{
143    GateRef x1 = PtrAdd(x, PtrSub(alignment, IntPtr(1)));
144    return IntPtrAnd(x1, IntPtrNot(PtrSub(alignment, IntPtr(1))));
145}
146
147inline GateRef CircuitBuilder::IsDictionaryMode(GateRef object)
148{
149    GateRef type = GetObjectType(LoadHClass(object));
150    return Int32Equal(type, Int32(static_cast<int32_t>(JSType::TAGGED_DICTIONARY)));
151}
152
153GateRef CircuitBuilder::IsStableArguments(GateRef hClass)
154{
155    GateRef objectType = GetObjectType(hClass);
156    GateRef isJsArguments = Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_ARGUMENTS)));
157    GateRef isStableElements = IsStableElements(hClass);
158    return BitAnd(isStableElements, isJsArguments);
159}
160
161GateRef CircuitBuilder::IsStableArray(GateRef hClass)
162{
163    GateRef objectType = GetObjectType(hClass);
164    GateRef isJsArray = Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_ARRAY)));
165    GateRef isStableElements = IsStableElements(hClass);
166    return BitAnd(isStableElements, isJsArray);
167}
168
169GateRef CircuitBuilder::IsAOTLiteralInfo(GateRef x)
170{
171    GateRef objType = GetObjectType(LoadHClass(x));
172    GateRef isAOTLiteralInfoObj = Equal(objType,
173        Int32(static_cast<int32_t>(JSType::AOT_LITERAL_INFO)));
174    return isAOTLiteralInfoObj;
175}
176
177GateRef CircuitBuilder::LoadHClass(GateRef object)
178{
179    GateRef offset = IntPtr(TaggedObject::HCLASS_OFFSET);
180    return Load(VariableType::JS_POINTER(), object, offset);
181}
182
183GateRef CircuitBuilder::LoadHClassByConstOffset(GateRef object)
184{
185    return LoadConstOffset(VariableType::JS_POINTER(), object, TaggedObject::HCLASS_OFFSET);
186}
187
188GateRef CircuitBuilder::LoadPrototype(GateRef hclass)
189{
190    return LoadConstOffset(VariableType::JS_POINTER(), hclass, JSHClass::PROTOTYPE_OFFSET);
191}
192
193GateRef CircuitBuilder::LoadPrototypeHClass(GateRef object)
194{
195    GateRef objectHClass = LoadHClassByConstOffset(object);
196    GateRef objectPrototype = LoadPrototype(objectHClass);
197    return LoadHClass(objectPrototype);
198}
199
200GateRef CircuitBuilder::LoadPrototypeOfPrototypeHClass(GateRef object)
201{
202    GateRef objectHClass = LoadHClassByConstOffset(object);
203    GateRef objectPrototype = LoadPrototype(objectHClass);
204    GateRef objectPrototypeHClass = LoadHClassByConstOffset(objectPrototype);
205    GateRef objectPrototypeOfPrototype = LoadPrototype(objectPrototypeHClass);
206    return LoadHClass(objectPrototypeOfPrototype);
207}
208
209GateRef CircuitBuilder::GetObjectSizeFromHClass(GateRef hClass)
210{
211    // NOTE: check for special case of string and TAGGED_ARRAY
212    GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD1_OFFSET));
213    GateRef objectSizeInWords = Int32And(Int32LSR(bitfield,
214        Int32(JSHClass::ObjectSizeInWordsBits::START_BIT)),
215        Int32((1LU << JSHClass::ObjectSizeInWordsBits::SIZE) - 1));
216    return PtrMul(ZExtInt32ToPtr(objectSizeInWords), IntPtr(JSTaggedValue::TaggedTypeSize()));
217}
218
219GateRef CircuitBuilder::IsDictionaryModeByHClass(GateRef hClass)
220{
221    GateRef bitfieldOffset = Int32(JSHClass::BIT_FIELD_OFFSET);
222    GateRef bitfield = Load(VariableType::INT32(), hClass, bitfieldOffset);
223    return NotEqual(Int32And(Int32LSR(bitfield,
224        Int32(JSHClass::IsDictionaryBit::START_BIT)),
225        Int32((1LU << JSHClass::IsDictionaryBit::SIZE) - 1)),
226        Int32(0));
227}
228
229void CircuitBuilder::StoreHClass(GateRef glue, GateRef object, GateRef hClass)
230{
231    Store(VariableType::JS_POINTER(), glue, object, IntPtr(TaggedObject::HCLASS_OFFSET), hClass,
232          MemoryAttribute::NeedBarrier());
233}
234
235void CircuitBuilder::StoreHClassWithoutBarrier(GateRef glue, GateRef object, GateRef hClass)
236{
237    Store(VariableType::JS_POINTER(), glue, object, IntPtr(TaggedObject::HCLASS_OFFSET), hClass,
238          MemoryAttribute::NoBarrier());
239}
240
241void CircuitBuilder::StorePrototype(GateRef glue, GateRef hclass, GateRef prototype)
242{
243    Store(VariableType::JS_POINTER(), glue, hclass, IntPtr(JSHClass::PROTOTYPE_OFFSET), prototype);
244}
245
246GateRef CircuitBuilder::GetObjectType(GateRef hClass)
247{
248    GateRef bitfieldOffset = IntPtr(JSHClass::BIT_FIELD_OFFSET);
249    GateRef bitfield = Load(VariableType::INT32(), hClass, bitfieldOffset);
250    return Int32And(bitfield, Int32((1LU << JSHClass::ObjectTypeBits::SIZE) - 1));
251}
252
253inline GateRef CircuitBuilder::CanFastCall(GateRef jsFunc)
254{
255    GateRef bitFieldOffset = IntPtr(JSFunctionBase::BIT_FIELD_OFFSET);
256    GateRef bitField = Load(VariableType::INT32(), jsFunc, bitFieldOffset);
257    return Int32NotEqual(
258        Int32And(
259            Int32LSR(bitField, Int32(JSFunctionBase::IsFastCallBit::START_BIT)),
260            Int32((1LU << JSFunctionBase::IsFastCallBit::SIZE) - 1)),
261        Int32(0));
262}
263
264GateRef CircuitBuilder::GetElementsKindByHClass(GateRef hClass)
265{
266    GateRef bitfieldOffset = IntPtr(JSHClass::BIT_FIELD_OFFSET);
267    GateRef bitfield = Load(VariableType::INT32(), hClass, bitfieldOffset);
268    return Int32And(Int32LSR(bitfield,
269        Int32(JSHClass::ElementsKindBits::START_BIT)),
270        Int32((1LLU << JSHClass::ElementsKindBits::SIZE) - 1));
271}
272
273GateRef CircuitBuilder::HasConstructorByHClass(GateRef hClass)
274{
275    GateRef bitfieldOffset = Int32(JSHClass::BIT_FIELD_OFFSET);
276    GateRef bitfield = Load(VariableType::INT32(), hClass, bitfieldOffset);
277    return NotEqual(Int32And(Int32LSR(bitfield,
278        Int32(JSHClass::HasConstructorBits::START_BIT)),
279        Int32((1LU << JSHClass::HasConstructorBits::SIZE) - 1)),
280        Int32(0));
281}
282
283GateRef CircuitBuilder::IsDictionaryElement(GateRef hClass)
284{
285    GateRef bitfieldOffset = Int32(JSHClass::BIT_FIELD_OFFSET);
286    GateRef bitfield = Load(VariableType::INT32(), hClass, bitfieldOffset);
287    return NotEqual(Int32And(Int32LSR(bitfield,
288        Int32(JSHClass::DictionaryElementBits::START_BIT)),
289        Int32((1LU << JSHClass::DictionaryElementBits::SIZE) - 1)),
290        Int32(0));
291}
292
293GateRef CircuitBuilder::IsStableElements(GateRef hClass)
294{
295    GateRef bitfieldOffset = Int32(JSHClass::BIT_FIELD_OFFSET);
296    GateRef bitfield = Load(VariableType::INT32(), hClass, bitfieldOffset);
297    return NotEqual(Int32And(Int32LSR(bitfield,
298        Int32(JSHClass::IsStableElementsBit::START_BIT)),
299        Int32((1LU << JSHClass::IsStableElementsBit::SIZE) - 1)),
300        Int32(0));
301}
302
303GateRef CircuitBuilder::HasConstructor(GateRef object)
304{
305    GateRef hClass = LoadHClass(object);
306    return HasConstructorByHClass(hClass);
307}
308
309GateRef CircuitBuilder::IsConstructor(GateRef object)
310{
311    GateRef hClass = LoadHClass(object);
312    GateRef bitfieldOffset = IntPtr(JSHClass::BIT_FIELD_OFFSET);
313    GateRef bitfield = Load(VariableType::INT32(), hClass, bitfieldOffset);
314    // decode
315    return Int32NotEqual(
316        Int32And(Int32LSR(bitfield, Int32(JSHClass::ConstructorBit::START_BIT)),
317                 Int32((1LU << JSHClass::ConstructorBit::SIZE) - 1)),
318        Int32(0));
319}
320
321GateRef CircuitBuilder::IsClassConstructor(GateRef object)
322{
323    GateRef hClass = LoadHClass(object);
324    GateRef bitfieldOffset = Int32(JSHClass::BIT_FIELD_OFFSET);
325    GateRef bitfield = Load(VariableType::INT32(), hClass, bitfieldOffset);
326    return IsClassConstructorWithBitField(bitfield);
327}
328
329GateRef CircuitBuilder::IsClassConstructorWithBitField(GateRef bitfield)
330{
331    auto classBitMask = 1LU << JSHClass::IsClassConstructorOrPrototypeBit::START_BIT;
332    auto ctorBitMask = 1LU << JSHClass::ConstructorBit::START_BIT;
333    auto mask = Int32(classBitMask | ctorBitMask);
334    auto classCtor = Int32And(bitfield, mask);
335    return Int32Equal(classCtor, mask);
336}
337
338GateRef CircuitBuilder::IsExtensible(GateRef object)
339{
340    GateRef hClass = LoadHClass(object);
341    GateRef bitfieldOffset = Int32(JSHClass::BIT_FIELD_OFFSET);
342    GateRef bitfield = Load(VariableType::INT32(), hClass, bitfieldOffset);
343    return NotEqual(Int32And(Int32LSR(bitfield,
344        Int32(JSHClass::ExtensibleBit::START_BIT)),
345        Int32((1LU << JSHClass::ExtensibleBit::SIZE) - 1)),
346        Int32(0));
347}
348
349GateRef CircuitBuilder::IsClassPrototype(GateRef object)
350{
351    GateRef hClass = LoadHClass(object);
352    GateRef bitfieldOffset = IntPtr(JSHClass::BIT_FIELD_OFFSET);
353    GateRef bitfield = Load(VariableType::INT32(), hClass, bitfieldOffset);
354    // decode
355    return IsClassPrototypeWithBitField(bitfield);
356}
357
358GateRef CircuitBuilder::IsClassPrototypeWithBitField(GateRef bitfield)
359{
360    auto classBitMask = 1LU << JSHClass::IsClassConstructorOrPrototypeBit::START_BIT;
361    auto ptBitMask = 1LU << JSHClass::IsPrototypeBit::START_BIT;
362    auto mask = Int32(classBitMask | ptBitMask);
363    auto classPt = Int32And(bitfield, mask);
364    return Int32Equal(classPt, mask);
365}
366
367GateRef CircuitBuilder::CreateWeakRef(GateRef x)
368{
369    return PtrAdd(x, IntPtr(JSTaggedValue::TAG_WEAK));
370}
371
372GateRef CircuitBuilder::LoadObjectFromWeakRef(GateRef x)
373{
374    return PtrAdd(x, IntPtr(-JSTaggedValue::TAG_WEAK));
375}
376
377// ctor is base but not builtin
378inline GateRef CircuitBuilder::IsBase(GateRef ctor)
379{
380    GateRef method = GetMethodFromFunction(ctor);
381    GateRef extraLiteralInfoOffset = IntPtr(Method::EXTRA_LITERAL_INFO_OFFSET);
382    GateRef bitfield = Load(VariableType::INT32(), method, extraLiteralInfoOffset);
383
384    GateRef kind = Int32And(Int32LSR(bitfield, Int32(MethodLiteral::FunctionKindBits::START_BIT)),
385                            Int32((1LU << MethodLiteral::FunctionKindBits::SIZE) - 1));
386    return Int32LessThanOrEqual(kind, Int32(static_cast<int32_t>(FunctionKind::CLASS_CONSTRUCTOR)));
387}
388
389inline GateRef CircuitBuilder::IsDerived(GateRef ctor)
390{
391    GateRef method = GetMethodFromFunction(ctor);
392    GateRef extraLiteralInfoOffset = IntPtr(Method::EXTRA_LITERAL_INFO_OFFSET);
393    GateRef bitfield = Load(VariableType::INT32(), method, extraLiteralInfoOffset);
394
395    GateRef kind = Int32And(Int32LSR(bitfield, Int32(MethodLiteral::FunctionKindBits::START_BIT)),
396                            Int32((1LU << MethodLiteral::FunctionKindBits::SIZE) - 1));
397    return Int32Equal(kind, Int32(static_cast<int32_t>(FunctionKind::DERIVED_CONSTRUCTOR)));
398}
399
400inline GateRef CircuitBuilder::GetMethodId(GateRef func)
401{
402    GateRef method = GetMethodFromFunction(func);
403    GateRef literalInfoOffset = IntPtr(Method::LITERAL_INFO_OFFSET);
404    GateRef literalInfo = Load(VariableType::INT64(), method, literalInfoOffset);
405    GateRef methodId = Int64And(Int64LSR(literalInfo, Int64(MethodLiteral::MethodIdBits::START_BIT)),
406        Int64((1LLU << MethodLiteral::MethodIdBits::SIZE) - 1));
407    return methodId;
408}
409
410inline GateRef CircuitBuilder::GetBuiltinsId(GateRef func)
411{
412    GateRef method = GetMethodFromFunction(func);
413    GateRef extraLiteralInfoOffset = IntPtr(Method::EXTRA_LITERAL_INFO_OFFSET);
414    GateRef extraLiteralInfo = Load(VariableType::INT64(), method, extraLiteralInfoOffset);
415    GateRef builtinsId = Int64And(Int64LSR(extraLiteralInfo, Int64(MethodLiteral::BuiltinIdBits::START_BIT)),
416        Int64((1LLU << MethodLiteral::BuiltinIdBits::SIZE) - 1));
417    return builtinsId;
418}
419}
420#endif  // ECMASCRIPT_COMPILER_HCR_CIRCUIT_BUILDER_H
421