Repository: nodejs/node
Pull request: src: implement util.types fast API calls

All util.types.is##Type() calls are ported to the fast API.

This improves the performance for multiple APIs such as:

- util.inspect (and util.format and console methods respectively)
- util.isDeepStrictEqual
- assert.(not)deepEqual (including strict and partial mode)

Local benchmark

```
                                                                                                             confidence improvement accuracy (*)   (**)   (***)
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='array'                    *      1.09 %       ±1.06% ±1.41%  ±1.85%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='boolean'                         1.68 %       ±2.20% ±2.93%  ±3.84%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='circular'                       -1.71 %       ±1.93% ±2.57%  ±3.35%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='date'                   ***     11.72 %       ±3.14% ±4.20%  ±5.52%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='empty_object'                   -1.81 %       ±3.40% ±4.52%  ±5.88%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='number'                          0.53 %       ±3.54% ±4.72%  ±6.16%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='object'                          1.30 %       ±1.86% ±2.49%  ±3.29%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='regexp'                 ***     16.65 %       ±1.88% ±2.52%  ±3.29%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='set_object'             ***      8.18 %       ±1.27% ±1.69%  ±2.20%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='set_simple'             ***     13.53 %       ±3.62% ±4.84%  ±6.34%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=0 n=100000 primitive='string'                          1.70 %       ±3.91% ±5.23%  ±6.88%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='array'                          -0.26 %       ±1.38% ±1.84%  ±2.39%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='boolean'                         1.06 %       ±2.10% ±2.80%  ±3.65%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='circular'                        0.62 %       ±1.14% ±1.51%  ±1.97%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='date'                   ***      5.26 %       ±1.39% ±1.86%  ±2.42%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='empty_object'                   -0.64 %       ±1.81% ±2.42%  ±3.17%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='number'                          1.42 %       ±2.56% ±3.40%  ±4.43%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='object'                          0.23 %       ±0.93% ±1.23%  ±1.60%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='regexp'                 ***     12.07 %       ±1.06% ±1.40%  ±1.83%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='set_object'             ***      9.73 %       ±1.01% ±1.35%  ±1.76%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='set_simple'             ***     11.74 %       ±1.45% ±1.92%  ±2.51%
assert/deepequal-prims-and-objs-big-loop.js method='deepEqual' strict=1 n=100000 primitive='string'                         -0.64 %       ±7.18% ±9.59% ±12.56%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='array'                        0.04 %       ±1.25% ±1.67%  ±2.17%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='boolean'                      1.15 %       ±1.92% ±2.55%  ±3.32%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='circular'                    -0.48 %       ±2.19% ±2.93%  ±3.84%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='date'                ***      4.27 %       ±2.05% ±2.73%  ±3.56%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='empty_object'                 1.09 %       ±3.53% ±4.70%  ±6.12%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='number'                       4.38 %       ±5.92% ±7.95% ±10.51%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='object'                       0.29 %       ±1.05% ±1.40%  ±1.82%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='regexp'              ***     13.66 %       ±5.20% ±6.99%  ±9.24%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='set_object'          ***      9.90 %       ±3.56% ±4.76%  ±6.24%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='set_simple'          ***     13.06 %       ±0.94% ±1.25%  ±1.63%
assert/deepequal-prims-and-objs-big-loop.js method='notDeepEqual' strict=1 n=100000 primitive='string'                      -0.95 %       ±3.34% ±4.45%  ±5.81%

                                                                                            confidence improvement accuracy (*)   (**)  (***)
assert/partial-deep-equal.js datasetName='array' extraProps=0 size=500 n=125                                0.48 %       ±3.02% ±4.02% ±5.23%
assert/partial-deep-equal.js datasetName='array' extraProps=1 size=500 n=125                                1.63 %       ±2.61% ±3.48% ±4.53%
assert/partial-deep-equal.js datasetName='arrayBuffers' extraProps=0 size=500 n=125                ***     14.79 %       ±1.43% ±1.91% ±2.49%
assert/partial-deep-equal.js datasetName='arrayBuffers' extraProps=1 size=500 n=125                ***      5.93 %       ±0.74% ±0.99% ±1.29%
assert/partial-deep-equal.js datasetName='circularRefs' extraProps=0 size=500 n=125                ***      4.61 %       ±0.58% ±0.78% ±1.01%
assert/partial-deep-equal.js datasetName='circularRefs' extraProps=1 size=500 n=125                ***      4.26 %       ±0.96% ±1.28% ±1.68%
assert/partial-deep-equal.js datasetName='dataViewArrayBuffers' extraProps=0 size=500 n=125        ***      3.60 %       ±1.30% ±1.73% ±2.25%
assert/partial-deep-equal.js datasetName='dataViewArrayBuffers' extraProps=1 size=500 n=125          *      1.33 %       ±1.14% ±1.51% ±1.97%
assert/partial-deep-equal.js datasetName='maps' extraProps=0 size=500 n=125                        ***      9.73 %       ±0.75% ±1.01% ±1.32%
assert/partial-deep-equal.js datasetName='maps' extraProps=1 size=500 n=125                        ***     10.36 %       ±0.86% ±1.15% ±1.49%
assert/partial-deep-equal.js datasetName='objects' extraProps=0 size=500 n=125                             -0.01 %       ±0.70% ±0.93% ±1.21%
assert/partial-deep-equal.js datasetName='objects' extraProps=1 size=500 n=125                              0.23 %       ±0.76% ±1.01% ±1.32%
assert/partial-deep-equal.js datasetName='sets' extraProps=0 size=500 n=125                        ***      7.94 %       ±0.78% ±1.05% ±1.37%
assert/partial-deep-equal.js datasetName='sets' extraProps=1 size=500 n=125                        ***      7.10 %       ±2.10% ±2.83% ±3.73%
assert/partial-deep-equal.js datasetName='setsWithObjects' extraProps=0 size=500 n=125             ***      5.96 %       ±1.09% ±1.46% ±1.90%
assert/partial-deep-equal.js datasetName='setsWithObjects' extraProps=1 size=500 n=125             ***      6.82 %       ±1.06% ±1.41% ±1.84%
assert/partial-deep-equal.js datasetName='typedArrays' extraProps=0 size=500 n=125                 ***      2.49 %       ±0.68% ±0.90% ±1.18%
assert/partial-deep-equal.js datasetName='typedArrays' extraProps=1 size=500 n=125                 ***      4.96 %       ±0.89% ±1.18% ±1.54%

                                                                      confidence improvement accuracy (*)   (**)  (***)
util/inspect.js option='colors' method='Array' n=80000                                0.21 %       ±0.76% ±1.02% ±1.32%
util/inspect.js option='colors' method='Date' n=80000                        ***      3.59 %       ±0.67% ±0.90% ±1.17%
util/inspect.js option='colors' method='Error' n=80000                       ***      2.68 %       ±0.68% ±0.91% ±1.18%
util/inspect.js option='colors' method='Number' n=80000                               0.52 %       ±1.62% ±2.16% ±2.81%
util/inspect.js option='colors' method='Object_deep_ln' n=80000                       0.44 %       ±0.63% ±0.84% ±1.10%
util/inspect.js option='colors' method='Object_empty' n=80000                ***      1.71 %       ±0.78% ±1.03% ±1.34%
util/inspect.js option='colors' method='Object' n=80000                              -0.04 %       ±0.76% ±1.02% ±1.33%
util/inspect.js option='colors' method='Set' n=80000                         ***      1.34 %       ±0.76% ±1.02% ±1.32%
util/inspect.js option='colors' method='String_boxed' n=80000                ***     26.23 %       ±0.79% ±1.05% ±1.38%
util/inspect.js option='colors' method='String_complex' n=80000                       0.61 %       ±1.01% ±1.35% ±1.75%
util/inspect.js option='colors' method='String' n=80000                              -0.17 %       ±0.94% ±1.25% ±1.63%
util/inspect.js option='colors' method='TypedArray_extra' n=80000                    -0.88 %       ±1.02% ±1.36% ±1.78%
util/inspect.js option='colors' method='TypedArray' n=80000                          -0.16 %       ±0.86% ±1.14% ±1.49%
util/inspect.js option='none' method='Array' n=80000                                  0.73 %       ±1.21% ±1.62% ±2.13%
util/inspect.js option='none' method='Date' n=80000                          ***      3.59 %       ±0.78% ±1.03% ±1.34%
util/inspect.js option='none' method='Error' n=80000                         ***      3.91 %       ±0.78% ±1.04% ±1.36%
util/inspect.js option='none' method='Number' n=80000                                 1.07 %       ±2.13% ±2.84% ±3.72%
util/inspect.js option='none' method='Object_deep_ln' n=80000                ***      2.10 %       ±0.63% ±0.84% ±1.09%
util/inspect.js option='none' method='Object_empty' n=80000                  ***      2.38 %       ±0.73% ±0.97% ±1.26%
util/inspect.js option='none' method='Object' n=80000                          *      1.07 %       ±0.83% ±1.11% ±1.44%
util/inspect.js option='none' method='Set' n=80000                           ***      1.82 %       ±0.73% ±0.98% ±1.27%
util/inspect.js option='none' method='String_boxed' n=80000                  ***     30.90 %       ±1.26% ±1.69% ±2.22%
util/inspect.js option='none' method='String_complex' n=80000                         0.62 %       ±0.96% ±1.27% ±1.66%
util/inspect.js option='none' method='String' n=80000                                -0.01 %       ±1.14% ±1.52% ±1.98%
util/inspect.js option='none' method='TypedArray_extra' n=80000                *      0.94 %       ±0.84% ±1.11% ±1.45%
util/inspect.js option='none' method='TypedArray' n=80000                             0.44 %       ±0.75% ±1.00% ±1.30%
util/inspect.js option='showHidden' method='Array' n=80000                           -0.54 %       ±0.89% ±1.19% ±1.55%
util/inspect.js option='showHidden' method='Date' n=80000                    ***      3.92 %       ±0.70% ±0.93% ±1.22%
util/inspect.js option='showHidden' method='Error' n=80000                   ***      3.24 %       ±0.80% ±1.07% ±1.39%
util/inspect.js option='showHidden' method='Number' n=80000                          -1.40 %       ±2.95% ±3.93% ±5.13%
util/inspect.js option='showHidden' method='Object_deep_ln' n=80000           **      1.40 %       ±0.95% ±1.27% ±1.68%
util/inspect.js option='showHidden' method='Object_empty' n=80000              *      2.66 %       ±2.27% ±3.01% ±3.92%
util/inspect.js option='showHidden' method='Object' n=80000                           0.60 %       ±0.60% ±0.80% ±1.05%
util/inspect.js option='showHidden' method='Set' n=80000                       *      0.95 %       ±0.80% ±1.06% ±1.38%
util/inspect.js option='showHidden' method='String_boxed' n=80000            ***     21.05 %       ±1.14% ±1.52% ±1.98%
util/inspect.js option='showHidden' method='String_complex' n=80000                   0.22 %       ±0.79% ±1.06% ±1.38%
util/inspect.js option='showHidden' method='String' n=80000                           1.10 %       ±1.59% ±2.12% ±2.77%
util/inspect.js option='showHidden' method='TypedArray_extra' n=80000        ***      2.48 %       ±0.87% ±1.16% ±1.51%
util/inspect.js option='showHidden' method='TypedArray' n=80000              ***      3.58 %       ±1.01% ±1.34% ±1.75%
```

