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