@@ -72,18 +72,28 @@ inline void Debug(WASI* wasi, Args&&... args) {
7272 } \
7373 } while (0 )
7474
75+ #define CHECK_BOUNDS_OR_RETURN2 (mem_size, offset, buf_size ) \
76+ do { \
77+ if (!uvwasi_serdes_check_bounds ((offset), (mem_size), (buf_size))) { \
78+ return UVWASI_EOVERFLOW; \
79+ } \
80+ } while (0 )
81+
7582using v8::Array;
7683using v8::BackingStore;
7784using v8::BigInt;
85+ using v8::CFunction;
7886using v8::Context;
7987using v8::Exception;
88+ using v8::FastApiCallbackOptions;
8089using v8::FunctionCallbackInfo;
8190using v8::FunctionTemplate;
8291using v8::Integer;
8392using v8::Isolate;
8493using v8::Local;
8594using v8::MaybeLocal;
8695using v8::Object;
96+ using v8::Signature;
8797using v8::String;
8898using v8::Uint32;
8999using v8::Value;
@@ -248,46 +258,155 @@ void WASI::New(const FunctionCallbackInfo<Value>& args) {
248258 }
249259}
250260
261+ struct WasmMemory {
262+ char * data;
263+ size_t size;
264+ };
265+
266+ template <auto F, typename R, typename ... Args>
267+ class WasiFunction {
268+ public:
269+ static void SetFunction (Environment* env,
270+ const char * name,
271+ Local<FunctionTemplate> tmpl) {
272+ auto c_function = CFunction::Make (FastCallback);
273+ Local<FunctionTemplate> t =
274+ v8::FunctionTemplate::New (env->isolate (),
275+ SlowCallback,
276+ Local<Value>(),
277+ Local<Signature>(),
278+ sizeof ...(Args),
279+ v8::ConstructorBehavior::kThrow ,
280+ v8::SideEffectType::kHasSideEffect ,
281+ &c_function);
282+ const v8::NewStringType type = v8::NewStringType::kInternalized ;
283+ v8::Local<v8::String> name_string =
284+ v8::String::NewFromUtf8 (env->isolate (), name, type).ToLocalChecked ();
285+ tmpl->PrototypeTemplate ()->Set (name_string, t);
286+ t->SetClassName (name_string);
287+ }
251288
252- void WASI::ArgsGet (const FunctionCallbackInfo<Value>& args) {
253- WASI* wasi;
254- uint32_t argv_offset;
255- uint32_t argv_buf_offset;
256- char * memory;
257- size_t mem_size;
258- RETURN_IF_BAD_ARG_COUNT (args, 2 );
259- CHECK_TO_TYPE_OR_RETURN (args, args[0 ], Uint32, argv_offset);
260- CHECK_TO_TYPE_OR_RETURN (args, args[1 ], Uint32, argv_buf_offset);
261- ASSIGN_INITIALIZED_OR_RETURN_UNWRAP (&wasi, args.This ());
262- Debug (wasi, " args_get(%d, %d)\n " , argv_offset, argv_buf_offset);
263- GET_BACKING_STORE_OR_RETURN (wasi, args, &memory, &mem_size);
264- CHECK_BOUNDS_OR_RETURN (args,
265- mem_size,
266- argv_buf_offset,
267- wasi->uvw_ .argv_buf_size );
268- CHECK_BOUNDS_OR_RETURN (args,
269- mem_size,
270- argv_offset,
271- wasi->uvw_ .argc * UVWASI_SERDES_SIZE_uint32_t);
272- std::vector<char *> argv (wasi->uvw_ .argc );
273- char * argv_buf = &memory[argv_buf_offset];
274- uvwasi_errno_t err = uvwasi_args_get (&wasi->uvw_ , argv.data (), argv_buf);
289+ private:
290+ static R FastCallback (Local<Object> receiver,
291+ Args... args,
292+ FastApiCallbackOptions& options) {
293+ WASI* wasi = reinterpret_cast <WASI*>(BaseObject::FromJSObject (receiver));
294+ if (UNLIKELY (wasi == nullptr )) return UVWASI_EINVAL;
295+
296+ if (UNLIKELY (options.wasm_memory == nullptr )) return UVWASI_EINVAL;
297+ uint8_t * memory = nullptr ;
298+ CHECK (LIKELY (options.wasm_memory ->getStorageIfAligned (&memory)));
299+
300+ return F (*wasi, {(char *)memory, options.wasm_memory ->length ()}, args...);
301+ }
302+
303+ template <typename VT>
304+ static uvwasi_errno_t CheckType (Local<Value> v);
305+
306+ template <typename VT>
307+ static VT ConvertType (Local<Value> V);
308+
309+ template <>
310+ static uvwasi_errno_t CheckType<uint32_t >(Local<Value> value) {
311+ if (!value->IsUint32 ()) return UVWASI_EINVAL;
312+ return UVWASI_ESUCCESS;
313+ }
314+
315+ template <>
316+ static uint32_t ConvertType (Local<Value> value) {
317+ return value.As <Uint32>()->Value ();
318+ }
319+
320+ template <>
321+ static uvwasi_errno_t CheckType<uint64_t >(Local<Value> value) {
322+ if (!value->IsBigInt ()) return UVWASI_EINVAL;
323+ return UVWASI_ESUCCESS;
324+ }
325+
326+ template <>
327+ static uint64_t ConvertType (Local<Value> value) {
328+ Local<BigInt> js_value = value.As <BigInt>();
329+ bool lossless;
330+ return js_value->Uint64Value (&lossless);
331+ }
332+
333+ template <>
334+ static uvwasi_errno_t CheckType<int64_t >(Local<Value> value) {
335+ if (!value->IsBigInt ()) return UVWASI_EINVAL;
336+ return UVWASI_ESUCCESS;
337+ }
338+
339+ template <>
340+ static int64_t ConvertType (Local<Value> value) {
341+ Local<BigInt> js_value = value.As <BigInt>();
342+ bool lossless;
343+ return js_value->Int64Value (&lossless);
344+ }
345+
346+ #pragma clang diagnostic push
347+ #pragma clang diagnostic ignored "-Wunsequenced"
348+ static void SlowCallback (const FunctionCallbackInfo<Value>& args) {
349+ WASI* wasi;
350+ char * memory;
351+ size_t mem_size;
352+ RETURN_IF_BAD_ARG_COUNT (args, sizeof ...(Args));
353+ {
354+ int counter = 0 ;
355+ uvwasi_errno_t results[sizeof ...(Args)] = {
356+ (CheckType<Args>(args[counter++]))...};
357+ for (size_t i = 0 ; i < sizeof ...(Args); i += 1 ) {
358+ if (results[i] != UVWASI_ESUCCESS) {
359+ args.GetReturnValue ().Set (results[i]);
360+ return ;
361+ }
362+ }
363+ }
364+ ASSIGN_INITIALIZED_OR_RETURN_UNWRAP (&wasi, args.This ());
365+ GET_BACKING_STORE_OR_RETURN (wasi, args, &memory, &mem_size);
366+
367+ {
368+ int counter = 0 ;
369+ args.GetReturnValue ().Set (
370+ F (*wasi, {memory, mem_size}, ConvertType<Args>(args[counter++])...));
371+ }
372+ }
373+ #pragma clang diagnostic pop
374+ };
375+
376+ template <auto F, typename R, typename ... Args>
377+ static void SetFunction (R (*)(WASI&, WasmMemory, Args...),
378+ Environment* env,
379+ const char* name,
380+ Local<FunctionTemplate> tmpl) {
381+ WasiFunction<F, R, Args...>::SetFunction (env, name, tmpl);
382+ }
383+
384+ static uint32_t ArgsGet (WASI& wasi,
385+ WasmMemory memory,
386+ uint32_t argv_offset,
387+ uint32_t argv_buf_offset) {
388+ Debug (&wasi, " args_get(%d, %d)\n " , argv_offset, argv_buf_offset);
389+
390+ CHECK_BOUNDS_OR_RETURN2 (
391+ memory.size , argv_buf_offset, wasi.uvw_ .argv_buf_size );
392+ CHECK_BOUNDS_OR_RETURN2 (
393+ memory.size , argv_offset, wasi.uvw_ .argc * UVWASI_SERDES_SIZE_uint32_t);
394+ std::vector<char *> argv (wasi.uvw_ .argc );
395+ char * argv_buf = &memory.data [argv_buf_offset];
396+ uvwasi_errno_t err = uvwasi_args_get (&wasi.uvw_ , argv.data (), argv_buf);
275397
276398 if (err == UVWASI_ESUCCESS) {
277- for (size_t i = 0 ; i < wasi-> uvw_ .argc ; i++) {
399+ for (size_t i = 0 ; i < wasi. uvw_ .argc ; i++) {
278400 uint32_t offset =
279401 static_cast <uint32_t >(argv_buf_offset + (argv[i] - argv[0 ]));
280- uvwasi_serdes_write_uint32_t (memory,
281- argv_offset +
282- (i * UVWASI_SERDES_SIZE_uint32_t),
283- offset);
402+ uvwasi_serdes_write_uint32_t (
403+ memory.data , argv_offset + (i * UVWASI_SERDES_SIZE_uint32_t), offset);
284404 }
285405 }
286406
287- args. GetReturnValue (). Set ( err) ;
407+ return err;
288408}
289409
290-
291410void WASI::ArgsSizesGet (const FunctionCallbackInfo<Value>& args) {
292411 WASI* wasi;
293412 uint32_t argc_offset;
@@ -454,25 +573,16 @@ void WASI::EnvironSizesGet(const FunctionCallbackInfo<Value>& args) {
454573 args.GetReturnValue ().Set (err);
455574}
456575
457-
458- void WASI::FdAdvise (const FunctionCallbackInfo<Value>& args) {
459- WASI* wasi;
460- uint32_t fd;
461- uint64_t offset;
462- uint64_t len;
463- uint8_t advice;
464- RETURN_IF_BAD_ARG_COUNT (args, 4 );
465- CHECK_TO_TYPE_OR_RETURN (args, args[0 ], Uint32, fd);
466- UNWRAP_BIGINT_OR_RETURN (args, args[1 ], Uint64, offset);
467- UNWRAP_BIGINT_OR_RETURN (args, args[2 ], Uint64, len);
468- CHECK_TO_TYPE_OR_RETURN (args, args[3 ], Uint32, advice);
469- ASSIGN_INITIALIZED_OR_RETURN_UNWRAP (&wasi, args.This ());
470- Debug (wasi, " fd_advise(%d, %d, %d, %d)\n " , fd, offset, len, advice);
471- uvwasi_errno_t err = uvwasi_fd_advise (&wasi->uvw_ , fd, offset, len, advice);
472- args.GetReturnValue ().Set (err);
576+ static uint32_t FdAdvise (WASI& wasi,
577+ WasmMemory,
578+ uint32_t fd,
579+ uint64_t offset,
580+ uint64_t len,
581+ uint32_t advice) {
582+ Debug (&wasi, " fd_advise(%d, %d, %d, %d)\n " , fd, offset, len, advice);
583+ return uvwasi_fd_advise (&wasi.uvw_ , fd, offset, len, advice);
473584}
474585
475-
476586void WASI::FdAllocate (const FunctionCallbackInfo<Value>& args) {
477587 WASI* wasi;
478588 uint32_t fd;
@@ -892,40 +1002,24 @@ void WASI::FdRenumber(const FunctionCallbackInfo<Value>& args) {
8921002 args.GetReturnValue ().Set (err);
8931003}
8941004
895-
896- void WASI::FdSeek (const FunctionCallbackInfo<Value>& args) {
897- WASI* wasi;
898- uint32_t fd;
899- int64_t offset;
900- uint8_t whence;
901- uint32_t newoffset_ptr;
902- char * memory;
903- size_t mem_size;
904- RETURN_IF_BAD_ARG_COUNT (args, 4 );
905- CHECK_TO_TYPE_OR_RETURN (args, args[0 ], Uint32, fd);
906- UNWRAP_BIGINT_OR_RETURN (args, args[1 ], Int64, offset);
907- CHECK_TO_TYPE_OR_RETURN (args, args[2 ], Uint32, whence);
908- CHECK_TO_TYPE_OR_RETURN (args, args[3 ], Uint32, newoffset_ptr);
909- ASSIGN_INITIALIZED_OR_RETURN_UNWRAP (&wasi, args.This ());
910- Debug (wasi, " fd_seek(%d, %d, %d, %d)\n " , fd, offset, whence, newoffset_ptr);
911- GET_BACKING_STORE_OR_RETURN (wasi, args, &memory, &mem_size);
912- CHECK_BOUNDS_OR_RETURN (args,
913- mem_size,
914- newoffset_ptr,
915- UVWASI_SERDES_SIZE_filesize_t);
1005+ uint32_t FdSeek (WASI& wasi,
1006+ WasmMemory memory,
1007+ uint32_t fd,
1008+ int64_t offset,
1009+ uint32_t whence,
1010+ uint32_t newoffset_ptr) {
1011+ Debug (&wasi, " fd_seek(%d, %d, %d, %d)\n " , fd, offset, whence, newoffset_ptr);
1012+ CHECK_BOUNDS_OR_RETURN2 (
1013+ memory.size , newoffset_ptr, UVWASI_SERDES_SIZE_filesize_t);
9161014 uvwasi_filesize_t newoffset;
917- uvwasi_errno_t err = uvwasi_fd_seek (&wasi->uvw_ ,
918- fd,
919- offset,
920- whence,
921- &newoffset);
1015+ uvwasi_errno_t err =
1016+ uvwasi_fd_seek (&wasi.uvw_ , fd, offset, whence, &newoffset);
9221017 if (err == UVWASI_ESUCCESS)
923- uvwasi_serdes_write_filesize_t (memory, newoffset_ptr, newoffset);
1018+ uvwasi_serdes_write_filesize_t (memory. data , newoffset_ptr, newoffset);
9241019
925- args. GetReturnValue (). Set ( err) ;
1020+ return err;
9261021}
9271022
928-
9291023void WASI::FdSync (const FunctionCallbackInfo<Value>& args) {
9301024 WASI* wasi;
9311025 uint32_t fd;
@@ -1673,13 +1767,14 @@ static void Initialize(Local<Object> target,
16731767 tmpl->InstanceTemplate ()->SetInternalFieldCount (WASI::kInternalFieldCount );
16741768 tmpl->Inherit (BaseObject::GetConstructorTemplate (env));
16751769
1676- env->SetProtoMethod (tmpl, " args_get" , WASI::ArgsGet);
1770+ SetFunction<ArgsGet>(ArgsGet, env, " args_get" , tmpl);
1771+
16771772 env->SetProtoMethod (tmpl, " args_sizes_get" , WASI::ArgsSizesGet);
16781773 env->SetProtoMethod (tmpl, " clock_res_get" , WASI::ClockResGet);
16791774 env->SetProtoMethod (tmpl, " clock_time_get" , WASI::ClockTimeGet);
16801775 env->SetProtoMethod (tmpl, " environ_get" , WASI::EnvironGet);
16811776 env->SetProtoMethod (tmpl, " environ_sizes_get" , WASI::EnvironSizesGet);
1682- env-> SetProtoMethod (tmpl, " fd_advise" , WASI::FdAdvise );
1777+ SetFunction<FdAdvise>(FdAdvise, env, " fd_advise" , tmpl );
16831778 env->SetProtoMethod (tmpl, " fd_allocate" , WASI::FdAllocate);
16841779 env->SetProtoMethod (tmpl, " fd_close" , WASI::FdClose);
16851780 env->SetProtoMethod (tmpl, " fd_datasync" , WASI::FdDatasync);
@@ -1696,7 +1791,7 @@ static void Initialize(Local<Object> target,
16961791 env->SetProtoMethod (tmpl, " fd_read" , WASI::FdRead);
16971792 env->SetProtoMethod (tmpl, " fd_readdir" , WASI::FdReaddir);
16981793 env->SetProtoMethod (tmpl, " fd_renumber" , WASI::FdRenumber);
1699- env-> SetProtoMethod (tmpl, " fd_seek" , WASI::FdSeek );
1794+ SetFunction<FdSeek>(FdSeek, env, " fd_seek" , tmpl );
17001795 env->SetProtoMethod (tmpl, " fd_sync" , WASI::FdSync);
17011796 env->SetProtoMethod (tmpl, " fd_tell" , WASI::FdTell);
17021797 env->SetProtoMethod (tmpl, " fd_write" , WASI::FdWrite);
0 commit comments