@@ -825,6 +825,58 @@ void Reference::WeakCallback(const v8::WeakCallbackInfo<Reference>& data) {
825
825
reference->env_ ->InvokeFinalizerFromGC (reference);
826
826
}
827
827
828
+ /* *
829
+ * A wrapper for `v8::External` to support type-tagging. `v8::External` doesn't
830
+ * support defining any properties and private properties on it, even though it
831
+ * is an object. This wrapper is used to store the type tag and the data of the
832
+ * external value.
833
+ */
834
+ class ExternalWrapper {
835
+ private:
836
+ ExternalWrapper (void * data) : data_(data) {}
837
+
838
+ static void WeakCallback (const v8::WeakCallbackInfo<ExternalWrapper>& data) {
839
+ ExternalWrapper* wrapper = data.GetParameter ();
840
+ delete wrapper;
841
+ }
842
+
843
+ public:
844
+ static v8::Local<v8::External> New (napi_env env, void * data) {
845
+ ExternalWrapper* wrapper = new ExternalWrapper (data);
846
+ v8::Local<v8::External> external = v8::External::New (env->isolate , wrapper);
847
+ wrapper->persistent_ .Reset (env->isolate , external);
848
+ wrapper->persistent_ .SetWeak (
849
+ wrapper, WeakCallback, v8::WeakCallbackType::kParameter );
850
+
851
+ return external;
852
+ }
853
+
854
+ static ExternalWrapper* From (v8::Local<v8::External> external) {
855
+ return static_cast <ExternalWrapper*>(external->Value ());
856
+ }
857
+
858
+ void * Data () { return data_; }
859
+
860
+ bool TypeTag (const napi_type_tag* type_tag) {
861
+ if (type_tag_ != nullptr ) {
862
+ return false ;
863
+ }
864
+ type_tag_ = type_tag;
865
+ return true ;
866
+ }
867
+
868
+ bool CheckTypeTag (const napi_type_tag* type_tag) {
869
+ return type_tag == type_tag_ ||
870
+ (type_tag_ && type_tag->lower == type_tag_->lower &&
871
+ type_tag->upper == type_tag_->upper );
872
+ }
873
+
874
+ private:
875
+ v8impl::Persistent<v8::Value> persistent_;
876
+ void * data_;
877
+ const napi_type_tag* type_tag_ = nullptr ;
878
+ };
879
+
828
880
} // end of namespace v8impl
829
881
830
882
// Warning: Keep in-sync with napi_status enum
@@ -2517,9 +2569,8 @@ napi_status NAPI_CDECL napi_create_external(napi_env env,
2517
2569
NAPI_PREAMBLE (env);
2518
2570
CHECK_ARG (env, result);
2519
2571
2520
- v8::Isolate* isolate = env->isolate ;
2521
-
2522
- v8::Local<v8::Value> external_value = v8::External::New (isolate, data);
2572
+ v8::Local<v8::External> external_value =
2573
+ v8impl::ExternalWrapper::New (env, data);
2523
2574
2524
2575
if (finalize_cb) {
2525
2576
// The Reference object will delete itself after invoking the finalizer
@@ -2539,12 +2590,24 @@ napi_status NAPI_CDECL napi_create_external(napi_env env,
2539
2590
}
2540
2591
2541
2592
napi_status NAPI_CDECL napi_type_tag_object (napi_env env,
2542
- napi_value object ,
2593
+ napi_value object_or_external ,
2543
2594
const napi_type_tag* type_tag) {
2544
2595
NAPI_PREAMBLE (env);
2545
2596
v8::Local<v8::Context> context = env->context ();
2597
+
2598
+ CHECK_ARG (env, object_or_external);
2599
+ v8::Local<v8::Value> val =
2600
+ v8impl::V8LocalValueFromJsValue (object_or_external);
2601
+ if (val->IsExternal ()) {
2602
+ v8impl::ExternalWrapper* wrapper =
2603
+ v8impl::ExternalWrapper::From (val.As <v8::External>());
2604
+ RETURN_STATUS_IF_FALSE_WITH_PREAMBLE (
2605
+ env, wrapper->TypeTag (type_tag), napi_invalid_arg);
2606
+ return GET_RETURN_STATUS (env);
2607
+ }
2608
+
2546
2609
v8::Local<v8::Object> obj;
2547
- CHECK_TO_OBJECT_WITH_PREAMBLE (env, context, obj, object );
2610
+ CHECK_TO_OBJECT_WITH_PREAMBLE (env, context, obj, object_or_external );
2548
2611
CHECK_ARG_WITH_PREAMBLE (env, type_tag);
2549
2612
2550
2613
auto key = NAPI_PRIVATE_KEY (context, type_tag);
@@ -2566,13 +2629,24 @@ napi_status NAPI_CDECL napi_type_tag_object(napi_env env,
2566
2629
}
2567
2630
2568
2631
napi_status NAPI_CDECL napi_check_object_type_tag (napi_env env,
2569
- napi_value object ,
2632
+ napi_value object_or_external ,
2570
2633
const napi_type_tag* type_tag,
2571
2634
bool * result) {
2572
2635
NAPI_PREAMBLE (env);
2573
2636
v8::Local<v8::Context> context = env->context ();
2637
+
2638
+ CHECK_ARG (env, object_or_external);
2639
+ v8::Local<v8::Value> obj_val =
2640
+ v8impl::V8LocalValueFromJsValue (object_or_external);
2641
+ if (obj_val->IsExternal ()) {
2642
+ v8impl::ExternalWrapper* wrapper =
2643
+ v8impl::ExternalWrapper::From (obj_val.As <v8::External>());
2644
+ *result = wrapper->CheckTypeTag (type_tag);
2645
+ return GET_RETURN_STATUS (env);
2646
+ }
2647
+
2574
2648
v8::Local<v8::Object> obj;
2575
- CHECK_TO_OBJECT_WITH_PREAMBLE (env, context, obj, object );
2649
+ CHECK_TO_OBJECT_WITH_PREAMBLE (env, context, obj, object_or_external );
2576
2650
CHECK_ARG_WITH_PREAMBLE (env, type_tag);
2577
2651
CHECK_ARG_WITH_PREAMBLE (env, result);
2578
2652
@@ -2617,7 +2691,7 @@ napi_status NAPI_CDECL napi_get_value_external(napi_env env,
2617
2691
RETURN_STATUS_IF_FALSE (env, val->IsExternal (), napi_invalid_arg);
2618
2692
2619
2693
v8::Local<v8::External> external_value = val.As <v8::External>();
2620
- *result = external_value-> Value ();
2694
+ *result = v8impl::ExternalWrapper::From ( external_value)-> Data ();
2621
2695
2622
2696
return napi_clear_last_error (env);
2623
2697
}
0 commit comments