1 /* 2 * Copyright (c) 2021 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_ECMA_MACROS_H 17 #define ECMASCRIPT_ECMA_MACROS_H 18 19 #include "ecmascript/common.h" 20 #include "ecmascript/log_wrapper.h" 21 22 #if defined(ENABLE_BYTRACE) 23 #include "hitrace_meter.h" 24 #endif 25 26 #if defined(__cplusplus) 27 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 28 29 #define OPTIONAL_LOG(vm, level) LOG_ECMA_IF(vm->IsOptionalLogEnabled(), level) 30 #define OPTIONAL_LOG_COMPILER(level) LOG_ECMA_IF(IsLogEnabled(), level) 31 32 #if !defined(ENABLE_BYTRACE) 33 #define ECMA_BYTRACE_NAME(tag, name) 34 #else 35 #define ECMA_BYTRACE_NAME(tag, name) HITRACE_METER_NAME(tag, name) 36 #endif 37 38 #if defined(ENABLE_HITRACE) 39 #define ENQUEUE_JOB_HITRACE(pendingJob, queueType) job::EnqueueJobScope hitraceScope(pendingJob, queueType) 40 #define EXECUTE_JOB_HITRACE(pendingJob) job::ExecuteJobScope hitraceScope(pendingJob) 41 #else 42 #define ENQUEUE_JOB_HITRACE(pendingJob, queueType) 43 #define EXECUTE_JOB_HITRACE(pendingJob) 44 #endif 45 46 /* Note: We can't statically decide the element type is a primitive or heap object, especially for */ 47 /* dynamically-typed languages like JavaScript. So we simply skip the read-barrier. */ 48 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 49 #define GET_VALUE(addr, offset) Barriers::GetValue<JSTaggedType>((addr), (offset)) 50 51 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 52 #define SET_VALUE_WITH_BARRIER(thread, addr, offset, value) \ 53 if ((value).IsHeapObject()) { \ 54 Barriers::SetObject<true>(thread, addr, offset, (value).GetRawData()); \ 55 } else { \ 56 Barriers::SetPrimitive<JSTaggedType>(addr, offset, (value).GetRawData()); \ 57 } 58 59 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 60 #define SET_VALUE_PRIMITIVE(addr, offset, value) \ 61 Barriers::SetPrimitive<JSTaggedType>(this, offset, (value).GetRawData()) 62 63 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 64 #define ACCESSORS(name, offset, endOffset) \ 65 static constexpr size_t endOffset = (offset) + JSTaggedValue::TaggedTypeSize(); \ 66 JSTaggedValue Get##name() const \ 67 { \ 68 /* Note: We can't statically decide the element type is a primitive or heap object, especially for */ \ 69 /* dynamically-typed languages like JavaScript. So we simply skip the read-barrier. */ \ 70 return JSTaggedValue(Barriers::GetValue<JSTaggedType>(this, offset)); \ 71 } \ 72 template<typename T> \ 73 void Set##name(const JSThread *thread, JSHandle<T> value, BarrierMode mode = WRITE_BARRIER) \ 74 { \ 75 if (mode == WRITE_BARRIER) { \ 76 if (value.GetTaggedValue().IsHeapObject()) { \ 77 Barriers::SetObject<true>(thread, this, offset, value.GetTaggedValue().GetRawData()); \ 78 } else { \ 79 Barriers::SetPrimitive<JSTaggedType>(this, offset, value.GetTaggedValue().GetRawData()); \ 80 } \ 81 } else { \ 82 Barriers::SetPrimitive<JSTaggedType>(this, offset, value.GetTaggedValue().GetRawData()); \ 83 } \ 84 } \ 85 void Set##name(const JSThread *thread, JSTaggedValue value, BarrierMode mode = WRITE_BARRIER) \ 86 { \ 87 if (mode == WRITE_BARRIER) { \ 88 if (value.IsHeapObject()) { \ 89 Barriers::SetObject<true>(thread, this, offset, value.GetRawData()); \ 90 } else { \ 91 Barriers::SetPrimitive<JSTaggedType>(this, offset, value.GetRawData()); \ 92 } \ 93 } else { \ 94 Barriers::SetPrimitive<JSTaggedType>(this, offset, value.GetRawData()); \ 95 } \ 96 } 97 98 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 99 #define ACCESSORS_SYNCHRONIZED(name, offset, endOffset) \ 100 static constexpr size_t endOffset = (offset) + JSTaggedValue::TaggedTypeSize(); \ 101 JSTaggedValue Get##name() const \ 102 { \ 103 /* Note: We can't statically decide the element type is a primitive or heap object, especially for */ \ 104 /* dynamically-typed languages like JavaScript. So we simply skip the read-barrier. */ \ 105 /* Synchronized means it will restrain the store and load in atomic. */ \ 106 return JSTaggedValue(reinterpret_cast<volatile std::atomic<JSTaggedType> *>(ToUintPtr(this) + offset) \ 107 ->load(std::memory_order_acquire)); \ 108 } \ 109 template<typename T> \ 110 void Set##name(const JSThread *thread, JSHandle<T> value) \ 111 { \ 112 bool isPrimitive = !value.GetTaggedValue().IsHeapObject(); \ 113 Barriers::SynchronizedSetObject(thread, this, offset, value.GetTaggedValue().GetRawData(), isPrimitive); \ 114 } \ 115 void Set##name(const JSThread *thread, JSTaggedValue value) \ 116 { \ 117 bool isPrimitive = !value.IsHeapObject(); \ 118 Barriers::SynchronizedSetObject(thread, this, offset, value.GetRawData(), isPrimitive); \ 119 } 120 121 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 122 #define DEFINE_ALIGN_SIZE(offset) \ 123 static constexpr size_t SIZE = ((offset) + sizeof(JSTaggedType) - 1U) & (~(sizeof(JSTaggedType) - 1U)) 124 125 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 126 #define ACCESSORS_FIXED_SIZE_FIELD(name, type, sizeType, offset, endOffset) \ 127 static_assert(sizeof(type) <= sizeof(sizeType)); \ 128 static constexpr size_t endOffset = (offset) + sizeof(sizeType); \ 129 inline void Set##name(type value) \ 130 { \ 131 Barriers::SetPrimitive<type>(this, offset, value); \ 132 } \ 133 inline type Get##name() const \ 134 { \ 135 return Barriers::GetValue<type>(this, offset); \ 136 } 137 138 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 139 #define ACCESSORS_NATIVE_FIELD(name, type, offset, endOffset) \ 140 ACCESSORS_FIXED_SIZE_FIELD(name, type *, type *, offset, endOffset) 141 142 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 143 #define ACCESSORS_PRIMITIVE_FIELD(name, type, offset, endOffset) \ 144 ACCESSORS_FIXED_SIZE_FIELD(name, type, type, offset, endOffset) 145 146 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 147 #define ACCESSORS_BIT_FIELD(name, offset, endOffset) \ 148 ACCESSORS_FIXED_SIZE_FIELD(name, uint32_t, uint32_t, offset, endOffset) \ 149 inline void Clear##name() \ 150 { \ 151 Set##name(0UL); \ 152 } 153 154 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 155 #define SET_GET_BIT_FIELD(bitFieldName, name, type) \ 156 inline type Get##name() const \ 157 { \ 158 return name##Bits::Decode(Get##bitFieldName()); \ 159 } \ 160 inline void Set##name(type t) \ 161 { \ 162 Set##bitFieldName(name##Bits::Update(Get##bitFieldName(), t)); \ 163 } 164 165 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 166 #define FIRST_BIT_FIELD(bitFieldName, name, type, bits) \ 167 using name##Bits = BitField<type, 0, bits>; \ 168 SET_GET_BIT_FIELD(bitFieldName, name, type) 169 170 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 171 #define NEXT_BIT_FIELD(bitFieldName, name, type, bits, lastName) \ 172 using name##Bits = lastName##Bits::NextField<type, bits>; \ 173 SET_GET_BIT_FIELD(bitFieldName, name, type) 174 175 #if !defined(NDEBUG) 176 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 177 #define DASSERT(cond) assert(cond) 178 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 179 #define DASSERT_PRINT(cond, message) \ 180 if (auto cond_val = (cond); UNLIKELY(!(cond_val))) { \ 181 std::cerr << (message) << std::endl; \ 182 ASSERT(#cond &&cond_val); \ 183 } 184 #else // NDEBUG 185 #define DASSERT(cond) static_cast<void>(0) // NOLINT(cppcoreguidelines-macro-usage) 186 #define DASSERT_PRINT(cond, message) static_cast<void>(0) // NOLINT(cppcoreguidelines-macro-usage) 187 #endif // !NDEBUG 188 189 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 190 #define RASSERT(cond) assert(cond) 191 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 192 #define RASSERT_PRINT(cond, message) \ 193 if (auto cond_val = cond; UNLIKELY(!(cond_val))) { \ 194 std::cerr << message << std::endl; \ 195 RASSERT(#cond &&cond_val); \ 196 } 197 198 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 199 #define RETURN_IF_ABRUPT_COMPLETION(thread) \ 200 do { \ 201 if ((thread)->HasPendingException()) { \ 202 return; \ 203 } \ 204 } while (false) 205 206 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 207 #define RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, value) \ 208 do { \ 209 if ((thread)->HasPendingException()) { \ 210 return (value); \ 211 } \ 212 } while (false) 213 214 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 215 #define RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread) \ 216 do { \ 217 if ((thread)->HasPendingException()) { \ 218 return JSTaggedValue::Exception(); \ 219 } \ 220 } while (false) 221 222 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 223 #define RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, value) \ 224 do { \ 225 if ((thread)->HasPendingException()) { \ 226 auto ecmaContext = thread->GetCurrentEcmaContext(); \ 227 ecmaContext->JoinStackPopFastPath(value); \ 228 return JSTaggedValue::Exception(); \ 229 } \ 230 } while (false) 231 232 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 233 #define RETURN_HANDLE_IF_ABRUPT_COMPLETION(type, thread) \ 234 do { \ 235 if ((thread)->HasPendingException()) { \ 236 return JSHandle<type>(thread, JSTaggedValue::Exception()); \ 237 } \ 238 } while (false) 239 240 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 241 #define ASSERT_NO_ABRUPT_COMPLETION(thread) ASSERT(!(thread)->HasPendingException()); 242 243 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 244 #define SET_DATE_VALUE(name, code, isLocal) \ 245 static JSTaggedValue name(EcmaRuntimeCallInfo *argv) \ 246 { \ 247 ASSERT(argv); \ 248 JSThread *thread = argv->GetThread(); \ 249 JSHandle<JSTaggedValue> msg = GetThis(argv); \ 250 if (!msg->IsDate()) { \ 251 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \ 252 } \ 253 JSHandle<JSDate> jsDate(thread, JSDate::Cast(msg->GetTaggedObject())); \ 254 JSTaggedValue result = jsDate->SetDateValue(argv, code, isLocal); \ 255 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); \ 256 jsDate->SetTimeValue(thread, result); \ 257 return result; \ 258 } 259 260 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 261 #define DATE_TO_STRING(name) \ 262 static JSTaggedValue name(EcmaRuntimeCallInfo *argv) \ 263 { \ 264 ASSERT(argv); \ 265 JSThread *thread = argv->GetThread(); \ 266 JSHandle<JSTaggedValue> msg = GetThis(argv); \ 267 if (!msg->IsDate()) { \ 268 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \ 269 } \ 270 if (std::isnan(JSDate::Cast(msg->GetTaggedObject())->GetTimeValue().GetDouble())) { \ 271 THROW_RANGE_ERROR_AND_RETURN(thread, "range error", JSTaggedValue::Exception()); \ 272 } \ 273 return JSDate::Cast(msg->GetTaggedObject())->name(thread); \ 274 } 275 276 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 277 #define DATE_STRING(name) \ 278 static JSTaggedValue name(EcmaRuntimeCallInfo *argv) \ 279 { \ 280 ASSERT(argv); \ 281 JSThread *thread = argv->GetThread(); \ 282 JSHandle<JSTaggedValue> msg = GetThis(argv); \ 283 if (!msg->IsDate()) { \ 284 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \ 285 } \ 286 if (std::isnan(JSDate::Cast(msg->GetTaggedObject())->GetTimeValue().GetDouble())) { \ 287 return thread->GetEcmaVM()->GetFactory()->NewFromASCII("Invalid Date").GetTaggedValue(); \ 288 } \ 289 return JSDate::Cast(msg->GetTaggedObject())->name(thread); \ 290 } 291 292 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 293 #define GET_DATE_VALUE(name, code, isLocal) \ 294 static JSTaggedValue name(EcmaRuntimeCallInfo *argv) \ 295 { \ 296 ASSERT(argv); \ 297 JSThread *thread = argv->GetThread(); \ 298 JSHandle<JSTaggedValue> msg = GetThis(argv); \ 299 if (!msg->IsDate()) { \ 300 THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \ 301 } \ 302 JSHandle<JSDate> jsDate(thread, JSDate::Cast(msg->GetTaggedObject())); \ 303 double result = jsDate->GetDateValue(jsDate->GetTimeValue().GetDouble(), code, isLocal); \ 304 return GetTaggedDouble(result); \ 305 } 306 307 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 308 #define THROW_NEW_ERROR_AND_RETURN(thread, error) \ 309 do { \ 310 if (!(thread)->HasPendingException()) { \ 311 (thread)->SetException(error); \ 312 } \ 313 return; \ 314 } while (false) 315 316 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 317 #define THROW_ERROR(thread, type, message) \ 318 do { \ 319 if ((thread)->HasPendingException()) { \ 320 return; \ 321 } \ 322 ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory(); \ 323 JSHandle<JSObject> _error = _factory->GetJSError(type, message); \ 324 (thread)->SetException(_error.GetTaggedValue()); \ 325 return; \ 326 } while (false) 327 328 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 329 #define THROW_UNCATCHABLE_ERROR(thread, type, message) \ 330 do { \ 331 EcmaVM *_ecmaVm = (thread)->GetEcmaVM(); \ 332 ObjectFactory *_factory = _ecmaVm->GetFactory(); \ 333 JSHandle<JSObject> _error = _factory->GetJSError(type, message); \ 334 (thread)->SetException(_error.GetTaggedValue()); \ 335 _ecmaVm->HandleUncatchableError(); \ 336 } while (false) 337 338 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 339 #define THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, value) \ 340 do { \ 341 if (!(thread)->HasPendingException()) { \ 342 (thread)->SetException(error); \ 343 } \ 344 return (value); \ 345 } while (false) 346 347 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 348 #define THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, errorType, type, message) \ 349 do { \ 350 if ((thread)->HasPendingException()) { \ 351 return JSHandle<type>(thread, JSTaggedValue::Exception()); \ 352 } \ 353 ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory(); \ 354 JSHandle<JSObject> _error = _factory->GetJSError(errorType, message); \ 355 (thread)->SetException(_error.GetTaggedValue()); \ 356 return JSHandle<type>(thread, JSTaggedValue::Exception()); \ 357 } while (false) 358 359 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 360 #define THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, errorType, message, value) \ 361 do { \ 362 if ((thread)->HasPendingException()) { \ 363 return (value); \ 364 } \ 365 ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory(); \ 366 JSHandle<JSObject> _error = _factory->GetJSError(errorType, message); \ 367 (thread)->SetException(_error.GetTaggedValue()); \ 368 return (value); \ 369 } while (false) 370 371 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 372 #define THROW_TYPE_ERROR_AND_RETURN(thread, message, value) \ 373 THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::TYPE_ERROR, message, value) 374 375 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 376 #define THROW_RANGE_ERROR_AND_RETURN(thread, message, value) \ 377 THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::RANGE_ERROR, message, value) 378 379 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 380 #define THROW_URI_ERROR_AND_RETURN(thread, message, value) \ 381 THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::URI_ERROR, message, value) 382 383 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 384 #define THROW_SYNTAX_ERROR_AND_RETURN(thread, message, value) \ 385 THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::SYNTAX_ERROR, message, value) 386 387 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 388 #define THROW_REFERENCE_ERROR_AND_RETURN(thread, message, value) \ 389 THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::REFERENCE_ERROR, message, value) 390 391 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 392 #define THROW_TYPE_ERROR(thread, message) \ 393 THROW_ERROR(thread, ErrorType::TYPE_ERROR, message) 394 395 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 396 #define THROW_OOM_ERROR(thread, message) \ 397 THROW_UNCATCHABLE_ERROR(thread, ErrorType::OOM_ERROR, message) 398 399 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 400 #define THROW_TERMINATION_ERROR(thread, message) \ 401 THROW_ERROR(thread, ErrorType::TERMINATION_ERROR, message) 402 403 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 404 #define RETURN_STACK_BEFORE_THROW_IF_ASM(thread) \ 405 do { \ 406 if ((thread)->IsAsmInterpreter()) { \ 407 FrameIterator it(const_cast<JSTaggedType *>((thread)->GetCurrentSPFrame()), (thread)); \ 408 it.Advance(); \ 409 (thread)->SetCurrentSPFrame(it.GetSp()); \ 410 } \ 411 } while (false) 412 413 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 414 #define RETURN_REJECT_PROMISE_IF_ABRUPT(thread, value, capability) \ 415 do { \ 416 const GlobalEnvConstants *globalConst = (thread)->GlobalConstants(); \ 417 if ((value).GetTaggedValue().IsCompletionRecord()) { \ 418 JSHandle<CompletionRecord> record = JSHandle<CompletionRecord>::Cast(value); \ 419 if (record->IsThrow()) { \ 420 JSHandle<JSTaggedValue> reject(thread, (capability)->GetReject()); \ 421 JSHandle<JSTaggedValue> undefine = globalConst->GetHandledUndefined(); \ 422 EcmaRuntimeCallInfo *info = \ 423 EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefine, undefine, 1); \ 424 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); \ 425 info->SetCallArg(record->GetValue()); \ 426 JSTaggedValue res = JSFunction::Call(info); \ 427 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res); \ 428 return (capability)->GetPromise(); \ 429 } \ 430 } \ 431 if ((thread)->HasPendingException()) { \ 432 (thread)->ClearException(); \ 433 JSHandle<JSTaggedValue> reject(thread, (capability)->GetReject()); \ 434 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); \ 435 EcmaRuntimeCallInfo *info = \ 436 EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1); \ 437 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); \ 438 info->SetCallArg(value.GetTaggedValue()); \ 439 JSTaggedValue res = JSFunction::Call(info); \ 440 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res); \ 441 return (capability)->GetPromise(); \ 442 } \ 443 } while (false) 444 445 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 446 #define RETURN_COMPLETION_IF_ABRUPT(thread, value) \ 447 do { \ 448 if ((thread)->HasPendingException()) { \ 449 JSHandle<CompletionRecord> completionRecord = \ 450 factory->NewCompletionRecord(CompletionRecordType::THROW, value); \ 451 return (completionRecord); \ 452 } \ 453 } while (false) 454 455 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 456 #define RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, value) \ 457 do { \ 458 if ((thread)->HasPendingException()) { \ 459 JSHandle<CompletionRecord> completionRecord = \ 460 factory->NewCompletionRecord(CompletionRecordType::THROW, value); \ 461 return (completionRecord).GetTaggedValue(); \ 462 } \ 463 } while (false) 464 465 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 466 #define DECL_DUMP() \ 467 void Dump(std::ostream &os) const DUMP_API_ATTR; \ 468 void Dump() const DUMP_API_ATTR \ 469 { \ 470 Dump(std::cout); \ 471 } \ 472 void DumpForSnapshot(std::vector<Reference> &vec) const; 473 474 #endif // defined(__cplusplus) 475 476 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 477 #define DECL_CAST(TYPE) \ 478 static TYPE *Cast(TaggedObject *object) \ 479 { \ 480 ASSERT(JSTaggedValue(object).Is##TYPE()); \ 481 return reinterpret_cast<TYPE *>(object); \ 482 } 483 484 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 485 #define DECL_VISIT_ARRAY(BEGIN_OFFSET, REF_LENGTH, LENGTH) \ 486 template <VisitType visitType> \ 487 void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ 488 { \ 489 ArrayBodyIterator<visitType, (BEGIN_OFFSET)>::IterateBody(this, visitor, (REF_LENGTH), (LENGTH)); \ 490 } 491 492 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 493 #define DECL_VISIT_OBJECT(BEGIN_OFFSET, END_OFFSET) \ 494 template <VisitType visitType> \ 495 void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ 496 { \ 497 ObjectBodyIterator<visitType, (BEGIN_OFFSET), (END_OFFSET), SIZE>::IterateRefBody(this, visitor); \ 498 } 499 500 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 501 #define DECL_VISIT_PRIMITIVE_OBJECT() \ 502 template <VisitType visitType> \ 503 void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ 504 { \ 505 PrimitiveObjectBodyIterator<visitType, SIZE>::IterateBody(this, visitor); \ 506 } 507 508 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 509 #define DECL_VISIT_NATIVE_FIELD(BEGIN_OFFSET, END_OFFSET) \ 510 template <VisitType visitType> \ 511 void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ 512 { \ 513 ObjectBodyIterator<visitType, (BEGIN_OFFSET), (END_OFFSET), SIZE>::IterateNativeBody(this, visitor); \ 514 } \ 515 516 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 517 #define DECL_VISIT_OBJECT_FOR_JS_OBJECT(PARENTCLASS, BEGIN_OFFSET, END_OFFSET) \ 518 template <VisitType visitType> \ 519 void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ 520 { \ 521 VisitObjects<visitType>(visitor); \ 522 JSObjectBodyIterator<visitType, SIZE>::IterateBody(this, visitor); \ 523 } \ 524 template <VisitType visitType> \ 525 void VisitObjects(const EcmaObjectRangeVisitor &visitor) \ 526 { \ 527 PARENTCLASS::VisitObjects<visitType>(visitor); \ 528 if ((BEGIN_OFFSET) == (END_OFFSET)) { \ 529 return; \ 530 } \ 531 ObjectBodyIterator<visitType, (BEGIN_OFFSET), \ 532 (END_OFFSET), SIZE>::IterateRefBody(this, visitor, PARENTCLASS::SIZE); \ 533 } 534 535 #if ECMASCRIPT_ENABLE_CAST_CHECK 536 #define CAST_CHECK(CAST_TYPE, CHECK_METHOD) \ 537 static inline CAST_TYPE *Cast(TaggedObject *object) \ 538 { \ 539 if (!JSTaggedValue(object).CHECK_METHOD()) { \ 540 std::abort(); \ 541 } \ 542 return static_cast<CAST_TYPE *>(object); \ 543 } \ 544 static inline const CAST_TYPE *ConstCast(const TaggedObject *object) \ 545 { \ 546 if (!JSTaggedValue(object).CHECK_METHOD()) { \ 547 std::abort(); \ 548 } \ 549 return static_cast<const CAST_TYPE *>(object); \ 550 } \ 551 static inline CAST_TYPE *Cast(JSTaggedValue value) \ 552 { \ 553 if (!value.CHECK_METHOD()) { \ 554 std::abort(); \ 555 } \ 556 return static_cast<CAST_TYPE *>(value.GetTaggedObject()); \ 557 } 558 # else 559 #define CAST_CHECK(CAST_TYPE, CHECK_METHOD) \ 560 static inline CAST_TYPE *Cast(TaggedObject *object) \ 561 { \ 562 ASSERT(JSTaggedValue(object).CHECK_METHOD()); \ 563 return static_cast<CAST_TYPE *>(object); \ 564 } \ 565 static const inline CAST_TYPE *ConstCast(const TaggedObject *object) \ 566 { \ 567 ASSERT(JSTaggedValue(object).CHECK_METHOD()); \ 568 return static_cast<const CAST_TYPE *>(object); \ 569 } \ 570 static inline CAST_TYPE *Cast(JSTaggedValue value) \ 571 { \ 572 ASSERT(value.CHECK_METHOD()); \ 573 return static_cast<CAST_TYPE *>(value.GetTaggedObject()); \ 574 } 575 576 #define CAST_NO_CHECK(CAST_TYPE) \ 577 static inline CAST_TYPE *Cast(TaggedObject *object) \ 578 { \ 579 return static_cast<CAST_TYPE *>(object); \ 580 } \ 581 static const inline CAST_TYPE *ConstCast(const TaggedObject *object) \ 582 { \ 583 return static_cast<const CAST_TYPE *>(object); \ 584 } 585 #endif 586 587 #define CHECK_OBJECT_SIZE(size) \ 588 if ((size) == 0) { \ 589 LOG_FULL(FATAL) << __func__ << ":" << __LINE__ << " objectSize is " << (size); \ 590 } 591 592 #define CHECK_REGION_END(begin, end) \ 593 if ((begin) > (end)) { \ 594 LOG_FULL(FATAL) << __func__ << ":" << __LINE__ << " begin: " << (begin) << " end: " << (end); \ 595 } 596 597 #define CHECK_JS_THREAD(vm) \ 598 if (!(vm)->GetJSThread()->IsCrossThreadExecutionEnable()) { \ 599 ASSERT((vm)->GetJSThread()->GetThreadId() == JSThread::GetCurrentThreadId()); \ 600 } 601 602 #if !defined(NDEBUG) 603 #define STACK_ASSERT_SCOPE(thread) [[maybe_unused]] StackAssertScope stackAssertScope = StackAssertScope(thread) 604 #else 605 #define STACK_ASSERT_SCOPE(thread) static_cast<void>(0) 606 #endif 607 608 #if !defined(NDEBUG) 609 #define BUILTINS_ENTRY_DEBUG_LOG() LOG_BUILTINS(DEBUG) << "Builtins C++ " << __func__ 610 #else 611 #define BUILTINS_ENTRY_DEBUG_LOG() static_cast<void>(0) 612 #endif 613 614 #if defined(ARK_NOT_SUPPORT_INTL_GLOBAL) 615 #define ARK_SUPPORT_INTL_RETURN_STR(msg) "Please use import intl lib "#msg 616 #define ARK_SUPPORT_INTL_RETURN(thread, message) \ 617 THROW_TYPE_ERROR(thread, ARK_SUPPORT_INTL_RETURN_STR(message)) 618 #define ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, message) \ 619 THROW_TYPE_ERROR_AND_RETURN(thread, \ 620 ARK_SUPPORT_INTL_RETURN_STR(message), JSTaggedValue::Exception()) 621 #else 622 #define ARK_SUPPORT_INTL_RETURN(thread, message) static_cast<void>(0) 623 #define ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, message) static_cast<void>(0) 624 #endif 625 626 #define STACK_LIMIT_CHECK(thread, retVal) \ 627 do { \ 628 if ((thread)->DoStackLimitCheck()) { \ 629 return (retVal); \ 630 } \ 631 } while (0) 632 633 #define STACK_LIMIT_CHECK_VOID(thread) \ 634 do { \ 635 if ((thread)->DoStackLimitCheck()) { \ 636 return; \ 637 } \ 638 } while (0) 639 640 #define CHECK_SLOTID_BREAK(slotId) \ 641 if ((slotId) == 0xff) { \ 642 break; \ 643 } 644 645 #endif // ECMASCRIPT_ECMA_MACROS_H 646