Skip to content

Commit ba9b2f0

Browse files
devsnektargos
authored andcommitted
wasi: use WasmMemoryObject handle for perf (#43544)
PR-URL: #43544 Reviewed-By: Tobias Nießen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent f8bdc53 commit ba9b2f0

5 files changed

+22
-129
lines changed

lib/wasi.js

-16
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@ const {
1010
} = primordials;
1111

1212
const {
13-
ERR_INVALID_ARG_TYPE,
1413
ERR_WASI_ALREADY_STARTED
1514
} = require('internal/errors').codes;
1615
const {
1716
emitExperimentalWarning,
1817
kEmptyObject,
1918
} = require('internal/util');
20-
const { isArrayBuffer } = require('internal/util/types');
2119
const {
2220
validateArray,
2321
validateBoolean,
@@ -39,20 +37,6 @@ function setupInstance(self, instance) {
3937
validateObject(instance, 'instance');
4038
validateObject(instance.exports, 'instance.exports');
4139

42-
// WASI::_SetMemory() in src/node_wasi.cc only expects that |memory| is
43-
// an object. It will try to look up the .buffer property when needed
44-
// and fail with UVWASI_EINVAL when the property is missing or is not
45-
// an ArrayBuffer. Long story short, we don't need much validation here
46-
// but we type-check anyway because it helps catch bugs in the user's
47-
// code early.
48-
validateObject(instance.exports.memory, 'instance.exports.memory');
49-
if (!isArrayBuffer(instance.exports.memory.buffer)) {
50-
throw new ERR_INVALID_ARG_TYPE(
51-
'instance.exports.memory.buffer',
52-
['WebAssembly.Memory'],
53-
instance.exports.memory.buffer);
54-
}
55-
5640
self[kInstance] = instance;
5741
self[kSetMemory](instance.exports.memory);
5842
}

src/node_wasi.cc

+12-18
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,7 @@ inline void Debug(WASI* wasi, Args&&... args) {
7272
} \
7373
} while (0)
7474

75-
7675
using v8::Array;
77-
using v8::ArrayBuffer;
7876
using v8::BackingStore;
7977
using v8::BigInt;
8078
using v8::Context;
@@ -89,7 +87,7 @@ using v8::Object;
8987
using v8::String;
9088
using v8::Uint32;
9189
using v8::Value;
92-
90+
using v8::WasmMemoryObject;
9391

9492
static MaybeLocal<Value> WASIException(Local<Context> context,
9593
int errorno,
@@ -1642,26 +1640,22 @@ void WASI::SockShutdown(const FunctionCallbackInfo<Value>& args) {
16421640

16431641
void WASI::_SetMemory(const FunctionCallbackInfo<Value>& args) {
16441642
WASI* wasi;
1645-
CHECK_EQ(args.Length(), 1);
1646-
CHECK(args[0]->IsObject());
16471643
ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This());
1648-
wasi->memory_.Reset(wasi->env()->isolate(), args[0].As<Object>());
1644+
CHECK_EQ(args.Length(), 1);
1645+
if (!args[0]->IsWasmMemoryObject()) {
1646+
return node::THROW_ERR_INVALID_ARG_TYPE(
1647+
wasi->env(),
1648+
"\"instance.exports.memory\" property must be a WebAssembly.Memory "
1649+
"object");
1650+
}
1651+
wasi->memory_.Reset(wasi->env()->isolate(), args[0].As<WasmMemoryObject>());
16491652
}
16501653

16511654

16521655
uvwasi_errno_t WASI::backingStore(char** store, size_t* byte_length) {
1653-
Environment* env = this->env();
1654-
Local<Object> memory = PersistentToLocal::Strong(this->memory_);
1655-
Local<Value> prop;
1656-
1657-
if (!memory->Get(env->context(), env->buffer_string()).ToLocal(&prop))
1658-
return UVWASI_EINVAL;
1659-
1660-
if (!prop->IsArrayBuffer())
1661-
return UVWASI_EINVAL;
1662-
1663-
Local<ArrayBuffer> ab = prop.As<ArrayBuffer>();
1664-
std::shared_ptr<BackingStore> backing_store = ab->GetBackingStore();
1656+
Local<WasmMemoryObject> memory = PersistentToLocal::Strong(this->memory_);
1657+
std::shared_ptr<BackingStore> backing_store =
1658+
memory->Buffer()->GetBackingStore();
16651659
*byte_length = backing_store->ByteLength();
16661660
*store = static_cast<char*>(backing_store->Data());
16671661
CHECK_NOT_NULL(*store);

src/node_wasi.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class WASI : public BaseObject,
9494
inline void writeUInt64(char* memory, uint64_t value, uint32_t offset);
9595
uvwasi_errno_t backingStore(char** store, size_t* byte_length);
9696
uvwasi_t uvw_;
97-
v8::Global<v8::Object> memory_;
97+
v8::Global<v8::WasmMemoryObject> memory_;
9898
uvwasi_mem_t alloc_info_;
9999
size_t current_uvwasi_memory_ = 0;
100100
};

test/wasi/test-wasi-initialize-validation.js

+6-47
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ const bufferSource = fixtures.readSync('simple.wasm');
4747

4848
Object.defineProperty(instance, 'exports', {
4949
get() {
50-
return { _initialize: 5, memory: new Uint8Array() };
50+
return {
51+
_initialize: 5,
52+
memory: new WebAssembly.Memory({ initial: 1 }),
53+
};
5154
},
5255
});
5356
assert.throws(
@@ -70,7 +73,7 @@ const bufferSource = fixtures.readSync('simple.wasm');
7073
return {
7174
_start() {},
7275
_initialize() {},
73-
memory: new Uint8Array(),
76+
memory: new WebAssembly.Memory({ initial: 1 }),
7477
};
7578
}
7679
});
@@ -97,55 +100,11 @@ const bufferSource = fixtures.readSync('simple.wasm');
97100
() => { wasi.initialize(instance); },
98101
{
99102
code: 'ERR_INVALID_ARG_TYPE',
100-
message: /"instance\.exports\.memory" property must be of type object/
103+
message: /"instance\.exports\.memory" property must be a WebAssembly\.Memory object/
101104
}
102105
);
103106
}
104107

