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