Changed files:
filename: src/node_types.cc
patch: @@ -1,7 +1,9 @@
 #include "env-inl.h"
 #include "node.h"
+#include "node_debug.h"
 #include "node_external_reference.h"
 
+using v8::CFunction;
 using v8::Context;
 using v8::FunctionCallbackInfo;
 using v8::Local;
@@ -11,47 +13,59 @@ using v8::Value;
 namespace node {
 namespace {
 
-#define VALUE_METHOD_MAP(V)                                                   \
-  V(External)                                                                 \
-  V(Date)                                                                     \
-  V(ArgumentsObject)                                                          \
-  V(BigIntObject)                                                             \
-  V(BooleanObject)                                                            \
-  V(NumberObject)                                                             \
-  V(StringObject)                                                             \
-  V(SymbolObject)                                                             \
-  V(NativeError)                                                              \
-  V(RegExp)                                                                   \
-  V(AsyncFunction)                                                            \
-  V(GeneratorFunction)                                                        \
-  V(GeneratorObject)                                                          \
-  V(Promise)                                                                  \
-  V(Map)                                                                      \
-  V(Set)                                                                      \
-  V(MapIterator)                                                              \
-  V(SetIterator)                                                              \
-  V(WeakMap)                                                                  \
-  V(WeakSet)                                                                  \
-  V(ArrayBuffer)                                                              \
-  V(DataView)                                                                 \
-  V(SharedArrayBuffer)                                                        \
-  V(Proxy)                                                                    \
-  V(ModuleNamespaceObject)                                                    \
-
-
-#define V(type) \
-  static void Is##type(const FunctionCallbackInfo<Value>& args) {             \
-    args.GetReturnValue().Set(args[0]->Is##type());                           \
-  }
+#define VALUE_METHOD_MAP(V)                                                    \
+  V(External)                                                                  \
+  V(Date)                                                                      \
+  V(ArgumentsObject)                                                           \
+  V(BigIntObject)                                                              \
+  V(BooleanObject)                                                             \
+  V(NumberObject)                                                              \
+  V(StringObject)                                                              \
+  V(SymbolObject)                                                              \
+  V(NativeError)                                                               \
+  V(RegExp)                                                                    \
+  V(AsyncFunction)                                                             \
+  V(GeneratorFunction)                                                         \
+  V(GeneratorObject)                                                           \
+  V(Promise)                                                                   \
+  V(Map)                                                                       \
+  V(Set)                                                                       \
+  V(MapIterator)                                                               \
+  V(SetIterator)                                                               \
+  V(WeakMap)                                                                   \
+  V(WeakSet)                                                                   \
+  V(ArrayBuffer)                                                               \
+  V(DataView)                                                                  \
+  V(SharedArrayBuffer)                                                         \
+  V(Proxy)                                                                     \
+  V(ModuleNamespaceObject)
 
-  VALUE_METHOD_MAP(V)
+#define V(type)                                                                \
+  static void Is##type(const FunctionCallbackInfo<Value>& args) {              \
+    args.GetReturnValue().Set(args[0]->Is##type());                            \
+  }                                                                            \
+  static bool Is##type##FastApi(Local<Value> unused, Local<Value> value) {     \
+    TRACK_V8_FAST_API_CALL("types.is" #type);                                  \
+    return value->Is##type();                                                  \
+  }                                                                            \
+  static CFunction fast_is_##type##_ = CFunction::Make(Is##type##FastApi);
+
+VALUE_METHOD_MAP(V)
 #undef V
 
 static void IsAnyArrayBuffer(const FunctionCallbackInfo<Value>& args) {
   args.GetReturnValue().Set(
     args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer());
 }
 
+static bool IsAnyArrayBufferFastApi(Local<Value> unused, Local<Value> value) {
+  TRACK_V8_FAST_API_CALL("types.isAnyArrayBuffer");
+  return value->IsArrayBuffer() || value->IsSharedArrayBuffer();
+}
+
+static CFunction fast_is_any_array_buffer_ =
+    CFunction::Make(IsAnyArrayBufferFastApi);
+
 static void IsBoxedPrimitive(const FunctionCallbackInfo<Value>& args) {
   args.GetReturnValue().Set(
     args[0]->IsNumberObject() ||
@@ -61,27 +75,56 @@ static void IsBoxedPrimitive(const FunctionCallbackInfo<Value>& args) {
     args[0]->IsSymbolObject());
 }
 
+static bool IsBoxedPrimitiveFastApi(Local<Value> unused, Local<Value> value) {
+  TRACK_V8_FAST_API_CALL("types.isBoxedPrimitive");
+  return value->IsNumberObject() || value->IsStringObject() ||
+         value->IsBooleanObject() || value->IsBigIntObject() ||
+         value->IsSymbolObject();
+}
+
+static CFunction fast_is_boxed_primitive_ =
+    CFunction::Make(IsBoxedPrimitiveFastApi);
+
 void InitializeTypes(Local<Object> target,
                      Local<Value> unused,
                      Local<Context> context,
                      void* priv) {
-#define V(type) SetMethodNoSideEffect(context, target, "is" #type, Is##type);
+#define V(type)                                                                \
+  SetFastMethodNoSideEffect(                                                   \
+      context, target, "is" #type, Is##type, &fast_is_##type##_);
+
   VALUE_METHOD_MAP(V)
 #undef V
 
-  SetMethodNoSideEffect(context, target, "isAnyArrayBuffer", IsAnyArrayBuffer);
-  SetMethodNoSideEffect(context, target, "isBoxedPrimitive", IsBoxedPrimitive);
+  SetFastMethodNoSideEffect(context,
+                            target,
+                            "isAnyArrayBuffer",
+                            IsAnyArrayBuffer,
+                            &fast_is_any_array_buffer_);
+  SetFastMethodNoSideEffect(context,
+                            target,
+                            "isBoxedPrimitive",
+                            IsBoxedPrimitive,
+                            &fast_is_boxed_primitive_);
 }
 
 }  // anonymous namespace
 
 void RegisterTypesExternalReferences(ExternalReferenceRegistry* registry) {
-#define V(type) registry->Register(Is##type);
+#define V(type)                                                                \
+  registry->Register(Is##type);                                                \
+  registry->Register(Is##type##FastApi);                                       \
+  registry->Register(fast_is_##type##_.GetTypeInfo());
+
   VALUE_METHOD_MAP(V)
 #undef V
 
   registry->Register(IsAnyArrayBuffer);
+  registry->Register(IsAnyArrayBufferFastApi);
+  registry->Register(fast_is_any_array_buffer_.GetTypeInfo());
   registry->Register(IsBoxedPrimitive);
+  registry->Register(IsBoxedPrimitiveFastApi);
+  registry->Register(fast_is_boxed_primitive_.GetTypeInfo());
 }
 }  // namespace node
 

filename: test/parallel/test-util-types.js
patch: @@ -1,4 +1,4 @@
-// Flags: --experimental-vm-modules --expose-internals
+// Flags: --experimental-vm-modules --expose-internals --allow-natives-syntax
 'use strict';
 const common = require('../common');
 const assert = require('assert');
@@ -291,3 +291,447 @@ for (const [ value, _method ] of [
   assert.ok(!types.isCryptoKey());
   assert.ok(!types.isKeyObject());
 }
+
+// Fast path tests for the types module.
+
+{
+  function testIsDate(input) {
+    return types.isDate(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsDate)');
+  testIsDate(new Date());
+  eval('%OptimizeFunctionOnNextCall(testIsDate)');
+  assert.strictEqual(testIsDate(new Date()), true);
+  assert.strictEqual(testIsDate(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isDate'), 2);
+  }
+}
+
+{
+  function testIsArgumentsObject(input) {
+    return types.isArgumentsObject(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsArgumentsObject)');
+  testIsArgumentsObject((function() { return arguments; })());
+  eval('%OptimizeFunctionOnNextCall(testIsArgumentsObject)');
+  assert.strictEqual(testIsArgumentsObject((function() { return arguments; })()), true);
+  assert.strictEqual(testIsArgumentsObject(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isArgumentsObject'), 2);
+  }
+}
+
+{
+  function testIsBigIntObject(input) {
+    return types.isBigIntObject(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsBigIntObject)');
+  testIsBigIntObject(Object(BigInt(0)));
+  eval('%OptimizeFunctionOnNextCall(testIsBigIntObject)');
+  assert.strictEqual(testIsBigIntObject(Object(BigInt(0))), true);
+  assert.strictEqual(testIsBigIntObject(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isBigIntObject'), 2);
+  }
+}
+
+{
+  function testIsBooleanObject(input) {
+    return types.isBooleanObject(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsBooleanObject)');
+  testIsBooleanObject(new Boolean());
+  eval('%OptimizeFunctionOnNextCall(testIsBooleanObject)');
+  assert.strictEqual(testIsBooleanObject(new Boolean()), true);
+  assert.strictEqual(testIsBooleanObject(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isBooleanObject'), 2);
+  }
+}
+
+{
+  function testIsNumberObject(input) {
+    return types.isNumberObject(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsNumberObject)');
+  testIsNumberObject(new Number());
+  eval('%OptimizeFunctionOnNextCall(testIsNumberObject)');
+  assert.strictEqual(testIsNumberObject(new Number()), true);
+  assert.strictEqual(testIsNumberObject(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isNumberObject'), 2);
+  }
+}
+
+{
+  function testIsStringObject(input) {
+    return types.isStringObject(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsStringObject)');
+  testIsStringObject(new String());
+  eval('%OptimizeFunctionOnNextCall(testIsStringObject)');
+  assert.strictEqual(testIsStringObject(new String()), true);
+  assert.strictEqual(testIsStringObject(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isStringObject'), 2);
+  }
+}
+
+{
+  function testIsSymbolObject(input) {
+    return types.isSymbolObject(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsSymbolObject)');
+  testIsSymbolObject(Object(Symbol()));
+  eval('%OptimizeFunctionOnNextCall(testIsSymbolObject)');
+  assert.strictEqual(testIsSymbolObject(Object(Symbol())), true);
+  assert.strictEqual(testIsSymbolObject(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isSymbolObject'), 2);
+  }
+}
+
+{
+  function testIsNativeError(input) {
+    return types.isNativeError(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsNativeError)');
+  testIsNativeError(new Error());
+  eval('%OptimizeFunctionOnNextCall(testIsNativeError)');
+  assert.strictEqual(testIsNativeError(new Error()), true);
+  assert.strictEqual(testIsNativeError(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isNativeError'), 2);
+  }
+}
+
+{
+  function testIsRegExp(input) {
+    return types.isRegExp(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsRegExp)');
+  testIsRegExp(new RegExp());
+  eval('%OptimizeFunctionOnNextCall(testIsRegExp)');
+  assert.strictEqual(testIsRegExp(new RegExp()), true);
+  assert.strictEqual(testIsRegExp(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isRegExp'), 2);
+  }
+}
+
+{
+  function testIsAsyncFunction(input) {
+    return types.isAsyncFunction(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsAsyncFunction)');
+  testIsAsyncFunction(async function() {});
+  eval('%OptimizeFunctionOnNextCall(testIsAsyncFunction)');
+  assert.strictEqual(testIsAsyncFunction(async function() {}), true);
+  assert.strictEqual(testIsAsyncFunction(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isAsyncFunction'), 2);
+  }
+}
+
+{
+  function testIsGeneratorFunction(input) {
+    return types.isGeneratorFunction(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsGeneratorFunction)');
+  testIsGeneratorFunction(function*() {});
+  eval('%OptimizeFunctionOnNextCall(testIsGeneratorFunction)');
+  assert.strictEqual(testIsGeneratorFunction(function*() {}), true);
+  assert.strictEqual(testIsGeneratorFunction(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isGeneratorFunction'), 2);
+  }
+}
+
+{
+  function testIsGeneratorObject(input) {
+    return types.isGeneratorObject(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsGeneratorObject)');
+  testIsGeneratorObject((function*() {})());
+  eval('%OptimizeFunctionOnNextCall(testIsGeneratorObject)');
+  assert.strictEqual(testIsGeneratorObject((function*() {})()), true);
+  assert.strictEqual(testIsGeneratorObject(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isGeneratorObject'), 2);
+  }
+}
+
+{
+  function testIsPromise(input) {
+    return types.isPromise(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsPromise)');
+  testIsPromise(Promise.resolve());
+  eval('%OptimizeFunctionOnNextCall(testIsPromise)');
+  assert.strictEqual(testIsPromise(Promise.resolve()), true);
+  assert.strictEqual(testIsPromise(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isPromise'), 2);
+  }
+}
+
+{
+  function testIsMap(input) {
+    return types.isMap(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsMap)');
+  testIsMap(new Map());
+  eval('%OptimizeFunctionOnNextCall(testIsMap)');
+  assert.strictEqual(testIsMap(new Map()), true);
+  assert.strictEqual(testIsMap(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isMap'), 2);
+  }
+}
+
+{
+  function testIsSet(input) {
+    return types.isSet(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsSet)');
+  testIsSet(new Set());
+  eval('%OptimizeFunctionOnNextCall(testIsSet)');
+  assert.strictEqual(testIsSet(new Set()), true);
+  assert.strictEqual(testIsSet(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isSet'), 2);
+  }
+}
+
+{
+  function testIsMapIterator(input) {
+    return types.isMapIterator(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsMapIterator)');
+  testIsMapIterator((new Map())[Symbol.iterator]());
+  eval('%OptimizeFunctionOnNextCall(testIsMapIterator)');
+  assert.strictEqual(testIsMapIterator((new Map())[Symbol.iterator]()), true);
+  assert.strictEqual(testIsMapIterator(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isMapIterator'), 2);
+  }
+}
+
+{
+  function testIsSetIterator(input) {
+    return types.isSetIterator(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsSetIterator)');
+  testIsSetIterator((new Set())[Symbol.iterator]());
+  eval('%OptimizeFunctionOnNextCall(testIsSetIterator)');
+  assert.strictEqual(testIsSetIterator((new Set())[Symbol.iterator]()), true);
+  assert.strictEqual(testIsSetIterator(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isSetIterator'), 2);
+  }
+}
+
+{
+  function testIsWeakMap(input) {
+    return types.isWeakMap(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsWeakMap)');
+  testIsWeakMap(new WeakMap());
+  eval('%OptimizeFunctionOnNextCall(testIsWeakMap)');
+  assert.strictEqual(testIsWeakMap(new WeakMap()), true);
+  assert.strictEqual(testIsWeakMap(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isWeakMap'), 2);
+  }
+}
+
+{
+  function testIsWeakSet(input) {
+    return types.isWeakSet(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsWeakSet)');
+  testIsWeakSet(new WeakSet());
+  eval('%OptimizeFunctionOnNextCall(testIsWeakSet)');
+  assert.strictEqual(testIsWeakSet(new WeakSet()), true);
+  assert.strictEqual(testIsWeakSet(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isWeakSet'), 2);
+  }
+}
+
+{
+  function testIsArrayBuffer(input) {
+    return types.isArrayBuffer(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsArrayBuffer)');
+  testIsArrayBuffer(new ArrayBuffer());
+  eval('%OptimizeFunctionOnNextCall(testIsArrayBuffer)');
+  assert.strictEqual(testIsArrayBuffer(new ArrayBuffer()), true);
+  assert.strictEqual(testIsArrayBuffer(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isArrayBuffer'), 2);
+  }
+}
+
+{
+  function testIsDataView(input) {
+    return types.isDataView(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsDataView)');
+  testIsDataView(new DataView(new ArrayBuffer()));
+  eval('%OptimizeFunctionOnNextCall(testIsDataView)');
+  assert.strictEqual(testIsDataView(new DataView(new ArrayBuffer())), true);
+  assert.strictEqual(testIsDataView(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isDataView'), 2);
+  }
+}
+
+{
+  function testIsSharedArrayBuffer(input) {
+    return types.isSharedArrayBuffer(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsSharedArrayBuffer)');
+  testIsSharedArrayBuffer(new SharedArrayBuffer());
+  eval('%OptimizeFunctionOnNextCall(testIsSharedArrayBuffer)');
+  assert.strictEqual(testIsSharedArrayBuffer(new SharedArrayBuffer()), true);
+  assert.strictEqual(testIsSharedArrayBuffer(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isSharedArrayBuffer'), 2);
+  }
+}
+
+{
+  function testIsProxy(input) {
+    return types.isProxy(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsProxy)');
+  testIsProxy(new Proxy({}, {}));
+  eval('%OptimizeFunctionOnNextCall(testIsProxy)');
+  assert.strictEqual(testIsProxy(new Proxy({}, {})), true);
+  assert.strictEqual(testIsProxy(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isProxy'), 2);
+  }
+}
+
+{
+  function testIsExternal(input) {
+    return types.isExternal(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsExternal)');
+  testIsExternal(external);
+  eval('%OptimizeFunctionOnNextCall(testIsExternal)');
+  assert.strictEqual(testIsExternal(external), true);
+  assert.strictEqual(testIsExternal(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isExternal'), 2);
+  }
+}
+
+{
+  function testIsAnyArrayBuffer(input) {
+    return types.isAnyArrayBuffer(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsAnyArrayBuffer)');
+  testIsAnyArrayBuffer(new ArrayBuffer());
+  eval('%OptimizeFunctionOnNextCall(testIsAnyArrayBuffer)');
+  assert.strictEqual(testIsAnyArrayBuffer(new ArrayBuffer()), true);
+  assert.strictEqual(testIsAnyArrayBuffer(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isAnyArrayBuffer'), 2);
+  }
+}
+
+{
+  function testIsBoxedPrimitive(input) {
+    return types.isBoxedPrimitive(input);
+  }
+
+  eval('%PrepareFunctionForOptimization(testIsBoxedPrimitive)');
+  testIsBoxedPrimitive(new String());
+  eval('%OptimizeFunctionOnNextCall(testIsBoxedPrimitive)');
+  assert.strictEqual(testIsBoxedPrimitive(new String()), true);
+  assert.strictEqual(testIsBoxedPrimitive(Math.random()), false);
+
+  if (common.isDebug) {
+    const { getV8FastApiCallCount } = internalBinding('debug');
+    assert.strictEqual(getV8FastApiCallCount('types.isBoxedPrimitive'), 2);
+  }
+}