chromium/v8/src/wasm/c-api.cc

// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This implementation is originally from
// https://github.com/WebAssembly/wasm-c-api/:

// Copyright 2019 Andreas Rossberg
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "src/wasm/c-api.h"

#include <cstring>
#include <iomanip>
#include <iostream>

#include "include/libplatform/libplatform.h"
#include "include/v8-initialization.h"
#include "src/api/api-inl.h"
#include "src/builtins/builtins.h"
#include "src/compiler/wasm-compiler.h"
#include "src/flags/flags.h"
#include "src/objects/call-site-info-inl.h"
#include "src/objects/js-collection-inl.h"
#include "src/objects/managed-inl.h"
#include "src/wasm/leb-helper.h"
#include "src/wasm/module-instantiate.h"
#include "src/wasm/serialized-signature-inl.h"
#include "src/wasm/signature-hashing.h"
#include "src/wasm/wasm-arguments.h"
#include "src/wasm/wasm-constants.h"
#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-result.h"
#include "src/wasm/wasm-serialization.h"
#include "third_party/wasm-api/wasm.h"
#ifdef ENABLE_VTUNE_JIT_INTERFACE
#include "src/third_party/vtune/v8-vtune.h"
#endif

#ifdef WASM_API_DEBUG
#error "WASM_API_DEBUG is unsupported"
#endif

// If you want counters support (what --dump-counters does for the d8 shell),
// then set this to 1 (in here, or via -DDUMP_COUNTERS=1 compiler argument).
#define DUMP_COUNTERS

namespace wasm {

namespace {

// Multi-cage pointer compression mode related note.
// Wasm C-Api is allowed to be used from a thread that's not bound to any
// Isolate. As a result, in a multi-cage pointer compression mode it's not
// guaranteed that current pointer compression cage base value is initialized
// for current thread (see V8HeapCompressionScheme::base_) which makes it
// impossible to read compressed pointers from V8 heap objects.
// This scope ensures that the pointer compression base value is set according
// to respective Wasm C-Api object.
// For all other configurations this scope is a no-op.
PtrComprCageAccessScope;

auto ReadLebU64(const byte_t** pos) -> uint64_t {}

ValKind V8ValueTypeToWasm(i::wasm::ValueType v8_valtype) {}

i::wasm::ValueType WasmValKindToV8(ValKind kind) {}

Name GetNameFromWireBytes(const i::wasm::WireBytesRef& ref,
                          v8::base::Vector<const uint8_t> wire_bytes) {}

own<FuncType> FunctionSigToFuncType(const i::wasm::FunctionSig* sig) {}

own<ExternType> GetImportExportType(const i::wasm::WasmModule* module,
                                    const i::wasm::ImportExportKindCode kind,
                                    const uint32_t index) {}

}  // namespace

/// BEGIN FILE wasm-v8.cc

///////////////////////////////////////////////////////////////////////////////
// Auxiliaries

[[noreturn]] void WASM_UNIMPLEMENTED(const char* s) {}

template <class T>
void ignore(T) {}

template <class C>
struct implement;

template <class C>
auto impl(C* x) -> typename implement<C>::type* {}

template <class C>
auto impl(const C* x) -> const typename implement<C>::type* {}

template <class C>
auto seal(typename implement<C>::type* x) -> C* {}

template <class C>
auto seal(const typename implement<C>::type* x) -> const C* {}

///////////////////////////////////////////////////////////////////////////////
// Runtime Environment

// Configuration

struct ConfigImpl {};

template <>
struct implement<Config> {};

Config::~Config() {}

void Config::operator delete(void* p) {}

auto Config::make() -> own<Config> {}

// Engine

#if DUMP_COUNTERS
class Counter {
 public:
  static const int kMaxNameSize = 64;
  int32_t* Bind(const char* name, bool is_histogram) {
    int i;
    for (i = 0; i < kMaxNameSize - 1 && name[i]; i++) {
      name_[i] = static_cast<char>(name[i]);
    }
    name_[i] = '\0';
    is_histogram_ = is_histogram;
    return ptr();
  }
  int32_t* ptr() { return &count_; }
  int32_t count() { return count_; }
  int32_t sample_total() { return sample_total_; }
  bool is_histogram() { return is_histogram_; }
  void AddSample(int32_t sample) {
    count_++;
    sample_total_ += sample;
  }

 private:
  int32_t count_;
  int32_t sample_total_;
  bool is_histogram_;
  uint8_t name_[kMaxNameSize];
};

class CounterCollection {
 public:
  CounterCollection() = default;
  Counter* GetNextCounter() {
    if (counters_in_use_ == kMaxCounters) return nullptr;
    return &counters_[counters_in_use_++];
  }

