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