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