%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/
Upload File :
Create Path :
Current File : //home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/node_wasm_web_api.cc

#include "node_wasm_web_api.h"

#include "memory_tracker-inl.h"
#include "node_errors.h"
#include "node_external_reference.h"

namespace node {
namespace wasm_web_api {

using v8::ArrayBuffer;
using v8::ArrayBufferView;
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::Object;
using v8::Value;
using v8::WasmStreaming;

Local<Function> WasmStreamingObject::Initialize(Environment* env) {
  Local<Function> templ = env->wasm_streaming_object_constructor();
  if (!templ.IsEmpty()) {
    return templ;
  }

  Isolate* isolate = env->isolate();
  Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New);
  t->InstanceTemplate()->SetInternalFieldCount(
      WasmStreamingObject::kInternalFieldCount);

  SetProtoMethod(isolate, t, "setURL", SetURL);
  SetProtoMethod(isolate, t, "push", Push);
  SetProtoMethod(isolate, t, "finish", Finish);
  SetProtoMethod(isolate, t, "abort", Abort);

  auto function = t->GetFunction(env->context()).ToLocalChecked();
  env->set_wasm_streaming_object_constructor(function);
  return function;
}

void WasmStreamingObject::RegisterExternalReferences(
    ExternalReferenceRegistry* registry) {
  registry->Register(New);
  registry->Register(Push);
  registry->Register(Finish);
  registry->Register(Abort);
}

void WasmStreamingObject::MemoryInfo(MemoryTracker* tracker) const {
  // v8::WasmStreaming is opaque. We assume that the size of the WebAssembly
  // module that is being compiled is roughly what V8 allocates (as in, off by
  // only a small factor).
  tracker->TrackFieldWithSize("streaming", wasm_size_);
}

MaybeLocal<Object> WasmStreamingObject::Create(
    Environment* env, std::shared_ptr<WasmStreaming> streaming) {
  Local<Function> ctor = Initialize(env);
  Local<Object> obj;
  if (!ctor->NewInstance(env->context(), 0, nullptr).ToLocal(&obj)) {
    return MaybeLocal<Object>();
  }

  CHECK(streaming);

  WasmStreamingObject* ptr = Unwrap<WasmStreamingObject>(obj);
  CHECK_NOT_NULL(ptr);
  ptr->streaming_ = streaming;
  ptr->wasm_size_ = 0;
  return obj;
}

void WasmStreamingObject::New(const FunctionCallbackInfo<Value>& args) {
  CHECK(args.IsConstructCall());
  Environment* env = Environment::GetCurrent(args);
  new WasmStreamingObject(env, args.This());
}

void WasmStreamingObject::SetURL(const FunctionCallbackInfo<Value>& args) {
  WasmStreamingObject* obj;
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.Holder());
  CHECK(obj->streaming_);

  CHECK_EQ(args.Length(), 1);
  CHECK(args[0]->IsString());
  Utf8Value url(Environment::GetCurrent(args)->isolate(), args[0]);
  obj->streaming_->SetUrl(url.out(), url.length());
}

void WasmStreamingObject::Push(const FunctionCallbackInfo<Value>& args) {
  WasmStreamingObject* obj;
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.Holder());
  CHECK(obj->streaming_);

  CHECK_EQ(args.Length(), 1);
  Local<Value> chunk = args[0];

  // The start of the memory section backing the ArrayBuffer(View), the offset
  // of the ArrayBuffer(View) within the memory section, and its size in bytes.
  const void* bytes;
  size_t offset;
  size_t size;

  if (LIKELY(chunk->IsArrayBufferView())) {
    Local<ArrayBufferView> view = chunk.As<ArrayBufferView>();
    bytes = view->Buffer()->Data();
    offset = view->ByteOffset();
    size = view->ByteLength();
  } else if (LIKELY(chunk->IsArrayBuffer())) {
    Local<ArrayBuffer> buffer = chunk.As<ArrayBuffer>();
    bytes = buffer->Data();
    offset = 0;
    size = buffer->ByteLength();
  } else {
    return node::THROW_ERR_INVALID_ARG_TYPE(
        Environment::GetCurrent(args),
        "chunk must be an ArrayBufferView or an ArrayBuffer");
  }

  // Forward the data to V8. Internally, V8 will make a copy.
  obj->streaming_->OnBytesReceived(static_cast<const uint8_t*>(bytes) + offset,
                                   size);
  obj->wasm_size_ += size;
}

