• 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_HANDLE_IF_ABRUPT_COMPLETION(type, thread)               \
201     do {                                                               \
202         if ((thread)->HasPendingException()) {                         \
203             return JSHandle<type>(thread, JSTaggedValue::Exception()); \
204         }                                                              \
205     } while (false)
206 
207 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
208 #define ASSERT_NO_ABRUPT_COMPLETION(thread) ASSERT(!(thread)->HasPendingException());
209 
210 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
211 #define SET_DATE_VALUE(name, code, isLocal)                                                       \
212     static JSTaggedValue name(EcmaRuntimeCallInfo *argv)                                          \
213     {                                                                                             \
214         ASSERT(argv);                                                                             \
215         JSThread *thread = argv->GetThread();                                                     \
216         JSHandle<JSTaggedValue> msg = GetThis(argv);                                              \
217         if (!msg->IsDate()) {                                                                     \
218             THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \
219         }                                                                                         \
220         JSHandle<JSDate> jsDate(thread, JSDate::Cast(msg->GetTaggedObject()));                    \
221         JSTaggedValue result = jsDate->SetDateValue(argv, code, isLocal);                         \
222         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);                                            \
223         jsDate->SetTimeValue(thread, result);                                                     \
224         return result;                                                                            \
225     }
226 
227 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
228 #define DATE_TO_STRING(name)                                                                      \
229     static JSTaggedValue name(EcmaRuntimeCallInfo *argv)                                          \
230     {                                                                                             \
231         ASSERT(argv);                                                                             \
232         JSThread *thread = argv->GetThread();                                                     \
233         JSHandle<JSTaggedValue> msg = GetThis(argv);                                              \
234         if (!msg->IsDate()) {                                                                     \
235             THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \
236         }                                                                                         \
237         if (std::isnan(JSDate::Cast(msg->GetTaggedObject())->GetTimeValue().GetDouble())) {       \
238             THROW_RANGE_ERROR_AND_RETURN(thread, "range error", JSTaggedValue::Exception());      \
239         }                                                                                         \
240         return JSDate::Cast(msg->GetTaggedObject())->name(thread);                                \
241     }
242 
243 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
244 #define DATE_STRING(name)                                                                                          \
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         if (std::isnan(JSDate::Cast(msg->GetTaggedObject())->GetTimeValue().GetDouble())) {                        \
254             return thread->GetEcmaVM()->GetFactory()->NewFromASCII("Invalid Date").GetTaggedValue();               \
255         }                                                                                                          \
256         return JSDate::Cast(msg->GetTaggedObject())->name(thread);                                                 \
257     }
258 
259 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
260 #define GET_DATE_VALUE(name, code, isLocal)                                                       \
261     static JSTaggedValue name(EcmaRuntimeCallInfo *argv)                                          \
262     {                                                                                             \
263         ASSERT(argv);                                                                             \
264         JSThread *thread = argv->GetThread();                                                     \
265         JSHandle<JSTaggedValue> msg = GetThis(argv);                                              \
266         if (!msg->IsDate()) {                                                                     \
267             THROW_TYPE_ERROR_AND_RETURN(thread, "Not a Date Object", JSTaggedValue::Exception()); \
268         }                                                                                         \
269         JSHandle<JSDate> jsDate(thread, JSDate::Cast(msg->GetTaggedObject()));                    \
270         double result = jsDate->GetDateValue(jsDate->GetTimeValue().GetDouble(), code, isLocal);  \
271         return GetTaggedDouble(result);                                                           \
272     }
273 
274 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
275 #define THROW_NEW_ERROR_AND_RETURN(thread, error)       \
276     do {                                                \
277         if (!(thread)->HasPendingException()) {         \
278             (thread)->SetException(error);              \
279             if ((thread)->IsPrintBCOffset()) {          \
280                 (thread)->CollectBCOffsetInfo();        \
281             }                                           \
282         }                                               \
283         return;                                         \
284     } while (false)
285 
286 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
287 #define THROW_ERROR(thread, type, message)                               \
288     do {                                                                 \
289         if ((thread)->HasPendingException()) {                           \
290             return;                                                      \
291         }                                                                \
292         ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory();   \
293         JSHandle<JSObject> _error = _factory->GetJSError(type, message); \
294         (thread)->SetException(_error.GetTaggedValue());                 \
295         if ((thread)->IsPrintBCOffset()) {                               \
296             (thread)->CollectBCOffsetInfo();                             \
297         }                                                                \
298         return;                                                          \
299     } while (false)
300 
301 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
302 #define THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, value) \
303     do {                                                       \
304         if (!(thread)->HasPendingException()) {                \
305             (thread)->SetException(error);                     \
306             if ((thread)->IsPrintBCOffset()) {                 \
307                 (thread)->CollectBCOffsetInfo();               \
308             }                                                  \
309         }                                                      \
310         return (value);                                        \
311     } while (false)
312 
313 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
314 #define THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, errorType, type, message)    \
315     do {                                                                       \
316         if ((thread)->HasPendingException()) {                                 \
317             return JSHandle<type>(thread, JSTaggedValue::Exception());         \
318         }                                                                      \
319         ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory();         \
320         JSHandle<JSObject> _error = _factory->GetJSError(errorType, message);  \
321         (thread)->SetException(_error.GetTaggedValue());                       \
322         if ((thread)->IsPrintBCOffset()) {                                     \
323             (thread)->CollectBCOffsetInfo();                                   \
324         }                                                                      \
325         return JSHandle<type>(thread, JSTaggedValue::Exception());             \
326     } while (false)
327 
328 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
329 #define THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, errorType, message, value) \
330     do {                                                                             \
331         if ((thread)->HasPendingException()) {                                       \
332             return (value);                                                          \
333         }                                                                            \
334         ObjectFactory *_factory = (thread)->GetEcmaVM()->GetFactory();               \
335         JSHandle<JSObject> _error = _factory->GetJSError(errorType, message);        \
336         (thread)->SetException(_error.GetTaggedValue());                             \
337         if ((thread)->IsPrintBCOffset()) {                                           \
338             (thread)->CollectBCOffsetInfo();                                         \
339         }                                                                            \
340         return (value);                                                              \
341     } while (false)
342 
343 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
344 #define THROW_TYPE_ERROR_AND_RETURN(thread, message, value)                                      \
345     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::TYPE_ERROR, message, value)
346 
347 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
348 #define THROW_RANGE_ERROR_AND_RETURN(thread, message, value)                                     \
349     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::RANGE_ERROR, message, value)
350 
351 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
352 #define THROW_URI_ERROR_AND_RETURN(thread, message, value)                                       \
353     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::URI_ERROR, message, value)
354 
355 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
356 #define THROW_SYNTAX_ERROR_AND_RETURN(thread, message, value)                                    \
357     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::SYNTAX_ERROR, message, value)
358 
359 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
360 #define THROW_REFERENCE_ERROR_AND_RETURN(thread, message, value)                                 \
361     THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread, ErrorType::REFERENCE_ERROR, message, value)
362 
363 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
364 #define THROW_TYPE_ERROR(thread, message)               \
365     THROW_ERROR(thread, ErrorType::TYPE_ERROR, message)
366 
367 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
368 #define THROW_OOM_ERROR(thread, message)               \
369     THROW_ERROR(thread, ErrorType::OOM_ERROR, message)
370 
371 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
372 #define RETURN_REJECT_PROMISE_IF_ABRUPT(thread, value, capability)                                 \
373     do {                                                                                           \
374         const GlobalEnvConstants *globalConst = (thread)->GlobalConstants();                       \
375         if ((value).GetTaggedValue().IsCompletionRecord()) {                                       \
376             JSHandle<CompletionRecord> record = JSHandle<CompletionRecord>::Cast(value);           \
377             if (record->IsThrow()) {                                                               \
378                 JSHandle<JSTaggedValue> reject(thread, (capability)->GetReject());                 \
379                 JSHandle<JSTaggedValue> undefine = globalConst->GetHandledUndefined();             \
380                 EcmaRuntimeCallInfo *info =                                                        \
381                     EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefine, undefine, 1);    \
382                 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());             \
383                 info->SetCallArg(record->GetValue());                                              \
384                 JSTaggedValue res = JSFunction::Call(info);                                        \
385                 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res);                                    \
386                 return (capability)->GetPromise();                                                 \
387             }                                                                                      \
388         }                                                                                          \
389         if ((thread)->HasPendingException()) {                                                     \
390             (thread)->ClearException();                                                            \
391             JSHandle<JSTaggedValue> reject(thread, (capability)->GetReject());                     \
392             JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();                \
393             EcmaRuntimeCallInfo *info =                                                            \
394                 EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1);      \
395             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());                 \
396             info->SetCallArg(value.GetTaggedValue());                                              \
397             JSTaggedValue res = JSFunction::Call(info);                                            \
398             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res);                                        \
399             return (capability)->GetPromise();                                                     \
400         }                                                                                          \
401     } while (false)
402 
403 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
404 #define RETURN_COMPLETION_IF_ABRUPT(thread, value)                                \
405     do {                                                                          \
406         if ((thread)->HasPendingException()) {                                    \
407             JSHandle<CompletionRecord> completionRecord =                         \
408                 factory->NewCompletionRecord(CompletionRecordType::THROW, value); \
409             return (completionRecord);                                            \
410         }                                                                         \
411     } while (false)
412 
413 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
414 #define RETURN_COMPLETION_VALUE_IF_ABRUPT(thread, value)                          \
415     do {                                                                          \
416         if ((thread)->HasPendingException()) {                                    \
417             JSHandle<CompletionRecord> completionRecord =                         \
418                 factory->NewCompletionRecord(CompletionRecordType::THROW, value); \
419             return (completionRecord).GetTaggedValue();                           \
420         }                                                                         \
421     } while (false)
422 
423 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
424 #define DECL_DUMP()                                  \
425     void Dump(std::ostream &os) const DUMP_API_ATTR; \
426     void Dump() const DUMP_API_ATTR                  \
427     {                                                \
428         Dump(std::cout);                             \
429     }                                                \
430     void DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &vec) const;
431 
432 #endif  // defined(__cplusplus)
433 
434 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
435 #define DECL_CAST(TYPE)                           \
436     static TYPE *Cast(TaggedObject *object)       \
437     {                                             \
438         ASSERT(JSTaggedValue(object).Is##TYPE()); \
439         return reinterpret_cast<TYPE *>(object);  \
440     }
441 
442 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
443 #define DECL_VISIT_ARRAY(BEGIN_OFFSET, LENGTH)                                                                       \
444     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)                                                       \
445     {                                                                                                                \
446         size_t endOffset = (BEGIN_OFFSET) + (LENGTH) * JSTaggedValue::TaggedTypeSize();                              \
447         visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)), ObjectSlot(ToUintPtr(this) + endOffset), false); \
448     }
449 
450 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
451 #define DECL_VISIT_OBJECT(BEGIN_OFFSET, END_OFFSET)                 \
452     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)      \
453     {                                                               \
454         visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)), \
455                 ObjectSlot(ToUintPtr(this) + (END_OFFSET)), false); \
456     }
457 
458 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
459 #define DECL_VISIT_NATIVE_FIELD(BEGIN_OFFSET, END_OFFSET)                                                              \
460     void VisitRangeSlotForNative(const EcmaObjectRangeVisitor &visitor)                                                \
461     {                                                                                                                  \
462         visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)), ObjectSlot(ToUintPtr(this) + (END_OFFSET)), true); \
463     }
464 
465 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
466 #define DECL_VISIT_OBJECT_FOR_JS_OBJECT(PARENTCLASS, BEGIN_OFFSET, END_OFFSET)                               \
467     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)                                               \
468     {                                                                                                        \
469         VisitObjects(visitor);                                                                               \
470         /* visit in object fields */                                                                         \
471         auto objSize = this->GetClass()->GetObjectSize();                                                    \
472         if (objSize > SIZE) {                                                                                \
473             visitor(this, ObjectSlot(ToUintPtr(this) + SIZE), ObjectSlot(ToUintPtr(this) + objSize), false); \
474         }                                                                                                    \
475     }                                                                                                        \
476     void VisitObjects(const EcmaObjectRangeVisitor &visitor)                                                 \
477     {                                                                                                        \
478         PARENTCLASS::VisitObjects(visitor);                                                                  \
479         if ((BEGIN_OFFSET) == (END_OFFSET)) {                                                                \
480             return;                                                                                          \
481         }                                                                                                    \
482         visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)),                                          \
483                 ObjectSlot(ToUintPtr(this) + (END_OFFSET)), false);                                          \
484     }
485 
486 #if ECMASCRIPT_ENABLE_CAST_CHECK
487     #define CAST_CHECK(CAST_TYPE, CHECK_METHOD)                                                 \
488         static inline CAST_TYPE *Cast(TaggedObject *object)                                     \
489         {                                                                                       \
490             if (!JSTaggedValue(object).CHECK_METHOD()) {                                        \
491                 std::abort();                                                                   \
492             }                                                                                   \
493             return static_cast<CAST_TYPE *>(object);                                            \
494         }                                                                                       \
495         static inline const CAST_TYPE *ConstCast(const TaggedObject *object)                    \
496         {                                                                                       \
497             if (!JSTaggedValue(object).CHECK_METHOD()) {                                        \
498                 std::abort();                                                                   \
499             }                                                                                   \
500             return static_cast<const CAST_TYPE *>(object);                                      \
501         }                                                                                       \
502         static inline CAST_TYPE *Cast(JSTaggedValue value)                                      \
503         {                                                                                       \
504             if (!value.CHECK_METHOD()) {                                                        \
505                 std::abort();                                                                   \
506             }                                                                                   \
507             return static_cast<CAST_TYPE *>(value.GetTaggedObject());                           \
508         }
509 # else
510     #define CAST_CHECK(CAST_TYPE, CHECK_METHOD)                                                   \
511         static inline CAST_TYPE *Cast(TaggedObject *object)                                       \
512         {                                                                                         \
513             ASSERT(JSTaggedValue(object).CHECK_METHOD());                                         \
514             return static_cast<CAST_TYPE *>(object);                                              \
515         }                                                                                         \
516         static const inline CAST_TYPE *ConstCast(const TaggedObject *object)                      \
517         {                                                                                         \
518             ASSERT(JSTaggedValue(object).CHECK_METHOD());                                         \
519             return static_cast<const CAST_TYPE *>(object);                                        \
520         }                                                                                         \
521         static inline CAST_TYPE *Cast(JSTaggedValue value)                                        \
522         {                                                                                         \
523             ASSERT(value.CHECK_METHOD());                                                         \
524             return static_cast<CAST_TYPE *>(value.GetTaggedObject());                             \
525         }
526 
527     #define CAST_NO_CHECK(CAST_TYPE)                                                              \
528         static inline CAST_TYPE *Cast(TaggedObject *object)                                       \
529         {                                                                                         \
530             return static_cast<CAST_TYPE *>(object);                                              \
531         }                                                                                         \
532         static const inline CAST_TYPE *ConstCast(const TaggedObject *object)                      \
533         {                                                                                         \
534             return static_cast<const CAST_TYPE *>(object);                                        \
535         }
536 #endif
537 
538 #define CHECK_OBJECT_SIZE(size)                                                        \
539     if ((size) == 0) {                                                                 \
540         LOG_FULL(FATAL) << __func__ << ":" << __LINE__ << " objectSize is " << (size); \
541     }
542 
543 #define CHECK_REGION_END(begin, end)                                                                  \
544     if ((begin) > (end)) {                                                                            \
545         LOG_FULL(FATAL) << __func__ << ":" << __LINE__ << " begin: " << (begin) << " end: " << (end); \
546     }
547 
548 #define CHECK_JS_THREAD(vm) ASSERT(vm->GetJSThread()->GetThreadId() == JSThread::GetCurrentThreadId())
549 
550 #if !defined(NDEBUG)
551 #define STACK_ASSERT_SCOPE(thread) [[maybe_unused]] StackAssertScope stackAssertScope = StackAssertScope(thread)
552 #else
553 #define STACK_ASSERT_SCOPE(thread) static_cast<void>(0)
554 #endif
555 
556 #if !defined(NDEBUG)
557 #define BUILTINS_ENTRY_DEBUG_LOG() LOG_BUILTINS(DEBUG) << "Builtins C++ " << __func__
558 #else
559 #define BUILTINS_ENTRY_DEBUG_LOG() static_cast<void>(0)
560 #endif
561 
562 #endif  // ECMASCRIPT_ECMA_MACROS_H
563