• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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