102auto ReadLebU64(
const byte_t**
pos) -> uint64_t {
109 n += (b & 0x7f) << shift;
111 }
while ((b & 0x80) != 0);
116ValKind V8ValueTypeToWasm(T v8_valtype)
117 requires(std::is_same_v<T, i::wasm::ValueType> ||
118 std::is_same_v<T, i::wasm::CanonicalValueType>)
120 switch (v8_valtype.kind()) {
130 case i::wasm::kRefNull:
131 switch (v8_valtype.heap_representation()) {
132 case i::wasm::HeapType::kFunc:
133 return ValKind::FUNCREF;
134 case i::wasm::HeapType::kExtern:
135 return ValKind::EXTERNREF;
144i::wasm::ValueType WasmValKindToV8(ValKind
kind) {
147 return i::wasm::kWasmI32;
149 return i::wasm::kWasmI64;
151 return i::wasm::kWasmF32;
153 return i::wasm::kWasmF64;
154 case ValKind::FUNCREF:
155 return i::wasm::kWasmFuncRef;
156 case ValKind::EXTERNREF:
157 return i::wasm::kWasmExternRef;
164Name GetNameFromWireBytes(
const i::wasm::WireBytesRef& ref,
168 if (ref.length() == 0)
return Name::make();
169 Name name = Name::make_uninitialized(ref.length());
170 std::memcpy(name.get(), wire_bytes.
begin() + ref.offset(), ref.length());
174own<FuncType> FunctionSigToFuncType(
const i::wasm::FunctionSig* sig) {
175 size_t param_count = sig->parameter_count();
176 ownvec<ValType> params = ownvec<ValType>::make_uninitialized(param_count);
177 for (
size_t i = 0;
i < param_count;
i++) {
178 params[
i] = ValType::make(V8ValueTypeToWasm(sig->GetParam(
i)));
180 size_t return_count = sig->return_count();
181 ownvec<ValType> results = ownvec<ValType>::make_uninitialized(return_count);
182 for (
size_t i = 0;
i < return_count;
i++) {
183 results[
i] = ValType::make(V8ValueTypeToWasm(sig->GetReturn(
i)));
185 return FuncType::make(std::move(params), std::move(results));
188own<ExternType> GetImportExportType(
const i::wasm::WasmModule* module,
189 const i::wasm::ImportExportKindCode
kind,
190 const uint32_t index) {
192 case i::wasm::kExternalFunction: {
193 return FunctionSigToFuncType(module->functions[index].sig);
195 case i::wasm::kExternalTable: {
196 const i::wasm::WasmTable& table =
module->tables[index];
197 own<ValType> elem = ValType::make(V8ValueTypeToWasm(table.type));
198 Limits limits(table.initial_size,
199 table.has_maximum_size
200 ? v8::base::checked_cast<int32_t>(table.maximum_size)
202 return TableType::make(std::move(elem), limits);
204 case i::wasm::kExternalMemory: {
205 const i::wasm::WasmMemory& memory =
module->memories[index];
206 Limits limits(memory.initial_pages,
207 memory.has_maximum_pages
208 ? v8::base::checked_cast<int32_t>(memory.maximum_pages)
210 return MemoryType::make(limits);
212 case i::wasm::kExternalGlobal: {
213 const i::wasm::WasmGlobal& global =
module->globals[index];
214 own<ValType> content = ValType::make(V8ValueTypeToWasm(global.type));
215 Mutability mutability =
216 global.mutability ? Mutability::VAR : Mutability::CONST;
217 return GlobalType::make(std::move(content), mutability);
219 case i::wasm::kExternalTag:
232 std::cerr <<
"Wasm API: " << s <<
" not supported yet!\n";
254 return reinterpret_cast<C*
>(
x);
259 return reinterpret_cast<const C*
>(
x);
277 return own<Config>(
seal<Config>(
new (std::nothrow) ConfigImpl()));
285 static const int kMaxNameSize = 64;
286 int32_t* Bind(
const char* name,
bool is_histogram) {
288 for (
i = 0;
i < kMaxNameSize - 1 && name[
i];
i++) {
289 name_[
i] =
static_cast<char>(name[
i]);
292 is_histogram_ = is_histogram;
297 int32_t sample_total() {
return sample_total_; }
298 bool is_histogram() {
return is_histogram_; }
299 void AddSample(int32_t sample) {
301 sample_total_ += sample;
308 uint8_t
name_[kMaxNameSize];
311class CounterCollection {
313 CounterCollection() =
default;
314 Counter* GetNextCounter() {
315 if (counters_in_use_ == kMaxCounters)
return nullptr;
320 static const unsigned kMaxCounters = 512;
321 uint32_t counters_in_use_{0};
325using CounterMap = std::unordered_map<std::string, Counter*>;
336 static CounterMap* counter_map_;
338 static Counter* GetCounter(
const char* name,
bool is_histogram) {
339 auto map_entry = counter_map_->find(name);
341 map_entry != counter_map_->end() ? map_entry->second :
nullptr;
343 if (counter ==
nullptr) {
345 if (counter !=
nullptr) {
346 (*counter_map_)[
name] = counter;
347 counter->Bind(name, is_histogram);
350 DCHECK(counter->is_histogram() == is_histogram);
355 static int* LookupCounter(
const char* name) {
356 Counter* counter = GetCounter(name,
false);
358 if (counter !=
nullptr) {
359 return counter->ptr();
365 static void* CreateHistogram(
const char* name,
int min,
int max,
367 return GetCounter(name,
true);
370 static void AddHistogramSample(
void* histogram,
int sample) {
371 Counter* counter =
reinterpret_cast<Counter*
>(histogram);
372 counter->AddSample(sample);
380 counter_map_ =
new CounterMap();
386 std::vector<std::pair<std::string, Counter*>> counters(
387 counter_map_->begin(), counter_map_->end());
388 std::sort(counters.begin(), counters.end());
390 constexpr int kNameBoxSize = 64;
391 constexpr int kValueBoxSize = 13;
392 std::cout <<
"+" << std::string(kNameBoxSize,
'-') <<
"+"
393 << std::string(kValueBoxSize,
'-') <<
"+\n";
394 std::cout <<
"| Name" << std::string(kNameBoxSize - 5,
' ') <<
"| Value"
395 << std::string(kValueBoxSize - 6,
' ') <<
"|\n";
396 std::cout <<
"+" << std::string(kNameBoxSize,
'-') <<
"+"
397 << std::string(kValueBoxSize,
'-') <<
"+\n";
398 for (
const auto& pair : counters) {
399 std::string
key = pair.first;
400 Counter* counter = pair.second;
401 if (counter->is_histogram()) {
402 std::cout <<
"| c:" << std::setw(kNameBoxSize - 4) << std::left <<
key
403 <<
" | " << std::setw(kValueBoxSize - 2) << std::right
404 << counter->count() <<
" |\n";
405 std::cout <<
"| t:" << std::setw(kNameBoxSize - 4) << std::left <<
key
406 <<
" | " << std::setw(kValueBoxSize - 2) << std::right
407 << counter->sample_total() <<
" |\n";
409 std::cout <<
"| " << std::setw(kNameBoxSize - 2) << std::left <<
key
410 <<
" | " << std::setw(kValueBoxSize - 2) << std::right
411 << counter->count() <<
" |\n";
414 std::cout <<
"+" << std::string(kNameBoxSize,
'-') <<
"+"
415 << std::string(kValueBoxSize,
'-') <<
"+\n";
426CounterCollection EngineImpl::counters_;
427CounterMap* EngineImpl::counter_map_;
437WASM_EXPORT auto Engine::make(own<Config>&& config) -> own<Engine> {
438 auto engine =
new (std::nothrow) EngineImpl;
439 if (!engine)
return own<Engine>();
442 :
v8::platform::NewDefaultPlatform(
443 i::v8_flags.wasm_capi_thread_pool_size);
449 "--prof is currently unreliable for V8's Wasm-C-API due to "
462 if (check.InterruptRequested()) {
463 isolate->stack_guard()->HandleInterrupts();
477 i::GCFlag::kForced, i::GarbageCollectionReason::kTesting,
501 void (*finalizer)(
void*)) {
510 std::make_shared<ManagedData>(info, finalizer));
511 int32_t hash = i::Object::GetOrCreateHash(*
object,
i_isolate()).value();
516 PtrComprCageAccessScope ptr_compr_cage_access_scope(
i_isolate());
519 if (IsTheHole(raw,
i_isolate()))
return nullptr;
530WASM_EXPORT auto Store::make(Engine*) -> own<Store> {
531 auto store = make_own(
new (std::nothrow) StoreImpl());
532 if (!store)
return own<Store>();
535 store->create_params_.array_buffer_allocator =
537#ifdef ENABLE_VTUNE_JIT_INTERFACE
538 store->create_params_.code_event_handler = vTune::GetVtuneCodeEventHandler();
541 store->create_params_.counter_lookup_callback = EngineImpl::LookupCounter;
542 store->create_params_.create_histogram_callback = EngineImpl::CreateHistogram;
543 store->create_params_.add_histogram_sample_callback =
544 EngineImpl::AddHistogramSample;
547 if (!isolate)
return own<Store>();
549 isolate->SetData(0, store.get());
561 if (context.IsEmpty())
return own<Store>();
571 constexpr int kStackLimit = 10;
572 isolate->SetCaptureStackTraceForUncaughtExceptions(
true, kStackLimit,
601WASM_EXPORT void ValType::destroy() { this->~ValType(); }
604 ValTypeImpl* valtype;
618 case ValKind::EXTERNREF:
621 case ValKind::FUNCREF:
631WASM_EXPORT auto ValType::copy() const -> own<ValType> {
return make(
kind()); }
633WASM_EXPORT auto ValType::kind() const -> ValKind {
return impl(
this)->kind; }
651WASM_EXPORT auto ExternType::copy() const -> own<ExternType> {
653 case ExternKind::FUNC:
654 return func()->copy();
655 case ExternKind::GLOBAL:
656 return global()->copy();
657 case ExternKind::TABLE:
658 return table()->copy();
659 case ExternKind::MEMORY:
660 return memory()->copy();
664WASM_EXPORT auto ExternType::kind() const -> ExternKind {
665 return impl(
this)->kind;
676 params(
std::move(params)),
687WASM_EXPORT auto FuncType::make(ownvec<ValType>&& params,
688 ownvec<ValType>&& results) -> own<FuncType> {
689 return params && results
691 FuncTypeImpl(params, results)))
695WASM_EXPORT auto FuncType::copy() const -> own<FuncType> {
696 return make(params().deep_copy(), results().deep_copy());
699WASM_EXPORT auto FuncType::params() const -> const ownvec<ValType>& {
700 return impl(
this)->params;
703WASM_EXPORT auto FuncType::results() const -> const ownvec<ValType>& {
704 return impl(
this)->results;
708 return kind() == ExternKind::FUNC
713WASM_EXPORT auto ExternType::func() const -> const FuncType* {
714 return kind() == ExternKind::FUNC
738void GlobalType::destroy() {
delete impl(
this); }
740auto GlobalType::make(own<ValType>&& content, Mutability mutability)
743 new (std::nothrow) GlobalTypeImpl(content, mutability)))
747auto GlobalType::copy() const -> own<GlobalType> {
748 return make(content()->copy(), mutability());
751auto GlobalType::content() const -> const ValType* {
752 return impl(
this)->content.get();
755auto GlobalType::mutability() const -> Mutability {
756 return impl(
this)->mutability;
759auto ExternType::global() -> GlobalType* {
760 return kind() == ExternKind::GLOBAL
765auto ExternType::global() const -> const GlobalType* {
766 return kind() == ExternKind::GLOBAL
792WASM_EXPORT auto TableType::make(own<ValType>&& element, Limits limits)
795 new (std::nothrow) TableTypeImpl(element, limits)))
799WASM_EXPORT auto TableType::copy() const -> own<TableType> {
800 return make(element()->copy(), limits());
803WASM_EXPORT auto TableType::element() const -> const ValType* {
804 return impl(
this)->element.get();
807WASM_EXPORT auto TableType::limits() const -> const Limits& {
808 return impl(
this)->limits;
811WASM_EXPORT auto ExternType::table() -> TableType* {
812 return kind() == ExternKind::TABLE
817WASM_EXPORT auto ExternType::table() const -> const TableType* {
818 return kind() == ExternKind::TABLE
839WASM_EXPORT auto MemoryType::make(Limits limits) -> own<MemoryType> {
840 return own<MemoryType>(
844void MemoryType::destroy() {
delete impl(
this); }
846WASM_EXPORT auto MemoryType::copy() const -> own<MemoryType> {
847 return MemoryType::make(limits());
850WASM_EXPORT auto MemoryType::limits() const -> const Limits& {
851 return impl(
this)->limits;
854WASM_EXPORT auto ExternType::memory() -> MemoryType* {
855 return kind() == ExternKind::MEMORY
860WASM_EXPORT auto ExternType::memory() const -> const MemoryType* {
861 return kind() == ExternKind::MEMORY
875 name(
std::move(name)),
876 type(
std::move(type)) {}
886WASM_EXPORT auto ImportType::make(Name&& module, Name&& name,
887 own<ExternType>&& type) -> own<ImportType> {
888 return module && name && type
889 ? own<ImportType>(seal<ImportType>(
890 new (std::nothrow) ImportTypeImpl(module, name, type)))
894WASM_EXPORT auto ImportType::copy() const -> own<ImportType> {
895 return make(module().copy(),
name().copy(),
type()->copy());
898WASM_EXPORT auto ImportType::module() const -> const Name& {
899 return impl(
this)->module;
902WASM_EXPORT auto ImportType::name() const -> const Name& {
903 return impl(
this)->name;
906WASM_EXPORT auto ImportType::type() const -> const ExternType* {
907 return impl(
this)->type.get();
917 : name(
std::move(name)), type(
std::move(type)) {}
927WASM_EXPORT auto ExportType::make(Name&& name, own<ExternType>&& type)
930 new (std::nothrow) ExportTypeImpl(name, type)))
934WASM_EXPORT auto ExportType::copy() const -> own<ExportType> {
935 return make(
name().copy(),
type()->copy());
938WASM_EXPORT auto ExportType::name() const -> const Name& {
939 return impl(
this)->name;
942WASM_EXPORT auto ExportType::type() const -> const ExternType* {
943 return impl(
this)->type.get();
947 const vec<byte_t>& chars) {
948 size_t length = chars.size();
951 if (length > 0 && chars[length - 1] == 0) length--;
952 return isolate->factory()
953 ->NewStringFromUtf8({chars.get(), length})
959template <
class Ref,
class JSType>
964 if (!self)
return nullptr;
967 self->
val_ = store->i_isolate()->global_handles()->Create(*obj);
1012WASM_EXPORT auto Ref::copy() const -> own<Ref> {
return impl(
this)->copy(); }
1014WASM_EXPORT auto Ref::same(
const Ref* that)
const ->
bool {
1018 return i::Object::SameValue(*
impl(
this)->v8_object(),
1019 *
impl(that)->v8_object());
1022WASM_EXPORT auto Ref::get_host_info() const ->
void* {
1023 return impl(
this)->get_host_info();
1026WASM_EXPORT void Ref::set_host_info(
void* info,
void (*finalizer)(
void*)) {
1027 impl(
this)->set_host_info(info, finalizer);
1038 FrameImpl(own<Instance>&& instance, uint32_t func_index,
size_t func_offset,
1039 size_t module_offset)
1040 : instance(
std::move(instance)),
1041 func_index(func_index),
1042 func_offset(func_offset),
1043 module_offset(module_offset) {}
1045 own<Instance> instance;
1046 uint32_t func_index;
1048 size_t module_offset;
1061 auto self =
impl(
this);
1063 new (std::nothrow) FrameImpl(self->instance->copy(), self->func_index,
1064 self->func_offset, self->module_offset)));
1068 return impl(
this)->instance.get();
1072 return impl(
this)->func_index;
1076 return impl(
this)->func_offset;
1080 return impl(
this)->module_offset;
1092WASM_EXPORT auto Trap::copy() const -> own<Trap> {
return impl(
this)->copy(); }
1094WASM_EXPORT auto Trap::make(Store* store_abs,
const Message& message)
1096 auto store =
impl(store_abs);
1102 isolate->factory()->NewError(isolate->error_function(),
string);
1103 i::JSObject::AddProperty(isolate, exception,
1104 isolate->factory()->wasm_uncatchable_symbol(),
1105 isolate->factory()->true_value(),
i::NONE);
1109WASM_EXPORT auto Trap::message() const -> Message {
1110 auto isolate =
impl(
this)->isolate();
1115 isolate->CreateMessage(
impl(
this)->v8_object(),
nullptr);
1117 i::MessageHandler::GetMessage(isolate, message);
1120 std::unique_ptr<char[]> utf8 =
result->ToCString(&length);
1121 return vec<byte_t>::adopt(length, utf8.release());
1126own<Instance> GetInstance(StoreImpl* store,
1132 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
1137 uint32_t func_index = frame->GetWasmFunctionIndex();
1138 size_t module_offset = i::CallSiteInfo::GetSourcePosition(frame);
1139 size_t func_offset = module_offset - i::wasm::GetWasmFunctionOffset(
1140 instance->module(), func_index);
1141 return own<Frame>(
seal<Frame>(
new (std::nothrow) FrameImpl(
1142 GetInstance(store, instance), func_index, func_offset, module_offset)));
1147own<Frame> Trap::origin()
const {
1149 PtrComprCageAccessScope ptr_compr_cage_access_scope(
impl(
this)->
isolate());
1154 isolate->GetSimpleStackTrace(
impl(
this)->v8_object());
1155 if (frames->length() == 0) {
1156 return own<Frame>();
1158 return CreateFrameFromInternal(frames, 0, isolate,
impl(
this)->
store());
1161ownvec<Frame> Trap::trace()
const {
1163 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
1168 isolate->GetSimpleStackTrace(
impl(
this)->v8_object());
1169 int num_frames = frames->length();
1171 ownvec<Frame>
result = ownvec<Frame>::make_uninitialized(num_frames);
1172 for (
int i = 0;
i < num_frames;
i++) {
1174 CreateFrameFromInternal(frames,
i, isolate,
impl(
this)->
store());
1188WASM_EXPORT auto Foreign::copy() const -> own<Foreign> {
1189 return impl(
this)->copy();
1192WASM_EXPORT auto Foreign::make(Store* store_abs) -> own<Foreign> {
1193 StoreImpl* store =
impl(store_abs);
1199 isolate->factory()->NewJSObject(isolate->object_function());
1212WASM_EXPORT auto Module::copy() const -> own<Module> {
1213 return impl(
this)->copy();
1216WASM_EXPORT auto Module::validate(Store* store_abs,
const vec<byte_t>& binary)
1220 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
1223 reinterpret_cast<const uint8_t*
>(binary.get()), binary.size());
1224 i::wasm::WasmEnabledFeatures features =
1225 i::wasm::WasmEnabledFeatures::FromIsolate(isolate);
1226 i::wasm::CompileTimeImports imports;
1227 return i::wasm::GetWasmEngine()->SyncValidate(isolate, features,
1228 std::move(imports), bytes);
1231WASM_EXPORT auto Module::make(Store* store_abs,
const vec<byte_t>& binary)
1233 StoreImpl* store =
impl(store_abs);
1239 reinterpret_cast<const uint8_t*
>(binary.get()), binary.size());
1240 i::wasm::WasmEnabledFeatures features =
1241 i::wasm::WasmEnabledFeatures::FromIsolate(isolate);
1242 i::wasm::CompileTimeImports imports;
1243 i::wasm::ErrorThrower thrower(isolate,
"ignored");
1245 if (!i::wasm::GetWasmEngine()
1246 ->SyncCompile(isolate, features, std::move(imports), &thrower,
1248 .ToHandle(&module)) {
1255WASM_EXPORT auto Module::imports() const -> ownvec<ImportType> {
1256 const i::wasm::NativeModule* native_module =
1257 impl(
this)->v8_object()->native_module();
1258 const i::wasm::WasmModule* module = native_module->module();
1260 native_module->wire_bytes();
1261 const std::vector<i::wasm::WasmImport>& import_table =
module->import_table;
1262 size_t size = import_table.size();
1263 ownvec<ImportType> imports = ownvec<ImportType>::make_uninitialized(size);
1264 for (uint32_t
i = 0;
i <
size;
i++) {
1265 const i::wasm::WasmImport& imp = import_table[
i];
1266 Name module_name = GetNameFromWireBytes(imp.module_name, wire_bytes);
1267 Name name = GetNameFromWireBytes(imp.field_name, wire_bytes);
1268 own<ExternType> type = GetImportExportType(module, imp.kind, imp.index);
1269 imports[
i] = ImportType::make(std::move(module_name), std::move(name),
1277 const i::wasm::NativeModule* native_module = module_obj->native_module();
1278 const i::wasm::WasmModule* module = native_module->module();
1280 native_module->wire_bytes();
1281 const std::vector<i::wasm::WasmExport>& export_table =
module->export_table;
1282 size_t size = export_table.size();
1283 ownvec<ExportType> exports = ownvec<ExportType>::make_uninitialized(size);
1284 for (uint32_t
i = 0;
i <
size;
i++) {
1285 const i::wasm::WasmExport& exp = export_table[
i];
1286 Name name = GetNameFromWireBytes(exp.name, wire_bytes);
1287 own<ExternType> type = GetImportExportType(module, exp.kind, exp.index);
1288 exports[
i] = ExportType::make(std::move(name), std::move(type));
1293WASM_EXPORT auto Module::exports() const -> ownvec<ExportType> {
1296 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
1303WASM_EXPORT auto Module::serialize() const -> vec<byte_t> {
1305 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
1307 i::wasm::NativeModule* native_module =
1308 impl(
this)->v8_object()->native_module();
1309 native_module->compilation_state()->TierUpAllFunctions();
1311 size_t binary_size = wire_bytes.
size();
1312 i::wasm::WasmSerializer serializer(native_module);
1313 size_t serial_size = serializer.GetSerializedNativeModuleSize();
1314 size_t size_size = i::wasm::LEBHelper::sizeof_u64v(binary_size);
1315 vec<byte_t> buffer =
1316 vec<byte_t>::make_uninitialized(size_size + binary_size + serial_size);
1317 byte_t* ptr = buffer.get();
1318 i::wasm::LEBHelper::write_u64v(
reinterpret_cast<uint8_t**
>(&ptr),
1320 std::memcpy(ptr, wire_bytes.
begin(), binary_size);
1322 if (!serializer.SerializeNativeModule(
1323 {reinterpret_cast<uint8_t*>(ptr), serial_size})) {
1328 buffer = vec<byte_t>::make_uninitialized(size_size + binary_size);
1329 byte_t* pointer = buffer.get();
1330 i::wasm::LEBHelper::write_u64v(
reinterpret_cast<uint8_t**
>(&pointer),
1332 std::memcpy(pointer, wire_bytes.
begin(), binary_size);
1337WASM_EXPORT auto Module::deserialize(Store* store_abs,
1338 const vec<byte_t>& serialized)
1340 StoreImpl* store =
impl(store_abs);
1344 const byte_t* ptr = serialized.get();
1345 uint64_t binary_size = ReadLebU64(&ptr);
1346 ptrdiff_t size_size = ptr - serialized.get();
1347 size_t serial_size = serialized.size() - size_size - binary_size;
1349 if (serial_size > 0) {
1350 size_t data_size =
static_cast<size_t>(binary_size);
1351 i::wasm::CompileTimeImports compile_imports{};
1352 if (!i::wasm::DeserializeNativeModule(
1354 {
reinterpret_cast<const uint8_t*
>(ptr + data_size), serial_size},
1355 {
reinterpret_cast<const uint8_t*
>(ptr), data_size},
1356 compile_imports, {})
1357 .ToHandle(&module_obj)) {
1365 vec<byte_t> binary = vec<byte_t>::make_uninitialized(binary_size);
1366 std::memcpy(binary.get(), ptr, binary_size);
1367 return make(store_abs, binary);
1380WASM_EXPORT auto Module::share() const -> own<Shared<Module>> {
1382 return make_own(shared);
1385WASM_EXPORT auto Module::obtain(Store* store,
const Shared<Module>* shared)
1387 return Module::deserialize(store, *
impl(shared));
1399WASM_EXPORT auto Extern::copy() const -> own<Extern> {
1400 return impl(
this)->copy();
1403WASM_EXPORT auto Extern::kind() const -> ExternKind {
1405 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
1409 if (i::WasmExternalFunction::IsWasmExternalFunction(*obj)) {
1410 return wasm::ExternKind::FUNC;
1412 if (IsWasmGlobalObject(*obj))
return wasm::ExternKind::GLOBAL;
1413 if (IsWasmTableObject(*obj))
return wasm::ExternKind::TABLE;
1414 if (IsWasmMemoryObject(*obj))
return wasm::ExternKind::MEMORY;
1418WASM_EXPORT auto Extern::type() const -> own<ExternType> {
1420 case ExternKind::FUNC:
1421 return func()->type();
1422 case ExternKind::GLOBAL:
1423 return global()->type();
1424 case ExternKind::TABLE:
1425 return table()->type();
1426 case ExternKind::MEMORY:
1427 return memory()->type();
1432 return kind() == ExternKind::FUNC ?
static_cast<Func*
>(
this) : nullptr;
1436 return kind() == ExternKind::GLOBAL ?
static_cast<Global*
>(
this) : nullptr;
1440 return kind() == ExternKind::TABLE ?
static_cast<Table*
>(
this) : nullptr;
1444 return kind() == ExternKind::MEMORY ?
static_cast<Memory*
>(
this) : nullptr;
1447WASM_EXPORT auto Extern::func() const -> const Func* {
1448 return kind() == ExternKind::FUNC ?
static_cast<const Func*
>(
this) : nullptr;
1451WASM_EXPORT auto Extern::global() const -> const Global* {
1452 return kind() == ExternKind::GLOBAL ?
static_cast<const Global*
>(
this)
1456WASM_EXPORT auto Extern::table() const -> const Table* {
1457 return kind() == ExternKind::TABLE ?
static_cast<const Table*
>(
this)
1461WASM_EXPORT auto Extern::memory() const -> const Memory* {
1462 return kind() == ExternKind::MEMORY ?
static_cast<const Memory*
>(
this)
1467 return impl(ex)->v8_object();
1479WASM_EXPORT auto Func::copy() const -> own<Func> {
return impl(
this)->copy(); }
1512 static const i::wasm::CanonicalTypeIndex Canonicalize(FuncType* type) {
1513 std::vector<i::wasm::ValueType> types;
1514 types.reserve(type->results().size() + type->params().size());
1517 for (
size_t i = 0;
i < type->results().
size();
i++) {
1518 types.push_back(WasmValKindToV8(type->results()[
i]->kind()));
1521 types.push_back(WasmValKindToV8(type->params()[
i]->kind()));
1524 i::wasm::FunctionSig non_canonical_sig{type->results().size(),
1525 type->params().size(), types.data()};
1526 return i::wasm::GetTypeCanonicalizer()->AddRecursiveGroup(
1527 &non_canonical_sig);
1530 static own<FuncType> FromV8Sig(
const i::wasm::CanonicalSig* sig) {
1531 int result_arity =
static_cast<int>(
sig->return_count());
1532 int param_arity =
static_cast<int>(
sig->parameter_count());
1533 ownvec<ValType> results = ownvec<ValType>::make_uninitialized(result_arity);
1534 ownvec<ValType> params = ownvec<ValType>::make_uninitialized(param_arity);
1536 for (
int i = 0;
i < result_arity; ++
i) {
1537 results[
i] = ValType::make(V8ValueTypeToWasm(
sig->GetReturn(
i)));
1539 for (
int i = 0;
i < param_arity; ++
i) {
1540 params[
i] = ValType::make(V8ValueTypeToWasm(
sig->GetParam(
i)));
1542 return FuncType::make(std::move(params), std::move(results));
1545 static const i::wasm::CanonicalSig* GetSig(
1550#if V8_ENABLE_SANDBOX
1552 struct FuncTypeAdapter {
1553 const FuncType* type =
nullptr;
1555 size_t return_count()
const {
return type->results().size(); }
1556 i::wasm::ValueType GetParam(
size_t i)
const {
1557 return WasmValKindToV8(type->params()[
i]->kind());
1559 i::wasm::ValueType GetReturn(
size_t i)
const {
1560 return WasmValKindToV8(type->results()[
i]->kind());
1563 static uint64_t Hash(FuncType* type) {
1564 FuncTypeAdapter adapter{type};
1565 return i::wasm::SignatureHasher::Hash(&adapter);
1570auto make_func(Store* store_abs, std::shared_ptr<FuncData> data) -> own<Func> {
1571 auto store =
impl(store_abs);
1578 i::wasm::CanonicalTypeIndex sig_index =
1579 SignatureHelper::Canonicalize(data->type.get());
1580 const i::wasm::CanonicalSig*
sig =
1581 i::wasm::GetTypeCanonicalizer()->LookupFunctionSignature(sig_index);
1584 embedder_data, sig_index, sig);
1586 function->shared()->wasm_capi_function_data()->internal()->implicit_arg())
1587 ->set_callable(*function);
1594WASM_EXPORT auto Func::make(Store* store,
const FuncType* type,
1595 Func::callback
callback) -> own<Func> {
1598 return make_func(store, data);
1601WASM_EXPORT auto Func::make(Store* store,
const FuncType* type,
1602 callback_with_env
callback,
void* env,
1603 void (*finalizer)(
void*)) -> own<Func> {
1606 data->callback_with_env =
callback;
1608 data->finalizer = finalizer;
1609 return make_func(store, data);
1612WASM_EXPORT auto Func::type() const -> own<FuncType> {
1615 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
1617 if (i::WasmCapiFunction::IsWasmCapiFunction(*func)) {
1618 return SignatureHelper::FromV8Sig(SignatureHelper::GetSig(func));
1620 DCHECK(i::WasmExportedFunction::IsWasmExportedFunction(*func));
1622 auto data = function->shared()->wasm_exported_function_data();
1623 return FunctionSigToFuncType(
1624 data->instance_data()->module()->functions[data->function_index()].sig);
1627WASM_EXPORT auto Func::param_arity() const ->
size_t {
1630 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
1632 if (i::WasmCapiFunction::IsWasmCapiFunction(*func)) {
1633 return SignatureHelper::GetSig(func)->parameter_count();
1635 DCHECK(i::WasmExportedFunction::IsWasmExportedFunction(*func));
1637 auto data = function->shared()->wasm_exported_function_data();
1638 const i::wasm::FunctionSig*
sig =
1639 data->instance_data()->module()->functions[data->function_index()].sig;
1640 return sig->parameter_count();
1643WASM_EXPORT auto Func::result_arity() const ->
size_t {
1646 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
1648 if (i::WasmCapiFunction::IsWasmCapiFunction(*func)) {
1649 return SignatureHelper::GetSig(func)->return_count();
1651 DCHECK(i::WasmExportedFunction::IsWasmExportedFunction(*func));
1653 auto data = function->shared()->wasm_exported_function_data();
1654 const i::wasm::FunctionSig*
sig =
1655 data->instance_data()->module()->functions[data->function_index()].sig;
1656 return sig->return_count();
1662 if (
IsNull(*value, store->i_isolate()))
return nullptr;
1667 if (ref ==
nullptr)
return isolate->factory()->null_value();
1668 return impl(ref)->v8_object();
1671void PrepareFunctionData(
1674 const i::wasm::CanonicalSig* sig) {
1679 if (!function_data->c_wrapper_code(isolate).SafeEquals(
1685 i::compiler::CompileCWasmEntry(isolate, sig);
1686 function_data->set_c_wrapper_code(*wrapper_code);
1688 function_data->set_packed_args_size(
1689 i::wasm::CWasmArgumentsPacker::TotalSize(sig));
1692void PushArgs(
const i::wasm::CanonicalSig* sig,
const vec<Val>&
args,
1693 i::wasm::CWasmArgumentsPacker* packer, StoreImpl* store) {
1694 for (
size_t i = 0;
i <
sig->parameter_count();
i++) {
1695 i::wasm::CanonicalValueType type =
sig->GetParam(
i);
1696 switch (type.kind()) {
1698 packer->Push(
args[
i].i32());
1701 packer->Push(
args[
i].i64());
1704 packer->Push(
args[
i].f32());
1707 packer->Push(
args[
i].f64());
1710 case i::wasm::kRefNull:
1712 packer->Push((*WasmRefToV8(store->i_isolate(),
args[
i].ref())).ptr());
1714 case i::wasm::kS128:
1720 case i::wasm::kVoid:
1722 case i::wasm::kBottom:
1728void PopArgs(
const i::wasm::CanonicalSig* sig, vec<Val>& results,
1729 i::wasm::CWasmArgumentsPacker* packer, StoreImpl* store) {
1731 for (
size_t i = 0;
i <
sig->return_count();
i++) {
1732 i::wasm::CanonicalValueType type =
sig->GetReturn(
i);
1733 switch (type.kind()) {
1735 results[
i] = Val(packer->Pop<int32_t>());
1738 results[
i] = Val(packer->Pop<int64_t>());
1741 results[
i] = Val(packer->Pop<
float>());
1744 results[
i] = Val(packer->Pop<
double>());
1747 case i::wasm::kRefNull: {
1751 store->i_isolate());
1752 results[
i] = Val(V8RefValueToWasm(store, obj));
1755 case i::wasm::kS128:
1761 case i::wasm::kVoid:
1763 case i::wasm::kBottom:
1770 const vec<Val>&
args, vec<Val>& results) {
1771 FuncData* func_data =
1774 return (func_data->callback)(
args, results);
1777 return (func_data->callback_with_env)(func_data->env,
args, results);
1782 if (IsJSReceiver(*maybe_exception)) {
1785 if (v8::internal::IsTerminationException(*maybe_exception)) {
1787 isolate->factory()->NewStringFromAsciiChecked(
"TerminationException");
1788 return isolate->factory()->NewError(isolate->error_function(),
string);
1791 i::Object::ToString(isolate, maybe_exception);
1793 if (!maybe_string.
ToHandle(&
string)) {
1796 isolate->clear_exception();
1801 isolate->factory()->NewError(isolate->error_function(),
string));
1806WASM_EXPORT auto Func::call(
const vec<Val>&
args, vec<Val>& results)
const
1808 auto func =
impl(
this);
1809 auto store = func->store();
1810 auto isolate = store->i_isolate();
1814 func->v8_object()->shared()->GetTrustedData(isolate);
1817 if (IsWasmCapiFunctionData(raw_function_data)) {
1818 return CallWasmCapiFunction(
1822 SBXCHECK(IsWasmExportedFunctionData(raw_function_data));
1826 function_data->instance_data(), isolate};
1827 int function_index = function_data->function_index();
1828 const i::wasm::WasmModule* module =
instance_data->module();
1830 const i::wasm::CanonicalSig*
sig =
1831 i::wasm::GetTypeCanonicalizer()->LookupFunctionSignature(
1832 module->canonical_sig_id(
1833 module->functions[function_index].sig_index));
1834 PrepareFunctionData(isolate, function_data, sig);
1839 i::wasm::CWasmArgumentsPacker packer(function_data->packed_args_size());
1840 PushArgs(sig,
args, &packer, store);
1843 if (function_index <
static_cast<int>(module->num_imported_functions)) {
1848 if (IsWasmImportData(*object_ref)) {
1852 if (IsWasmCapiFunctionData(data)) {
1862 DCHECK(IsWasmInstanceObject(*object_ref));
1870 i::Execution::CallWasm(isolate, wrapper_code, call_target, object_ref,
1873 if (isolate->has_exception()) {
1875 isolate->clear_exception();
1877 GetProperException(isolate, exception));
1880 PopArgs(sig, results, &packer, store);
1896 const ownvec<ValType>& param_types = self->
type->params();
1897 const ownvec<ValType>& result_types = self->
type->results();
1899 int num_param_types =
static_cast<int>(param_types.size());
1900 int num_result_types =
static_cast<int>(result_types.size());
1902 auto params = vec<Val>::make_uninitialized(num_param_types);
1903 auto results = vec<Val>::make_uninitialized(num_result_types);
1905 for (
int i = 0;
i < num_param_types; ++
i) {
1906 switch (param_types[
i]->
kind()) {
1923 case ValKind::EXTERNREF:
1924 case ValKind::FUNCREF: {
1928 params[
i] = Val(V8RefValueToWasm(store, obj));
1942 isolate->Throw(*
impl(
trap.get())->v8_object());
1944 isolate->clear_exception();
1949 for (
int i = 0;
i < num_result_types; ++
i) {
1950 switch (result_types[
i]->
kind()) {
1967 case ValKind::EXTERNREF:
1968 case ValKind::FUNCREF: {
1970 p, (*WasmRefToV8(isolate, results[
i].ref())).ptr());
1986WASM_EXPORT void Global::destroy() {
delete (
this); }
1988WASM_EXPORT auto Global::copy() const -> own<Global> {
1992WASM_EXPORT auto Global::make(Store* store_abs,
const GlobalType* type,
1993 const Val& val) -> own<Global> {
1994 StoreImpl* store =
impl(store_abs);
2000 DCHECK_EQ(type->content()->kind(), val.kind());
2002 i::wasm::ValueType i_type = WasmValKindToV8(type->content()->kind());
2003 bool is_mutable = (type->mutability() == Mutability::VAR);
2006 i::WasmGlobalObject::New(
2018WASM_EXPORT auto Global::type() const -> own<GlobalType> {
2020 ValKind
kind = V8ValueTypeToWasm(v8_global->type());
2021 Mutability mutability =
2022 v8_global->is_mutable() ? Mutability::VAR : Mutability::CONST;
2023 return GlobalType::make(ValType::make(
kind), mutability);
2029 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
2031 switch (v8_global->type().kind()) {
2033 return Val(v8_global->GetI32());
2035 return Val(v8_global->GetI64());
2037 return Val(v8_global->GetF32());
2039 return Val(v8_global->GetF64());
2041 case i::wasm::kRefNull: {
2043 StoreImpl* store =
impl(
this)->store();
2046 if (IsWasmFuncRef(*
result)) {
2049 store->i_isolate()));
2051 if (IsWasmNull(*
result)) {
2052 result = v8_global->GetIsolate()->factory()->null_value();
2054 return Val(V8RefValueToWasm(store,
result));
2056 case i::wasm::kS128:
2062 case i::wasm::kVoid:
2064 case i::wasm::kBottom:
2072 switch (val.kind()) {
2074 return v8_global->SetI32(val.i32());
2076 return v8_global->SetI64(val.i64());
2078 return v8_global->SetF32(val.f32());
2080 return v8_global->SetF64(val.f64());
2081 case ValKind::EXTERNREF:
2082 return v8_global->SetRef(
2083 WasmRefToV8(
impl(
this)->
store()->i_isolate(), val.ref()));
2084 case ValKind::FUNCREF: {
2086 auto external = WasmRefToV8(
impl(
this)->
store()->i_isolate(), val.ref());
2087 const char* error_message;
2088 auto internal = i::wasm::JSToWasmObject(isolate,
nullptr, external,
2089 v8_global->type(), &error_message)
2091 v8_global->SetRef(internal);
2109WASM_EXPORT auto Table::copy() const -> own<Table> {
2110 return impl(
this)->copy();
2113WASM_EXPORT auto Table::make(Store* store_abs,
const TableType* type,
2114 const Ref* ref) -> own<Table> {
2115 StoreImpl* store =
impl(store_abs);
2122 i::wasm::ValueType i_type;
2123 i::wasm::CanonicalValueType canonical_type;
2124 switch (type->element()->kind()) {
2125 case ValKind::FUNCREF:
2126 i_type = i::wasm::kWasmFuncRef;
2127 canonical_type = i::wasm::kWasmFuncRef;
2129 case ValKind::EXTERNREF:
2131 i_type = i::wasm::kWasmExternRef;
2132 canonical_type = i::wasm::kWasmExternRef;
2138 const Limits& limits = type->limits();
2139 uint32_t minimum = limits.min;
2140 if (minimum > i::wasm::max_table_init_entries())
return nullptr;
2141 uint32_t maximum = limits.max;
2142 bool has_maximum =
false;
2143 if (maximum != Limits(0).max) {
2145 if (maximum < minimum)
return nullptr;
2146 if (maximum > i::wasm::max_table_init_entries())
return nullptr;
2151 canonical_type, minimum, has_maximum, maximum,
2152 isolate->factory()->null_value(), i::wasm::AddressType::kI32);
2156 for (uint32_t
i = 0;
i < minimum;
i++) {
2157 table_obj->Set(isolate, table_obj,
i, init);
2163WASM_EXPORT auto Table::type() const -> own<TableType> {
2165 uint32_t min = table->current_length();
2168 uint32_t max =
static_cast<uint32_t
>(std::min<uint64_t>(
2171 switch (table->unsafe_type().heap_representation()) {
2172 case i::wasm::HeapType::kFunc:
2173 kind = ValKind::FUNCREF;
2175 case i::wasm::HeapType::kExtern:
2176 kind = ValKind::EXTERNREF;
2181 return TableType::make(ValType::make(
kind), Limits(min, max));
2185WASM_EXPORT auto Table::get(
size_t index)
const -> own<Ref> {
2189 if (index >=
static_cast<size_t>(table->current_length()))
return own<Ref>();
2190 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
2193 i::WasmTableObject::Get(isolate, table,
static_cast<uint32_t
>(index));
2194 if (IsWasmFuncRef(*
result)) {
2198 if (IsWasmNull(*
result)) {
2199 result = isolate->factory()->null_value();
2205WASM_EXPORT auto Table::set(
size_t index,
const Ref* ref) ->
bool {
2209 if (index >=
static_cast<size_t>(table->current_length()))
return false;
2212 const char* error_message;
2215 DCHECK(!table->unsafe_type().has_index());
2217 i::wasm::JSToWasmObject(isolate,
nullptr, obj, table->unsafe_type(),
2220 i::WasmTableObject::Set(isolate, table,
static_cast<uint32_t
>(index),
2229 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
2230 return impl(
this)->v8_object()->current_length();
2233WASM_EXPORT auto Table::grow(
size_t delta,
const Ref* ref) ->
bool {
2239 const char* error_message;
2242 DCHECK(!table->unsafe_type().has_index());
2244 i::wasm::JSToWasmObject(isolate,
nullptr, obj, table->unsafe_type(),
2247 int result = i::WasmTableObject::Grow(
2248 isolate, table,
static_cast<uint32_t
>(delta), obj_as_wasm);
2261WASM_EXPORT auto Memory::copy() const -> own<Memory> {
2262 return impl(
this)->copy();
2265WASM_EXPORT auto Memory::make(Store* store_abs,
const MemoryType* type)
2267 StoreImpl* store =
impl(store_abs);
2273 const Limits& limits = type->limits();
2274 uint32_t minimum = limits.min;
2277 if (minimum > i::wasm::kSpecMaxMemory32Pages)
return nullptr;
2278 uint32_t maximum = limits.max;
2279 if (maximum != Limits(0).max) {
2280 if (maximum < minimum)
return nullptr;
2281 if (maximum > i::wasm::kSpecMaxMemory32Pages)
return nullptr;
2285 i::wasm::AddressType address_type = i::wasm::AddressType::kI32;
2287 if (!i::WasmMemoryObject::New(isolate, minimum, maximum, shared, address_type)
2288 .ToHandle(&memory_obj)) {
2289 return own<Memory>();
2294WASM_EXPORT auto Memory::type() const -> own<MemoryType> {
2295 PtrComprCageAccessScope ptr_compr_cage_access_scope(
impl(
this)->
isolate());
2297 uint32_t min =
static_cast<uint32_t
>(memory->array_buffer()->byte_length() /
2298 i::wasm::kWasmPageSize);
2300 memory->has_maximum_pages() ? memory->maximum_pages() : 0xFFFFFFFFu;
2301 return MemoryType::make(Limits(min, max));
2307 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
2308 return reinterpret_cast<byte_t*
>(
2309 impl(
this)->v8_object()->array_buffer()->backing_store());
2312WASM_EXPORT auto Memory::data_size() const ->
size_t {
2315 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
2316 return impl(
this)->v8_object()->array_buffer()->byte_length();
2322 PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate);
2323 return static_cast<pages_t
>(
2324 impl(
this)->v8_object()->array_buffer()->byte_length() /
2325 i::wasm::kWasmPageSize);
2328WASM_EXPORT auto Memory::grow(pages_t delta) ->
bool {
2333 int32_t old = i::WasmMemoryObject::Grow(isolate, memory, delta);
2345WASM_EXPORT auto Instance::copy() const -> own<Instance> {
2346 return impl(
this)->copy();
2349WASM_EXPORT own<Instance> Instance::make(Store* store_abs,
2350 const Module* module_abs,
2351 const vec<Extern*>& imports,
2353 StoreImpl* store =
impl(store_abs);
2360 DCHECK_EQ(module->v8_object()->GetIsolate(), isolate);
2363 ownvec<ImportType> import_types = module_abs->imports();
2365 isolate->factory()->NewJSObject(isolate->object_function());
2366 for (
size_t i = 0;
i < import_types.
size(); ++
i) {
2367 ImportType* type = import_types[
i].get();
2374 i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2375 if (i::JSObject::HasProperty(&module_it).ToChecked()) {
2377 i::Object::GetProperty(&module_it).ToHandleChecked());
2379 module_obj = isolate->factory()->NewJSObject(isolate->object_function());
2381 i::Object::SetProperty(isolate, imports_obj, module_str, module_obj));
2383 ignore(i::Object::SetProperty(isolate, module_obj, name_str,
2384 impl(imports[
i])->v8_object()));
2386 i::wasm::ErrorThrower thrower(isolate,
"instantiation");
2388 i::wasm::GetWasmEngine()->SyncInstantiate(
2389 isolate, &thrower, module->v8_object(), imports_obj,
2392 if (thrower.error()) {
2394 store, GetProperException(isolate, thrower.Reify()));
2395 DCHECK(!thrower.error());
2396 DCHECK(!isolate->has_exception());
2397 return own<Instance>();
2398 }
else if (isolate->has_exception()) {
2401 store, GetProperException(isolate, maybe_exception));
2402 isolate->clear_exception();
2403 return own<Instance>();
2405 }
else if (instance_obj.
is_null()) {
2408 isolate->clear_exception();
2409 return own<Instance>();
2416own<Instance> GetInstance(StoreImpl* store,
2423WASM_EXPORT auto Instance::exports() const -> ownvec<Extern> {
2425 StoreImpl* store = instance->store();
2436 ownvec<ExportType> export_types =
ExportsImpl(module_obj);
2437 ownvec<Extern> exports =
2438 ownvec<Extern>::make_uninitialized(export_types.size());
2439 if (!exports)
return ownvec<Extern>::invalid();
2441 for (
size_t i = 0;
i < export_types.
size(); ++
i) {
2442 auto& name = export_types[
i]->name();
2445 i::Object::GetProperty(isolate, exports_obj, name_str)
2448 const ExternType* type = export_types[
i]->type();
2449 switch (type->kind()) {
2450 case ExternKind::FUNC: {
2451 DCHECK(i::WasmExternalFunction::IsWasmExternalFunction(*obj));
2455 case ExternKind::GLOBAL: {
2459 case ExternKind::TABLE: {
2463 case ExternKind::MEMORY: {