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 ACCESSORS_PRIMITIVE_FIELD_ATOMIC(name, type, offset)                                                     \
189     inline void AtomicSet##name(type value)                                                                      \
190     {                                                                                                            \
191         volatile auto *atomicField = reinterpret_cast<volatile std::atomic<type> *>(ToUintPtr(this) + (offset)); \
192         atomicField->store(value, std::memory_order_release);                                                    \
193     }                                                                                                            \
194     inline type AtomicGet##name() const                                                                          \
195     {                                                                                                            \
196         volatile auto *atomicField = reinterpret_cast<volatile std::atomic<type> *>(ToUintPtr(this) + (offset)); \
197         return atomicField->load(std::memory_order_acquire);                                                     \
198     }
199 
200 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
201 #define ACCESSORS_PRIMITIVE_FIELD_HAS_ATOMIC_INTERFACE(name, type, offset, endOffset) \
202     ACCESSORS_PRIMITIVE_FIELD(name, type, offset, endOffset)                          \
203     ACCESSORS_PRIMITIVE_FIELD_ATOMIC(name, type, offset)
204 
205 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
206 #define FIRST_BIT_FIELD(bitFieldName, name, type, bits) \
207     using name##Bits = BitField<type, 0, bits>;         \
208     SET_GET_BIT_FIELD(bitFieldName, name, type)
209 
210 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
211 #define NEXT_BIT_FIELD(bitFieldName, name, type, bits, lastName) \
212     using name##Bits = lastName##Bits::NextField<type, bits>;    \
213     SET_GET_BIT_FIELD(bitFieldName, name, type)
214 
215 #if !defined(NDEBUG)
216 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
217 #define DASSERT(cond) assert(cond)
218 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
219 #define DASSERT_PRINT(cond, message)                     \
220     if (auto cond_val = (cond); UNLIKELY(!(cond_val))) { \
221         std::cerr << (message) << std::endl;             \
222         ASSERT(#cond &&cond_val);                        \
223     }
224 #else                                                      // NDEBUG
225 #define DASSERT(cond) static_cast<void>(0)                 // NOLINT(cppcoreguidelines-macro-usage)
226 #define DASSERT_PRINT(cond, message) static_cast<void>(0)  // NOLINT(cppcoreguidelines-macro-usage)
227 #endif                                                     // !NDEBUG
228 
229 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
230 #define RASSERT(cond) assert(cond)
231 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
232 #define RASSERT_PRINT(cond, message)                   \
233     if (auto cond_val = cond; UNLIKELY(!(cond_val))) { \
234         std::cerr << message << std::endl;             \
235         RASSERT(#cond &&cond_val);                     \
236     }
237 
238 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
239 #define RETURN_IF_ABRUPT_COMPLETION(thread)    \
240     do {                                       \
241         if ((thread)->HasPendingException()) { \
242             return;                            \
243         }                                      \
244     } while (false)
245 
246 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
247 #define RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, value) \
248     do {                                                 \
249         if ((thread)->HasPendingException()) {           \
250             return (value);                              \
251         }                                                \
252     } while (false)
253 
254 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
255 #define RETURN_VALUE_IF_ABRUPT_COMPLETION_WITH_DATA_DELETE(thread, value, flagsStr) \
256     do {                                                                            \
257         if ((thread)->HasPendingException()) {                                      \
258             delete[] flagsStr;                                                      \
259             return (value);                                                         \
260         }                                                                           \
261     } while (false)
262 
263 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
264 #define RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread) \
265     do {                                              \
266         if ((thread)->HasPendingException()) {        \
267             return JSTaggedValue::Exception();        \
268         }                                             \
269     } while (false)
270 
271 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
272 #define RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, value)       \
273     do {                                                        \
274         if ((thread)->HasPendingException()) {                  \
275             auto ecmaContext = thread->GetCurrentEcmaContext(); \
276             ecmaContext->JoinStackPopFastPath(value);           \
277             return JSTaggedValue::Exception();                  \
278         }                                                       \
279     } while (false)
280 
281 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
282 #define RETURN_HANDLE_IF_ABRUPT_COMPLETION(type, thread)               \
283     do {                                                               \
284         if ((thread)->HasPendingException()) {                         \
285             return JSHandle<type>(thread, JSTaggedValue::Exception()); \
286         }                                                              \
287     } while (false)
288 
289 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
290 #define ASSERT_NO_ABRUPT_COMPLETION(thread) ASSERT(!(thread)->HasPendingException());
291 
292 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
293 #define SET_DATE_VALUE(name, code, isLocal)                                                       \
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         JSHandle<JSDate> jsDate(msg);                                                             \
304         JSTaggedValue result = jsDate->SetDateValue(argv, code, isLocal);                         \
305         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);                                            \
306         jsDate->SetTimeValue(thread, result);                                                     \
307         return result;                                                                            \
308     }
309 
310 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
311 #define DATE_TO_STRING(name)                                                                      \
312     static JSTaggedValue name(EcmaRuntimeCallInfo *argv)                                          \
313     {                                                                                             \
314         ASSERT(argv);                                                                             \
315         JSThread *thread = argv->GetThread();                                                     \
316         [[maybe_unused]] EcmaHandleScope handleScope(thread);                                     \
317         JSHandle<JSTaggedValue> msg = GetThis(argv);                                              \
318         if (!msg->IsDate()) {                                                                     \
319             THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \
320         }                                                                                         \
321         if (std::isnan(JSDate::Cast(msg->GetTaggedObject())->GetTimeValue().GetDouble())) {       \
322             THROW_RANGE_ERROR_AND_RETURN(thread, "range error", JSTaggedValue::Exception());      \
323         }                                                                                         \
324         return JSDate::Cast(msg->GetTaggedObject())->name(thread);                                \
325     }
326 
327 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
328 #define DATE_STRING(name)                                                                                          \
329     static JSTaggedValue name(EcmaRuntimeCallInfo *argv)                                                           \
330     {                                                                                                              \
331         ASSERT(argv);                                                                                              \
332         JSThread *thread = argv->GetThread();                                                                      \
333         [[maybe_unused]] EcmaHandleScope handleScope(thread);                                                      \
334         JSHandle<JSTaggedValue> msg = GetThis(argv);                                                               \
335         if (!msg->IsDate()) {                                                                                      \
336             THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception());                  \
337         }                                                                                                          \
338         if (std::isnan(JSDate::Cast(msg->GetTaggedObject())->GetTimeValue().GetDouble())) {                        \
339             return thread->GetEcmaVM()->GetFactory()->NewFromASCII("Invalid Date").GetTaggedValue();               \
340         }                                                                                                          \
341         return JSDate::Cast(msg->GetTaggedObject())->name(thread);                                                 \
342     }
343 
344 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
345 #define GET_DATE_VALUE(name, code, isLocal)                                                       \
346     static JSTaggedValue name(EcmaRuntimeCallInfo *argv)                                          \
347     {                                                                                             \
348         ASSERT(argv);                                                                             \
349         JSThread *thread = argv->GetThread();                                                     \
350         [[maybe_unused]] EcmaHandleScope handleScope(thread);                                     \
351         JSHandle<JSTaggedValue> msg = GetThis(argv);                                              \
352         if (!msg->IsDate()) {                                                                     \
353             THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \
354         }                                                                                         \
355         JSHandle<JSDate> jsDate(msg);                                                             \
356         double result = jsDate->GetDateValue(jsDate->GetTimeValue().GetDouble(), code, isLocal);  \
357         return GetTaggedDouble(result);                                                           \
358     }
359 
360 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
361 #define THROW_NEW_ERROR_AND_RETURN(thread, error)       \
362     do {                                                \
363         if (!(thread)->HasPendingException()) {         \
364             (thread)->SetException(error);              \
365         }                                               \
366         return;                                         \
367     } while (false)
368 
369 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
370 #define THROW_ERROR(thread, type, message)                                                              \
371     do {                                                                                                \
372         if ((thread)->HasPendingException()) {                                                          \
373             return;                                                                                     \
374         }                                                                                               \
375         ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory();                                  \
376         JSHandle<JSObject> _error = _factory->GetJSError(type, message, StackCheck::NO);                \
377         (thread)->SetException(_error.GetTaggedValue());                                                \
378         return;                                                                                         \
379     } while (false)
380 
381 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
382 #define THROW_UNCATCHABLE_ERROR(thread, type, message)                                                  \
383     do {                                                                                                \
384         EcmaVM *_ecmaVm = (thread)->GetEcmaVM();                                                        \
385         ObjectFactory *_factory = _ecmaVm->GetFactory();                                                \
386         JSHandle<JSObject> _error = _factory->GetJSError(type, message, StackCheck::NO);                \
387         (thread)->SetException(_error.GetTaggedValue());                                                \
388         _ecmaVm->HandleUncatchableError();                                                              \
389     } while (false)
390 
391 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
392 #define THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, value) \
393     do {                                                       \
394         if (!(thread)->HasPendingException()) {                \
395             (thread)->SetException(error);                     \
396         }                                                      \
397         return (value);                                        \
398     } while (false)
399 
400 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
401 #define THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, errorType, type, message)                                 \
402     do {                                                                                                    \
403         if ((thread)->HasPendingException()) {                                                              \
404             return JSHandle<type>(thread, JSTaggedValue::Exception());                                      \
405         }                                                                                                   \
406         ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory();                                      \
407         JSHandle<JSObject> _error = _factory->GetJSError(errorType, message, StackCheck::NO);               \
408         (thread)->SetException(_error.GetTaggedValue());                                                    \
409         return JSHandle<type>(thread, JSTaggedValue::Exception());                                          \
410     } while (false)
411 
412 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
413 #define THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, errorType, message, value)                        \
414     do {                                                                                                    \
415         if ((thread)->HasPendingException()) {                                                              \
416             return (value);                                                                                 \
417         }                                                                                                   \
418         ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory();                                      \
419         JSHandle<JSObject> _error = _factory->GetJSError(errorType, message, ecmascript::StackCheck::NO);   \
420         (thread)->SetException(_error.GetTaggedValue());                                                    \
421         return (value);                                                                                     \
422     } while (false)
423 
424 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
425 #define THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, requestStr, currentRecord, value)            \
426     do {                                                                                                    \
427         if ((thread)->HasPendingException()) {                                                              \
428             return (value);                                                                                 \
429         }                                                                                                   \
430         ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory();                                      \
431         CString normalizeStr = ModulePathHelper::ReformatPath(currentRecord);                               \
432         CString msg =  "Cannot find module '" + requestStr + "' imported from '" + normalizeStr + "'.";     \
433         JSHandle<JSObject> _error = _factory->GetJSError(ErrorType::REFERENCE_ERROR,                        \
434                                                          msg.c_str(), StackCheck::NO);                      \
435         (thread)->SetException(_error.GetTaggedValue());                                                    \
436         return (value);                                                                                     \
437     } while (false)
438 
439 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
440 #define THROW_TYPE_ERROR_AND_RETURN(thread, message, value)                                      \
441     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::TYPE_ERROR, message, value)
442 
443 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
444 #define THROW_RANGE_ERROR_AND_RETURN(thread, message, value)                                     \
445     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::RANGE_ERROR, message, value)
446 
447 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
448 #define THROW_URI_ERROR_AND_RETURN(thread, message, value)                                       \
449     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::URI_ERROR, message, value)
450 
451 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
452 #define THROW_SYNTAX_ERROR_AND_RETURN(thread, message, value)                                    \
453     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::SYNTAX_ERROR, message, value)
454 
455 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
456 #define THROW_REFERENCE_ERROR_AND_RETURN(thread, message, value)                                 \
457     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::REFERENCE_ERROR, message, value)
458 
459 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
460 #define THROW_TYPE_ERROR(thread, message)               \
461     THROW_ERROR(thread, ErrorType::TYPE_ERROR, message)
462 
463 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
464 #define THROW_OOM_ERROR(thread, message)                \
465     THROW_UNCATCHABLE_ERROR(thread, ErrorType::OOM_ERROR, message)
466 
467 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
468 #define THROW_TERMINATION_ERROR(thread, message)               \
469     THROW_ERROR(thread, ErrorType::TERMINATION_ERROR, message)
470 
471 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
472 #define RETURN_STACK_BEFORE_THROW_IF_ASM(thread)                                                   \
473     do {                                                                                           \
474         if ((thread)->IsAsmInterpreter()) {                                                        \
475             FrameIterator it(const_cast<JSTaggedType *>((thread)->GetCurrentSPFrame()), (thread)); \
476             it.Advance();                                                                          \
477             (thread)->SetCurrentSPFrame(it.GetSp());                                               \
478         }                                                                                          \
479     } while (false)
480 
481 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
482 #define RETURN_REJECT_PROMISE_IF_ABRUPT(thread, value, capability)                                 \
483     do {                                                                                           \
484         const GlobalEnvConstants *globalConst = (thread)->GlobalConstants();                       \
485         if ((value).GetTaggedValue().IsCompletionRecord()) {                                       \
486             JSHandle<CompletionRecord> record = JSHandle<CompletionRecord>::Cast(value);           \
487             if (record->IsThrow()) {                                                               \
488                 JSHandle<JSTaggedValue> reject(thread, (capability)->GetReject());                 \
489                 JSHandle<JSTaggedValue> undefine = globalConst->GetHandledUndefined();             \
490                 EcmaRuntimeCallInfo *info =                                                        \
491                     EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefine, undefine, 1);    \
492                 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());             \
493                 info->SetCallArg(record->GetValue());                                              \
494                 JSTaggedValue res = JSFunction::Call(info);                                        \
495                 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res);                                    \
496                 return (capability)->GetPromise();                                                 \
497             }                                                                                      \
498         }                                                                                          \
499         if ((thread)->HasPendingException()) {                                                     \
500             (thread)->ClearException();                                                            \
501             JSHandle<JSTaggedValue> reject(thread, (capability)->GetReject());                     \
502             JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();                \
503             EcmaRuntimeCallInfo *info =                                                            \
504                 EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1);      \
505             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());                 \
506             info->SetCallArg(value.GetTaggedValue());                                              \
507             JSTaggedValue res = JSFunction::Call(info);                                            \
508             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res);                                        \
509             return (capability)->GetPromise();                                                     \
510         }                                                                                          \
511     } while (false)
512 
513 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
514 #define RETURN_COMPLETION_IF_ABRUPT(thread, value)                                \
515     do {                                                                          \
516         if ((thread)->HasPendingException()) {                                    \
517             JSHandle<CompletionRecord> completionRecord =                         \
518                 factory->NewCompletionRecord(CompletionRecordType::THROW, value); \
519             return (completionRecord);                                            \
520         }                                                                         \
521     } while (false)
522 
523 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
524 #define RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, value)                          \
525     do {                                                                          \
526         if ((thread)->HasPendingException()) {                                    \
527             JSHandle<CompletionRecord> completionRecord =                         \
528                 factory->NewCompletionRecord(CompletionRecordType::THROW, value); \
529             return (completionRecord).GetTaggedValue();                           \
530         }                                                                         \
531     } while (false)
532 
533 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
534 #define DECL_DUMP()                                  \
535     void Dump(std::ostream &os) const DUMP_API_ATTR; \
536     void Dump() const DUMP_API_ATTR                  \
537     {                                                \
538         Dump(std::cout);                             \
539     }                                                \
540     void DumpForSnapshot(std::vector<Reference> &vec) const;
541 
542 #endif  // defined(__cplusplus)
543 
544 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
545 #define DECL_CAST(TYPE)                           \
546     static TYPE *Cast(TaggedObject *object)       \
547     {                                             \
548         ASSERT(JSTaggedValue(object).Is##TYPE()); \
549         return reinterpret_cast<TYPE *>(object);  \
550     }
551 
552 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
553 #define DECL_VISIT_ARRAY(BEGIN_OFFSET, REF_LENGTH, LENGTH)                                                \
554     template <VisitType visitType>                                                                        \
555     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)                                            \
556     {                                                                                                     \
557         ArrayBodyIterator<visitType, (BEGIN_OFFSET)>::IterateBody(this, visitor, (REF_LENGTH), (LENGTH)); \
558     }
559 
560 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
561 #define DECL_VISIT_OBJECT(BEGIN_OFFSET, END_OFFSET)                                                       \
562     template <VisitType visitType>                                                                        \
563     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)                                            \
564     {                                                                                                     \
565         ObjectBodyIterator<visitType, (BEGIN_OFFSET), (END_OFFSET), SIZE>::IterateRefBody(this, visitor); \
566     }
567 
568 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
569 #define DECL_VISIT_PRIMITIVE_OBJECT()                                               \
570     template <VisitType visitType>                                                  \
571     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)                      \
572     {                                                                               \
573         PrimitiveObjectBodyIterator<visitType, SIZE>::IterateBody(this, visitor);   \
574     }
575 
576 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
577 #define DECL_VISIT_NATIVE_FIELD(BEGIN_OFFSET, END_OFFSET)                                                    \
578     template <VisitType visitType>                                                                           \
579     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)                                               \
580     {                                                                                                        \
581         ObjectBodyIterator<visitType, (BEGIN_OFFSET), (END_OFFSET), SIZE>::IterateNativeBody(this, visitor); \
582     }                                                                                                        \
583 
584 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
585 #define DECL_VISIT_OBJECT_FOR_JS_OBJECT(PARENTCLASS, BEGIN_OFFSET, END_OFFSET)                         \
586     template <VisitType visitType>                                                                     \
587     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)                                         \
588     {                                                                                                  \
589         VisitObjects<visitType>(visitor);                                                              \
590         JSObjectBodyIterator<visitType, SIZE>::IterateBody(this, visitor);                             \
591     }                                                                                                  \
592     template <VisitType visitType>                                                                     \
593     void VisitObjects(const EcmaObjectRangeVisitor &visitor)                                           \
594     {                                                                                                  \
595         PARENTCLASS::VisitObjects<visitType>(visitor);                                                 \
596         static constexpr size_t PARENT_SIZE = PARENTCLASS::SIZE;                                       \
597         ObjectBodyIterator<visitType, (BEGIN_OFFSET),                                                  \
598             (END_OFFSET), SIZE, PARENT_SIZE>::IterateDerivedRefBody(this, visitor);                    \
599     }
600 
601 #if ECMASCRIPT_ENABLE_CAST_CHECK
602     #define CAST_CHECK(CAST_TYPE, CHECK_METHOD)                                                 \
603         static inline CAST_TYPE *Cast(TaggedObject *object)                                     \
604         {                                                                                       \
605             if (!JSTaggedValue(object).CHECK_METHOD()) {                                        \
606                 std::abort();                                                                   \
607             }                                                                                   \
608             return static_cast<CAST_TYPE *>(object);                                            \
609         }                                                                                       \
610         static inline const CAST_TYPE *ConstCast(const TaggedObject *object)                    \
611         {                                                                                       \
612             if (!JSTaggedValue(object).CHECK_METHOD()) {                                        \
613                 std::abort();                                                                   \
614             }                                                                                   \
615             return static_cast<const CAST_TYPE *>(object);                                      \
616         }                                                                                       \
617         static inline CAST_TYPE *Cast(JSTaggedValue value)                                      \
618         {                                                                                       \
619             if (!value.CHECK_METHOD()) {                                                        \
620                 std::abort();                                                                   \
621             }                                                                                   \
622             return static_cast<CAST_TYPE *>(value.GetTaggedObject());                           \
623         }
624 #else
625     #define CAST_CHECK(CAST_TYPE, CHECK_METHOD)                                                   \
626         static inline CAST_TYPE *Cast(TaggedObject *object)                                       \
627         {                                                                                         \
628             ASSERT(JSTaggedValue(object).CHECK_METHOD());                                         \
629             return static_cast<CAST_TYPE *>(object);                                              \
630         }                                                                                         \
631         static const inline CAST_TYPE *ConstCast(const TaggedObject *object)                      \
632         {                                                                                         \
633             ASSERT(JSTaggedValue(object).CHECK_METHOD());                                         \
634             return static_cast<const CAST_TYPE *>(object);                                        \
635         }                                                                                         \
636         static inline CAST_TYPE *Cast(JSTaggedValue value)                                        \
637         {                                                                                         \
638             ASSERT(value.CHECK_METHOD());                                                         \
639             return static_cast<CAST_TYPE *>(value.GetTaggedObject());                             \
640         }
641 #endif
642 
643 #define CAST_NO_CHECK(CAST_TYPE)                                                              \
644     static inline CAST_TYPE *Cast(TaggedObject *object)                                       \
645     {                                                                                         \
646         return static_cast<CAST_TYPE *>(object);                                              \
647     }                                                                                         \
648     static const inline CAST_TYPE *ConstCast(const TaggedObject *object)                      \
649     {                                                                                         \
650         return static_cast<const CAST_TYPE *>(object);                                        \
651     }
652 
653 #define CHECK_OBJECT_SIZE(size)                                                        \
654     if ((size) == 0) {                                                                 \
655         LOG_FULL(FATAL) << __func__ << ":" << __LINE__ << " objectSize is " << (size); \
656     }
657 
658 #define CHECK_REGION_END(begin, end)                                                                  \
659     if ((begin) > (end)) {                                                                            \
660         LOG_FULL(FATAL) << __func__ << ":" << __LINE__ << " begin: " << (begin) << " end: " << (end); \
661     }
662 
663 #define CHECK_JS_THREAD(vm)                                                           \
664     if (!(vm)->GetJSThread()->IsCrossThreadExecutionEnable()) {                       \
665         ASSERT((vm)->GetJSThread()->GetThreadId() == JSThread::GetCurrentThreadId()); \
666     }
667 #define CHECK_DAEMON_THREAD()                                                               \
668     ASSERT(os::thread::GetCurrentThreadId() == DaemonThread::GetInstance()->GetThreadId())
669 
670 #if !defined(NDEBUG)
671 #define STACK_ASSERT_SCOPE(thread) [[maybe_unused]] StackAssertScope stackAssertScope = StackAssertScope(thread)
672 #else
673 #define STACK_ASSERT_SCOPE(thread) static_cast<void>(0)
674 #endif
675 
676 #if !defined(NDEBUG)
677 #define BUILTINS_ENTRY_DEBUG_LOG() LOG_BUILTINS(DEBUG) << "Builtins C++ " << __func__
678 #else
679 #define BUILTINS_ENTRY_DEBUG_LOG() static_cast<void>(0)
680 #endif
681 
682 #if defined(ARK_NOT_SUPPORT_INTL_GLOBAL)
683 #define ARK_SUPPORT_INTL_RETURN_STR(msg) "Please use import intl lib "#msg
684 #define ARK_SUPPORT_INTL_RETURN(thread, message)                            \
685     THROW_TYPE_ERROR(thread, ARK_SUPPORT_INTL_RETURN_STR(message))
686 #define ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, message)                                                        \
687     THROW_TYPE_ERROR_AND_RETURN(thread,                                                                         \
688         ARK_SUPPORT_INTL_RETURN_STR(message), JSTaggedValue::Exception())
689 #else
690 #define ARK_SUPPORT_INTL_RETURN(thread, message) static_cast<void>(0)
691 #define ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, message) static_cast<void>(0)
692 #endif
693 
694 #define STACK_LIMIT_CHECK(thread, retVal)     \
695     do {                                      \
696         if ((thread)->DoStackLimitCheck()) {  \
697             return (retVal);                  \
698         }                                     \
699     } while (0)
700 
701 #define STACK_LIMIT_CHECK_VOID(thread)        \
702     do {                                      \
703         if ((thread)->DoStackLimitCheck()) {  \
704             return;                           \
705         }                                     \
706     } while (0)
707 
708 #define CHECK_SLOTID_BREAK(slotId)        \
709     if ((slotId) == 0xff) {               \
710         break;                            \
711     }
712 
713 #define CHECK_INPUT_NULLPTR(ptr, msg)     \
714     if ((ptr) == nullptr) {               \
715         LOG_FULL(FATAL) << (msg);         \
716         UNREACHABLE();                    \
717     }
718 
719 #endif  // ECMASCRIPT_ECMA_MACROS_H
720