11cb0ef41Sopenharmony_ci# Adding V8 Fast API 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciNode.js uses [V8](https://v8.dev/) as its JavaScript engine. 41cb0ef41Sopenharmony_ciEmbedding functions implemented in C++ incur a high overhead, so V8 51cb0ef41Sopenharmony_ciprovides an API to implement native functions which may be invoked directly 61cb0ef41Sopenharmony_cifrom JIT-ed code. These functions also come with additional constraints, 71cb0ef41Sopenharmony_cifor example, they may not trigger garbage collection. 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci## Limitations 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ci* Fast API functions may not trigger garbage collection. This means by proxy 121cb0ef41Sopenharmony_ci that JavaScript execution and heap allocation are also forbidden, including 131cb0ef41Sopenharmony_ci `v8::Array::Get()` or `v8::Number::New()`. 141cb0ef41Sopenharmony_ci* Throwing errors is not available from within a fast API call, but can be done 151cb0ef41Sopenharmony_ci through the fallback to the slow API. 161cb0ef41Sopenharmony_ci* Not all parameter and return types are supported in fast API calls. 171cb0ef41Sopenharmony_ci For a full list, please look into 181cb0ef41Sopenharmony_ci [`v8-fast-api-calls.h`](../../deps/v8/include/v8-fast-api-calls.h). 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci## Requirements 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci* Any function passed to `CFunction::Make`, including fast API function 231cb0ef41Sopenharmony_ci declarations, should have their signature registered in 241cb0ef41Sopenharmony_ci [`node_external_reference.h`](../../src/node_external_reference.h) file. 251cb0ef41Sopenharmony_ci Although, it would not start failing or crashing until the function ends up 261cb0ef41Sopenharmony_ci in a snapshot (either the built-in or a user-land one). Please refer to the 271cb0ef41Sopenharmony_ci [binding functions documentation](../../src#binding-functions) for more 281cb0ef41Sopenharmony_ci information. 291cb0ef41Sopenharmony_ci* To test fast APIs, make sure to run the tests in a loop with a decent 301cb0ef41Sopenharmony_ci iterations count to trigger relevant optimizations that prefer the fast API 311cb0ef41Sopenharmony_ci over the slow one. 321cb0ef41Sopenharmony_ci* The fast callback must be idempotent up to the point where error and fallback 331cb0ef41Sopenharmony_ci conditions are checked, because otherwise executing the slow callback might 341cb0ef41Sopenharmony_ci produce visible side effects twice. 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ci## Fallback to slow path 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ciFast API supports fallback to slow path for when it is desirable to do so, 391cb0ef41Sopenharmony_cifor example, when throwing a custom error or executing JavaScript code is 401cb0ef41Sopenharmony_cineeded. The fallback mechanism can be enabled and changed from the C++ 411cb0ef41Sopenharmony_ciimplementation of the fast API function declaration. 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ciPassing `true` to the `fallback` option will force V8 to run the slow path 441cb0ef41Sopenharmony_ciwith the same arguments. 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ciIn V8, the options fallback is defined as `FastApiCallbackOptions` inside 471cb0ef41Sopenharmony_ci[`v8-fast-api-calls.h`](../../deps/v8/include/v8-fast-api-calls.h). 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci* C++ land 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci Example of a conditional fast path on C++ 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci ```cpp 541cb0ef41Sopenharmony_ci // Anywhere in the execution flow, you can set fallback and stop the execution. 551cb0ef41Sopenharmony_ci static double divide(const int32_t a, 561cb0ef41Sopenharmony_ci const int32_t b, 571cb0ef41Sopenharmony_ci v8::FastApiCallbackOptions& options) { 581cb0ef41Sopenharmony_ci if (b == 0) { 591cb0ef41Sopenharmony_ci options.fallback = true; 601cb0ef41Sopenharmony_ci return 0; 611cb0ef41Sopenharmony_ci } else { 621cb0ef41Sopenharmony_ci return a / b; 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci } 651cb0ef41Sopenharmony_ci ``` 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci## Example 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ciA typical function that communicates between JavaScript and C++ is as follows. 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci* On the JavaScript side: 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci ```js 741cb0ef41Sopenharmony_ci const { divide } = internalBinding('custom_namespace'); 751cb0ef41Sopenharmony_ci ``` 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci* On the C++ side: 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci ```cpp 801cb0ef41Sopenharmony_ci #include "v8-fast-api-calls.h" 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci namespace node { 831cb0ef41Sopenharmony_ci namespace custom_namespace { 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci static void SlowDivide(const FunctionCallbackInfo<Value>& args) { 861cb0ef41Sopenharmony_ci Environment* env = Environment::GetCurrent(args); 871cb0ef41Sopenharmony_ci CHECK_GE(args.Length(), 2); 881cb0ef41Sopenharmony_ci CHECK(args[0]->IsInt32()); 891cb0ef41Sopenharmony_ci CHECK(args[1]->IsInt32()); 901cb0ef41Sopenharmony_ci auto a = args[0].As<v8::Int32>(); 911cb0ef41Sopenharmony_ci auto b = args[1].As<v8::Int32>(); 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci if (b->Value() == 0) { 941cb0ef41Sopenharmony_ci return node::THROW_ERR_INVALID_STATE(env, "Error"); 951cb0ef41Sopenharmony_ci } 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci double result = a->Value() / b->Value(); 981cb0ef41Sopenharmony_ci args.GetReturnValue().Set(v8::Number::New(env->isolate(), result)); 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci static double FastDivide(const int32_t a, 1021cb0ef41Sopenharmony_ci const int32_t b, 1031cb0ef41Sopenharmony_ci v8::FastApiCallbackOptions& options) { 1041cb0ef41Sopenharmony_ci if (b == 0) { 1051cb0ef41Sopenharmony_ci options.fallback = true; 1061cb0ef41Sopenharmony_ci return 0; 1071cb0ef41Sopenharmony_ci } else { 1081cb0ef41Sopenharmony_ci return a / b; 1091cb0ef41Sopenharmony_ci } 1101cb0ef41Sopenharmony_ci } 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci CFunction fast_divide_(CFunction::Make(FastDivide)); 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci static void Initialize(Local<Object> target, 1151cb0ef41Sopenharmony_ci Local<Value> unused, 1161cb0ef41Sopenharmony_ci Local<Context> context, 1171cb0ef41Sopenharmony_ci void* priv) { 1181cb0ef41Sopenharmony_ci SetFastMethod(context, target, "divide", SlowDivide, &fast_divide_); 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci void RegisterExternalReferences(ExternalReferenceRegistry* registry) { 1221cb0ef41Sopenharmony_ci registry->Register(SlowDivide); 1231cb0ef41Sopenharmony_ci registry->Register(FastDivide); 1241cb0ef41Sopenharmony_ci registry->Register(fast_divide_.GetTypeInfo()); 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci } // namespace custom_namespace 1281cb0ef41Sopenharmony_ci } // namespace node 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci NODE_BINDING_CONTEXT_AWARE_INTERNAL(custom_namespace, 1311cb0ef41Sopenharmony_ci node::custom_namespace::Initialize); 1321cb0ef41Sopenharmony_ci NODE_BINDING_EXTERNAL_REFERENCE( 1331cb0ef41Sopenharmony_ci custom_namespace, 1341cb0ef41Sopenharmony_ci node::custom_namespace::RegisterExternalReferences); 1351cb0ef41Sopenharmony_ci ``` 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci* Update external references ([`node_external_reference.h`](../../src/node_external_reference.h)) 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci Since our implementation used 1401cb0ef41Sopenharmony_ci `double(const int32_t a, const int32_t b, v8::FastApiCallbackOptions& options)` 1411cb0ef41Sopenharmony_ci signature, we need to add it to external references and in 1421cb0ef41Sopenharmony_ci `ALLOWED_EXTERNAL_REFERENCE_TYPES`. 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci Example declaration: 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci ```cpp 1471cb0ef41Sopenharmony_ci using CFunctionCallbackReturningDouble = double (*)(const int32_t a, 1481cb0ef41Sopenharmony_ci const int32_t b, 1491cb0ef41Sopenharmony_ci v8::FastApiCallbackOptions& options); 1501cb0ef41Sopenharmony_ci ``` 151