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