105-
{
106-
// Verify that a non-ArrayBuffer memory.buffer is rejected.
107-
const wasi = new WASI({});
108-
const wasm = await WebAssembly.compile(bufferSource);
109-
const instance = await WebAssembly.instantiate(wasm);
110-
111-
Object.defineProperty(instance, 'exports', {
112-
get() {
113-
return {
114-
_initialize() {},
115-
memory: {},
116-
};
117-
}
118-
});
119-
// The error message is a little white lie because any object
120-
// with a .buffer property of type ArrayBuffer is accepted,
121-
// but 99% of the time a WebAssembly.Memory object is used.
122-
assert.throws(
123-
() => { wasi.initialize(instance); },
124-
{
125-
code: 'ERR_INVALID_ARG_TYPE',
126-
message: /"instance\.exports\.memory\.buffer" property must be an WebAssembly\.Memory/
127-
}
128-
);
129-
}
130-
131-
{
132-
// Verify that an argument that duck-types as a WebAssembly.Instance
133-
// is accepted.
134-
const wasi = new WASI({});
135-
const wasm = await WebAssembly.compile(bufferSource);
136-
const instance = await WebAssembly.instantiate(wasm);
137-
138-
Object.defineProperty(instance, 'exports', {
139-
get() {
140-
return {
141-
_initialize() {},
142-
memory: { buffer: new ArrayBuffer(0) },
143-
};
144-
}
145-
});
146-
wasi.initialize(instance);
147-
}
148-
149108
{
150109
// Verify that a WebAssembly.Instance from another VM context is accepted.
151110
const wasi = new WASI({});

test/wasi/test-wasi-start-validation.js

+3-47
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const bufferSource = fixtures.readSync('simple.wasm');
4747

4848
Object.defineProperty(instance, 'exports', {
4949
get() {
50-
return { memory: new Uint8Array() };
50+
return { memory: new WebAssembly.Memory({ initial: 1 }) };
5151
},
5252
});
5353
assert.throws(
@@ -70,7 +70,7 @@ const bufferSource = fixtures.readSync('simple.wasm');
7070
return {
7171
_start() {},
7272
_initialize() {},
73-
memory: new Uint8Array(),
73+
memory: new WebAssembly.Memory({ initial: 1 }),
7474
};
7575
}
7676
});
@@ -97,55 +97,11 @@ const bufferSource = fixtures.readSync('simple.wasm');
9797
() => { wasi.start(instance); },
9898
{
9999
code: 'ERR_INVALID_ARG_TYPE',
100-
message: /"instance\.exports\.memory" property must be of type object/
100+
message: /"instance\.exports\.memory" property must be a WebAssembly\.Memory object/
101101
}
102102
);
103103
}
104104

105-
{
106-
// Verify that a non-ArrayBuffer memory.buffer is rejected.
107-
const wasi = new WASI({});
108-
const wasm = await WebAssembly.compile(bufferSource);
109-
const instance = await WebAssembly.instantiate(wasm);
110-
111-
Object.defineProperty(instance, 'exports', {
112-
get() {
113-
return {
114-
_start() {},
115-
memory: {},
116-
};
117-
}
118-
});
119-
// The error message is a little white lie because any object
120-
// with a .buffer property of type ArrayBuffer is accepted,
121-
// but 99% of the time a WebAssembly.Memory object is used.
122-
assert.throws(
123-
() => { wasi.start(instance); },
124-
{
125-
code: 'ERR_INVALID_ARG_TYPE',
126-
message: /"instance\.exports\.memory\.buffer" property must be an WebAssembly\.Memory/
127-
}
128-
);
129-
}
130-
131-
{
132-
// Verify that an argument that duck-types as a WebAssembly.Instance
133-
// is accepted.
134-
const wasi = new WASI({});
135-
const wasm = await WebAssembly.compile(bufferSource);
136-
const instance = await WebAssembly.instantiate(wasm);
137-
138-
Object.defineProperty(instance, 'exports', {
139-
get() {
140-
return {
141-
_start() {},
142-
memory: { buffer: new ArrayBuffer(0) },
143-
};
144-
}
145-
});
146-
wasi.start(instance);
147-
}
148-
149105
{
150106
// Verify that a WebAssembly.Instance from another VM context is accepted.
151107
const wasi = new WASI({});

0 commit comments

Comments
 (0)