 private:
  static const unsigned kMaxCounters = 512;
  uint32_t counters_in_use_{0};
  Counter counters_[kMaxCounters];
};

using CounterMap = std::unordered_map<std::string, Counter*>;

#endif

struct EngineImpl {};

bool EngineImpl::created =;

#if DUMP_COUNTERS
CounterCollection EngineImpl::counters_;
CounterMap* EngineImpl::counter_map_;
#endif

template <>
struct implement<Engine> {};

Engine::~Engine() {}

void Engine::operator delete(void* p) {}

auto Engine::make(own<Config>&& config) -> own<Engine> {}

// This should be called somewhat regularly, especially on potentially hot
// sections of pure C++ execution. To achieve that, we call it on API entry
// points that heap-allocate but don't call into generated code.
// For example, finalization of incremental marking is relying on it.
void CheckAndHandleInterrupts(i::Isolate* isolate) {}

// Stores

StoreImpl::~StoreImpl() {}

struct ManagedData {};

void StoreImpl::SetHostInfo(i::Handle<i::Object> object, void* info,
                            void (*finalizer)(void*)) {}

void* StoreImpl::GetHostInfo(i::Handle<i::Object> key) {}

template <>
struct implement<Store> {};

Store::~Store() {}

void Store::operator delete(void* p) {}

auto Store::make(Engine*) -> own<Store> {}

///////////////////////////////////////////////////////////////////////////////
// Type Representations

// Value Types

struct ValTypeImpl {};

template <>
struct implement<ValType> {};

ValTypeImpl* valtype_i32 =;
ValTypeImpl* valtype_i64 =;
ValTypeImpl* valtype_f32 =;
ValTypeImpl* valtype_f64 =;
ValTypeImpl* valtype_externref =;
ValTypeImpl* valtype_funcref =;

ValType::~ValType() = default;

void ValType::operator delete(void*) {}

own<ValType> ValType::make(ValKind k) {}

auto ValType::copy() const -> own<ValType> {}

auto ValType::kind() const -> ValKind {}

// Extern Types

struct ExternTypeImpl {};

template <>
struct implement<ExternType> {};

ExternType::~ExternType() {}

void ExternType::operator delete(void* p) {}

auto ExternType::copy() const -> own<ExternType> {}

auto ExternType::kind() const -> ExternKind {}

// Function Types

struct FuncTypeImpl : ExternTypeImpl {};

template <>
struct implement<FuncType> {};

FuncType::~FuncType() = default;

auto FuncType::make(ownvec<ValType>&& params, ownvec<ValType>&& results)
    -> own<FuncType> {}

auto FuncType::copy() const -> own<FuncType> {}

auto FuncType::params() const -> const ownvec<ValType>& {}

auto FuncType::results() const -> const ownvec<ValType>& {}

auto ExternType::func() -> FuncType* {}

auto ExternType::func() const -> const FuncType* {}

// Global Types

struct GlobalTypeImpl : ExternTypeImpl {};

template <>
struct implement<GlobalType> {};

GlobalType::~GlobalType() = default;

auto GlobalType::make(own<ValType>&& content, Mutability mutability)
    -> own<GlobalType> {}

auto GlobalType::copy() const -> own<GlobalType> {}

auto GlobalType::content() const -> const ValType* {}

auto GlobalType::mutability() const -> Mutability {}

auto ExternType::global() -> GlobalType* {}

auto ExternType::global() const -> const GlobalType* {}

// Table Types

struct TableTypeImpl : ExternTypeImpl {};

template <>
struct implement<TableType> {};

TableType::~TableType() = default;

auto TableType::make(own<ValType>&& element, Limits limits) -> own<TableType> {}

auto TableType::copy() const -> own<TableType> {}

auto TableType::element() const -> const ValType* {}

auto TableType::limits() const -> const Limits& {}

auto ExternType::table() -> TableType* {}

auto ExternType::table() const -> const TableType* {}

// Memory Types

struct MemoryTypeImpl : ExternTypeImpl {};

template <>
struct implement<MemoryType> {};

MemoryType::~MemoryType() = default;

auto MemoryType::make(Limits limits) -> own<MemoryType> {}

auto MemoryType::copy() const -> own<MemoryType> {}

auto MemoryType::limits() const -> const Limits& {}

auto ExternType::memory() -> MemoryType* {}

auto ExternType::memory() const -> const MemoryType* {}

// Import Types

struct ImportTypeImpl {};

template <>
struct implement<ImportType> {};

ImportType::~ImportType() {}

void ImportType::operator delete(void* p) {}

auto ImportType::make(Name&& module, Name&& name, own<ExternType>&& type)
    -> own<ImportType> {}

auto ImportType::copy() const -> own<ImportType> {}

auto ImportType::module() const -> const Name& {}

auto ImportType::name() const -> const Name& {}

auto ImportType::type() const -> const ExternType* {}

// Export Types

struct ExportTypeImpl {};

template <>
struct implement<ExportType> {};

ExportType::~ExportType() {}

void ExportType::operator delete(void* p) {}

auto ExportType::make(Name&& name, own<ExternType>&& type) -> own<ExportType> {}

auto ExportType::copy() const -> own<ExportType> {}

auto ExportType::name() const -> const Name& {}

auto ExportType::type() const -> const ExternType* {}

i::Handle<i::String> VecToString(i::Isolate* isolate,
                                 const vec<byte_t>& chars) {}

// References

template <class Ref, class JSType>
class RefImpl {};

template <>
struct implement<Ref> {};

Ref::~Ref() {}

void Ref::operator delete(void* p) {}

auto Ref::copy() const -> own<Ref> {}

auto Ref::same(const Ref* that) const -> bool {}

auto Ref::get_host_info() const -> void* {}

void Ref::set_host_info(void* info, void (*finalizer)(void*)) {}

///////////////////////////////////////////////////////////////////////////////
// Runtime Objects

// Frames

namespace {

struct FrameImpl {};

}  // namespace

template <>
struct implement<Frame> {};

Frame::~Frame() {}

void Frame::operator delete(void* p) {}

own<Frame> Frame::copy() const {}

Instance* Frame::instance() const {}

uint32_t Frame::func_index() const {}

size_t Frame::func_offset() const {}

size_t Frame::module_offset() const {}

// Traps

template <>
struct implement<Trap> {};

Trap::~Trap() = default;

auto Trap::copy() const -> own<Trap> {}

auto Trap::make(Store* store_abs, const Message& message) -> own<Trap> {}

auto Trap::message() const -> Message {}

namespace {

own<Instance> GetInstance(StoreImpl* store,
                          i::Handle<i::WasmInstanceObject> instance);

own<Frame> CreateFrameFromInternal(i::DirectHandle<i::FixedArray> frames,
                                   int index, i::Isolate* isolate,
                                   StoreImpl* store) {}

}  // namespace

own<Frame> Trap::origin() const {}

ownvec<Frame> Trap::trace() const {}

// Foreign Objects

template <>
struct implement<Foreign> {};

Foreign::~Foreign() = default;

auto Foreign::copy() const -> own<Foreign> {}

auto Foreign::make(Store* store_abs) -> own<Foreign> {}

// Modules

template <>
struct implement<Module> {};

Module::~Module() = default;

auto Module::copy() const -> own<Module> {}

auto Module::validate(Store* store_abs, const vec<byte_t>& binary) -> bool {}

auto Module::make(Store* store_abs, const vec<byte_t>& binary) -> own<Module> {}

auto Module::imports() const -> ownvec<ImportType> {}

ownvec<ExportType> ExportsImpl(
    i::DirectHandle<i::WasmModuleObject> module_obj) {}

auto Module::exports() const -> ownvec<ExportType> {}

// We tier up all functions to TurboFan, and then serialize all TurboFan code.
// If no TurboFan code existed before calling this function, then the call to
// {serialize} may take a long time.
auto Module::serialize() const -> vec<byte_t> {}

auto Module::deserialize(Store* store_abs, const vec<byte_t>& serialized)
    -> own<Module> {}

// TODO(v8): do better when V8 can do better.
template <>
struct implement<Shared<Module>> {};

template <>
Shared<Module>::~Shared() {
  impl(this)->~vec();
}

template <>
void Shared<Module>::operator delete(void* p) {
  ::operator delete(p);
}

auto Module::share() const -> own<Shared<Module>> {}

auto Module::obtain(Store* store, const Shared<Module>* shared) -> own<Module> {}

// Externals

template <>
struct implement<Extern> {};

Extern::~Extern() = default;

auto Extern::copy() const -> own<Extern> {}

auto Extern::kind() const -> ExternKind {}

auto Extern::type() const -> own<ExternType> {}

auto Extern::func() -> Func* {}

auto Extern::global() -> Global* {}

auto Extern::table() -> Table* {}

auto Extern::memory() -> Memory* {}

auto Extern::func() const -> const Func* {}

auto Extern::global() const -> const Global* {}

auto Extern::table() const -> const Table* {}

auto Extern::memory() const -> const Memory* {}

auto extern_to_v8(const Extern* ex) -> i::Handle<i::JSReceiver> {}

// Function Instances

template <>
struct implement<Func> {};

Func::~Func() = default;

auto Func::copy() const -> own<Func> {}

struct FuncData {};

namespace {

class SignatureHelper : public i::AllStatic {};

auto make_func(Store* store_abs, std::shared_ptr<FuncData> data) -> own<Func> {}

}  // namespace

auto Func::make(Store* store, const FuncType* type, Func::callback callback)
    -> own<Func> {}

auto Func::make(Store* store, const FuncType* type, callback_with_env callback,
                void* env, void (*finalizer)(void*)) -> own<Func> {}

auto Func::type() const -> own<FuncType> {}

auto Func::param_arity() const -> size_t {}

auto Func::result_arity() const -> size_t {}

namespace {

own<Ref> V8RefValueToWasm(StoreImpl* store, i::Handle<i::Object> value) {}

i::Handle<i::Object> WasmRefToV8(i::Isolate* isolate, const Ref* ref) {}

void PrepareFunctionData(
    i::Isolate* isolate,
    i::DirectHandle<i::WasmExportedFunctionData> function_data,
    const i::wasm::FunctionSig* sig, const i::wasm::WasmModule* module) {}

void PushArgs(const i::wasm::FunctionSig* sig, const Val args[],
              i::wasm::CWasmArgumentsPacker* packer, StoreImpl* store) {}

void PopArgs(const i::wasm::FunctionSig* sig, Val results[],
             i::wasm::CWasmArgumentsPacker* packer, StoreImpl* store) {}

own<Trap> CallWasmCapiFunction(i::Tagged<i::WasmCapiFunctionData> data,
                               const Val args[], Val results[]) {}

i::Handle<i::JSReceiver> GetProperException(
    i::Isolate* isolate, i::Handle<i::Object> maybe_exception) {}

}  // namespace

auto Func::call(const Val args[], Val results[]) const -> own<Trap> {}

i::Address FuncData::v8_callback(i::Address host_data_foreign,
                                 i::Address argv) {}

// Global Instances

template <>
struct implement<Global> {};

Global::~Global() = default;

auto Global::copy() const -> own<Global> {}

auto Global::make(Store* store_abs, const GlobalType* type, const Val& val)
    -> own<Global> {}

auto Global::type() const -> own<GlobalType> {}

auto Global::get() const -> Val {}

void Global::set(const Val& val) {}

// Table Instances

template <>
struct implement<Table> {};

Table::~Table() = default;

auto Table::copy() const -> own<Table> {}

auto Table::make(Store* store_abs, const TableType* type, const Ref* ref)
    -> own<Table> {}

auto Table::type() const -> own<TableType> {}

// TODO(14034): Handle types other than funcref and externref if needed.
auto Table::get(size_t index) const -> own<Ref> {}

auto Table::set(size_t index, const Ref* ref) -> bool {}

// TODO(jkummerow): Having Table::size_t shadowing "std" size_t is ugly.
auto Table::size() const -> size_t {}

auto Table::grow(size_t delta, const Ref* ref) -> bool {}

// Memory Instances

template <>
struct implement<Memory> {};

Memory::~Memory() = default;

auto Memory::copy() const -> own<Memory> {}

auto Memory::make(Store* store_abs, const MemoryType* type) -> own<Memory> {}

auto Memory::type() const -> own<MemoryType> {}

auto Memory::data() const -> byte_t* {}

auto Memory::data_size() const -> size_t {}

auto Memory::size() const -> pages_t {}

auto Memory::grow(pages_t delta) -> bool {}

// Module Instances

template <>
struct implement<Instance> {};

Instance::~Instance() = default;

auto Instance::copy() const -> own<Instance> {}

own<Instance> Instance::make(Store* store_abs, const Module* module_abs,
                             const Extern* const imports[], own<Trap>* trap) {}

namespace {

own<Instance> GetInstance(StoreImpl* store,
                          i::Handle<i::WasmInstanceObject> instance) {}

}  // namespace

auto Instance::exports() const -> ownvec<Extern> {}

///////////////////////////////////////////////////////////////////////////////

}  // namespace wasm

// BEGIN FILE wasm-c.cc

extern  // extern "C"