summaryrefslogtreecommitdiff
path: root/deps/v8/src/api/api-macros.h
blob: bcad7df2881231502f5a350b3db5bd45d4f22bce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Note 1: Any file that includes this one should include api-macros-undef.h
// at the bottom.

// Note 2: This file is deliberately missing the include guards (the undeffing
// approach wouldn't work otherwise).
//
// PRESUBMIT_INTENTIONALLY_MISSING_INCLUDE_GUARD

/*
 * Most API methods should use one of the three macros:
 *
 * ENTER_V8, ENTER_V8_NO_SCRIPT, ENTER_V8_NO_SCRIPT_NO_EXCEPTION.
 *
 * The latter two assume that no script is executed, and no exceptions are
 * scheduled in addition (respectively). Creating a pending exception and
 * removing it before returning is ok.
 *
 * Exceptions should be handled either by invoking one of the
 * RETURN_ON_FAILED_EXECUTION* macros.
 *
 * API methods that are part of the debug interface should use
 *
 * PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE
 *
 * in a similar fashion to ENTER_V8.
 *
 * Don't use macros with DO_NOT_USE in their name.
 *
 * TODO(cbruni): Document LOG_API and other RuntimeCallStats macros.
 * TODO(verwaest): All API methods should invoke one of the ENTER_V8* macros.
 * TODO(verwaest): Remove calls form API methods to DO_NOT_USE macros.
 */

#define API_RCS_SCOPE(i_isolate, class_name, function_name) \
  RCS_SCOPE(i_isolate,                                      \
            i::RuntimeCallCounterId::kAPI_##class_name##_##function_name);

#define ENTER_V8_BASIC(i_isolate)                            \
  /* Embedders should never enter V8 after terminating it */ \
  DCHECK_IMPLIES(i::v8_flags.strict_termination_checks,      \
                 !i_isolate->is_execution_terminating());    \
  i::VMState<v8::OTHER> __state__((i_isolate))

#define ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name,    \
                                 function_name, bailout_value,      \
                                 HandleScopeClass, do_callback)     \
  if (i_isolate->is_execution_terminating()) {                      \
    return bailout_value;                                           \
  }                                                                 \
  HandleScopeClass handle_scope(i_isolate);                         \
  CallDepthScope<do_callback> call_depth_scope(i_isolate, context); \
  API_RCS_SCOPE(i_isolate, class_name, function_name);              \
  i::VMState<v8::OTHER> __state__((i_isolate));                     \
  bool has_pending_exception = false

#define PREPARE_FOR_DEBUG_INTERFACE_EXECUTION_WITH_ISOLATE(i_isolate, T)       \
  if (i_isolate->is_execution_terminating()) {                                 \
    return MaybeLocal<T>();                                                    \
  }                                                                            \
  InternalEscapableScope handle_scope(i_isolate);                              \
  CallDepthScope<false> call_depth_scope(i_isolate, v8::Local<v8::Context>()); \
  i::VMState<v8::OTHER> __state__((i_isolate));                                \
  bool has_pending_exception = false

#define PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name, \
                                           bailout_value, HandleScopeClass,    \
                                           do_callback)                        \
  auto i_isolate = context.IsEmpty()                                           \
                       ? i::Isolate::Current()                                 \
                       : reinterpret_cast<i::Isolate*>(context->GetIsolate()); \
  ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name,      \
                           bailout_value, HandleScopeClass, do_callback);

#define PREPARE_FOR_EXECUTION(context, class_name, function_name, T)          \
  PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, class_name, function_name,      \
                                     MaybeLocal<T>(), InternalEscapableScope, \
                                     false)

#define ENTER_V8(i_isolate, context, class_name, function_name, bailout_value, \
                 HandleScopeClass)                                             \
  ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name,      \
                           bailout_value, HandleScopeClass, true)

#ifdef DEBUG
#define ENTER_V8_NO_SCRIPT(i_isolate, context, class_name, function_name, \
                           bailout_value, HandleScopeClass)               \
  ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name, \
                           bailout_value, HandleScopeClass, false);       \
  i::DisallowJavascriptExecutionDebugOnly __no_script__((i_isolate))

// Lightweight version for APIs that don't require an active context.
#define DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate)                      \
  i::DisallowJavascriptExecutionDebugOnly __no_script__((i_isolate)); \
  i::DisallowExceptions __no_exceptions__((i_isolate))

#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate) \
  i::VMState<v8::OTHER> __state__((i_isolate));    \
  DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate)

#define ENTER_V8_FOR_NEW_CONTEXT(i_isolate)                 \
  DCHECK_IMPLIES(i::v8_flags.strict_termination_checks,     \
                 !(i_isolate)->is_execution_terminating()); \
  i::VMState<v8::OTHER> __state__((i_isolate));             \
  i::DisallowExceptions __no_exceptions__((i_isolate))
#else  // DEBUG
#define ENTER_V8_NO_SCRIPT(i_isolate, context, class_name, function_name, \
                           bailout_value, HandleScopeClass)               \
  ENTER_V8_HELPER_INTERNAL(i_isolate, context, class_name, function_name, \
                           bailout_value, HandleScopeClass, false)

#define DCHECK_NO_SCRIPT_NO_EXCEPTION(i_isolate)

#define ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate) \
  i::VMState<v8::OTHER> __state__((i_isolate));

#define ENTER_V8_FOR_NEW_CONTEXT(i_isolate) \
  i::VMState<v8::OTHER> __state__((i_isolate));
#endif  // DEBUG

#define EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(i_isolate, value) \
  do {                                                              \
    if (has_pending_exception) {                                    \
      call_depth_scope.Escape();                                    \
      return value;                                                 \
    }                                                               \
  } while (false)

#define RETURN_ON_FAILED_EXECUTION(T) \
  EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(i_isolate, MaybeLocal<T>())

#define RETURN_ON_FAILED_EXECUTION_PRIMITIVE(T) \
  EXCEPTION_BAILOUT_CHECK_SCOPED_DO_NOT_USE(i_isolate, Nothing<T>())

#define RETURN_ESCAPED(value) return handle_scope.Escape(value);