• 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 DEFINE_ALIGN_SIZE(offset) \
100     static constexpr size_t SIZE = ((offset) + sizeof(JSTaggedType) - 1U) & (~(sizeof(JSTaggedType) - 1U))
101 
102 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
103 #define ACCESSORS_FIXED_SIZE_FIELD(name, type, sizeType, offset, endOffset) \
104     static_assert(sizeof(type) <= sizeof(sizeType));                        \
105     static constexpr size_t endOffset = (offset) + sizeof(sizeType);        \
106     inline void Set##name(type value)                                       \
107     {                                                                       \
108         Barriers::SetPrimitive<type>(this, offset, value);               \
109     }                                                                       \
110     inline type Get##name() const                                           \
111     {                                                                       \
112         return Barriers::GetValue<type>(this, offset);                   \
113     }
114 
115 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
116 #define ACCESSORS_NATIVE_FIELD(name, type, offset, endOffset) \
117     ACCESSORS_FIXED_SIZE_FIELD(name, type *, type *, offset, endOffset)
118 
119 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
120 #define ACCESSORS_PRIMITIVE_FIELD(name, type, offset, endOffset) \
121     ACCESSORS_FIXED_SIZE_FIELD(name, type, type, offset, endOffset)
122 
123 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
124 #define ACCESSORS_BIT_FIELD(name, offset, endOffset)                        \
125     ACCESSORS_FIXED_SIZE_FIELD(name, uint32_t, uint32_t, offset, endOffset) \
126     inline void Clear##name()                                               \
127     {                                                                       \
128         Set##name(0UL);                                                     \
129     }
130 
131 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
132 #define SET_GET_BIT_FIELD(bitFieldName, name, type)                    \
133     inline type Get##name() const                                      \
134     {                                                                  \
135         return name##Bits::Decode(Get##bitFieldName());                \
136     }                                                                  \
137     inline void Set##name(type t)                                      \
138     {                                                                  \
139         Set##bitFieldName(name##Bits::Update(Get##bitFieldName(), t)); \
140     }
141 
142 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
143 #define FIRST_BIT_FIELD(bitFieldName, name, type, bits) \
144     using name##Bits = BitField<type, 0, bits>;         \
145     SET_GET_BIT_FIELD(bitFieldName, name, type)
146 
147 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
148 #define NEXT_BIT_FIELD(bitFieldName, name, type, bits, lastName) \
149     using name##Bits = lastName##Bits::NextField<type, bits>;    \
150     SET_GET_BIT_FIELD(bitFieldName, name, type)
151 
152 #if !defined(NDEBUG)
153 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
154 #define DASSERT(cond) assert(cond)
155 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
156 #define DASSERT_PRINT(cond, message)                     \
157     if (auto cond_val = (cond); UNLIKELY(!(cond_val))) { \
158         std::cerr << (message) << std::endl;             \
159         ASSERT(#cond &&cond_val);                        \
160     }
161 #else                                                      // NDEBUG
162 #define DASSERT(cond) static_cast<void>(0)                 // NOLINT(cppcoreguidelines-macro-usage)
163 #define DASSERT_PRINT(cond, message) static_cast<void>(0)  // NOLINT(cppcoreguidelines-macro-usage)
164 #endif                                                     // !NDEBUG
165 
166 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
167 #define RASSERT(cond) assert(cond)
168 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
169 #define RASSERT_PRINT(cond, message)                   \
170     if (auto cond_val = cond; UNLIKELY(!(cond_val))) { \
171         std::cerr << message << std::endl;             \
172         RASSERT(#cond &&cond_val);                     \
173     }
174 
175 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
176 #define RETURN_IF_ABRUPT_COMPLETION(thread)  \
177     do {                                     \
178         if ((thread)->HasPendingException()) { \
179             return;                          \
180         }                                    \
181     } while (false)
182 
183 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
184 #define RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, value) \
185     do {                                                 \
186         if ((thread)->HasPendingException()) {           \
187             return (value);                              \
188         }                                                \
189     } while (false)
190 
191 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
192 #define RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread) \
193     do {                                              \
194         if ((thread)->HasPendingException()) {        \
195             return JSTaggedValue::Exception();        \
196         }                                             \
197     } while (false)
198 
199 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
200 #define RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, value)       \
201     do {                                                        \
202         if ((thread)->HasPendingException()) {                  \
203             auto ecmaContext = thread->GetCurrentEcmaContext(); \
204             ecmaContext->JoinStackPopFastPath(value);           \
205             return JSTaggedValue::Exception();                  \
206         }                                                       \
207     } while (false)
208 
209 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
210 #define RETURN_HANDLE_IF_ABRUPT_COMPLETION(type, thread)               \
211     do {                                                               \
212         if ((thread)->HasPendingException()) {                         \
213             return JSHandle<type>(thread, JSTaggedValue::Exception()); \
214         }                                                              \
215     } while (false)
216 
217 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
218 #define ASSERT_NO_ABRUPT_COMPLETION(thread) ASSERT(!(thread)->HasPendingException());
219 
220 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
221 #define SET_DATE_VALUE(name, code, isLocal)                                                       \
222     static JSTaggedValue name(EcmaRuntimeCallInfo *argv)                                          \
223     {                                                                                             \
224         ASSERT(argv);                                                                             \
225         JSThread *thread = argv->GetThread();                                                     \
226         JSHandle<JSTaggedValue> msg = GetThis(argv);                                              \
227         if (!msg->IsDate()) {                                                                     \
228             THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \
229         }                                                                                         \
230         JSHandle<JSDate> jsDate(thread, JSDate::Cast(msg->GetTaggedObject()));                    \
231         JSTaggedValue result = jsDate->SetDateValue(argv, code, isLocal);                         \
232         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);                                            \
233         jsDate->SetTimeValue(thread, result);                                                     \
234         return result;                                                                            \
235     }
236 
237 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
238 #define DATE_TO_STRING(name)                                                                      \
239     static JSTaggedValue name(EcmaRuntimeCallInfo *argv)                                          \
240     {                                                                                             \
241         ASSERT(argv);                                                                             \
242         JSThread *thread = argv->GetThread();                                                     \
243         JSHandle<JSTaggedValue> msg = GetThis(argv);                                              \
244         if (!msg->IsDate()) {                                                                     \
245             THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \
246         }                                                                                         \
247         if (std::isnan(JSDate::Cast(msg->GetTaggedObject())->GetTimeValue().GetDouble())) {       \
248             THROW_RANGE_ERROR_AND_RETURN(thread, "range error", JSTaggedValue::Exception());      \
249         }                                                                                         \
250         return JSDate::Cast(msg->GetTaggedObject())->name(thread);                                \
251     }
252 
253 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
254 #define DATE_STRING(name)                                                                                          \
255     static JSTaggedValue name(EcmaRuntimeCallInfo *argv)                                                           \
256     {                                                                                                              \
257         ASSERT(argv);                                                                                              \
258         JSThread *thread = argv->GetThread();                                                                      \
259         JSHandle<JSTaggedValue> msg = GetThis(argv);                                                               \
260         if (!msg->IsDate()) {                                                                                      \
261             THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception());                  \
262         }                                                                                                          \
263         if (std::isnan(JSDate::Cast(msg->GetTaggedObject())->GetTimeValue().GetDouble())) {                        \
264             return thread->GetEcmaVM()->GetFactory()->NewFromASCII("Invalid Date").GetTaggedValue();               \
265         }                                                                                                          \
266         return JSDate::Cast(msg->GetTaggedObject())->name(thread);                                                 \
267     }
268 
269 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
270 #define GET_DATE_VALUE(name, code, isLocal)                                                       \
271     static JSTaggedValue name(EcmaRuntimeCallInfo *argv)                                          \
272     {                                                                                             \
273         ASSERT(argv);                                                                             \
274         JSThread *thread = argv->GetThread();                                                     \
275         JSHandle<JSTaggedValue> msg = GetThis(argv);                                              \
276         if (!msg->IsDate()) {                                                                     \
277             THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \
278         }                                                                                         \
279         JSHandle<JSDate> jsDate(thread, JSDate::Cast(msg->GetTaggedObject()));                    \
280         double result = jsDate->GetDateValue(jsDate->GetTimeValue().GetDouble(), code, isLocal);  \
281         return GetTaggedDouble(result);                                                           \
282     }
283 
284 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
285 #define THROW_NEW_ERROR_AND_RETURN(thread, error)       \
286     do {                                                \
287         if (!(thread)->HasPendingException()) {         \
288             (thread)->SetException(error);              \
289         }                                               \
290         return;                                         \
291     } while (false)
292 
293 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
294 #define THROW_ERROR(thread, type, message)                               \
295     do {                                                                 \
296         if ((thread)->HasPendingException()) {                           \
297             return;                                                      \
298         }                                                                \
299         ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory();   \
300         JSHandle<JSObject> _error = _factory->GetJSError(type, message); \
301         (thread)->SetException(_error.GetTaggedValue());                 \
302         return;                                                          \
303     } while (false)
304 
305 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
306 #define THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, value) \
307     do {                                                       \
308         if (!(thread)->HasPendingException()) {                \
309             (thread)->SetException(error);                     \
310         }                                                      \
311         return (value);                                        \
312     } while (false)
313 
314 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
315 #define THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, errorType, type, message)    \
316     do {                                                                       \
317         if ((thread)->HasPendingException()) {                                 \
318             return JSHandle<type>(thread, JSTaggedValue::Exception());         \
319         }                                                                      \
320         ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory();         \
321         JSHandle<JSObject> _error = _factory->GetJSError(errorType, message);  \
322         (thread)->SetException(_error.GetTaggedValue());                       \
323         return JSHandle<type>(thread, JSTaggedValue::Exception());             \
324     } while (false)
325 
326 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
327 #define THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, errorType, message, value) \
328     do {                                                                             \
329         if ((thread)->HasPendingException()) {                                       \
330             return (value);                                                          \
331         }                                                                            \
332         ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory();               \
333         JSHandle<JSObject> _error = _factory->GetJSError(errorType, message);        \
334         (thread)->SetException(_error.GetTaggedValue());                             \
335         return (value);                                                              \
336     } while (false)
337 
338 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
339 #define THROW_TYPE_ERROR_AND_RETURN(thread, message, value)                                      \
340     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::TYPE_ERROR, message, value)
341 
342 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
343 #define THROW_RANGE_ERROR_AND_RETURN(thread, message, value)                                     \
344     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::RANGE_ERROR, message, value)
345 
346 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
347 #define THROW_URI_ERROR_AND_RETURN(thread, message, value)                                       \
348     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::URI_ERROR, message, value)
349 
350 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
351 #define THROW_SYNTAX_ERROR_AND_RETURN(thread, message, value)                                    \
352     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::SYNTAX_ERROR, message, value)
353 
354 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
355 #define THROW_REFERENCE_ERROR_AND_RETURN(thread, message, value)                                 \
356     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::REFERENCE_ERROR, message, value)
357 
358 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
359 #define THROW_TYPE_ERROR(thread, message)               \
360     THROW_ERROR(thread, ErrorType::TYPE_ERROR, message)
361 
362 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
363 #define THROW_OOM_ERROR(thread, message)               \
364     THROW_ERROR(thread, ErrorType::OOM_ERROR, message)
365 
366 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
367 #define RETURN_STACK_BEFORE_THROW_IF_ASM(thread)                                                   \
368     do {                                                                                           \
369         if ((thread)->IsAsmInterpreter()) {                                                        \
370             FrameIterator it(const_cast<JSTaggedType *>((thread)->GetCurrentSPFrame()), (thread)); \
371             it.Advance();                                                                          \
372             (thread)->SetCurrentSPFrame(it.GetSp());                                               \
373         }                                                                                          \
374     } while (false)
375 
376 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
377 #define RETURN_REJECT_PROMISE_IF_ABRUPT(thread, value, capability)                                 \
378     do {                                                                                           \
379         const GlobalEnvConstants *globalConst = (thread)->GlobalConstants();                       \
380         if ((value).GetTaggedValue().IsCompletionRecord()) {                                       \
381             JSHandle<CompletionRecord> record = JSHandle<CompletionRecord>::Cast(value);           \
382             if (record->IsThrow()) {                                                               \
383                 JSHandle<JSTaggedValue> reject(thread, (capability)->GetReject());                 \
384                 JSHandle<JSTaggedValue> undefine = globalConst->GetHandledUndefined();             \
385                 EcmaRuntimeCallInfo *info =                                                        \
386                     EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefine, undefine, 1);    \
387                 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());             \
388                 info->SetCallArg(record->GetValue());                                              \
389                 JSTaggedValue res = JSFunction::Call(info);                                        \
390                 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res);                                    \
391                 return (capability)->GetPromise();                                                 \
392             }                                                                                      \
393         }                                                                                          \
394         if ((thread)->HasPendingException()) {                                                     \
395             (thread)->ClearException();                                                            \
396             JSHandle<JSTaggedValue> reject(thread, (capability)->GetReject());                     \
397             JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();                \
398             EcmaRuntimeCallInfo *info =                                                            \
399                 EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1);      \
400             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());                 \
401             info->SetCallArg(value.GetTaggedValue());                                              \
402             JSTaggedValue res = JSFunction::Call(info);                                            \
403             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res);                                        \
404             return (capability)->GetPromise();                                                     \
405         }                                                                                          \
406     } while (false)
407 
408 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
409 #define RETURN_COMPLETION_IF_ABRUPT(thread, value)                                \
410     do {                                                                          \
411         if ((thread)->HasPendingException()) {                                    \
412             JSHandle<CompletionRecord> completionRecord =                         \
413                 factory->NewCompletionRecord(CompletionRecordType::THROW, value); \
414             return (completionRecord);                                            \
415         }                                                                         \
416     } while (false)
417 
418 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
419 #define RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, value)                          \
420     do {                                                                          \
421         if ((thread)->HasPendingException()) {                                    \
422             JSHandle<CompletionRecord> completionRecord =                         \
423                 factory->NewCompletionRecord(CompletionRecordType::THROW, value); \
424             return (completionRecord).GetTaggedValue();                           \
425         }                                                                         \
426     } while (false)
427 
428 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
429 #define DECL_DUMP()                                  \
430     void Dump(std::ostream &os) const DUMP_API_ATTR; \
431     void Dump() const DUMP_API_ATTR                  \
432     {                                                \
433         Dump(std::cout);                             \
434     }                                                \
435     void DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const;
436 
437 #endif  // defined(__cplusplus)
438 
439 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
440 #define DECL_CAST(TYPE)                           \
441     static TYPE *Cast(TaggedObject *object)       \
442     {                                             \
443         ASSERT(JSTaggedValue(object).Is##TYPE()); \
444         return reinterpret_cast<TYPE *>(object);  \
445     }
446 
447 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
448 #define DECL_VISIT_ARRAY(BEGIN_OFFSET, LENGTH)                                          \
449     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)                          \
450     {                                                                                   \
451         size_t endOffset = (BEGIN_OFFSET) + (LENGTH) * JSTaggedValue::TaggedTypeSize(); \
452         visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)),                     \
453                 ObjectSlot(ToUintPtr(this) + endOffset), VisitObjectArea::NORMAL);      \
454     }
455 
456 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
457 #define DECL_VISIT_OBJECT(BEGIN_OFFSET, END_OFFSET)                                   \
458     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)                        \
459     {                                                                                 \
460         visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)),                   \
461                 ObjectSlot(ToUintPtr(this) + (END_OFFSET)), VisitObjectArea::NORMAL); \
462     }
463 
464 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
465 #define DECL_VISIT_NATIVE_FIELD(BEGIN_OFFSET, END_OFFSET)                                     \
466     void VisitRangeSlotForNative(const EcmaObjectRangeVisitor &visitor)                       \
467     {                                                                                         \
468         visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)),                           \
469                 ObjectSlot(ToUintPtr(this) + (END_OFFSET)), VisitObjectArea::NATIVE_POINTER); \
470     }
471 
472 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
473 #define DECL_VISIT_OBJECT_FOR_JS_OBJECT(PARENTCLASS, BEGIN_OFFSET, END_OFFSET)          \
474     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)                          \
475     {                                                                                   \
476         VisitObjects(visitor);                                                          \
477         /* visit in object fields */                                                    \
478         auto objSize = this->GetClass()->GetObjectSize();                               \
479         if (objSize > SIZE) {                                                           \
480             visitor(this, ObjectSlot(ToUintPtr(this) + SIZE),                           \
481                     ObjectSlot(ToUintPtr(this) + objSize), VisitObjectArea::IN_OBJECT); \
482         }                                                                               \
483     }                                                                                   \
484     void VisitObjects(const EcmaObjectRangeVisitor &visitor)                            \
485     {                                                                                   \
486         PARENTCLASS::VisitObjects(visitor);                                             \
487         if ((BEGIN_OFFSET) == (END_OFFSET)) {                                           \
488             return;                                                                     \
489         }                                                                               \
490         visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)),                     \
491                 ObjectSlot(ToUintPtr(this) + (END_OFFSET)), VisitObjectArea::NORMAL);   \
492     }
493 
494 #if ECMASCRIPT_ENABLE_CAST_CHECK
495     #define CAST_CHECK(CAST_TYPE, CHECK_METHOD)                                                 \
496         static inline CAST_TYPE *Cast(TaggedObject *object)                                     \
497         {                                                                                       \
498             if (!JSTaggedValue(object).CHECK_METHOD()) {                                        \
499                 std::abort();                                                                   \
500             }                                                                                   \
501             return static_cast<CAST_TYPE *>(object);                                            \
502         }                                                                                       \
503         static inline const CAST_TYPE *ConstCast(const TaggedObject *object)                    \
504         {                                                                                       \
505             if (!JSTaggedValue(object).CHECK_METHOD()) {                                        \
506                 std::abort();                                                                   \
507             }                                                                                   \
508             return static_cast<const CAST_TYPE *>(object);                                      \
509         }                                                                                       \
510         static inline CAST_TYPE *Cast(JSTaggedValue value)                                      \
511         {                                                                                       \
512             if (!value.CHECK_METHOD()) {                                                        \
513                 std::abort();                                                                   \
514             }                                                                                   \
515             return static_cast<CAST_TYPE *>(value.GetTaggedObject());                           \
516         }
517 # else
518     #define CAST_CHECK(CAST_TYPE, CHECK_METHOD)                                                   \
519         static inline CAST_TYPE *Cast(TaggedObject *object)                                       \
520         {                                                                                         \
521             ASSERT(JSTaggedValue(object).CHECK_METHOD());                                         \
522             return static_cast<CAST_TYPE *>(object);                                              \
523         }                                                                                         \
524         static const inline CAST_TYPE *ConstCast(const TaggedObject *object)                      \
525         {                                                                                         \
526             ASSERT(JSTaggedValue(object).CHECK_METHOD());                                         \
527             return static_cast<const CAST_TYPE *>(object);                                        \
528         }                                                                                         \
529         static inline CAST_TYPE *Cast(JSTaggedValue value)                                        \
530         {                                                                                         \
531             ASSERT(value.CHECK_METHOD());                                                         \
532             return static_cast<CAST_TYPE *>(value.GetTaggedObject());                             \
533         }
534 
535     #define CAST_NO_CHECK(CAST_TYPE)                                                              \
536         static inline CAST_TYPE *Cast(TaggedObject *object)                                       \
537         {                                                                                         \
538             return static_cast<CAST_TYPE *>(object);                                              \
539         }                                                                                         \
540         static const inline CAST_TYPE *ConstCast(const TaggedObject *object)                      \
541         {                                                                                         \
542             return static_cast<const CAST_TYPE *>(object);                                        \
543         }
544 #endif
545 
546 #define CHECK_OBJECT_SIZE(size)                                                        \
547     if ((size) == 0) {                                                                 \
548         LOG_FULL(FATAL) << __func__ << ":" << __LINE__ << " objectSize is " << (size); \
549     }
550 
551 #define CHECK_REGION_END(begin, end)                                                                  \
552     if ((begin) > (end)) {                                                                            \
553         LOG_FULL(FATAL) << __func__ << ":" << __LINE__ << " begin: " << (begin) << " end: " << (end); \
554     }
555 
556 #define CHECK_JS_THREAD(vm)                                                         \
557     if (!(vm)->GetJSThread()->IsCrossThreadExecutionEnable()) {                     \
558         ASSERT((vm)->GetJSThread()->GetThreadId() == JSThread::GetCurrentThreadId()); \
559     }
560 
561 #if !defined(NDEBUG)
562 #define STACK_ASSERT_SCOPE(thread) [[maybe_unused]] StackAssertScope stackAssertScope = StackAssertScope(thread)
563 #else
564 #define STACK_ASSERT_SCOPE(thread) static_cast<void>(0)
565 #endif
566 
567 #if !defined(NDEBUG)
568 #define BUILTINS_ENTRY_DEBUG_LOG() LOG_BUILTINS(DEBUG) << "Builtins C++ " << __func__
569 #else
570 #define BUILTINS_ENTRY_DEBUG_LOG() static_cast<void>(0)
571 #endif
572 
573 #if defined(ARK_NOT_SUPPORT_INTL_GLOBAL)
574 #define ARK_SUPPORT_INTL_RETURN_STR(msg) "Please use import intl lib "#msg
575 #define ARK_SUPPORT_INTL_RETURN(thread, message)                            \
576     THROW_TYPE_ERROR(thread, ARK_SUPPORT_INTL_RETURN_STR(message))
577 #define ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, message)                                                        \
578     THROW_TYPE_ERROR_AND_RETURN(thread,                                                                         \
579         ARK_SUPPORT_INTL_RETURN_STR(message), JSTaggedValue::Exception())
580 #else
581 #define ARK_SUPPORT_INTL_RETURN(thread, message) static_cast<void>(0)
582 #define ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, message) static_cast<void>(0)
583 #endif
584 #endif  // ECMASCRIPT_ECMA_MACROS_H
585