1+ #include " env-inl.h"
12#include " node_binding.h"
3+ #include " node_errors.h"
24#include " node_external_reference.h"
35#include " util-inl.h"
46#include " v8.h"
@@ -12,50 +14,35 @@ using v8::Context;
1214using v8::FunctionCallbackInfo;
1315using v8::Isolate;
1416using v8::Local;
17+ using v8::Name;
18+ using v8::Null;
19+ using v8::Number;
1520using v8::Object;
16- using v8::SharedArrayBuffer;
1721using v8::Uint32;
1822using v8::Uint8Array;
1923using v8::Value;
2024
21- namespace {
22-
23- inline bool BufferIsDetached (Local<Value> buffer) {
24- if (buffer->IsArrayBuffer ()) {
25- return buffer.As <ArrayBuffer>()->WasDetached ();
26- }
27- // SharedArrayBuffers cannot be detached.
28- return false ;
29- }
30-
31- inline size_t BufferByteLength (Local<Value> buffer) {
32- if (buffer->IsArrayBuffer ()) {
33- return buffer.As <ArrayBuffer>()->ByteLength ();
34- }
35- return buffer.As <SharedArrayBuffer>()->ByteLength ();
36- }
37-
38- } // namespace
39-
40- // Equivalent to:
41- // Reflect.get(view.constructor.prototype, 'buffer', view)
42- // but uses the V8 API directly so it is immune to prototype tampering and
43- // avoids the JS-side overhead of the defensive accessor in lib/internal/.
44- void ArrayBufferViewGetBuffer (const FunctionCallbackInfo<Value>& args) {
45- CHECK (args[0 ]->IsArrayBufferView ());
46- args.GetReturnValue ().Set (args[0 ].As <ArrayBufferView>()->Buffer ());
47- }
48-
49- void ArrayBufferViewGetByteLength (const FunctionCallbackInfo<Value>& args) {
50- CHECK (args[0 ]->IsArrayBufferView ());
51- Local<ArrayBufferView> view = args[0 ].As <ArrayBufferView>();
52- args.GetReturnValue ().Set (static_cast <double >(view->ByteLength ()));
53- }
54-
55- void ArrayBufferViewGetByteOffset (const FunctionCallbackInfo<Value>& args) {
25+ // Returns { buffer, byteOffset, byteLength } in a single binding crossing,
26+ // equivalent to reading the three properties via
27+ // Reflect.get(view.constructor.prototype, ..., view). Uses the V8 API
28+ // directly so it is immune to prototype tampering and avoids the JS-side
29+ // overhead of the defensive accessors in lib/internal/.
30+ void GetArrayBufferView (const FunctionCallbackInfo<Value>& args) {
31+ Isolate* isolate = args.GetIsolate ();
5632 CHECK (args[0 ]->IsArrayBufferView ());
5733 Local<ArrayBufferView> view = args[0 ].As <ArrayBufferView>();
58- args.GetReturnValue ().Set (static_cast <double >(view->ByteOffset ()));
34+ Local<Name> names[] = {
35+ FIXED_ONE_BYTE_STRING (isolate, " buffer" ),
36+ FIXED_ONE_BYTE_STRING (isolate, " byteOffset" ),
37+ FIXED_ONE_BYTE_STRING (isolate, " byteLength" ),
38+ };
39+ Local<Value> values[] = {
40+ view->Buffer (),
41+ Number::New (isolate, static_cast <double >(view->ByteOffset ())),
42+ Number::New (isolate, static_cast <double >(view->ByteLength ())),
43+ };
44+ args.GetReturnValue ().Set (Object::New (
45+ isolate, Null (isolate), names, values, arraysize (names)));
5946}
6047
6148// Returns true iff bytes can be safely copied between the buffers given the
@@ -72,14 +59,17 @@ void CanCopyArrayBuffer(const FunctionCallbackInfo<Value>& args) {
7259 CHECK (args[3 ]->IsUint32 ());
7360 CHECK (args[4 ]->IsUint32 ());
7461
75- Local<Object> to_buffer = args[0 ].As <Object>();
76- Local<Object> from_buffer = args[2 ].As <Object>();
62+ // SharedArrayBuffer handles are interoperable with ArrayBuffer handles in
63+ // V8, so we can use the ArrayBuffer accessors uniformly. WasDetached()
64+ // always returns false on a SAB.
65+ Local<ArrayBuffer> to_buffer = args[0 ].As <ArrayBuffer>();
66+ Local<ArrayBuffer> from_buffer = args[2 ].As <ArrayBuffer>();
7767
7868 if (to_buffer->StrictEquals (from_buffer)) {
7969 args.GetReturnValue ().Set (false );
8070 return ;
8171 }
82- if (BufferIsDetached (args[ 0 ] ) || BufferIsDetached (args[ 2 ] )) {
72+ if (to_buffer-> WasDetached ( ) || from_buffer-> WasDetached ( )) {
8373 args.GetReturnValue ().Set (false );
8474 return ;
8575 }
@@ -88,8 +78,8 @@ void CanCopyArrayBuffer(const FunctionCallbackInfo<Value>& args) {
8878 uint32_t from_index = args[3 ].As <Uint32>()->Value ();
8979 uint32_t count = args[4 ].As <Uint32>()->Value ();
9080
91- size_t to_byte_length = BufferByteLength (args[ 0 ] );
92- size_t from_byte_length = BufferByteLength (args[ 2 ] );
81+ size_t to_byte_length = to_buffer-> ByteLength ( );
82+ size_t from_byte_length = from_buffer-> ByteLength ( );
9383
9484 bool ok = static_cast <uint64_t >(to_index) + count <= to_byte_length &&
9585 static_cast <uint64_t >(from_index) + count <= from_byte_length;
@@ -103,11 +93,17 @@ void CanCopyArrayBuffer(const FunctionCallbackInfo<Value>& args) {
10393// returns a Uint8Array over the full new buffer. Avoids the JS-side
10494// Reflect.get + slice round-trip.
10595void CloneAsUint8Array (const FunctionCallbackInfo<Value>& args) {
106- Isolate* isolate = args.GetIsolate ();
96+ Environment* env = Environment::GetCurrent (args);
97+ Isolate* isolate = env->isolate ();
10798 CHECK (args[0 ]->IsArrayBufferView ());
10899 Local<ArrayBufferView> view = args[0 ].As <ArrayBufferView>();
109100 size_t byte_length = view->ByteLength ();
110- Local<ArrayBuffer> new_buffer = ArrayBuffer::New (isolate, byte_length);
101+ Local<ArrayBuffer> new_buffer;
102+ if (!ArrayBuffer::MaybeNew (isolate, byte_length).ToLocal (&new_buffer)) {
103+ // MaybeNew does not schedule an exception on allocation failure.
104+ env->ThrowRangeError (" Array buffer allocation failed" );
105+ return ;
106+ }
111107 if (byte_length > 0 ) {
112108 size_t copied = view->CopyContents (new_buffer->Data (), byte_length);
113109 CHECK_EQ (copied, byte_length);
@@ -119,20 +115,13 @@ void Initialize(Local<Object> target,
119115 Local<Value> unused,
120116 Local<Context> context,
121117 void * priv) {
122- SetMethod (context, target, " arrayBufferViewGetBuffer" ,
123- ArrayBufferViewGetBuffer);
124- SetMethod (context, target, " arrayBufferViewGetByteLength" ,
125- ArrayBufferViewGetByteLength);
126- SetMethod (context, target, " arrayBufferViewGetByteOffset" ,
127- ArrayBufferViewGetByteOffset);
118+ SetMethod (context, target, " getArrayBufferView" , GetArrayBufferView);
128119 SetMethod (context, target, " canCopyArrayBuffer" , CanCopyArrayBuffer);
129120 SetMethod (context, target, " cloneAsUint8Array" , CloneAsUint8Array);
130121}
131122
132123void RegisterExternalReferences (ExternalReferenceRegistry* registry) {
133- registry->Register (ArrayBufferViewGetBuffer);
134- registry->Register (ArrayBufferViewGetByteLength);
135- registry->Register (ArrayBufferViewGetByteOffset);
124+ registry->Register (GetArrayBufferView);
136125 registry->Register (CanCopyArrayBuffer);
137126 registry->Register (CloneAsUint8Array);
138127}
0 commit comments