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