void WasmStreamingObject::Finish(const FunctionCallbackInfo<Value>& args) {
  WasmStreamingObject* obj;
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.Holder());
  CHECK(obj->streaming_);

  CHECK_EQ(args.Length(), 0);
  obj->streaming_->Finish();
}

void WasmStreamingObject::Abort(const FunctionCallbackInfo<Value>& args) {
  WasmStreamingObject* obj;
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.Holder());
  CHECK(obj->streaming_);

  CHECK_EQ(args.Length(), 1);
  obj->streaming_->Abort(args[0]);
}

void StartStreamingCompilation(const FunctionCallbackInfo<Value>& info) {
  // V8 passes an instance of v8::WasmStreaming to this callback, which we can
  // use to pass the WebAssembly module bytes to V8 as we receive them.
  // Unfortunately, our fetch() implementation is a JavaScript dependency, so it
  // is difficult to implement the required logic here. Instead, we create a
  // a WasmStreamingObject that encapsulates v8::WasmStreaming and that we can
  // pass to the JavaScript implementation. The JavaScript implementation can
  // then push() bytes from the Response and eventually either finish() or
  // abort() the operation.

  // Create the wrapper object.
  std::shared_ptr<WasmStreaming> streaming =
      WasmStreaming::Unpack(info.GetIsolate(), info.Data());
  Environment* env = Environment::GetCurrent(info);
  Local<Object> obj;
  if (!WasmStreamingObject::Create(env, streaming).ToLocal(&obj)) {
    // A JavaScript exception is pending. Let V8 deal with it.
    return;
  }

  // V8 always passes one argument to this callback.
  CHECK_EQ(info.Length(), 1);

  // Prepare the JavaScript implementation for invocation. We will pass the
  // WasmStreamingObject as the first argument, followed by the argument that we
  // received from V8, i.e., the first argument passed to compileStreaming (or
  // instantiateStreaming).
  Local<Function> impl = env->wasm_streaming_compilation_impl();
  CHECK(!impl.IsEmpty());
  Local<Value> args[] = {obj, info[0]};

  // Hand control to the JavaScript implementation. It should never throw an
  // error, but if it does, we leave it to the calling V8 code to handle that
  // gracefully. Otherwise, we assert that the JavaScript function does not
  // return anything.
  MaybeLocal<Value> maybe_ret =
      impl->Call(env->context(), info.This(), 2, args);
  Local<Value> ret;
  CHECK_IMPLIES(maybe_ret.ToLocal(&ret), ret->IsUndefined());
}

// Called once by JavaScript during initialization.
void SetImplementation(const FunctionCallbackInfo<Value>& info) {
  Environment* env = Environment::GetCurrent(info);
  env->set_wasm_streaming_compilation_impl(info[0].As<Function>());
}

void Initialize(Local<Object> target,
                Local<Value>,
                Local<Context> context,
                void*) {
  SetMethod(context, target, "setImplementation", SetImplementation);
}

void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
  registry->Register(SetImplementation);
  registry->Register(StartStreamingCompilation);
  WasmStreamingObject::RegisterExternalReferences(registry);
}

}  // namespace wasm_web_api
}  // namespace node

NODE_BINDING_CONTEXT_AWARE_INTERNAL(wasm_web_api,
                                    node::wasm_web_api::Initialize)
NODE_BINDING_EXTERNAL_REFERENCE(wasm_web_api,
                                node::wasm_web_api::RegisterExternalReferences)

Zerion Mini Shell 1.0