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 
23 namespace panda::ecmascript::kungfu {
24 
IsSpecial(GateRef x, JSTaggedType type)25 GateRef 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 
IsJSHClass(GateRef obj)33 inline GateRef CircuitBuilder::IsJSHClass(GateRef obj)
34 {
35     return Int32Equal(GetObjectType(LoadHClass(obj)), Int32(static_cast<int32_t>(JSType::HCLASS)));
36 }
37 
IsJSFunction(GateRef obj)38 inline 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 
IsJsType(GateRef obj, JSType type)48 GateRef 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 
IsJSObject(GateRef obj)54 GateRef 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 
IsCallableFromBitField(GateRef bitfield)77 GateRef 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 
IsCallable(GateRef obj)85 GateRef 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 
IsProtoTypeHClass(GateRef hClass)93 GateRef 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 
IsJsProxy(GateRef obj)101 GateRef 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 
IsTreeString(GateRef obj)107 GateRef 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 
IsSlicedString(GateRef obj)113 GateRef 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 
IsLineString(GateRef obj)119 GateRef 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 
IsConstantString(GateRef obj)125 GateRef 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 
ComputeSizeUtf8(GateRef length)131 GateRef CircuitBuilder::ComputeSizeUtf8(GateRef length)
132 {
133     return PtrAdd(IntPtr(LineEcmaString::DATA_OFFSET), length);
134 }
135 
ComputeSizeUtf16(GateRef length)136 GateRef CircuitBuilder::ComputeSizeUtf16(GateRef length)
137 {
138     return PtrAdd(IntPtr(LineEcmaString::DATA_OFFSET), PtrMul(length, IntPtr(sizeof(uint16_t))));
139 }
140 
AlignUp(GateRef x, GateRef alignment)141 GateRef 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 
IsDictionaryMode(GateRef object)147 inline 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 
IsStableArguments(GateRef hClass)153 GateRef 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 
IsStableArray(GateRef hClass)161 GateRef 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 
IsAOTLiteralInfo(GateRef x)169 GateRef 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 
LoadHClass(GateRef object)177 GateRef CircuitBuilder::LoadHClass(GateRef object)
178 {
179     GateRef offset = IntPtr(TaggedObject::HCLASS_OFFSET);
180     return Load(VariableType::JS_POINTER(), object, offset);
181 }
182 
LoadHClassByConstOffset(GateRef object)183 GateRef CircuitBuilder::LoadHClassByConstOffset(GateRef object)
184 {
185     return LoadConstOffset(VariableType::JS_POINTER(), object, TaggedObject::HCLASS_OFFSET);
186 }
187 
LoadPrototype(GateRef hclass)188 GateRef CircuitBuilder::LoadPrototype(GateRef hclass)
189 {
190     return LoadConstOffset(VariableType::JS_POINTER(), hclass, JSHClass::PROTOTYPE_OFFSET);
191 }
192 
LoadPrototypeHClass(GateRef object)193 GateRef CircuitBuilder::LoadPrototypeHClass(GateRef object)
194 {
195     GateRef objectHClass = LoadHClassByConstOffset(object);
196     GateRef objectPrototype = LoadPrototype(objectHClass);
197     return LoadHClass(objectPrototype);
198 }
199 
LoadPrototypeOfPrototypeHClass(GateRef object)200 GateRef 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 
GetObjectSizeFromHClass(GateRef hClass)209 GateRef 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 
IsDictionaryModeByHClass(GateRef hClass)219 GateRef 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 
StoreHClass(GateRef glue, GateRef object, GateRef hClass)229 void 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 
StoreHClassWithoutBarrier(GateRef glue, GateRef object, GateRef hClass)235 void 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 
StorePrototype(GateRef glue, GateRef hclass, GateRef prototype)241 void CircuitBuilder::StorePrototype(GateRef glue, GateRef hclass, GateRef prototype)
242 {
243     Store(VariableType::JS_POINTER(), glue, hclass, IntPtr(JSHClass::PROTOTYPE_OFFSET), prototype);
244 }
245 
GetObjectType(GateRef hClass)246 GateRef 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 
CanFastCall(GateRef jsFunc)253 inline 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 
GetElementsKindByHClass(GateRef hClass)264 GateRef 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 
HasConstructorByHClass(GateRef hClass)273 GateRef 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 
IsDictionaryElement(GateRef hClass)283 GateRef 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 
IsStableElements(GateRef hClass)293 GateRef 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 
HasConstructor(GateRef object)303 GateRef CircuitBuilder::HasConstructor(GateRef object)
304 {
305     GateRef hClass = LoadHClass(object);
306     return HasConstructorByHClass(hClass);
307 }
308 
IsConstructor(GateRef object)309 GateRef 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 
IsClassConstructor(GateRef object)321 GateRef 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 
IsClassConstructorWithBitField(GateRef bitfield)329 GateRef 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 
IsExtensible(GateRef object)338 GateRef 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 
IsClassPrototype(GateRef object)349 GateRef 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 
IsClassPrototypeWithBitField(GateRef bitfield)358 GateRef 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 
CreateWeakRef(GateRef x)367 GateRef CircuitBuilder::CreateWeakRef(GateRef x)
368 {
369     return PtrAdd(x, IntPtr(JSTaggedValue::TAG_WEAK));
370 }
371 
LoadObjectFromWeakRef(GateRef x)372 GateRef CircuitBuilder::LoadObjectFromWeakRef(GateRef x)
373 {
374     return PtrAdd(x, IntPtr(-JSTaggedValue::TAG_WEAK));
375 }
376 
377 // ctor is base but not builtin
IsBase(GateRef ctor)378 inline 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 
IsDerived(GateRef ctor)389 inline 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 
GetMethodId(GateRef func)400 inline 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 
GetBuiltinsId(GateRef func)410 inline 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