Skip to content

Commit 92d14c0

Browse files
kfarnungmhdawson
authored andcommitted
Update files from node
* Added `node_internals.cc/h` to shim missing internal functions * Added `util.h` and `util-inl.h` for incoming changes to error helpers PR-URL: #79 Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Jason Ginchereau <[email protected]>
1 parent 10ef293 commit 92d14c0

File tree

8 files changed

+413
-29
lines changed

8 files changed

+413
-29
lines changed

src/node_api.cc

Lines changed: 182 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#include <vector>
1818
#include "uv.h"
1919
#include "node_api.h"
20+
#include "node_internals.h"
21+
22+
#define NAPI_VERSION 1
2023

2124
static
2225
napi_status napi_set_last_error(napi_env env, napi_status error_code,
@@ -31,14 +34,33 @@ struct napi_env__ {
3134
~napi_env__() {
3235
last_exception.Reset();
3336
has_instance.Reset();
37+
wrap_template.Reset();
38+
function_data_template.Reset();
39+
accessor_data_template.Reset();
3440
}
3541
v8::Isolate* isolate;
3642
v8::Persistent<v8::Value> last_exception;
3743
v8::Persistent<v8::Value> has_instance;
44+
v8::Persistent<v8::ObjectTemplate> wrap_template;
45+
v8::Persistent<v8::ObjectTemplate> function_data_template;
46+
v8::Persistent<v8::ObjectTemplate> accessor_data_template;
3847
bool has_instance_available;
3948
napi_extended_error_info last_error;
4049
};
4150

51+
#define ENV_OBJECT_TEMPLATE(env, prefix, destination, field_count) \
52+
do { \
53+
if ((env)->prefix ## _template.IsEmpty()) { \
54+
(destination) = v8::ObjectTemplate::New(isolate); \
55+
(destination)->SetInternalFieldCount((field_count)); \
56+
(env)->prefix ## _template.Reset(isolate, (destination)); \
57+
} else { \
58+
(destination) = v8::Local<v8::ObjectTemplate>::New( \
59+
isolate, env->prefix ## _template); \
60+
} \
61+
} while (0)
62+
63+
4264
#define RETURN_STATUS_IF_FALSE(env, condition, status) \
4365
do { \
4466
if (!(condition)) { \
@@ -154,14 +176,20 @@ class HandleScopeWrapper {
154176
// across different versions.
155177
class EscapableHandleScopeWrapper {
156178
public:
157-
explicit EscapableHandleScopeWrapper(v8::Isolate* isolate) : scope(isolate) {}
179+
explicit EscapableHandleScopeWrapper(v8::Isolate* isolate)
180+
: scope(isolate), escape_called_(false) {}
181+
bool escape_called() const {
182+
return escape_called_;
183+
}
158184
template <typename T>
159185
v8::Local<T> Escape(v8::Local<T> handle) {
186+
escape_called_ = true;
160187
return scope.Escape(handle);
161188
}
162189

163190
private:
164191
v8::EscapableHandleScope scope;
192+
bool escape_called_;
165193
};
166194

167195
napi_handle_scope JsHandleScopeFromV8HandleScope(HandleScopeWrapper* s) {
@@ -594,8 +622,8 @@ v8::Local<v8::Object> CreateFunctionCallbackData(napi_env env,
594622
v8::Isolate* isolate = env->isolate;
595623
v8::Local<v8::Context> context = isolate->GetCurrentContext();
596624

597-
v8::Local<v8::ObjectTemplate> otpl = v8::ObjectTemplate::New(isolate);
598-
otpl->SetInternalFieldCount(v8impl::kFunctionFieldCount);
625+
v8::Local<v8::ObjectTemplate> otpl;
626+
ENV_OBJECT_TEMPLATE(env, function_data, otpl, v8impl::kFunctionFieldCount);
599627
v8::Local<v8::Object> cbdata = otpl->NewInstance(context).ToLocalChecked();
600628

601629
cbdata->SetInternalField(
@@ -620,8 +648,8 @@ v8::Local<v8::Object> CreateAccessorCallbackData(napi_env env,
620648
v8::Isolate* isolate = env->isolate;
621649
v8::Local<v8::Context> context = isolate->GetCurrentContext();
622650

623-
v8::Local<v8::ObjectTemplate> otpl = v8::ObjectTemplate::New(isolate);
624-
otpl->SetInternalFieldCount(v8impl::kAccessorFieldCount);
651+
v8::Local<v8::ObjectTemplate> otpl;
652+
ENV_OBJECT_TEMPLATE(env, accessor_data, otpl, v8impl::kAccessorFieldCount);
625653
v8::Local<v8::Object> cbdata = otpl->NewInstance(context).ToLocalChecked();
626654

627655
cbdata->SetInternalField(
@@ -646,6 +674,38 @@ v8::Local<v8::Object> CreateAccessorCallbackData(napi_env env,
646674
return cbdata;
647675
}
648676

677+
// Pointer used to identify items wrapped by N-API. Used by FindWrapper and
678+
// napi_wrap().
679+
const char napi_wrap_name[] = "N-API Wrapper";
680+
681+
// Search the object's prototype chain for the wrapper object. Usually the
682+
// wrapper would be the first in the chain, but it is OK for other objects to
683+
// be inserted in the prototype chain.
684+
bool FindWrapper(v8::Local<v8::Object> obj,
685+
v8::Local<v8::Object>* result = nullptr) {
686+
v8::Local<v8::Object> wrapper = obj;
687+
688+
do {
689+
v8::Local<v8::Value> proto = wrapper->GetPrototype();
690+
if (proto.IsEmpty() || !proto->IsObject()) {
691+
return false;
692+
}
693+
wrapper = proto.As<v8::Object>();
694+
if (wrapper->InternalFieldCount() == 2) {
695+
v8::Local<v8::Value> external = wrapper->GetInternalField(1);
696+
if (external->IsExternal() &&
697+
external.As<v8::External>()->Value() == v8impl::napi_wrap_name) {
698+
break;
699+
}
700+
}
701+
} while (true);
702+
703+
if (result != nullptr) {
704+
*result = wrapper;
705+
}
706+
return true;
707+
}
708+
649709
} // end of namespace v8impl
650710

651711
// Intercepts the Node-V8 module registration callback. Converts parameters
@@ -716,7 +776,8 @@ const char* error_messages[] = {nullptr,
716776
"An array was expected",
717777
"Unknown failure",
718778
"An exception is pending",
719-
"The async work item was cancelled"};
779+
"The async work item was cancelled",
780+
"napi_escape_handle already called on scope"};
720781

721782
static napi_status napi_clear_last_error(napi_env env) {
722783
CHECK_ENV(env);
@@ -744,10 +805,14 @@ napi_status napi_get_last_error_info(napi_env env,
744805
CHECK_ENV(env);
745806
CHECK_ARG(env, result);
746807

808+
// you must update this assert to reference the last message
809+
// in the napi_status enum each time a new error message is added.
810+
// We don't have a napi_status_last as this would result in an ABI
811+
// change each time a message was added.
747812
static_assert(
748-
(sizeof (error_messages) / sizeof (*error_messages)) == napi_status_last,
813+
node::arraysize(error_messages) == napi_escape_called_twice + 1,
749814
"Count of error messages must match count of error values");
750-
assert(env->last_error.error_code < napi_status_last);
815+
assert(env->last_error.error_code <= napi_escape_called_twice);
751816

752817
// Wait until someone requests the last error information to fetch the error
753818
// message string
@@ -817,9 +882,6 @@ napi_status napi_define_class(napi_env env,
817882
v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(
818883
isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
819884

820-
// we need an internal field to stash the wrapped object
821-
tpl->InstanceTemplate()->SetInternalFieldCount(1);
822-
823885
v8::Local<v8::String> name_string;
824886
CHECK_NEW_FROM_UTF8(env, name_string, utf8name);
825887
tpl->SetClassName(name_string);
@@ -991,6 +1053,49 @@ napi_status napi_get_property(napi_env env,
9911053
return GET_RETURN_STATUS(env);
9921054
}
9931055

1056+
napi_status napi_delete_property(napi_env env,
1057+
napi_value object,
1058+
napi_value key,
1059+
bool* result) {
1060+
NAPI_PREAMBLE(env);
1061+
CHECK_ARG(env, key);
1062+
1063+
v8::Isolate* isolate = env->isolate;
1064+
v8::Local<v8::Context> context = isolate->GetCurrentContext();
1065+
v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1066+
v8::Local<v8::Object> obj;
1067+
1068+
CHECK_TO_OBJECT(env, context, obj, object);
1069+
v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1070+
CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1071+
1072+
if (result != NULL)
1073+
*result = delete_maybe.FromMaybe(false);
1074+
1075+
return GET_RETURN_STATUS(env);
1076+
}
1077+
1078+
NAPI_EXTERN napi_status napi_has_own_property(napi_env env,
1079+
napi_value object,
1080+
napi_value key,
1081+
bool* result) {
1082+
NAPI_PREAMBLE(env);
1083+
CHECK_ARG(env, key);
1084+
1085+
v8::Isolate* isolate = env->isolate;
1086+
v8::Local<v8::Context> context = isolate->GetCurrentContext();
1087+
v8::Local<v8::Object> obj;
1088+
1089+
CHECK_TO_OBJECT(env, context, obj, object);
1090+
v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1091+
RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1092+
v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1093+
CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1094+
*result = has_maybe.FromMaybe(false);
1095+
1096+
return GET_RETURN_STATUS(env);
1097+
}
1098+
9941099
napi_status napi_set_named_property(napi_env env,
9951100
napi_value object,
9961101
const char* utf8name,
@@ -1128,6 +1233,26 @@ napi_status napi_get_element(napi_env env,
11281233
return GET_RETURN_STATUS(env);
11291234
}
11301235

1236+
napi_status napi_delete_element(napi_env env,
1237+
napi_value object,
1238+
uint32_t index,
1239+
bool* result) {
1240+
NAPI_PREAMBLE(env);
1241+
1242+
v8::Isolate* isolate = env->isolate;
1243+
v8::Local<v8::Context> context = isolate->GetCurrentContext();
1244+
v8::Local<v8::Object> obj;
1245+
1246+
CHECK_TO_OBJECT(env, context, obj, object);
1247+
v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1248+
CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1249+
1250+
if (result != NULL)
1251+
*result = delete_maybe.FromMaybe(false);
1252+
1253+
return GET_RETURN_STATUS(env);
1254+
}
1255+
11311256
napi_status napi_define_properties(napi_env env,
11321257
napi_value object,
11331258
size_t property_count,
@@ -1948,14 +2073,34 @@ napi_status napi_wrap(napi_env env,
19482073
CHECK_ARG(env, js_object);
19492074

19502075
v8::Isolate* isolate = env->isolate;
1951-
v8::Local<v8::Object> obj =
1952-
v8impl::V8LocalValueFromJsValue(js_object).As<v8::Object>();
2076+
v8::Local<v8::Context> context = isolate->GetCurrentContext();
2077+
2078+
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
2079+
RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
2080+
v8::Local<v8::Object> obj = value.As<v8::Object>();
19532081

1954-
// Only objects that were created from a NAPI constructor's prototype
1955-
// via napi_define_class() can be (un)wrapped.
1956-
RETURN_STATUS_IF_FALSE(env, obj->InternalFieldCount() > 0, napi_invalid_arg);
2082+
// If we've already wrapped this object, we error out.
2083+
RETURN_STATUS_IF_FALSE(env, !v8impl::FindWrapper(obj), napi_invalid_arg);
19572084

1958-
obj->SetInternalField(0, v8::External::New(isolate, native_object));
2085+
// Create a wrapper object with an internal field to hold the wrapped pointer
2086+
// and a second internal field to identify the owner as N-API.
2087+
v8::Local<v8::ObjectTemplate> wrapper_template;
2088+
ENV_OBJECT_TEMPLATE(env, wrap, wrapper_template, 2);
2089+
2090+
auto maybe_object = wrapper_template->NewInstance(context);
2091+
CHECK_MAYBE_EMPTY(env, maybe_object, napi_generic_failure);
2092+
2093+
v8::Local<v8::Object> wrapper = maybe_object.ToLocalChecked();
2094+
wrapper->SetInternalField(1, v8::External::New(isolate,
2095+
reinterpret_cast<void*>(const_cast<char*>(v8impl::napi_wrap_name))));
2096+
2097+
// Store the pointer as an external in the wrapper.
2098+
wrapper->SetInternalField(0, v8::External::New(isolate, native_object));
2099+
2100+
// Insert the wrapper into the object's prototype chain.
2101+
v8::Local<v8::Value> proto = obj->GetPrototype();
2102+
CHECK(wrapper->SetPrototype(context, proto).FromJust());
2103+
CHECK(obj->SetPrototype(context, wrapper).FromJust());
19592104

19602105
if (result != nullptr) {
19612106
// The returned reference should be deleted via napi_delete_reference()
@@ -1986,11 +2131,11 @@ napi_status napi_unwrap(napi_env env, napi_value js_object, void** result) {
19862131
RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
19872132
v8::Local<v8::Object> obj = value.As<v8::Object>();
19882133

1989-
// Only objects that were created from a NAPI constructor's prototype
1990-
// via napi_define_class() can be (un)wrapped.
1991-
RETURN_STATUS_IF_FALSE(env, obj->InternalFieldCount() > 0, napi_invalid_arg);
2134+
v8::Local<v8::Object> wrapper;
2135+
RETURN_STATUS_IF_FALSE(
2136+
env, v8impl::FindWrapper(obj, &wrapper), napi_invalid_arg);
19922137

1993-
v8::Local<v8::Value> unwrappedValue = obj->GetInternalField(0);
2138+
v8::Local<v8::Value> unwrappedValue = wrapper->GetInternalField(0);
19942139
RETURN_STATUS_IF_FALSE(env, unwrappedValue->IsExternal(), napi_invalid_arg);
19952140

19962141
*result = unwrappedValue.As<v8::External>()->Value();
@@ -2195,9 +2340,12 @@ napi_status napi_escape_handle(napi_env env,
21952340

21962341
v8impl::EscapableHandleScopeWrapper* s =
21972342
v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope);
2198-
*result = v8impl::JsValueFromV8LocalValue(
2199-
s->Escape(v8impl::V8LocalValueFromJsValue(escapee)));
2200-
return napi_clear_last_error(env);
2343+
if (!s->escape_called()) {
2344+
*result = v8impl::JsValueFromV8LocalValue(
2345+
s->Escape(v8impl::V8LocalValueFromJsValue(escapee)));
2346+
return napi_clear_last_error(env);
2347+
}
2348+
return napi_set_last_error(env, napi_escape_called_twice);
22012349
}
22022350

22032351
napi_status napi_new_instance(napi_env env,
@@ -2250,7 +2398,7 @@ napi_status napi_instanceof(napi_env env,
22502398
}
22512399

22522400
if (env->has_instance_available) {
2253-
napi_value value, js_result, has_instance = nullptr;
2401+
napi_value value, js_result = nullptr, has_instance = nullptr;
22542402
napi_status status = napi_generic_failure;
22552403
napi_valuetype value_type;
22562404

@@ -2530,7 +2678,7 @@ napi_status napi_create_arraybuffer(napi_env env,
25302678
v8::ArrayBuffer::New(isolate, byte_length);
25312679

25322680
// Optionally return a pointer to the buffer's data, to avoid another call to
2533-
// retreive it.
2681+
// retrieve it.
25342682
if (data != nullptr) {
25352683
*data = buffer->GetContents().Data();
25362684
}
@@ -2713,6 +2861,13 @@ napi_status napi_get_typedarray_info(napi_env env,
27132861
return napi_clear_last_error(env);
27142862
}
27152863

2864+
napi_status napi_get_version(napi_env env, uint32_t* result) {
2865+
CHECK_ENV(env);
2866+
CHECK_ARG(env, result);
2867+
*result = NAPI_VERSION;
2868+
return napi_clear_last_error(env);
2869+
}
2870+
27162871
namespace uvimpl {
27172872

27182873
static napi_status ConvertUVErrorCode(int code) {
@@ -2781,7 +2936,7 @@ class Work {
27812936
// report it as a fatal exception. (There is no JavaScript on the
27822937
// callstack that can possibly handle it.)
27832938
if (!env->last_exception.IsEmpty()) {
2784-
v8::TryCatch try_catch;
2939+
v8::TryCatch try_catch(env->isolate);
27852940
env->isolate->ThrowException(
27862941
v8::Local<v8::Value>::New(env->isolate, env->last_exception));
27872942
node::FatalException(env->isolate, try_catch);

src/node_api.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
'type': 'static_library',
99
'sources': [
1010
'node_api.cc',
11+
'node_internals.cc',
1112
],
1213
'defines': [
1314
'EXTERNAL_NAPI',

0 commit comments

Comments
 (0)