[][src]Type Definition dart_sys::Dart_Handle

type Dart_Handle = *mut _Dart_Handle;

An object reference managed by the Dart VM garbage collector.

Because the garbage collector may move objects, it is unsafe to refer to objects directly. Instead, we refer to objects through handles, which are known to the garbage collector and updated automatically when the object is moved. Handles should be passed by value (except in cases like out-parameters) and should never be allocated on the heap.

Most functions in the Dart Embedding API return a handle. When a function completes normally, this will be a valid handle to an object in the Dart VM heap. This handle may represent the result of the operation or it may be a special valid handle used merely to indicate successful completion. Note that a valid handle may in some cases refer to the null object.

--- Error handles ---

When a function encounters a problem that prevents it from completing normally, it returns an error handle (See Dart_IsError). An error handle has an associated error message that gives more details about the problem (See Dart_GetError).

There are four kinds of error handles that can be produced, depending on what goes wrong:

  • Api error handles are produced when an api function is misused. This happens when a Dart embedding api function is called with invalid arguments or in an invalid context.

  • Unhandled exception error handles are produced when, during the execution of Dart code, an exception is thrown but not caught. Prototypically this would occur during a call to Dart_Invoke, but it can occur in any function which triggers the execution of Dart code (for example, Dart_ToString).

    An unhandled exception error provides access to an exception and stacktrace via the functions Dart_ErrorGetException and Dart_ErrorGetStackTrace.

  • Compilation error handles are produced when, during the execution of Dart code, a compile-time error occurs. As above, this can occur in any function which triggers the execution of Dart code.

  • Fatal error handles are produced when the system wants to shut down the current isolate.

--- Propagating errors ---

When an error handle is returned from the top level invocation of Dart code in a program, the embedder must handle the error as they see fit. Often, the embedder will print the error message produced by Dart_Error and exit the program.

When an error is returned while in the body of a native function, it can be propagated up the call stack by calling Dart_PropagateError, Dart_SetReturnValue, or Dart_ThrowException. Errors should be propagated unless there is a specific reason not to. If an error is not propagated then it is ignored. For example, if an unhandled exception error is ignored, that effectively "catches" the unhandled exception. Fatal errors must always be propagated.

When an error is propagated, any current scopes created by Dart_EnterScope will be exited.

Using Dart_SetReturnValue to propagate an exception is somewhat more convenient than using Dart_PropagateError, and should be preferred for reasons discussed below.

Dart_PropagateError and Dart_ThrowException do not return. Instead they transfer control non-locally using a setjmp-like mechanism. This can be inconvenient if you have resources that you need to clean up before propagating the error.

When relying on Dart_PropagateError, we often return error handles rather than propagating them from helper functions. Consider the following contrived example:

1 Dart_Handle isLongStringHelper(Dart_Handle arg) { 2 intptr_t* length = 0; 3 result = Dart_StringLength(arg, &length); 4 if (Dart_IsError(result)) { 5 return result 6 } 7 return Dart_NewBoolean(length > 100); 8 } 9 10 void NativeFunction_isLongString(Dart_NativeArguments args) { 11 Dart_EnterScope(); 12 AllocateMyResource(); 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0); 14 Dart_Handle result = isLongStringHelper(arg); 15 if (Dart_IsError(result)) { 16 FreeMyResource(); 17 Dart_PropagateError(result); 18 abort(); // will not reach here 19 } 20 Dart_SetReturnValue(result); 21 FreeMyResource(); 22 Dart_ExitScope(); 23 }

In this example, we have a native function which calls a helper function to do its work. On line 5, the helper function could call Dart_PropagateError, but that would not give the native function a chance to call FreeMyResource(), causing a leak. Instead, the helper function returns the error handle to the caller, giving the caller a chance to clean up before propagating the error handle.

When an error is propagated by calling Dart_SetReturnValue, the native function will be allowed to complete normally and then the exception will be propagated only once the native call returns. This can be convenient, as it allows the C code to clean up normally.

The example can be written more simply using Dart_SetReturnValue to propagate the error.

1 Dart_Handle isLongStringHelper(Dart_Handle arg) { 2 intptr_t* length = 0; 3 result = Dart_StringLength(arg, &length); 4 if (Dart_IsError(result)) { 5 return result 6 } 7 return Dart_NewBoolean(length > 100); 8 } 9 10 void NativeFunction_isLongString(Dart_NativeArguments args) { 11 Dart_EnterScope(); 12 AllocateMyResource(); 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0); 14 Dart_SetReturnValue(isLongStringHelper(arg)); 15 FreeMyResource(); 16 Dart_ExitScope(); 17 }

In this example, the call to Dart_SetReturnValue on line 14 will either return the normal return value or the error (potentially generated on line 3). The call to FreeMyResource on line 15 will execute in either case.

--- Local and persistent handles ---

Local handles are allocated within the current scope (see Dart_EnterScope) and go away when the current scope exits. Unless otherwise indicated, callers should assume that all functions in the Dart embedding api return local handles.

Persistent handles are allocated within the current isolate. They can be used to store objects across scopes. Persistent handles have the lifetime of the current isolate unless they are explicitly deallocated (see Dart_DeletePersistentHandle). The type Dart_Handle represents a handle (both local and persistent). The type Dart_PersistentHandle is a Dart_Handle and it is used to document that a persistent handle is expected as a parameter to a call or the return value from a call is a persistent handle.