1# V8-Blink bindings tips
2
3## How to throw/handle an exception?
4
5There are two options to throw/handle an exception; a) let Blink does it, or b)
6let V8 does it.
7
8### Use blink::ExceptionState
9
10The best way is to use `[RaisesException]` IDL extended attribute in *.idl file.
11Then, the bindings code generator creates an `ExceptionState` and initializes it
12with the API name.  The implementation function takes the `ExceptionState` as
13the last argument.  Now you can use the `ExceptionState` to throw and catch an
14exception.
15
16```webidl
17interface MyInterface {
18  // Use [RaisesException] in your *.idl file.
19  [RaisesException] void foo(DOMString s);
20};
21```
22
23```c++
24class MyInterface : public ScriptWrappable {
25  // The implementation of |foo| takes |ExceptionState&| as the last argument.
26  void foo(const StringView& s, ExceptionState& exception_state) {
27    // MaybeThrowFunc may throw an exception.
28    MaybeThrowFunc(exception_state);
29    // Check if MaybeThrowFunc threw an exception or not.
30    if (exception_state.HadException())
31      return;
32
33    if (s.IsEmpty()) {
34      // Throw a ECMAScript TypeError.
35      exception_state.ThrowTypeError("s must not be empty");
36      return;
37    }
38  }
39};
40```
41
42### Use v8::Maybe / v8::MaybeLocal / v8::TryCatch
43
44Sometimes we need to directly use V8 to manage exceptions as not all APIs use
45ExceptionState.  Some APIs use `v8::Maybe` / `v8::MaybeLocal` to indicate an
46exception.  The important convention is that, if and only if the maybe object is
47Nothing, an exception must be thrown.  It's not allowed to return Nothing
48without throwing an exception or to throw an exception without returning
49Nothing.  You can catch a V8 exception with `v8::TryCatch` and rethrow it into
50`ExceptionState`.
51
52```c++
53void foo(v8::Isolate* isolate, ExceptionState& exception_state) {
54  // v8::TryCatch works like |try { … } catch (e) { … }| in ECMAScript.
55  v8::TryCatch try_catch(isolate);
56
57  Type value;
58  // ReturnMaybe() returns a v8::Maybe<Type>.
59  // v8::Maybe::To is preferred to v8::Maybe::IsJust / IsNothing.
60  if (!ReturnMaybe().To(&value)) {
61    // An exception is thrown.
62    exception_state.RethrowV8Exception(try_catch.Exception());
63    return;
64  }
65
66  v8::Local<V8Type> local_value;
67  // ReturnMaybeLocal() returns a v8::MaybeLocal<V8Type>.
68  // v8::MaybeLocal::ToLocal is preferred to v8::MaybeLocal::IsJust / IsNothing.
69  if (!ReturnMaybeLocal().ToLocal(&local_value)) {
70    // An exception is thrown.
71    exception_state.RethrowV8Exception(try_catch.Exception());
72    return;
73  }
74}
75```
76
77## How to retain an ECMAScript value (v8::Value) in a Blink object?
78
79In general, ECMAScript values (v8::Values) are associated with a realm
80(v8::Context) and must be protected against a leak across v8::Context and/or
81isolated worlds.  You must be extra careful when storing a v8::Value in a Blink
82object.
83
84The best way is to avoid storing a v8::Value in Blink, however, if you end up
85storing a v8::Value in a Blink object, there are two options;
86`TraceWrapperV8Reference` and `WorldSafeWrapperReference`.
87
88`TraceWrapperV8Reference<V8Type>` works just like Member<BlinkType> and makes the
89V8Type value alive as long as it's traced via `Trace` member function.  If
90you're pretty sure that the value never be accessible across isolated worlds,
91this is the default choice.
92
93`WorldSafeWrapperReference<V8Type>` is recommended if the value is accessible
94across isolated worlds and/or if there are any security concerns.  Compared to
95TraceWrapperV8Reference, WorldSafeWrapperReference provides extra checks against
96cross-world access and object-cloning across isolated worlds.
97WorldSafeWrapperReference doesn't prevent information leak, but it prevents world
98leak.  An example use case is Event.  Events are often dispatched not only in
99the main world but also in isolated worlds, too.  Event objects may be
100accessible in a variety of worlds, so it's a good choice to use
101WorldSafeWrapperReference to store a v8::Value in an Event object.
102
103`ScriptValue`, `v8::Persistent`, `v8::Global`, and `v8::Eternal` are _NOT_
104recommended as a way of storing v8::Value in a Blink object.  They had been used
105in the past, but they're now obsolete after the unified heap project.  Now
106TraceWrapperV8Reference and WorldSafeWrapperReference are recommended.
107