1 // Copyright 2019 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This implementation is originally from
6 // https://github.com/WebAssembly/wasm-c-api/:
7
8 // Copyright 2019 Andreas Rossberg
9 //
10 // Licensed under the Apache License, Version 2.0 (the "License");
11 // you may not use this file except in compliance with the License.
12 // You may obtain a copy of the License at
13 //
14 // http://www.apache.org/licenses/LICENSE-2.0
15 //
16 // Unless required by applicable law or agreed to in writing, software
17 // distributed under the License is distributed on an "AS IS" BASIS,
18 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 // See the License for the specific language governing permissions and
20 // limitations under the License.
21
22 #include <cstring>
23 #include <iostream>
24
25 #include "src/wasm/c-api.h"
26
27 #include "third_party/wasm-api/wasm.h"
28
29 #include "include/libplatform/libplatform.h"
30 #include "src/api/api-inl.h"
31 #include "src/compiler/wasm-compiler.h"
32 #include "src/objects/js-collection-inl.h"
33 #include "src/objects/managed.h"
34 #include "src/objects/stack-frame-info-inl.h"
35 #include "src/wasm/leb-helper.h"
36 #include "src/wasm/module-instantiate.h"
37 #include "src/wasm/wasm-arguments.h"
38 #include "src/wasm/wasm-constants.h"
39 #include "src/wasm/wasm-objects.h"
40 #include "src/wasm/wasm-result.h"
41 #include "src/wasm/wasm-serialization.h"
42
43 #ifdef WASM_API_DEBUG
44 #error "WASM_API_DEBUG is unsupported"
45 #endif
46
47 namespace wasm {
48
49 namespace {
50
ReadLebU64(const byte_t ** pos)51 auto ReadLebU64(const byte_t** pos) -> uint64_t {
52 uint64_t n = 0;
53 uint64_t shift = 0;
54 byte_t b;
55 do {
56 b = **pos;
57 (*pos)++;
58 n += (b & 0x7f) << shift;
59 shift += 7;
60 } while ((b & 0x80) != 0);
61 return n;
62 }
63
V8ValueTypeToWasm(i::wasm::ValueType v8_valtype)64 ValKind V8ValueTypeToWasm(i::wasm::ValueType v8_valtype) {
65 switch (v8_valtype.kind()) {
66 case i::wasm::ValueType::kI32:
67 return I32;
68 case i::wasm::ValueType::kI64:
69 return I64;
70 case i::wasm::ValueType::kF32:
71 return F32;
72 case i::wasm::ValueType::kF64:
73 return F64;
74 case i::wasm::ValueType::kRef:
75 case i::wasm::ValueType::kOptRef:
76 switch (v8_valtype.heap_representation()) {
77 case i::wasm::HeapType::kFunc:
78 return FUNCREF;
79 case i::wasm::HeapType::kExtern:
80 // TODO(7748): Rename this to EXTERNREF if/when third-party API
81 // changes.
82 return ANYREF;
83 default:
84 // TODO(wasm+): support new value types
85 UNREACHABLE();
86 }
87 default:
88 // TODO(wasm+): support new value types
89 UNREACHABLE();
90 }
91 }
92
WasmValKindToV8(ValKind kind)93 i::wasm::ValueType WasmValKindToV8(ValKind kind) {
94 switch (kind) {
95 case I32:
96 return i::wasm::kWasmI32;
97 case I64:
98 return i::wasm::kWasmI64;
99 case F32:
100 return i::wasm::kWasmF32;
101 case F64:
102 return i::wasm::kWasmF64;
103 case FUNCREF:
104 return i::wasm::kWasmFuncRef;
105 case ANYREF:
106 return i::wasm::kWasmExternRef;
107 default:
108 // TODO(wasm+): support new value types
109 UNREACHABLE();
110 }
111 }
112
GetNameFromWireBytes(const i::wasm::WireBytesRef & ref,const i::Vector<const uint8_t> & wire_bytes)113 Name GetNameFromWireBytes(const i::wasm::WireBytesRef& ref,
114 const i::Vector<const uint8_t>& wire_bytes) {
115 DCHECK_LE(ref.offset(), wire_bytes.length());
116 DCHECK_LE(ref.end_offset(), wire_bytes.length());
117 if (ref.length() == 0) return Name::make();
118 Name name = Name::make_uninitialized(ref.length());
119 std::memcpy(name.get(), wire_bytes.begin() + ref.offset(), ref.length());
120 return name;
121 }
122
FunctionSigToFuncType(const i::wasm::FunctionSig * sig)123 own<FuncType> FunctionSigToFuncType(const i::wasm::FunctionSig* sig) {
124 size_t param_count = sig->parameter_count();
125 ownvec<ValType> params = ownvec<ValType>::make_uninitialized(param_count);
126 for (size_t i = 0; i < param_count; i++) {
127 params[i] = ValType::make(V8ValueTypeToWasm(sig->GetParam(i)));
128 }
129 size_t return_count = sig->return_count();
130 ownvec<ValType> results = ownvec<ValType>::make_uninitialized(return_count);
131 for (size_t i = 0; i < return_count; i++) {
132 results[i] = ValType::make(V8ValueTypeToWasm(sig->GetReturn(i)));
133 }
134 return FuncType::make(std::move(params), std::move(results));
135 }
136
GetImportExportType(const i::wasm::WasmModule * module,const i::wasm::ImportExportKindCode kind,const uint32_t index)137 own<ExternType> GetImportExportType(const i::wasm::WasmModule* module,
138 const i::wasm::ImportExportKindCode kind,
139 const uint32_t index) {
140 switch (kind) {
141 case i::wasm::kExternalFunction: {
142 return FunctionSigToFuncType(module->functions[index].sig);
143 }
144 case i::wasm::kExternalTable: {
145 const i::wasm::WasmTable& table = module->tables[index];
146 own<ValType> elem = ValType::make(V8ValueTypeToWasm(table.type));
147 Limits limits(table.initial_size,
148 table.has_maximum_size ? table.maximum_size : -1);
149 return TableType::make(std::move(elem), limits);
150 }
151 case i::wasm::kExternalMemory: {
152 DCHECK(module->has_memory);
153 Limits limits(module->initial_pages,
154 module->has_maximum_pages ? module->maximum_pages : -1);
155 return MemoryType::make(limits);
156 }
157 case i::wasm::kExternalGlobal: {
158 const i::wasm::WasmGlobal& global = module->globals[index];
159 own<ValType> content = ValType::make(V8ValueTypeToWasm(global.type));
160 Mutability mutability = global.mutability ? VAR : CONST;
161 return GlobalType::make(std::move(content), mutability);
162 }
163 case i::wasm::kExternalException:
164 UNREACHABLE();
165 return {};
166 }
167 }
168
169 } // namespace
170
171 /// BEGIN FILE wasm-v8.cc
172
173 ///////////////////////////////////////////////////////////////////////////////
174 // Auxiliaries
175
WASM_UNIMPLEMENTED(const char * s)176 [[noreturn]] void WASM_UNIMPLEMENTED(const char* s) {
177 std::cerr << "Wasm API: " << s << " not supported yet!\n";
178 exit(1);
179 }
180
181 template <class T>
ignore(T)182 void ignore(T) {}
183
184 template <class C>
185 struct implement;
186
187 template <class C>
impl(C * x)188 auto impl(C* x) -> typename implement<C>::type* {
189 return reinterpret_cast<typename implement<C>::type*>(x);
190 }
191
192 template <class C>
impl(const C * x)193 auto impl(const C* x) -> const typename implement<C>::type* {
194 return reinterpret_cast<const typename implement<C>::type*>(x);
195 }
196
197 template <class C>
seal(typename implement<C>::type * x)198 auto seal(typename implement<C>::type* x) -> C* {
199 return reinterpret_cast<C*>(x);
200 }
201
202 template <class C>
seal(const typename implement<C>::type * x)203 auto seal(const typename implement<C>::type* x) -> const C* {
204 return reinterpret_cast<const C*>(x);
205 }
206
207 ///////////////////////////////////////////////////////////////////////////////
208 // Runtime Environment
209
210 // Configuration
211
212 struct ConfigImpl {};
213
214 template <>
215 struct implement<Config> {
216 using type = ConfigImpl;
217 };
218
~Config()219 Config::~Config() { impl(this)->~ConfigImpl(); }
220
operator delete(void * p)221 void Config::operator delete(void* p) { ::operator delete(p); }
222
make()223 auto Config::make() -> own<Config> {
224 return own<Config>(seal<Config>(new (std::nothrow) ConfigImpl()));
225 }
226
227 // Engine
228
229 struct EngineImpl {
230 static bool created;
231
232 std::unique_ptr<v8::Platform> platform;
233
EngineImplwasm::EngineImpl234 EngineImpl() {
235 assert(!created);
236 created = true;
237 }
238
~EngineImplwasm::EngineImpl239 ~EngineImpl() {
240 v8::V8::Dispose();
241 v8::V8::ShutdownPlatform();
242 }
243 };
244
245 bool EngineImpl::created = false;
246
247 template <>
248 struct implement<Engine> {
249 using type = EngineImpl;
250 };
251
~Engine()252 Engine::~Engine() { impl(this)->~EngineImpl(); }
253
operator delete(void * p)254 void Engine::operator delete(void* p) { ::operator delete(p); }
255
make(own<Config> && config)256 auto Engine::make(own<Config>&& config) -> own<Engine> {
257 i::FLAG_expose_gc = true;
258 i::FLAG_experimental_wasm_reftypes = true;
259 i::FLAG_experimental_wasm_bigint = true;
260 i::FLAG_experimental_wasm_mv = true;
261 auto engine = new (std::nothrow) EngineImpl;
262 if (!engine) return own<Engine>();
263 engine->platform = v8::platform::NewDefaultPlatform();
264 v8::V8::InitializePlatform(engine->platform.get());
265 v8::V8::Initialize();
266 return make_own(seal<Engine>(engine));
267 }
268
269 // Stores
270
~StoreImpl()271 StoreImpl::~StoreImpl() {
272 #ifdef DEBUG
273 reinterpret_cast<i::Isolate*>(isolate_)->heap()->PreciseCollectAllGarbage(
274 i::Heap::kForcedGC, i::GarbageCollectionReason::kTesting,
275 v8::kNoGCCallbackFlags);
276 #endif
277 context()->Exit();
278 isolate_->Dispose();
279 delete create_params_.array_buffer_allocator;
280 }
281
282 struct ManagedData {
ManagedDatawasm::ManagedData283 ManagedData(void* info, void (*finalizer)(void*))
284 : info(info), finalizer(finalizer) {}
285
~ManagedDatawasm::ManagedData286 ~ManagedData() {
287 if (finalizer) (*finalizer)(info);
288 }
289
290 void* info;
291 void (*finalizer)(void*);
292 };
293
SetHostInfo(i::Handle<i::Object> object,void * info,void (* finalizer)(void *))294 void StoreImpl::SetHostInfo(i::Handle<i::Object> object, void* info,
295 void (*finalizer)(void*)) {
296 i::HandleScope scope(i_isolate());
297 // Ideally we would specify the total size kept alive by {info} here,
298 // but all we get from the embedder is a {void*}, so our best estimate
299 // is the size of the metadata.
300 size_t estimated_size = sizeof(ManagedData);
301 i::Handle<i::Object> wrapper = i::Managed<ManagedData>::FromRawPtr(
302 i_isolate(), estimated_size, new ManagedData(info, finalizer));
303 int32_t hash = object->GetOrCreateHash(i_isolate()).value();
304 i::JSWeakCollection::Set(host_info_map_, object, wrapper, hash);
305 }
306
GetHostInfo(i::Handle<i::Object> key)307 void* StoreImpl::GetHostInfo(i::Handle<i::Object> key) {
308 i::Object raw =
309 i::EphemeronHashTable::cast(host_info_map_->table()).Lookup(key);
310 if (raw.IsTheHole(i_isolate())) return nullptr;
311 return i::Managed<ManagedData>::cast(raw).raw()->info;
312 }
313
314 template <>
315 struct implement<Store> {
316 using type = StoreImpl;
317 };
318
~Store()319 Store::~Store() { impl(this)->~StoreImpl(); }
320
operator delete(void * p)321 void Store::operator delete(void* p) { ::operator delete(p); }
322
make(Engine *)323 auto Store::make(Engine*) -> own<Store> {
324 auto store = make_own(new (std::nothrow) StoreImpl());
325 if (!store) return own<Store>();
326
327 // Create isolate.
328 store->create_params_.array_buffer_allocator =
329 v8::ArrayBuffer::Allocator::NewDefaultAllocator();
330 v8::Isolate* isolate = v8::Isolate::New(store->create_params_);
331 if (!isolate) return own<Store>();
332 store->isolate_ = isolate;
333 isolate->SetData(0, store.get());
334 // We intentionally do not call isolate->Enter() here, because that would
335 // prevent embedders from using stores with overlapping but non-nested
336 // lifetimes. The consequence is that Isolate::Current() is dysfunctional
337 // and hence must not be called by anything reachable via this file.
338
339 {
340 v8::HandleScope handle_scope(isolate);
341
342 // Create context.
343 v8::Local<v8::Context> context = v8::Context::New(isolate);
344 if (context.IsEmpty()) return own<Store>();
345 context->Enter(); // The Exit() call is in ~StoreImpl.
346 store->context_ = v8::Eternal<v8::Context>(isolate, context);
347
348 // Create weak map for Refs with host info.
349 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
350 store->host_info_map_ = i_isolate->global_handles()->Create(
351 *i_isolate->factory()->NewJSWeakMap());
352 }
353 // We want stack traces for traps.
354 constexpr int kStackLimit = 10;
355 isolate->SetCaptureStackTraceForUncaughtExceptions(true, kStackLimit,
356 v8::StackTrace::kOverview);
357
358 return make_own(seal<Store>(store.release()));
359 }
360
361 ///////////////////////////////////////////////////////////////////////////////
362 // Type Representations
363
364 // Value Types
365
366 struct ValTypeImpl {
367 ValKind kind;
368
ValTypeImplwasm::ValTypeImpl369 explicit ValTypeImpl(ValKind kind) : kind(kind) {}
370 };
371
372 template <>
373 struct implement<ValType> {
374 using type = ValTypeImpl;
375 };
376
377 ValTypeImpl* valtype_i32 = new ValTypeImpl(I32);
378 ValTypeImpl* valtype_i64 = new ValTypeImpl(I64);
379 ValTypeImpl* valtype_f32 = new ValTypeImpl(F32);
380 ValTypeImpl* valtype_f64 = new ValTypeImpl(F64);
381 ValTypeImpl* valtype_externref = new ValTypeImpl(ANYREF);
382 ValTypeImpl* valtype_funcref = new ValTypeImpl(FUNCREF);
383
384 ValType::~ValType() = default;
385
operator delete(void *)386 void ValType::operator delete(void*) {}
387
make(ValKind k)388 own<ValType> ValType::make(ValKind k) {
389 ValTypeImpl* valtype;
390 switch (k) {
391 case I32:
392 valtype = valtype_i32;
393 break;
394 case I64:
395 valtype = valtype_i64;
396 break;
397 case F32:
398 valtype = valtype_f32;
399 break;
400 case F64:
401 valtype = valtype_f64;
402 break;
403 case ANYREF:
404 valtype = valtype_externref;
405 break;
406 case FUNCREF:
407 valtype = valtype_funcref;
408 break;
409 default:
410 // TODO(wasm+): support new value types
411 UNREACHABLE();
412 }
413 return own<ValType>(seal<ValType>(valtype));
414 }
415
copy() const416 auto ValType::copy() const -> own<ValType> { return make(kind()); }
417
kind() const418 auto ValType::kind() const -> ValKind { return impl(this)->kind; }
419
420 // Extern Types
421
422 struct ExternTypeImpl {
423 ExternKind kind;
424
ExternTypeImplwasm::ExternTypeImpl425 explicit ExternTypeImpl(ExternKind kind) : kind(kind) {}
426 virtual ~ExternTypeImpl() = default;
427 };
428
429 template <>
430 struct implement<ExternType> {
431 using type = ExternTypeImpl;
432 };
433
~ExternType()434 ExternType::~ExternType() { impl(this)->~ExternTypeImpl(); }
435
operator delete(void * p)436 void ExternType::operator delete(void* p) { ::operator delete(p); }
437
copy() const438 auto ExternType::copy() const -> own<ExternType> {
439 switch (kind()) {
440 case EXTERN_FUNC:
441 return func()->copy();
442 case EXTERN_GLOBAL:
443 return global()->copy();
444 case EXTERN_TABLE:
445 return table()->copy();
446 case EXTERN_MEMORY:
447 return memory()->copy();
448 }
449 }
450
kind() const451 auto ExternType::kind() const -> ExternKind { return impl(this)->kind; }
452
453 // Function Types
454
455 struct FuncTypeImpl : ExternTypeImpl {
456 ownvec<ValType> params;
457 ownvec<ValType> results;
458
FuncTypeImplwasm::FuncTypeImpl459 FuncTypeImpl(ownvec<ValType>& params, // NOLINT(runtime/references)
460 ownvec<ValType>& results) // NOLINT(runtime/references)
461 : ExternTypeImpl(EXTERN_FUNC),
462 params(std::move(params)),
463 results(std::move(results)) {}
464 };
465
466 template <>
467 struct implement<FuncType> {
468 using type = FuncTypeImpl;
469 };
470
471 FuncType::~FuncType() = default;
472
make(ownvec<ValType> && params,ownvec<ValType> && results)473 auto FuncType::make(ownvec<ValType>&& params, ownvec<ValType>&& results)
474 -> own<FuncType> {
475 return params && results
476 ? own<FuncType>(seal<FuncType>(new (std::nothrow)
477 FuncTypeImpl(params, results)))
478 : own<FuncType>();
479 }
480
copy() const481 auto FuncType::copy() const -> own<FuncType> {
482 return make(params().deep_copy(), results().deep_copy());
483 }
484
params() const485 auto FuncType::params() const -> const ownvec<ValType>& {
486 return impl(this)->params;
487 }
488
results() const489 auto FuncType::results() const -> const ownvec<ValType>& {
490 return impl(this)->results;
491 }
492
func()493 auto ExternType::func() -> FuncType* {
494 return kind() == EXTERN_FUNC
495 ? seal<FuncType>(static_cast<FuncTypeImpl*>(impl(this)))
496 : nullptr;
497 }
498
func() const499 auto ExternType::func() const -> const FuncType* {
500 return kind() == EXTERN_FUNC
501 ? seal<FuncType>(static_cast<const FuncTypeImpl*>(impl(this)))
502 : nullptr;
503 }
504
505 // Global Types
506
507 struct GlobalTypeImpl : ExternTypeImpl {
508 own<ValType> content;
509 Mutability mutability;
510
GlobalTypeImplwasm::GlobalTypeImpl511 GlobalTypeImpl(own<ValType>& content, // NOLINT(runtime/references)
512 Mutability mutability)
513 : ExternTypeImpl(EXTERN_GLOBAL),
514 content(std::move(content)),
515 mutability(mutability) {}
516
517 ~GlobalTypeImpl() override = default;
518 };
519
520 template <>
521 struct implement<GlobalType> {
522 using type = GlobalTypeImpl;
523 };
524
525 GlobalType::~GlobalType() = default;
526
make(own<ValType> && content,Mutability mutability)527 auto GlobalType::make(own<ValType>&& content, Mutability mutability)
528 -> own<GlobalType> {
529 return content ? own<GlobalType>(seal<GlobalType>(
530 new (std::nothrow) GlobalTypeImpl(content, mutability)))
531 : own<GlobalType>();
532 }
533
copy() const534 auto GlobalType::copy() const -> own<GlobalType> {
535 return make(content()->copy(), mutability());
536 }
537
content() const538 auto GlobalType::content() const -> const ValType* {
539 return impl(this)->content.get();
540 }
541
mutability() const542 auto GlobalType::mutability() const -> Mutability {
543 return impl(this)->mutability;
544 }
545
global()546 auto ExternType::global() -> GlobalType* {
547 return kind() == EXTERN_GLOBAL
548 ? seal<GlobalType>(static_cast<GlobalTypeImpl*>(impl(this)))
549 : nullptr;
550 }
551
global() const552 auto ExternType::global() const -> const GlobalType* {
553 return kind() == EXTERN_GLOBAL
554 ? seal<GlobalType>(static_cast<const GlobalTypeImpl*>(impl(this)))
555 : nullptr;
556 }
557
558 // Table Types
559
560 struct TableTypeImpl : ExternTypeImpl {
561 own<ValType> element;
562 Limits limits;
563
TableTypeImplwasm::TableTypeImpl564 TableTypeImpl(own<ValType>& element, // NOLINT(runtime/references)
565 Limits limits)
566 : ExternTypeImpl(EXTERN_TABLE),
567 element(std::move(element)),
568 limits(limits) {}
569
570 ~TableTypeImpl() override = default;
571 };
572
573 template <>
574 struct implement<TableType> {
575 using type = TableTypeImpl;
576 };
577
578 TableType::~TableType() = default;
579
make(own<ValType> && element,Limits limits)580 auto TableType::make(own<ValType>&& element, Limits limits) -> own<TableType> {
581 return element ? own<TableType>(seal<TableType>(
582 new (std::nothrow) TableTypeImpl(element, limits)))
583 : own<TableType>();
584 }
585
copy() const586 auto TableType::copy() const -> own<TableType> {
587 return make(element()->copy(), limits());
588 }
589
element() const590 auto TableType::element() const -> const ValType* {
591 return impl(this)->element.get();
592 }
593
limits() const594 auto TableType::limits() const -> const Limits& { return impl(this)->limits; }
595
table()596 auto ExternType::table() -> TableType* {
597 return kind() == EXTERN_TABLE
598 ? seal<TableType>(static_cast<TableTypeImpl*>(impl(this)))
599 : nullptr;
600 }
601
table() const602 auto ExternType::table() const -> const TableType* {
603 return kind() == EXTERN_TABLE
604 ? seal<TableType>(static_cast<const TableTypeImpl*>(impl(this)))
605 : nullptr;
606 }
607
608 // Memory Types
609
610 struct MemoryTypeImpl : ExternTypeImpl {
611 Limits limits;
612
MemoryTypeImplwasm::MemoryTypeImpl613 explicit MemoryTypeImpl(Limits limits)
614 : ExternTypeImpl(EXTERN_MEMORY), limits(limits) {}
615
616 ~MemoryTypeImpl() override = default;
617 };
618
619 template <>
620 struct implement<MemoryType> {
621 using type = MemoryTypeImpl;
622 };
623
624 MemoryType::~MemoryType() = default;
625
make(Limits limits)626 auto MemoryType::make(Limits limits) -> own<MemoryType> {
627 return own<MemoryType>(
628 seal<MemoryType>(new (std::nothrow) MemoryTypeImpl(limits)));
629 }
630
copy() const631 auto MemoryType::copy() const -> own<MemoryType> {
632 return MemoryType::make(limits());
633 }
634
limits() const635 auto MemoryType::limits() const -> const Limits& { return impl(this)->limits; }
636
memory()637 auto ExternType::memory() -> MemoryType* {
638 return kind() == EXTERN_MEMORY
639 ? seal<MemoryType>(static_cast<MemoryTypeImpl*>(impl(this)))
640 : nullptr;
641 }
642
memory() const643 auto ExternType::memory() const -> const MemoryType* {
644 return kind() == EXTERN_MEMORY
645 ? seal<MemoryType>(static_cast<const MemoryTypeImpl*>(impl(this)))
646 : nullptr;
647 }
648
649 // Import Types
650
651 struct ImportTypeImpl {
652 Name module;
653 Name name;
654 own<ExternType> type;
655
ImportTypeImplwasm::ImportTypeImpl656 ImportTypeImpl(Name& module, // NOLINT(runtime/references)
657 Name& name, // NOLINT(runtime/references)
658 own<ExternType>& type) // NOLINT(runtime/references)
659 : module(std::move(module)),
660 name(std::move(name)),
661 type(std::move(type)) {}
662 };
663
664 template <>
665 struct implement<ImportType> {
666 using type = ImportTypeImpl;
667 };
668
~ImportType()669 ImportType::~ImportType() { impl(this)->~ImportTypeImpl(); }
670
operator delete(void * p)671 void ImportType::operator delete(void* p) { ::operator delete(p); }
672
make(Name && module,Name && name,own<ExternType> && type)673 auto ImportType::make(Name&& module, Name&& name, own<ExternType>&& type)
674 -> own<ImportType> {
675 return module && name && type
676 ? own<ImportType>(seal<ImportType>(
677 new (std::nothrow) ImportTypeImpl(module, name, type)))
678 : own<ImportType>();
679 }
680
copy() const681 auto ImportType::copy() const -> own<ImportType> {
682 return make(module().copy(), name().copy(), type()->copy());
683 }
684
module() const685 auto ImportType::module() const -> const Name& { return impl(this)->module; }
686
name() const687 auto ImportType::name() const -> const Name& { return impl(this)->name; }
688
type() const689 auto ImportType::type() const -> const ExternType* {
690 return impl(this)->type.get();
691 }
692
693 // Export Types
694
695 struct ExportTypeImpl {
696 Name name;
697 own<ExternType> type;
698
ExportTypeImplwasm::ExportTypeImpl699 ExportTypeImpl(Name& name, // NOLINT(runtime/references)
700 own<ExternType>& type) // NOLINT(runtime/references)
701 : name(std::move(name)), type(std::move(type)) {}
702 };
703
704 template <>
705 struct implement<ExportType> {
706 using type = ExportTypeImpl;
707 };
708
~ExportType()709 ExportType::~ExportType() { impl(this)->~ExportTypeImpl(); }
710
operator delete(void * p)711 void ExportType::operator delete(void* p) { ::operator delete(p); }
712
make(Name && name,own<ExternType> && type)713 auto ExportType::make(Name&& name, own<ExternType>&& type) -> own<ExportType> {
714 return name && type ? own<ExportType>(seal<ExportType>(
715 new (std::nothrow) ExportTypeImpl(name, type)))
716 : own<ExportType>();
717 }
718
copy() const719 auto ExportType::copy() const -> own<ExportType> {
720 return make(name().copy(), type()->copy());
721 }
722
name() const723 auto ExportType::name() const -> const Name& { return impl(this)->name; }
724
type() const725 auto ExportType::type() const -> const ExternType* {
726 return impl(this)->type.get();
727 }
728
VecToString(i::Isolate * isolate,const vec<byte_t> & chars)729 i::Handle<i::String> VecToString(i::Isolate* isolate,
730 const vec<byte_t>& chars) {
731 size_t length = chars.size();
732 // Some, but not all, {chars} vectors we get here are null-terminated,
733 // so let's be robust to that.
734 if (length > 0 && chars[length - 1] == 0) length--;
735 return isolate->factory()
736 ->NewStringFromUtf8({chars.get(), length})
737 .ToHandleChecked();
738 }
739
740 // References
741
742 template <class Ref, class JSType>
743 class RefImpl {
744 public:
make(StoreImpl * store,i::Handle<JSType> obj)745 static own<Ref> make(StoreImpl* store, i::Handle<JSType> obj) {
746 RefImpl* self = new (std::nothrow) RefImpl();
747 if (!self) return nullptr;
748 i::Isolate* isolate = store->i_isolate();
749 self->val_ = isolate->global_handles()->Create(*obj);
750 return make_own(seal<Ref>(self));
751 }
752
~RefImpl()753 ~RefImpl() { i::GlobalHandles::Destroy(location()); }
754
copy() const755 own<Ref> copy() const { return make(store(), v8_object()); }
756
store() const757 StoreImpl* store() const { return StoreImpl::get(isolate()); }
758
isolate() const759 i::Isolate* isolate() const { return val_->GetIsolate(); }
760
v8_object() const761 i::Handle<JSType> v8_object() const { return i::Handle<JSType>::cast(val_); }
762
get_host_info() const763 void* get_host_info() const { return store()->GetHostInfo(v8_object()); }
764
set_host_info(void * info,void (* finalizer)(void *))765 void set_host_info(void* info, void (*finalizer)(void*)) {
766 store()->SetHostInfo(v8_object(), info, finalizer);
767 }
768
769 private:
770 RefImpl() = default;
771
location() const772 i::Address* location() const {
773 return reinterpret_cast<i::Address*>(val_.address());
774 }
775
776 i::Handle<i::JSReceiver> val_;
777 };
778
779 template <>
780 struct implement<Ref> {
781 using type = RefImpl<Ref, i::JSReceiver>;
782 };
783
~Ref()784 Ref::~Ref() { delete impl(this); }
785
operator delete(void * p)786 void Ref::operator delete(void* p) {}
787
copy() const788 auto Ref::copy() const -> own<Ref> { return impl(this)->copy(); }
789
same(const Ref * that) const790 auto Ref::same(const Ref* that) const -> bool {
791 i::HandleScope handle_scope(impl(this)->isolate());
792 return impl(this)->v8_object()->SameValue(*impl(that)->v8_object());
793 }
794
get_host_info() const795 auto Ref::get_host_info() const -> void* { return impl(this)->get_host_info(); }
796
set_host_info(void * info,void (* finalizer)(void *))797 void Ref::set_host_info(void* info, void (*finalizer)(void*)) {
798 impl(this)->set_host_info(info, finalizer);
799 }
800
801 ///////////////////////////////////////////////////////////////////////////////
802 // Runtime Objects
803
804 // Frames
805
806 namespace {
807
808 struct FrameImpl {
FrameImplwasm::__anonb185283e0211::FrameImpl809 FrameImpl(own<Instance>&& instance, uint32_t func_index, size_t func_offset,
810 size_t module_offset)
811 : instance(std::move(instance)),
812 func_index(func_index),
813 func_offset(func_offset),
814 module_offset(module_offset) {}
815
816 own<Instance> instance;
817 uint32_t func_index;
818 size_t func_offset;
819 size_t module_offset;
820 };
821
822 } // namespace
823
824 template <>
825 struct implement<Frame> {
826 using type = FrameImpl;
827 };
828
~Frame()829 Frame::~Frame() { impl(this)->~FrameImpl(); }
830
operator delete(void * p)831 void Frame::operator delete(void* p) { ::operator delete(p); }
832
copy() const833 own<Frame> Frame::copy() const {
834 auto self = impl(this);
835 return own<Frame>(seal<Frame>(
836 new (std::nothrow) FrameImpl(self->instance->copy(), self->func_index,
837 self->func_offset, self->module_offset)));
838 }
839
instance() const840 Instance* Frame::instance() const { return impl(this)->instance.get(); }
841
func_index() const842 uint32_t Frame::func_index() const { return impl(this)->func_index; }
843
func_offset() const844 size_t Frame::func_offset() const { return impl(this)->func_offset; }
845
module_offset() const846 size_t Frame::module_offset() const { return impl(this)->module_offset; }
847
848 // Traps
849
850 template <>
851 struct implement<Trap> {
852 using type = RefImpl<Trap, i::JSReceiver>;
853 };
854
855 Trap::~Trap() = default;
856
copy() const857 auto Trap::copy() const -> own<Trap> { return impl(this)->copy(); }
858
make(Store * store_abs,const Message & message)859 auto Trap::make(Store* store_abs, const Message& message) -> own<Trap> {
860 auto store = impl(store_abs);
861 i::Isolate* isolate = store->i_isolate();
862 i::HandleScope handle_scope(isolate);
863 i::Handle<i::String> string = VecToString(isolate, message);
864 i::Handle<i::JSReceiver> exception = i::Handle<i::JSReceiver>::cast(
865 isolate->factory()->NewError(isolate->error_function(), string));
866 return implement<Trap>::type::make(store, exception);
867 }
868
message() const869 auto Trap::message() const -> Message {
870 auto isolate = impl(this)->isolate();
871 i::HandleScope handle_scope(isolate);
872
873 i::Handle<i::JSMessageObject> message =
874 isolate->CreateMessage(impl(this)->v8_object(), nullptr);
875 i::Handle<i::String> result = i::MessageHandler::GetMessage(isolate, message);
876 result = i::String::Flatten(isolate, result); // For performance.
877 int length = 0;
878 std::unique_ptr<char[]> utf8 =
879 result->ToCString(i::DISALLOW_NULLS, i::FAST_STRING_TRAVERSAL, &length);
880 return vec<byte_t>::adopt(length, utf8.release());
881 }
882
883 namespace {
884
885 own<Instance> GetInstance(StoreImpl* store,
886 i::Handle<i::WasmInstanceObject> instance);
887
CreateFrameFromInternal(i::Handle<i::FixedArray> frames,int index,i::Isolate * isolate,StoreImpl * store)888 own<Frame> CreateFrameFromInternal(i::Handle<i::FixedArray> frames, int index,
889 i::Isolate* isolate, StoreImpl* store) {
890 i::Handle<i::StackTraceFrame> frame(
891 i::StackTraceFrame::cast(frames->get(index)), isolate);
892 i::Handle<i::WasmInstanceObject> instance =
893 i::StackTraceFrame::GetWasmInstance(frame);
894 uint32_t func_index = i::StackTraceFrame::GetWasmFunctionIndex(frame);
895 size_t func_offset = i::StackTraceFrame::GetFunctionOffset(frame);
896 size_t module_offset = i::StackTraceFrame::GetColumnNumber(frame);
897 return own<Frame>(seal<Frame>(new (std::nothrow) FrameImpl(
898 GetInstance(store, instance), func_index, func_offset, module_offset)));
899 }
900
901 } // namespace
902
origin() const903 own<Frame> Trap::origin() const {
904 i::Isolate* isolate = impl(this)->isolate();
905 i::HandleScope handle_scope(isolate);
906
907 i::Handle<i::JSMessageObject> message =
908 isolate->CreateMessage(impl(this)->v8_object(), nullptr);
909 i::Handle<i::FixedArray> frames(i::FixedArray::cast(message->stack_frames()),
910 isolate);
911 if (frames->length() == 0) {
912 return own<Frame>();
913 }
914 return CreateFrameFromInternal(frames, 0, isolate, impl(this)->store());
915 }
916
trace() const917 ownvec<Frame> Trap::trace() const {
918 i::Isolate* isolate = impl(this)->isolate();
919 i::HandleScope handle_scope(isolate);
920
921 i::Handle<i::JSMessageObject> message =
922 isolate->CreateMessage(impl(this)->v8_object(), nullptr);
923 i::Handle<i::FixedArray> frames(i::FixedArray::cast(message->stack_frames()),
924 isolate);
925 int num_frames = frames->length();
926 // {num_frames} can be 0; the code below can handle that case.
927 ownvec<Frame> result = ownvec<Frame>::make_uninitialized(num_frames);
928 for (int i = 0; i < num_frames; i++) {
929 result[i] =
930 CreateFrameFromInternal(frames, i, isolate, impl(this)->store());
931 }
932 return result;
933 }
934
935 // Foreign Objects
936
937 template <>
938 struct implement<Foreign> {
939 using type = RefImpl<Foreign, i::JSReceiver>;
940 };
941
942 Foreign::~Foreign() = default;
943
copy() const944 auto Foreign::copy() const -> own<Foreign> { return impl(this)->copy(); }
945
make(Store * store_abs)946 auto Foreign::make(Store* store_abs) -> own<Foreign> {
947 StoreImpl* store = impl(store_abs);
948 i::Isolate* isolate = store->i_isolate();
949 i::HandleScope handle_scope(isolate);
950
951 i::Handle<i::JSObject> obj =
952 isolate->factory()->NewJSObject(isolate->object_function());
953 return implement<Foreign>::type::make(store, obj);
954 }
955
956 // Modules
957
958 template <>
959 struct implement<Module> {
960 using type = RefImpl<Module, i::WasmModuleObject>;
961 };
962
963 Module::~Module() = default;
964
copy() const965 auto Module::copy() const -> own<Module> { return impl(this)->copy(); }
966
validate(Store * store_abs,const vec<byte_t> & binary)967 auto Module::validate(Store* store_abs, const vec<byte_t>& binary) -> bool {
968 i::wasm::ModuleWireBytes bytes(
969 {reinterpret_cast<const uint8_t*>(binary.get()), binary.size()});
970 i::Isolate* isolate = impl(store_abs)->i_isolate();
971 i::wasm::WasmFeatures features = i::wasm::WasmFeatures::FromIsolate(isolate);
972 return isolate->wasm_engine()->SyncValidate(isolate, features, bytes);
973 }
974
make(Store * store_abs,const vec<byte_t> & binary)975 auto Module::make(Store* store_abs, const vec<byte_t>& binary) -> own<Module> {
976 StoreImpl* store = impl(store_abs);
977 i::Isolate* isolate = store->i_isolate();
978 i::HandleScope scope(isolate);
979 i::wasm::ModuleWireBytes bytes(
980 {reinterpret_cast<const uint8_t*>(binary.get()), binary.size()});
981 i::wasm::WasmFeatures features = i::wasm::WasmFeatures::FromIsolate(isolate);
982 i::wasm::ErrorThrower thrower(isolate, "ignored");
983 i::Handle<i::WasmModuleObject> module;
984 if (!isolate->wasm_engine()
985 ->SyncCompile(isolate, features, &thrower, bytes)
986 .ToHandle(&module)) {
987 thrower.Reset(); // The API provides no way to expose the error.
988 return nullptr;
989 }
990 return implement<Module>::type::make(store, module);
991 }
992
imports() const993 auto Module::imports() const -> ownvec<ImportType> {
994 const i::wasm::NativeModule* native_module =
995 impl(this)->v8_object()->native_module();
996 const i::wasm::WasmModule* module = native_module->module();
997 const i::Vector<const uint8_t> wire_bytes = native_module->wire_bytes();
998 const std::vector<i::wasm::WasmImport>& import_table = module->import_table;
999 size_t size = import_table.size();
1000 ownvec<ImportType> imports = ownvec<ImportType>::make_uninitialized(size);
1001 for (uint32_t i = 0; i < size; i++) {
1002 const i::wasm::WasmImport& imp = import_table[i];
1003 Name module_name = GetNameFromWireBytes(imp.module_name, wire_bytes);
1004 Name name = GetNameFromWireBytes(imp.field_name, wire_bytes);
1005 own<ExternType> type = GetImportExportType(module, imp.kind, imp.index);
1006 imports[i] = ImportType::make(std::move(module_name), std::move(name),
1007 std::move(type));
1008 }
1009 return imports;
1010 }
1011
ExportsImpl(i::Handle<i::WasmModuleObject> module_obj)1012 ownvec<ExportType> ExportsImpl(i::Handle<i::WasmModuleObject> module_obj) {
1013 const i::wasm::NativeModule* native_module = module_obj->native_module();
1014 const i::wasm::WasmModule* module = native_module->module();
1015 const i::Vector<const uint8_t> wire_bytes = native_module->wire_bytes();
1016 const std::vector<i::wasm::WasmExport>& export_table = module->export_table;
1017 size_t size = export_table.size();
1018 ownvec<ExportType> exports = ownvec<ExportType>::make_uninitialized(size);
1019 for (uint32_t i = 0; i < size; i++) {
1020 const i::wasm::WasmExport& exp = export_table[i];
1021 Name name = GetNameFromWireBytes(exp.name, wire_bytes);
1022 own<ExternType> type = GetImportExportType(module, exp.kind, exp.index);
1023 exports[i] = ExportType::make(std::move(name), std::move(type));
1024 }
1025 return exports;
1026 }
1027
exports() const1028 auto Module::exports() const -> ownvec<ExportType> {
1029 return ExportsImpl(impl(this)->v8_object());
1030 }
1031
serialize() const1032 auto Module::serialize() const -> vec<byte_t> {
1033 i::wasm::NativeModule* native_module =
1034 impl(this)->v8_object()->native_module();
1035 i::Vector<const uint8_t> wire_bytes = native_module->wire_bytes();
1036 size_t binary_size = wire_bytes.size();
1037 // We can only serialize after top-tier compilation (TurboFan) finished.
1038 native_module->compilation_state()->WaitForTopTierFinished();
1039 i::wasm::WasmSerializer serializer(native_module);
1040 size_t serial_size = serializer.GetSerializedNativeModuleSize();
1041 size_t size_size = i::wasm::LEBHelper::sizeof_u64v(binary_size);
1042 vec<byte_t> buffer =
1043 vec<byte_t>::make_uninitialized(size_size + binary_size + serial_size);
1044 byte_t* ptr = buffer.get();
1045 i::wasm::LEBHelper::write_u64v(reinterpret_cast<uint8_t**>(&ptr),
1046 binary_size);
1047 std::memcpy(ptr, wire_bytes.begin(), binary_size);
1048 ptr += binary_size;
1049 if (!serializer.SerializeNativeModule(
1050 {reinterpret_cast<uint8_t*>(ptr), serial_size})) {
1051 buffer.reset();
1052 }
1053 return buffer;
1054 }
1055
deserialize(Store * store_abs,const vec<byte_t> & serialized)1056 auto Module::deserialize(Store* store_abs, const vec<byte_t>& serialized)
1057 -> own<Module> {
1058 StoreImpl* store = impl(store_abs);
1059 i::Isolate* isolate = store->i_isolate();
1060 i::HandleScope handle_scope(isolate);
1061 const byte_t* ptr = serialized.get();
1062 uint64_t binary_size = ReadLebU64(&ptr);
1063 ptrdiff_t size_size = ptr - serialized.get();
1064 size_t serial_size = serialized.size() - size_size - binary_size;
1065 i::Handle<i::WasmModuleObject> module_obj;
1066 size_t data_size = static_cast<size_t>(binary_size);
1067 if (!i::wasm::DeserializeNativeModule(
1068 isolate,
1069 {reinterpret_cast<const uint8_t*>(ptr + data_size), serial_size},
1070 {reinterpret_cast<const uint8_t*>(ptr), data_size}, {})
1071 .ToHandle(&module_obj)) {
1072 return nullptr;
1073 }
1074 return implement<Module>::type::make(store, module_obj);
1075 }
1076
1077 // TODO(v8): do better when V8 can do better.
1078 template <>
1079 struct implement<Shared<Module>> {
1080 using type = vec<byte_t>;
1081 };
1082
1083 template <>
~Shared()1084 Shared<Module>::~Shared() {
1085 impl(this)->~vec();
1086 }
1087
1088 template <>
operator delete(void * p)1089 void Shared<Module>::operator delete(void* p) {
1090 ::operator delete(p);
1091 }
1092
share() const1093 auto Module::share() const -> own<Shared<Module>> {
1094 auto shared = seal<Shared<Module>>(new vec<byte_t>(serialize()));
1095 return make_own(shared);
1096 }
1097
obtain(Store * store,const Shared<Module> * shared)1098 auto Module::obtain(Store* store, const Shared<Module>* shared) -> own<Module> {
1099 return Module::deserialize(store, *impl(shared));
1100 }
1101
1102 // Externals
1103
1104 template <>
1105 struct implement<Extern> {
1106 using type = RefImpl<Extern, i::JSReceiver>;
1107 };
1108
1109 Extern::~Extern() = default;
1110
copy() const1111 auto Extern::copy() const -> own<Extern> { return impl(this)->copy(); }
1112
kind() const1113 auto Extern::kind() const -> ExternKind {
1114 i::Handle<i::JSReceiver> obj = impl(this)->v8_object();
1115 if (i::WasmExportedFunction::IsWasmExportedFunction(*obj)) {
1116 return wasm::EXTERN_FUNC;
1117 }
1118 if (obj->IsWasmGlobalObject()) return wasm::EXTERN_GLOBAL;
1119 if (obj->IsWasmTableObject()) return wasm::EXTERN_TABLE;
1120 if (obj->IsWasmMemoryObject()) return wasm::EXTERN_MEMORY;
1121 UNREACHABLE();
1122 }
1123
type() const1124 auto Extern::type() const -> own<ExternType> {
1125 switch (kind()) {
1126 case EXTERN_FUNC:
1127 return func()->type();
1128 case EXTERN_GLOBAL:
1129 return global()->type();
1130 case EXTERN_TABLE:
1131 return table()->type();
1132 case EXTERN_MEMORY:
1133 return memory()->type();
1134 }
1135 }
1136
func()1137 auto Extern::func() -> Func* {
1138 return kind() == EXTERN_FUNC ? static_cast<Func*>(this) : nullptr;
1139 }
1140
global()1141 auto Extern::global() -> Global* {
1142 return kind() == EXTERN_GLOBAL ? static_cast<Global*>(this) : nullptr;
1143 }
1144
table()1145 auto Extern::table() -> Table* {
1146 return kind() == EXTERN_TABLE ? static_cast<Table*>(this) : nullptr;
1147 }
1148
memory()1149 auto Extern::memory() -> Memory* {
1150 return kind() == EXTERN_MEMORY ? static_cast<Memory*>(this) : nullptr;
1151 }
1152
func() const1153 auto Extern::func() const -> const Func* {
1154 return kind() == EXTERN_FUNC ? static_cast<const Func*>(this) : nullptr;
1155 }
1156
global() const1157 auto Extern::global() const -> const Global* {
1158 return kind() == EXTERN_GLOBAL ? static_cast<const Global*>(this) : nullptr;
1159 }
1160
table() const1161 auto Extern::table() const -> const Table* {
1162 return kind() == EXTERN_TABLE ? static_cast<const Table*>(this) : nullptr;
1163 }
1164
memory() const1165 auto Extern::memory() const -> const Memory* {
1166 return kind() == EXTERN_MEMORY ? static_cast<const Memory*>(this) : nullptr;
1167 }
1168
extern_to_v8(const Extern * ex)1169 auto extern_to_v8(const Extern* ex) -> i::Handle<i::JSReceiver> {
1170 return impl(ex)->v8_object();
1171 }
1172
1173 // Function Instances
1174
1175 template <>
1176 struct implement<Func> {
1177 using type = RefImpl<Func, i::JSFunction>;
1178 };
1179
1180 Func::~Func() = default;
1181
copy() const1182 auto Func::copy() const -> own<Func> { return impl(this)->copy(); }
1183
1184 struct FuncData {
1185 Store* store;
1186 own<FuncType> type;
1187 enum Kind { kCallback, kCallbackWithEnv } kind;
1188 union {
1189 Func::callback callback;
1190 Func::callback_with_env callback_with_env;
1191 };
1192 void (*finalizer)(void*);
1193 void* env;
1194
FuncDatawasm::FuncData1195 FuncData(Store* store, const FuncType* type, Kind kind)
1196 : store(store),
1197 type(type->copy()),
1198 kind(kind),
1199 finalizer(nullptr),
1200 env(nullptr) {}
1201
~FuncDatawasm::FuncData1202 ~FuncData() {
1203 if (finalizer) (*finalizer)(env);
1204 }
1205
1206 static i::Address v8_callback(i::Address host_data_foreign, i::Address argv);
1207 };
1208
1209 namespace {
1210
1211 // TODO(jkummerow): Generalize for WasmExportedFunction and WasmCapiFunction.
1212 class SignatureHelper : public i::AllStatic {
1213 public:
1214 // Use an invalid type as a marker separating params and results.
1215 static constexpr i::wasm::ValueType kMarker = i::wasm::kWasmStmt;
1216
Serialize(i::Isolate * isolate,FuncType * type)1217 static i::Handle<i::PodArray<i::wasm::ValueType>> Serialize(
1218 i::Isolate* isolate, FuncType* type) {
1219 int sig_size =
1220 static_cast<int>(type->params().size() + type->results().size() + 1);
1221 i::Handle<i::PodArray<i::wasm::ValueType>> sig =
1222 i::PodArray<i::wasm::ValueType>::New(isolate, sig_size,
1223 i::AllocationType::kOld);
1224 int index = 0;
1225 // TODO(jkummerow): Consider making vec<> range-based for-iterable.
1226 for (size_t i = 0; i < type->results().size(); i++) {
1227 sig->set(index++, WasmValKindToV8(type->results()[i]->kind()));
1228 }
1229 // {sig->set} needs to take the address of its second parameter,
1230 // so we can't pass in the static const kMarker directly.
1231 i::wasm::ValueType marker = kMarker;
1232 sig->set(index++, marker);
1233 for (size_t i = 0; i < type->params().size(); i++) {
1234 sig->set(index++, WasmValKindToV8(type->params()[i]->kind()));
1235 }
1236 return sig;
1237 }
1238
Deserialize(i::PodArray<i::wasm::ValueType> sig)1239 static own<FuncType> Deserialize(i::PodArray<i::wasm::ValueType> sig) {
1240 int result_arity = ResultArity(sig);
1241 int param_arity = sig.length() - result_arity - 1;
1242 ownvec<ValType> results = ownvec<ValType>::make_uninitialized(result_arity);
1243 ownvec<ValType> params = ownvec<ValType>::make_uninitialized(param_arity);
1244
1245 int i = 0;
1246 for (; i < result_arity; ++i) {
1247 results[i] = ValType::make(V8ValueTypeToWasm(sig.get(i)));
1248 }
1249 i++; // Skip marker.
1250 for (int p = 0; i < sig.length(); ++i, ++p) {
1251 params[p] = ValType::make(V8ValueTypeToWasm(sig.get(i)));
1252 }
1253 return FuncType::make(std::move(params), std::move(results));
1254 }
1255
ResultArity(i::PodArray<i::wasm::ValueType> sig)1256 static int ResultArity(i::PodArray<i::wasm::ValueType> sig) {
1257 int count = 0;
1258 for (; count < sig.length(); count++) {
1259 if (sig.get(count) == kMarker) return count;
1260 }
1261 UNREACHABLE();
1262 }
1263
ParamArity(i::PodArray<i::wasm::ValueType> sig)1264 static int ParamArity(i::PodArray<i::wasm::ValueType> sig) {
1265 return sig.length() - ResultArity(sig) - 1;
1266 }
1267
GetSig(i::Handle<i::JSFunction> function)1268 static i::PodArray<i::wasm::ValueType> GetSig(
1269 i::Handle<i::JSFunction> function) {
1270 return i::WasmCapiFunction::cast(*function).GetSerializedSignature();
1271 }
1272 };
1273
1274 // Explicit instantiation makes the linker happy for component builds of
1275 // wasm_api_tests.
1276 constexpr i::wasm::ValueType SignatureHelper::kMarker;
1277
make_func(Store * store_abs,FuncData * data)1278 auto make_func(Store* store_abs, FuncData* data) -> own<Func> {
1279 auto store = impl(store_abs);
1280 i::Isolate* isolate = store->i_isolate();
1281 i::HandleScope handle_scope(isolate);
1282 i::Handle<i::Managed<FuncData>> embedder_data =
1283 i::Managed<FuncData>::FromRawPtr(isolate, sizeof(FuncData), data);
1284 i::Handle<i::WasmCapiFunction> function = i::WasmCapiFunction::New(
1285 isolate, reinterpret_cast<i::Address>(&FuncData::v8_callback),
1286 embedder_data, SignatureHelper::Serialize(isolate, data->type.get()));
1287 auto func = implement<Func>::type::make(store, function);
1288 return func;
1289 }
1290
1291 } // namespace
1292
make(Store * store,const FuncType * type,Func::callback callback)1293 auto Func::make(Store* store, const FuncType* type, Func::callback callback)
1294 -> own<Func> {
1295 auto data = new FuncData(store, type, FuncData::kCallback);
1296 data->callback = callback;
1297 return make_func(store, data);
1298 }
1299
make(Store * store,const FuncType * type,callback_with_env callback,void * env,void (* finalizer)(void *))1300 auto Func::make(Store* store, const FuncType* type, callback_with_env callback,
1301 void* env, void (*finalizer)(void*)) -> own<Func> {
1302 auto data = new FuncData(store, type, FuncData::kCallbackWithEnv);
1303 data->callback_with_env = callback;
1304 data->env = env;
1305 data->finalizer = finalizer;
1306 return make_func(store, data);
1307 }
1308
type() const1309 auto Func::type() const -> own<FuncType> {
1310 i::Handle<i::JSFunction> func = impl(this)->v8_object();
1311 if (i::WasmCapiFunction::IsWasmCapiFunction(*func)) {
1312 return SignatureHelper::Deserialize(SignatureHelper::GetSig(func));
1313 }
1314 DCHECK(i::WasmExportedFunction::IsWasmExportedFunction(*func));
1315 i::Handle<i::WasmExportedFunction> function =
1316 i::Handle<i::WasmExportedFunction>::cast(func);
1317 return FunctionSigToFuncType(
1318 function->instance().module()->functions[function->function_index()].sig);
1319 }
1320
param_arity() const1321 auto Func::param_arity() const -> size_t {
1322 i::Handle<i::JSFunction> func = impl(this)->v8_object();
1323 if (i::WasmCapiFunction::IsWasmCapiFunction(*func)) {
1324 return SignatureHelper::ParamArity(SignatureHelper::GetSig(func));
1325 }
1326 DCHECK(i::WasmExportedFunction::IsWasmExportedFunction(*func));
1327 i::Handle<i::WasmExportedFunction> function =
1328 i::Handle<i::WasmExportedFunction>::cast(func);
1329 const i::wasm::FunctionSig* sig =
1330 function->instance().module()->functions[function->function_index()].sig;
1331 return sig->parameter_count();
1332 }
1333
result_arity() const1334 auto Func::result_arity() const -> size_t {
1335 i::Handle<i::JSFunction> func = impl(this)->v8_object();
1336 if (i::WasmCapiFunction::IsWasmCapiFunction(*func)) {
1337 return SignatureHelper::ResultArity(SignatureHelper::GetSig(func));
1338 }
1339 DCHECK(i::WasmExportedFunction::IsWasmExportedFunction(*func));
1340 i::Handle<i::WasmExportedFunction> function =
1341 i::Handle<i::WasmExportedFunction>::cast(func);
1342 const i::wasm::FunctionSig* sig =
1343 function->instance().module()->functions[function->function_index()].sig;
1344 return sig->return_count();
1345 }
1346
1347 namespace {
1348
V8RefValueToWasm(StoreImpl * store,i::Handle<i::Object> value)1349 own<Ref> V8RefValueToWasm(StoreImpl* store, i::Handle<i::Object> value) {
1350 if (value->IsNull(store->i_isolate())) return nullptr;
1351 return implement<Ref>::type::make(store,
1352 i::Handle<i::JSReceiver>::cast(value));
1353 }
1354
WasmRefToV8(i::Isolate * isolate,const Ref * ref)1355 i::Handle<i::Object> WasmRefToV8(i::Isolate* isolate, const Ref* ref) {
1356 if (ref == nullptr) return i::ReadOnlyRoots(isolate).null_value_handle();
1357 return impl(ref)->v8_object();
1358 }
1359
CallTargetForCaching(i::Isolate * isolate,i::Address real_call_target)1360 i::Handle<i::Object> CallTargetForCaching(i::Isolate* isolate,
1361 i::Address real_call_target) {
1362 if (i::kTaggedSize == i::kInt32Size) {
1363 return isolate->factory()->NewForeign(real_call_target);
1364 } else {
1365 // 64-bit uncompressed platform.
1366 return i::handle(i::Smi((real_call_target << i::kSmiTagSize) | i::kSmiTag),
1367 isolate);
1368 }
1369 }
1370
CallTargetFromCache(i::Object cached_call_target)1371 i::Address CallTargetFromCache(i::Object cached_call_target) {
1372 if (i::kTaggedSize == i::kInt32Size) {
1373 return i::Foreign::cast(cached_call_target).foreign_address();
1374 } else {
1375 // 64-bit uncompressed platform.
1376 return cached_call_target.ptr() >> i::kSmiTagSize;
1377 }
1378 }
1379
PrepareFunctionData(i::Isolate * isolate,i::Handle<i::WasmExportedFunctionData> function_data,const i::wasm::FunctionSig * sig,const i::wasm::WasmModule * module)1380 void PrepareFunctionData(i::Isolate* isolate,
1381 i::Handle<i::WasmExportedFunctionData> function_data,
1382 const i::wasm::FunctionSig* sig,
1383 const i::wasm::WasmModule* module) {
1384 // If the data is already populated, return immediately.
1385 if (!function_data->c_wrapper_code().IsSmi()) return;
1386 // Compile wrapper code.
1387 i::Handle<i::Code> wrapper_code =
1388 i::compiler::CompileCWasmEntry(isolate, sig, module);
1389 function_data->set_c_wrapper_code(*wrapper_code);
1390 // Compute packed args size.
1391 function_data->set_packed_args_size(
1392 i::wasm::CWasmArgumentsPacker::TotalSize(sig));
1393 // Get call target (function table offset), and wrap it as a cacheable object
1394 // (pseudo-Smi or Foreign, depending on platform).
1395 i::Handle<i::Object> call_target = CallTargetForCaching(
1396 isolate,
1397 function_data->instance().GetCallTarget(function_data->function_index()));
1398 function_data->set_wasm_call_target(*call_target);
1399 }
1400
PushArgs(const i::wasm::FunctionSig * sig,const Val args[],i::wasm::CWasmArgumentsPacker * packer,StoreImpl * store)1401 void PushArgs(const i::wasm::FunctionSig* sig, const Val args[],
1402 i::wasm::CWasmArgumentsPacker* packer, StoreImpl* store) {
1403 for (size_t i = 0; i < sig->parameter_count(); i++) {
1404 i::wasm::ValueType type = sig->GetParam(i);
1405 switch (type.kind()) {
1406 case i::wasm::ValueType::kI32:
1407 packer->Push(args[i].i32());
1408 break;
1409 case i::wasm::ValueType::kI64:
1410 packer->Push(args[i].i64());
1411 break;
1412 case i::wasm::ValueType::kF32:
1413 packer->Push(args[i].f32());
1414 break;
1415 case i::wasm::ValueType::kF64:
1416 packer->Push(args[i].f64());
1417 break;
1418 case i::wasm::ValueType::kRef:
1419 case i::wasm::ValueType::kOptRef:
1420 // TODO(7748): Make sure this works for all heap types.
1421 packer->Push(WasmRefToV8(store->i_isolate(), args[i].ref())->ptr());
1422 break;
1423 case i::wasm::ValueType::kRtt:
1424 case i::wasm::ValueType::kS128:
1425 // TODO(7748): Implement.
1426 UNIMPLEMENTED();
1427 case i::wasm::ValueType::kI8:
1428 case i::wasm::ValueType::kI16:
1429 case i::wasm::ValueType::kStmt:
1430 case i::wasm::ValueType::kBottom:
1431 UNREACHABLE();
1432 break;
1433 }
1434 }
1435 }
1436
PopArgs(const i::wasm::FunctionSig * sig,Val results[],i::wasm::CWasmArgumentsPacker * packer,StoreImpl * store)1437 void PopArgs(const i::wasm::FunctionSig* sig, Val results[],
1438 i::wasm::CWasmArgumentsPacker* packer, StoreImpl* store) {
1439 packer->Reset();
1440 for (size_t i = 0; i < sig->return_count(); i++) {
1441 i::wasm::ValueType type = sig->GetReturn(i);
1442 switch (type.kind()) {
1443 case i::wasm::ValueType::kI32:
1444 results[i] = Val(packer->Pop<int32_t>());
1445 break;
1446 case i::wasm::ValueType::kI64:
1447 results[i] = Val(packer->Pop<int64_t>());
1448 break;
1449 case i::wasm::ValueType::kF32:
1450 results[i] = Val(packer->Pop<float>());
1451 break;
1452 case i::wasm::ValueType::kF64:
1453 results[i] = Val(packer->Pop<double>());
1454 break;
1455 case i::wasm::ValueType::kRef:
1456 case i::wasm::ValueType::kOptRef: {
1457 // TODO(7748): Make sure this works for all heap types.
1458 i::Address raw = packer->Pop<i::Address>();
1459 i::Handle<i::Object> obj(i::Object(raw), store->i_isolate());
1460 results[i] = Val(V8RefValueToWasm(store, obj));
1461 break;
1462 }
1463 case i::wasm::ValueType::kRtt:
1464 case i::wasm::ValueType::kS128:
1465 // TODO(7748): Implement.
1466 UNIMPLEMENTED();
1467 case i::wasm::ValueType::kI8:
1468 case i::wasm::ValueType::kI16:
1469 case i::wasm::ValueType::kStmt:
1470 case i::wasm::ValueType::kBottom:
1471 UNREACHABLE();
1472 break;
1473 }
1474 }
1475 }
1476
CallWasmCapiFunction(i::WasmCapiFunctionData data,const Val args[],Val results[])1477 own<Trap> CallWasmCapiFunction(i::WasmCapiFunctionData data, const Val args[],
1478 Val results[]) {
1479 FuncData* func_data = i::Managed<FuncData>::cast(data.embedder_data()).raw();
1480 if (func_data->kind == FuncData::kCallback) {
1481 return (func_data->callback)(args, results);
1482 }
1483 DCHECK(func_data->kind == FuncData::kCallbackWithEnv);
1484 return (func_data->callback_with_env)(func_data->env, args, results);
1485 }
1486
GetProperException(i::Isolate * isolate,i::Handle<i::Object> maybe_exception)1487 i::Handle<i::JSReceiver> GetProperException(
1488 i::Isolate* isolate, i::Handle<i::Object> maybe_exception) {
1489 if (maybe_exception->IsJSReceiver()) {
1490 return i::Handle<i::JSReceiver>::cast(maybe_exception);
1491 }
1492 i::MaybeHandle<i::String> maybe_string =
1493 i::Object::ToString(isolate, maybe_exception);
1494 i::Handle<i::String> string = isolate->factory()->empty_string();
1495 if (!maybe_string.ToHandle(&string)) {
1496 // If converting the {maybe_exception} to string threw another exception,
1497 // just give up and leave {string} as the empty string.
1498 isolate->clear_pending_exception();
1499 }
1500 // {NewError} cannot fail when its input is a plain String, so we always
1501 // get an Error object here.
1502 return i::Handle<i::JSReceiver>::cast(
1503 isolate->factory()->NewError(isolate->error_function(), string));
1504 }
1505
1506 } // namespace
1507
call(const Val args[],Val results[]) const1508 auto Func::call(const Val args[], Val results[]) const -> own<Trap> {
1509 auto func = impl(this);
1510 auto store = func->store();
1511 auto isolate = store->i_isolate();
1512 i::HandleScope handle_scope(isolate);
1513 i::Object raw_function_data =
1514 func->v8_object()->shared().function_data(v8::kAcquireLoad);
1515
1516 // WasmCapiFunctions can be called directly.
1517 if (raw_function_data.IsWasmCapiFunctionData()) {
1518 return CallWasmCapiFunction(
1519 i::WasmCapiFunctionData::cast(raw_function_data), args, results);
1520 }
1521
1522 DCHECK(raw_function_data.IsWasmExportedFunctionData());
1523 i::Handle<i::WasmExportedFunctionData> function_data(
1524 i::WasmExportedFunctionData::cast(raw_function_data), isolate);
1525 i::Handle<i::WasmInstanceObject> instance(function_data->instance(), isolate);
1526 int function_index = function_data->function_index();
1527 // Caching {sig} would give a ~10% reduction in overhead.
1528 const i::wasm::FunctionSig* sig =
1529 instance->module()->functions[function_index].sig;
1530 PrepareFunctionData(isolate, function_data, sig, instance->module());
1531 i::Handle<i::Code> wrapper_code = i::Handle<i::Code>(
1532 i::Code::cast(function_data->c_wrapper_code()), isolate);
1533 i::Address call_target =
1534 CallTargetFromCache(function_data->wasm_call_target());
1535
1536 i::wasm::CWasmArgumentsPacker packer(function_data->packed_args_size());
1537 PushArgs(sig, args, &packer, store);
1538
1539 i::Handle<i::Object> object_ref = instance;
1540 if (function_index <
1541 static_cast<int>(instance->module()->num_imported_functions)) {
1542 object_ref = i::handle(
1543 instance->imported_function_refs().get(function_index), isolate);
1544 if (object_ref->IsTuple2()) {
1545 i::JSFunction jsfunc =
1546 i::JSFunction::cast(i::Tuple2::cast(*object_ref).value2());
1547 i::Object data = jsfunc.shared().function_data(v8::kAcquireLoad);
1548 if (data.IsWasmCapiFunctionData()) {
1549 return CallWasmCapiFunction(i::WasmCapiFunctionData::cast(data), args,
1550 results);
1551 }
1552 // TODO(jkummerow): Imported and then re-exported JavaScript functions
1553 // are not supported yet. If we support C-API + JavaScript, we'll need
1554 // to call those here.
1555 UNIMPLEMENTED();
1556 } else {
1557 // A WasmFunction from another module.
1558 DCHECK(object_ref->IsWasmInstanceObject());
1559 }
1560 }
1561
1562 i::Execution::CallWasm(isolate, wrapper_code, call_target, object_ref,
1563 packer.argv());
1564
1565 if (isolate->has_pending_exception()) {
1566 i::Handle<i::Object> exception(isolate->pending_exception(), isolate);
1567 isolate->clear_pending_exception();
1568 return implement<Trap>::type::make(store,
1569 GetProperException(isolate, exception));
1570 }
1571
1572 PopArgs(sig, results, &packer, store);
1573 return nullptr;
1574 }
1575
v8_callback(i::Address host_data_foreign,i::Address argv)1576 i::Address FuncData::v8_callback(i::Address host_data_foreign,
1577 i::Address argv) {
1578 FuncData* self =
1579 i::Managed<FuncData>::cast(i::Object(host_data_foreign)).raw();
1580 StoreImpl* store = impl(self->store);
1581 i::Isolate* isolate = store->i_isolate();
1582 i::HandleScope scope(isolate);
1583
1584 const ownvec<ValType>& param_types = self->type->params();
1585 const ownvec<ValType>& result_types = self->type->results();
1586
1587 int num_param_types = static_cast<int>(param_types.size());
1588 int num_result_types = static_cast<int>(result_types.size());
1589
1590 std::unique_ptr<Val[]> params(new Val[num_param_types]);
1591 std::unique_ptr<Val[]> results(new Val[num_result_types]);
1592 i::Address p = argv;
1593 for (int i = 0; i < num_param_types; ++i) {
1594 switch (param_types[i]->kind()) {
1595 case I32:
1596 params[i] = Val(v8::base::ReadUnalignedValue<int32_t>(p));
1597 p += 4;
1598 break;
1599 case I64:
1600 params[i] = Val(v8::base::ReadUnalignedValue<int64_t>(p));
1601 p += 8;
1602 break;
1603 case F32:
1604 params[i] = Val(v8::base::ReadUnalignedValue<float32_t>(p));
1605 p += 4;
1606 break;
1607 case F64:
1608 params[i] = Val(v8::base::ReadUnalignedValue<float64_t>(p));
1609 p += 8;
1610 break;
1611 case ANYREF:
1612 case FUNCREF: {
1613 i::Address raw = v8::base::ReadUnalignedValue<i::Address>(p);
1614 p += sizeof(raw);
1615 i::Handle<i::Object> obj(i::Object(raw), isolate);
1616 params[i] = Val(V8RefValueToWasm(store, obj));
1617 break;
1618 }
1619 }
1620 }
1621
1622 own<Trap> trap;
1623 if (self->kind == kCallbackWithEnv) {
1624 trap = self->callback_with_env(self->env, params.get(), results.get());
1625 } else {
1626 trap = self->callback(params.get(), results.get());
1627 }
1628
1629 if (trap) {
1630 isolate->Throw(*impl(trap.get())->v8_object());
1631 i::Object ex = isolate->pending_exception();
1632 isolate->clear_pending_exception();
1633 return ex.ptr();
1634 }
1635
1636 p = argv;
1637 for (int i = 0; i < num_result_types; ++i) {
1638 switch (result_types[i]->kind()) {
1639 case I32:
1640 v8::base::WriteUnalignedValue(p, results[i].i32());
1641 p += 4;
1642 break;
1643 case I64:
1644 v8::base::WriteUnalignedValue(p, results[i].i64());
1645 p += 8;
1646 break;
1647 case F32:
1648 v8::base::WriteUnalignedValue(p, results[i].f32());
1649 p += 4;
1650 break;
1651 case F64:
1652 v8::base::WriteUnalignedValue(p, results[i].f64());
1653 p += 8;
1654 break;
1655 case ANYREF:
1656 case FUNCREF: {
1657 v8::base::WriteUnalignedValue(
1658 p, WasmRefToV8(isolate, results[i].ref())->ptr());
1659 p += sizeof(i::Address);
1660 break;
1661 }
1662 }
1663 }
1664 return i::kNullAddress;
1665 }
1666
1667 // Global Instances
1668
1669 template <>
1670 struct implement<Global> {
1671 using type = RefImpl<Global, i::WasmGlobalObject>;
1672 };
1673
1674 Global::~Global() = default;
1675
copy() const1676 auto Global::copy() const -> own<Global> { return impl(this)->copy(); }
1677
make(Store * store_abs,const GlobalType * type,const Val & val)1678 auto Global::make(Store* store_abs, const GlobalType* type, const Val& val)
1679 -> own<Global> {
1680 StoreImpl* store = impl(store_abs);
1681 i::Isolate* isolate = store->i_isolate();
1682 i::HandleScope handle_scope(isolate);
1683
1684 DCHECK_EQ(type->content()->kind(), val.kind());
1685
1686 i::wasm::ValueType i_type = WasmValKindToV8(type->content()->kind());
1687 bool is_mutable = (type->mutability() == VAR);
1688 const int32_t offset = 0;
1689 i::Handle<i::WasmGlobalObject> obj =
1690 i::WasmGlobalObject::New(isolate, i::Handle<i::WasmInstanceObject>(),
1691 i::MaybeHandle<i::JSArrayBuffer>(),
1692 i::MaybeHandle<i::FixedArray>(), i_type, offset,
1693 is_mutable)
1694 .ToHandleChecked();
1695
1696 auto global = implement<Global>::type::make(store, obj);
1697 assert(global);
1698 global->set(val);
1699 return global;
1700 }
1701
type() const1702 auto Global::type() const -> own<GlobalType> {
1703 i::Handle<i::WasmGlobalObject> v8_global = impl(this)->v8_object();
1704 ValKind kind = V8ValueTypeToWasm(v8_global->type());
1705 Mutability mutability = v8_global->is_mutable() ? VAR : CONST;
1706 return GlobalType::make(ValType::make(kind), mutability);
1707 }
1708
get() const1709 auto Global::get() const -> Val {
1710 i::Handle<i::WasmGlobalObject> v8_global = impl(this)->v8_object();
1711 switch (v8_global->type().kind()) {
1712 case i::wasm::ValueType::kI32:
1713 return Val(v8_global->GetI32());
1714 case i::wasm::ValueType::kI64:
1715 return Val(v8_global->GetI64());
1716 case i::wasm::ValueType::kF32:
1717 return Val(v8_global->GetF32());
1718 case i::wasm::ValueType::kF64:
1719 return Val(v8_global->GetF64());
1720 case i::wasm::ValueType::kRef:
1721 case i::wasm::ValueType::kOptRef: {
1722 // TODO(7748): Make sure this works for all heap types.
1723 StoreImpl* store = impl(this)->store();
1724 i::HandleScope scope(store->i_isolate());
1725 return Val(V8RefValueToWasm(store, v8_global->GetRef()));
1726 }
1727 case i::wasm::ValueType::kRtt:
1728 case i::wasm::ValueType::kS128:
1729 // TODO(7748): Implement these.
1730 UNIMPLEMENTED();
1731 case i::wasm::ValueType::kI8:
1732 case i::wasm::ValueType::kI16:
1733 case i::wasm::ValueType::kStmt:
1734 case i::wasm::ValueType::kBottom:
1735 UNREACHABLE();
1736 }
1737 }
1738
set(const Val & val)1739 void Global::set(const Val& val) {
1740 i::Handle<i::WasmGlobalObject> v8_global = impl(this)->v8_object();
1741 switch (val.kind()) {
1742 case I32:
1743 return v8_global->SetI32(val.i32());
1744 case I64:
1745 return v8_global->SetI64(val.i64());
1746 case F32:
1747 return v8_global->SetF32(val.f32());
1748 case F64:
1749 return v8_global->SetF64(val.f64());
1750 case ANYREF:
1751 return v8_global->SetExternRef(
1752 WasmRefToV8(impl(this)->store()->i_isolate(), val.ref()));
1753 case FUNCREF: {
1754 i::Isolate* isolate = impl(this)->store()->i_isolate();
1755 bool result =
1756 v8_global->SetFuncRef(isolate, WasmRefToV8(isolate, val.ref()));
1757 DCHECK(result);
1758 USE(result);
1759 return;
1760 }
1761 default:
1762 // TODO(wasm+): support new value types
1763 UNREACHABLE();
1764 }
1765 }
1766
1767 // Table Instances
1768
1769 template <>
1770 struct implement<Table> {
1771 using type = RefImpl<Table, i::WasmTableObject>;
1772 };
1773
1774 Table::~Table() = default;
1775
copy() const1776 auto Table::copy() const -> own<Table> { return impl(this)->copy(); }
1777
make(Store * store_abs,const TableType * type,const Ref * ref)1778 auto Table::make(Store* store_abs, const TableType* type, const Ref* ref)
1779 -> own<Table> {
1780 StoreImpl* store = impl(store_abs);
1781 i::Isolate* isolate = store->i_isolate();
1782 i::HandleScope scope(isolate);
1783
1784 // Get "element".
1785 i::wasm::ValueType i_type;
1786 switch (type->element()->kind()) {
1787 case FUNCREF:
1788 i_type = i::wasm::kWasmFuncRef;
1789 break;
1790 case ANYREF:
1791 // See Engine::make().
1792 DCHECK(i::wasm::WasmFeatures::FromFlags().has_reftypes());
1793 i_type = i::wasm::kWasmExternRef;
1794 break;
1795 default:
1796 UNREACHABLE();
1797 return nullptr;
1798 }
1799
1800 const Limits& limits = type->limits();
1801 uint32_t minimum = limits.min;
1802 if (minimum > i::wasm::max_table_init_entries()) return nullptr;
1803 uint32_t maximum = limits.max;
1804 bool has_maximum = false;
1805 if (maximum != Limits(0).max) {
1806 has_maximum = true;
1807 if (maximum < minimum) return nullptr;
1808 if (maximum > i::wasm::max_table_init_entries()) return nullptr;
1809 }
1810
1811 i::Handle<i::FixedArray> backing_store;
1812 i::Handle<i::WasmTableObject> table_obj = i::WasmTableObject::New(
1813 isolate, i::Handle<i::WasmInstanceObject>(), i_type, minimum, has_maximum,
1814 maximum, &backing_store);
1815
1816 if (ref) {
1817 i::Handle<i::JSReceiver> init = impl(ref)->v8_object();
1818 DCHECK(i::wasm::max_table_init_entries() <= i::kMaxInt);
1819 for (int i = 0; i < static_cast<int>(minimum); i++) {
1820 // This doesn't call WasmTableObject::Set because the table has
1821 // just been created, so it can't be imported by any instances
1822 // yet that might require updating.
1823 DCHECK_EQ(table_obj->dispatch_tables().length(), 0);
1824 backing_store->set(i, *init);
1825 }
1826 }
1827 return implement<Table>::type::make(store, table_obj);
1828 }
1829
type() const1830 auto Table::type() const -> own<TableType> {
1831 i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
1832 uint32_t min = table->current_length();
1833 uint32_t max;
1834 if (!table->maximum_length().ToUint32(&max)) max = 0xFFFFFFFFu;
1835 ValKind kind;
1836 switch (table->type().heap_representation()) {
1837 case i::wasm::HeapType::kFunc:
1838 kind = FUNCREF;
1839 break;
1840 case i::wasm::HeapType::kExtern:
1841 kind = ANYREF;
1842 break;
1843 default:
1844 UNREACHABLE();
1845 }
1846 return TableType::make(ValType::make(kind), Limits(min, max));
1847 }
1848
get(size_t index) const1849 auto Table::get(size_t index) const -> own<Ref> {
1850 i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
1851 if (index >= static_cast<size_t>(table->current_length())) return own<Ref>();
1852 i::Isolate* isolate = table->GetIsolate();
1853 i::HandleScope handle_scope(isolate);
1854 i::Handle<i::Object> result =
1855 i::WasmTableObject::Get(isolate, table, static_cast<uint32_t>(index));
1856 // TODO(jkummerow): If we support both JavaScript and the C-API at the same
1857 // time, we need to handle Smis and other JS primitives here.
1858 DCHECK(result->IsNull(isolate) || result->IsJSReceiver());
1859 return V8RefValueToWasm(impl(this)->store(), result);
1860 }
1861
set(size_t index,const Ref * ref)1862 auto Table::set(size_t index, const Ref* ref) -> bool {
1863 i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
1864 if (index >= static_cast<size_t>(table->current_length())) return false;
1865 i::Isolate* isolate = table->GetIsolate();
1866 i::HandleScope handle_scope(isolate);
1867 i::Handle<i::Object> obj = WasmRefToV8(isolate, ref);
1868 i::WasmTableObject::Set(isolate, table, static_cast<uint32_t>(index), obj);
1869 return true;
1870 }
1871
1872 // TODO(jkummerow): Having Table::size_t shadowing "std" size_t is ugly.
size() const1873 auto Table::size() const -> size_t {
1874 return impl(this)->v8_object()->current_length();
1875 }
1876
grow(size_t delta,const Ref * ref)1877 auto Table::grow(size_t delta, const Ref* ref) -> bool {
1878 i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
1879 i::Isolate* isolate = table->GetIsolate();
1880 i::HandleScope scope(isolate);
1881 i::Handle<i::Object> init_value = WasmRefToV8(isolate, ref);
1882 int result = i::WasmTableObject::Grow(
1883 isolate, table, static_cast<uint32_t>(delta), init_value);
1884 return result >= 0;
1885 }
1886
1887 // Memory Instances
1888
1889 template <>
1890 struct implement<Memory> {
1891 using type = RefImpl<Memory, i::WasmMemoryObject>;
1892 };
1893
1894 Memory::~Memory() = default;
1895
copy() const1896 auto Memory::copy() const -> own<Memory> { return impl(this)->copy(); }
1897
make(Store * store_abs,const MemoryType * type)1898 auto Memory::make(Store* store_abs, const MemoryType* type) -> own<Memory> {
1899 StoreImpl* store = impl(store_abs);
1900 i::Isolate* isolate = store->i_isolate();
1901 i::HandleScope scope(isolate);
1902
1903 const Limits& limits = type->limits();
1904 uint32_t minimum = limits.min;
1905 // The max_mem_pages limit is only spec'ed for JS embeddings, so we'll
1906 // directly use the maximum pages limit here.
1907 if (minimum > i::wasm::kSpecMaxMemoryPages) return nullptr;
1908 uint32_t maximum = limits.max;
1909 if (maximum != Limits(0).max) {
1910 if (maximum < minimum) return nullptr;
1911 if (maximum > i::wasm::kSpecMaxMemoryPages) return nullptr;
1912 }
1913 // TODO(wasm+): Support shared memory.
1914 i::SharedFlag shared = i::SharedFlag::kNotShared;
1915 i::Handle<i::WasmMemoryObject> memory_obj;
1916 if (!i::WasmMemoryObject::New(isolate, minimum, maximum, shared)
1917 .ToHandle(&memory_obj)) {
1918 return own<Memory>();
1919 }
1920 return implement<Memory>::type::make(store, memory_obj);
1921 }
1922
type() const1923 auto Memory::type() const -> own<MemoryType> {
1924 i::Handle<i::WasmMemoryObject> memory = impl(this)->v8_object();
1925 uint32_t min = static_cast<uint32_t>(memory->array_buffer().byte_length() /
1926 i::wasm::kWasmPageSize);
1927 uint32_t max =
1928 memory->has_maximum_pages() ? memory->maximum_pages() : 0xFFFFFFFFu;
1929 return MemoryType::make(Limits(min, max));
1930 }
1931
data() const1932 auto Memory::data() const -> byte_t* {
1933 return reinterpret_cast<byte_t*>(
1934 impl(this)->v8_object()->array_buffer().backing_store());
1935 }
1936
data_size() const1937 auto Memory::data_size() const -> size_t {
1938 return impl(this)->v8_object()->array_buffer().byte_length();
1939 }
1940
size() const1941 auto Memory::size() const -> pages_t {
1942 return static_cast<pages_t>(
1943 impl(this)->v8_object()->array_buffer().byte_length() /
1944 i::wasm::kWasmPageSize);
1945 }
1946
grow(pages_t delta)1947 auto Memory::grow(pages_t delta) -> bool {
1948 i::Handle<i::WasmMemoryObject> memory = impl(this)->v8_object();
1949 i::Isolate* isolate = memory->GetIsolate();
1950 i::HandleScope handle_scope(isolate);
1951 int32_t old = i::WasmMemoryObject::Grow(isolate, memory, delta);
1952 return old != -1;
1953 }
1954
1955 // Module Instances
1956
1957 template <>
1958 struct implement<Instance> {
1959 using type = RefImpl<Instance, i::WasmInstanceObject>;
1960 };
1961
1962 Instance::~Instance() = default;
1963
copy() const1964 auto Instance::copy() const -> own<Instance> { return impl(this)->copy(); }
1965
make(Store * store_abs,const Module * module_abs,const Extern * const imports[],own<Trap> * trap)1966 own<Instance> Instance::make(Store* store_abs, const Module* module_abs,
1967 const Extern* const imports[], own<Trap>* trap) {
1968 StoreImpl* store = impl(store_abs);
1969 const implement<Module>::type* module = impl(module_abs);
1970 i::Isolate* isolate = store->i_isolate();
1971 i::HandleScope handle_scope(isolate);
1972
1973 DCHECK_EQ(module->v8_object()->GetIsolate(), isolate);
1974
1975 if (trap) *trap = nullptr;
1976 ownvec<ImportType> import_types = module_abs->imports();
1977 i::Handle<i::JSObject> imports_obj =
1978 isolate->factory()->NewJSObject(isolate->object_function());
1979 for (size_t i = 0; i < import_types.size(); ++i) {
1980 ImportType* type = import_types[i].get();
1981 i::Handle<i::String> module_str = VecToString(isolate, type->module());
1982 i::Handle<i::String> name_str = VecToString(isolate, type->name());
1983
1984 i::Handle<i::JSObject> module_obj;
1985 i::LookupIterator module_it(isolate, imports_obj, module_str,
1986 i::LookupIterator::OWN_SKIP_INTERCEPTOR);
1987 if (i::JSObject::HasProperty(&module_it).ToChecked()) {
1988 module_obj = i::Handle<i::JSObject>::cast(
1989 i::Object::GetProperty(&module_it).ToHandleChecked());
1990 } else {
1991 module_obj = isolate->factory()->NewJSObject(isolate->object_function());
1992 ignore(
1993 i::Object::SetProperty(isolate, imports_obj, module_str, module_obj));
1994 }
1995 ignore(i::Object::SetProperty(isolate, module_obj, name_str,
1996 impl(imports[i])->v8_object()));
1997 }
1998 i::wasm::ErrorThrower thrower(isolate, "instantiation");
1999 i::MaybeHandle<i::WasmInstanceObject> instance_obj =
2000 isolate->wasm_engine()->SyncInstantiate(
2001 isolate, &thrower, module->v8_object(), imports_obj,
2002 i::MaybeHandle<i::JSArrayBuffer>());
2003 if (trap) {
2004 if (thrower.error()) {
2005 *trap = implement<Trap>::type::make(
2006 store, GetProperException(isolate, thrower.Reify()));
2007 DCHECK(!thrower.error()); // Reify() called Reset().
2008 DCHECK(!isolate->has_pending_exception()); // Hasn't been thrown yet.
2009 return own<Instance>();
2010 } else if (isolate->has_pending_exception()) {
2011 i::Handle<i::Object> maybe_exception(isolate->pending_exception(),
2012 isolate);
2013 *trap = implement<Trap>::type::make(
2014 store, GetProperException(isolate, maybe_exception));
2015 isolate->clear_pending_exception();
2016 return own<Instance>();
2017 }
2018 } else if (instance_obj.is_null()) {
2019 // If no {trap} output is specified, silently swallow all errors.
2020 thrower.Reset();
2021 isolate->clear_pending_exception();
2022 return own<Instance>();
2023 }
2024 return implement<Instance>::type::make(store, instance_obj.ToHandleChecked());
2025 }
2026
2027 namespace {
2028
GetInstance(StoreImpl * store,i::Handle<i::WasmInstanceObject> instance)2029 own<Instance> GetInstance(StoreImpl* store,
2030 i::Handle<i::WasmInstanceObject> instance) {
2031 return implement<Instance>::type::make(store, instance);
2032 }
2033
2034 } // namespace
2035
exports() const2036 auto Instance::exports() const -> ownvec<Extern> {
2037 const implement<Instance>::type* instance = impl(this);
2038 StoreImpl* store = instance->store();
2039 i::Isolate* isolate = store->i_isolate();
2040 i::HandleScope handle_scope(isolate);
2041 i::Handle<i::WasmInstanceObject> instance_obj = instance->v8_object();
2042 i::Handle<i::WasmModuleObject> module_obj(instance_obj->module_object(),
2043 isolate);
2044 i::Handle<i::JSObject> exports_obj(instance_obj->exports_object(), isolate);
2045
2046 ownvec<ExportType> export_types = ExportsImpl(module_obj);
2047 ownvec<Extern> exports =
2048 ownvec<Extern>::make_uninitialized(export_types.size());
2049 if (!exports) return ownvec<Extern>::invalid();
2050
2051 for (size_t i = 0; i < export_types.size(); ++i) {
2052 auto& name = export_types[i]->name();
2053 i::Handle<i::String> name_str = VecToString(isolate, name);
2054 i::Handle<i::Object> obj =
2055 i::Object::GetProperty(isolate, exports_obj, name_str)
2056 .ToHandleChecked();
2057
2058 const ExternType* type = export_types[i]->type();
2059 switch (type->kind()) {
2060 case EXTERN_FUNC: {
2061 DCHECK(i::WasmExportedFunction::IsWasmExportedFunction(*obj));
2062 exports[i] = implement<Func>::type::make(
2063 store, i::Handle<i::WasmExportedFunction>::cast(obj));
2064 } break;
2065 case EXTERN_GLOBAL: {
2066 exports[i] = implement<Global>::type::make(
2067 store, i::Handle<i::WasmGlobalObject>::cast(obj));
2068 } break;
2069 case EXTERN_TABLE: {
2070 exports[i] = implement<Table>::type::make(
2071 store, i::Handle<i::WasmTableObject>::cast(obj));
2072 } break;
2073 case EXTERN_MEMORY: {
2074 exports[i] = implement<Memory>::type::make(
2075 store, i::Handle<i::WasmMemoryObject>::cast(obj));
2076 } break;
2077 }
2078 }
2079
2080 return exports;
2081 }
2082
2083 ///////////////////////////////////////////////////////////////////////////////
2084
2085 } // namespace wasm
2086
2087 // BEGIN FILE wasm-c.cc
2088
2089 extern "C" {
2090
2091 ///////////////////////////////////////////////////////////////////////////////
2092 // Auxiliaries
2093
2094 // Backing implementation
2095
2096 extern "C++" {
2097
2098 template <class T>
2099 struct borrowed_vec {
2100 wasm::vec<T> it;
borrowed_vecborrowed_vec2101 explicit borrowed_vec(wasm::vec<T>&& v) : it(std::move(v)) {}
borrowed_vecborrowed_vec2102 borrowed_vec(borrowed_vec<T>&& that) : it(std::move(that.it)) {}
~borrowed_vecborrowed_vec2103 ~borrowed_vec() { it.release(); }
2104 };
2105
2106 } // extern "C++"
2107
2108 #define WASM_DEFINE_OWN(name, Name) \
2109 struct wasm_##name##_t : Name {}; \
2110 \
2111 void wasm_##name##_delete(wasm_##name##_t* x) { delete x; } \
2112 \
2113 extern "C++" inline auto hide_##name(Name* x)->wasm_##name##_t* { \
2114 return static_cast<wasm_##name##_t*>(x); \
2115 } \
2116 extern "C++" inline auto hide_##name(const Name* x) \
2117 ->const wasm_##name##_t* { \
2118 return static_cast<const wasm_##name##_t*>(x); \
2119 } \
2120 extern "C++" inline auto reveal_##name(wasm_##name##_t* x)->Name* { \
2121 return x; \
2122 } \
2123 extern "C++" inline auto reveal_##name(const wasm_##name##_t* x) \
2124 ->const Name* { \
2125 return x; \
2126 } \
2127 extern "C++" inline auto get_##name(wasm::own<Name>& x)->wasm_##name##_t* { \
2128 return hide_##name(x.get()); \
2129 } \
2130 extern "C++" inline auto get_##name(const wasm::own<Name>& x) \
2131 ->const wasm_##name##_t* { \
2132 return hide_##name(x.get()); \
2133 } \
2134 extern "C++" inline auto release_##name(wasm::own<Name>&& x) \
2135 ->wasm_##name##_t* { \
2136 return hide_##name(x.release()); \
2137 } \
2138 extern "C++" inline auto adopt_##name(wasm_##name##_t* x)->wasm::own<Name> { \
2139 return make_own(x); \
2140 }
2141
2142 // Vectors
2143
2144 #define WASM_DEFINE_VEC_BASE(name, Name, vec, ptr_or_none) \
2145 static_assert(sizeof(wasm_##name##_vec_t) == sizeof(vec<Name>), \
2146 "C/C++ incompatibility"); \
2147 static_assert( \
2148 sizeof(wasm_##name##_t ptr_or_none) == sizeof(vec<Name>::elem_type), \
2149 "C/C++ incompatibility"); \
2150 extern "C++" inline auto hide_##name##_vec(vec<Name>& v) \
2151 ->wasm_##name##_vec_t* { \
2152 return reinterpret_cast<wasm_##name##_vec_t*>(&v); \
2153 } \
2154 extern "C++" inline auto hide_##name##_vec(const vec<Name>& v) \
2155 ->const wasm_##name##_vec_t* { \
2156 return reinterpret_cast<const wasm_##name##_vec_t*>(&v); \
2157 } \
2158 extern "C++" inline auto hide_##name##_vec(vec<Name>::elem_type* v) \
2159 ->wasm_##name##_t ptr_or_none* { \
2160 return reinterpret_cast<wasm_##name##_t ptr_or_none*>(v); \
2161 } \
2162 extern "C++" inline auto hide_##name##_vec(const vec<Name>::elem_type* v) \
2163 ->wasm_##name##_t ptr_or_none const* { \
2164 return reinterpret_cast<wasm_##name##_t ptr_or_none const*>(v); \
2165 } \
2166 extern "C++" inline auto reveal_##name##_vec(wasm_##name##_t ptr_or_none* v) \
2167 ->vec<Name>::elem_type* { \
2168 return reinterpret_cast<vec<Name>::elem_type*>(v); \
2169 } \
2170 extern "C++" inline auto reveal_##name##_vec( \
2171 wasm_##name##_t ptr_or_none const* v) \
2172 ->const vec<Name>::elem_type* { \
2173 return reinterpret_cast<const vec<Name>::elem_type*>(v); \
2174 } \
2175 extern "C++" inline auto get_##name##_vec(vec<Name>& v) \
2176 ->wasm_##name##_vec_t { \
2177 wasm_##name##_vec_t v2 = {v.size(), hide_##name##_vec(v.get())}; \
2178 return v2; \
2179 } \
2180 extern "C++" inline auto get_##name##_vec(const vec<Name>& v) \
2181 ->const wasm_##name##_vec_t { \
2182 wasm_##name##_vec_t v2 = { \
2183 v.size(), \
2184 const_cast<wasm_##name##_t ptr_or_none*>(hide_##name##_vec(v.get()))}; \
2185 return v2; \
2186 } \
2187 extern "C++" inline auto release_##name##_vec(vec<Name>&& v) \
2188 ->wasm_##name##_vec_t { \
2189 wasm_##name##_vec_t v2 = {v.size(), hide_##name##_vec(v.release())}; \
2190 return v2; \
2191 } \
2192 extern "C++" inline auto adopt_##name##_vec(wasm_##name##_vec_t* v) \
2193 ->vec<Name> { \
2194 return vec<Name>::adopt(v->size, reveal_##name##_vec(v->data)); \
2195 } \
2196 extern "C++" inline auto borrow_##name##_vec(const wasm_##name##_vec_t* v) \
2197 ->borrowed_vec<vec<Name>::elem_type> { \
2198 return borrowed_vec<vec<Name>::elem_type>( \
2199 vec<Name>::adopt(v->size, reveal_##name##_vec(v->data))); \
2200 } \
2201 \
2202 void wasm_##name##_vec_new_uninitialized(wasm_##name##_vec_t* out, \
2203 size_t size) { \
2204 *out = release_##name##_vec(vec<Name>::make_uninitialized(size)); \
2205 } \
2206 void wasm_##name##_vec_new_empty(wasm_##name##_vec_t* out) { \
2207 wasm_##name##_vec_new_uninitialized(out, 0); \
2208 } \
2209 \
2210 void wasm_##name##_vec_delete(wasm_##name##_vec_t* v) { \
2211 adopt_##name##_vec(v); \
2212 }
2213
2214 // Vectors with no ownership management of elements
2215 #define WASM_DEFINE_VEC_PLAIN(name, Name) \
2216 WASM_DEFINE_VEC_BASE(name, Name, \
2217 wasm::vec, ) /* NOLINT(whitespace/parens) */ \
2218 \
2219 void wasm_##name##_vec_new(wasm_##name##_vec_t* out, size_t size, \
2220 const wasm_##name##_t data[]) { \
2221 auto v2 = wasm::vec<Name>::make_uninitialized(size); \
2222 if (v2.size() != 0) { \
2223 memcpy(v2.get(), data, size * sizeof(wasm_##name##_t)); \
2224 } \
2225 *out = release_##name##_vec(std::move(v2)); \
2226 } \
2227 \
2228 void wasm_##name##_vec_copy(wasm_##name##_vec_t* out, \
2229 wasm_##name##_vec_t* v) { \
2230 wasm_##name##_vec_new(out, v->size, v->data); \
2231 }
2232
2233 // Vectors that own their elements
2234 #define WASM_DEFINE_VEC_OWN(name, Name) \
2235 WASM_DEFINE_VEC_BASE(name, Name, wasm::ownvec, *) \
2236 \
2237 void wasm_##name##_vec_new(wasm_##name##_vec_t* out, size_t size, \
2238 wasm_##name##_t* const data[]) { \
2239 auto v2 = wasm::ownvec<Name>::make_uninitialized(size); \
2240 for (size_t i = 0; i < v2.size(); ++i) { \
2241 v2[i] = adopt_##name(data[i]); \
2242 } \
2243 *out = release_##name##_vec(std::move(v2)); \
2244 } \
2245 \
2246 void wasm_##name##_vec_copy(wasm_##name##_vec_t* out, \
2247 wasm_##name##_vec_t* v) { \
2248 auto v2 = wasm::ownvec<Name>::make_uninitialized(v->size); \
2249 for (size_t i = 0; i < v2.size(); ++i) { \
2250 v2[i] = adopt_##name(wasm_##name##_copy(v->data[i])); \
2251 } \
2252 *out = release_##name##_vec(std::move(v2)); \
2253 }
2254
2255 extern "C++" {
2256 template <class T>
is_empty(T * p)2257 inline auto is_empty(T* p) -> bool {
2258 return !p;
2259 }
2260 }
2261
2262 // Byte vectors
2263
2264 using byte = byte_t;
WASM_DEFINE_VEC_PLAIN(byte,byte)2265 WASM_DEFINE_VEC_PLAIN(byte, byte)
2266
2267 ///////////////////////////////////////////////////////////////////////////////
2268 // Runtime Environment
2269
2270 // Configuration
2271
2272 WASM_DEFINE_OWN(config, wasm::Config)
2273
2274 wasm_config_t* wasm_config_new() {
2275 return release_config(wasm::Config::make());
2276 }
2277
2278 // Engine
2279
WASM_DEFINE_OWN(engine,wasm::Engine)2280 WASM_DEFINE_OWN(engine, wasm::Engine)
2281
2282 wasm_engine_t* wasm_engine_new() {
2283 return release_engine(wasm::Engine::make());
2284 }
2285
wasm_engine_new_with_config(wasm_config_t * config)2286 wasm_engine_t* wasm_engine_new_with_config(wasm_config_t* config) {
2287 return release_engine(wasm::Engine::make(adopt_config(config)));
2288 }
2289
2290 // Stores
2291
WASM_DEFINE_OWN(store,wasm::Store)2292 WASM_DEFINE_OWN(store, wasm::Store)
2293
2294 wasm_store_t* wasm_store_new(wasm_engine_t* engine) {
2295 return release_store(wasm::Store::make(engine));
2296 }
2297
2298 ///////////////////////////////////////////////////////////////////////////////
2299 // Type Representations
2300
2301 // Type attributes
2302
hide_mutability(wasm::Mutability mutability)2303 extern "C++" inline auto hide_mutability(wasm::Mutability mutability)
2304 -> wasm_mutability_t {
2305 return static_cast<wasm_mutability_t>(mutability);
2306 }
2307
reveal_mutability(wasm_mutability_t mutability)2308 extern "C++" inline auto reveal_mutability(wasm_mutability_t mutability)
2309 -> wasm::Mutability {
2310 return static_cast<wasm::Mutability>(mutability);
2311 }
2312
hide_limits(const wasm::Limits & limits)2313 extern "C++" inline auto hide_limits(const wasm::Limits& limits)
2314 -> const wasm_limits_t* {
2315 return reinterpret_cast<const wasm_limits_t*>(&limits);
2316 }
2317
reveal_limits(wasm_limits_t limits)2318 extern "C++" inline auto reveal_limits(wasm_limits_t limits) -> wasm::Limits {
2319 return wasm::Limits(limits.min, limits.max);
2320 }
2321
hide_valkind(wasm::ValKind kind)2322 extern "C++" inline auto hide_valkind(wasm::ValKind kind) -> wasm_valkind_t {
2323 return static_cast<wasm_valkind_t>(kind);
2324 }
2325
reveal_valkind(wasm_valkind_t kind)2326 extern "C++" inline auto reveal_valkind(wasm_valkind_t kind) -> wasm::ValKind {
2327 return static_cast<wasm::ValKind>(kind);
2328 }
2329
hide_externkind(wasm::ExternKind kind)2330 extern "C++" inline auto hide_externkind(wasm::ExternKind kind)
2331 -> wasm_externkind_t {
2332 return static_cast<wasm_externkind_t>(kind);
2333 }
2334
reveal_externkind(wasm_externkind_t kind)2335 extern "C++" inline auto reveal_externkind(wasm_externkind_t kind)
2336 -> wasm::ExternKind {
2337 return static_cast<wasm::ExternKind>(kind);
2338 }
2339
2340 // Generic
2341
2342 #define WASM_DEFINE_TYPE(name, Name) \
2343 WASM_DEFINE_OWN(name, Name) \
2344 WASM_DEFINE_VEC_OWN(name, Name) \
2345 \
2346 wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t* t) { \
2347 return release_##name(t->copy()); \
2348 }
2349
2350 // Value Types
2351
WASM_DEFINE_TYPE(valtype,wasm::ValType)2352 WASM_DEFINE_TYPE(valtype, wasm::ValType)
2353
2354 wasm_valtype_t* wasm_valtype_new(wasm_valkind_t k) {
2355 return release_valtype(wasm::ValType::make(reveal_valkind(k)));
2356 }
2357
wasm_valtype_kind(const wasm_valtype_t * t)2358 wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t* t) {
2359 return hide_valkind(t->kind());
2360 }
2361
2362 // Function Types
2363
WASM_DEFINE_TYPE(functype,wasm::FuncType)2364 WASM_DEFINE_TYPE(functype, wasm::FuncType)
2365
2366 wasm_functype_t* wasm_functype_new(wasm_valtype_vec_t* params,
2367 wasm_valtype_vec_t* results) {
2368 return release_functype(wasm::FuncType::make(adopt_valtype_vec(params),
2369 adopt_valtype_vec(results)));
2370 }
2371
wasm_functype_params(const wasm_functype_t * ft)2372 const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t* ft) {
2373 return hide_valtype_vec(ft->params());
2374 }
2375
wasm_functype_results(const wasm_functype_t * ft)2376 const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t* ft) {
2377 return hide_valtype_vec(ft->results());
2378 }
2379
2380 // Global Types
2381
WASM_DEFINE_TYPE(globaltype,wasm::GlobalType)2382 WASM_DEFINE_TYPE(globaltype, wasm::GlobalType)
2383
2384 wasm_globaltype_t* wasm_globaltype_new(wasm_valtype_t* content,
2385 wasm_mutability_t mutability) {
2386 return release_globaltype(wasm::GlobalType::make(
2387 adopt_valtype(content), reveal_mutability(mutability)));
2388 }
2389
wasm_globaltype_content(const wasm_globaltype_t * gt)2390 const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t* gt) {
2391 return hide_valtype(gt->content());
2392 }
2393
wasm_globaltype_mutability(const wasm_globaltype_t * gt)2394 wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t* gt) {
2395 return hide_mutability(gt->mutability());
2396 }
2397
2398 // Table Types
2399
WASM_DEFINE_TYPE(tabletype,wasm::TableType)2400 WASM_DEFINE_TYPE(tabletype, wasm::TableType)
2401
2402 wasm_tabletype_t* wasm_tabletype_new(wasm_valtype_t* element,
2403 const wasm_limits_t* limits) {
2404 return release_tabletype(
2405 wasm::TableType::make(adopt_valtype(element), reveal_limits(*limits)));
2406 }
2407
wasm_tabletype_element(const wasm_tabletype_t * tt)2408 const wasm_valtype_t* wasm_tabletype_element(const wasm_tabletype_t* tt) {
2409 return hide_valtype(tt->element());
2410 }
2411
wasm_tabletype_limits(const wasm_tabletype_t * tt)2412 const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t* tt) {
2413 return hide_limits(tt->limits());
2414 }
2415
2416 // Memory Types
2417
WASM_DEFINE_TYPE(memorytype,wasm::MemoryType)2418 WASM_DEFINE_TYPE(memorytype, wasm::MemoryType)
2419
2420 wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t* limits) {
2421 return release_memorytype(wasm::MemoryType::make(reveal_limits(*limits)));
2422 }
2423
wasm_memorytype_limits(const wasm_memorytype_t * mt)2424 const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t* mt) {
2425 return hide_limits(mt->limits());
2426 }
2427
2428 // Extern Types
2429
WASM_DEFINE_TYPE(externtype,wasm::ExternType)2430 WASM_DEFINE_TYPE(externtype, wasm::ExternType)
2431
2432 wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t* et) {
2433 return hide_externkind(et->kind());
2434 }
2435
wasm_functype_as_externtype(wasm_functype_t * ft)2436 wasm_externtype_t* wasm_functype_as_externtype(wasm_functype_t* ft) {
2437 return hide_externtype(static_cast<wasm::ExternType*>(ft));
2438 }
wasm_globaltype_as_externtype(wasm_globaltype_t * gt)2439 wasm_externtype_t* wasm_globaltype_as_externtype(wasm_globaltype_t* gt) {
2440 return hide_externtype(static_cast<wasm::ExternType*>(gt));
2441 }
wasm_tabletype_as_externtype(wasm_tabletype_t * tt)2442 wasm_externtype_t* wasm_tabletype_as_externtype(wasm_tabletype_t* tt) {
2443 return hide_externtype(static_cast<wasm::ExternType*>(tt));
2444 }
wasm_memorytype_as_externtype(wasm_memorytype_t * mt)2445 wasm_externtype_t* wasm_memorytype_as_externtype(wasm_memorytype_t* mt) {
2446 return hide_externtype(static_cast<wasm::ExternType*>(mt));
2447 }
2448
wasm_functype_as_externtype_const(const wasm_functype_t * ft)2449 const wasm_externtype_t* wasm_functype_as_externtype_const(
2450 const wasm_functype_t* ft) {
2451 return hide_externtype(static_cast<const wasm::ExternType*>(ft));
2452 }
wasm_globaltype_as_externtype_const(const wasm_globaltype_t * gt)2453 const wasm_externtype_t* wasm_globaltype_as_externtype_const(
2454 const wasm_globaltype_t* gt) {
2455 return hide_externtype(static_cast<const wasm::ExternType*>(gt));
2456 }
wasm_tabletype_as_externtype_const(const wasm_tabletype_t * tt)2457 const wasm_externtype_t* wasm_tabletype_as_externtype_const(
2458 const wasm_tabletype_t* tt) {
2459 return hide_externtype(static_cast<const wasm::ExternType*>(tt));
2460 }
wasm_memorytype_as_externtype_const(const wasm_memorytype_t * mt)2461 const wasm_externtype_t* wasm_memorytype_as_externtype_const(
2462 const wasm_memorytype_t* mt) {
2463 return hide_externtype(static_cast<const wasm::ExternType*>(mt));
2464 }
2465
wasm_externtype_as_functype(wasm_externtype_t * et)2466 wasm_functype_t* wasm_externtype_as_functype(wasm_externtype_t* et) {
2467 return et->kind() == wasm::EXTERN_FUNC
2468 ? hide_functype(
2469 static_cast<wasm::FuncType*>(reveal_externtype(et)))
2470 : nullptr;
2471 }
wasm_externtype_as_globaltype(wasm_externtype_t * et)2472 wasm_globaltype_t* wasm_externtype_as_globaltype(wasm_externtype_t* et) {
2473 return et->kind() == wasm::EXTERN_GLOBAL
2474 ? hide_globaltype(
2475 static_cast<wasm::GlobalType*>(reveal_externtype(et)))
2476 : nullptr;
2477 }
wasm_externtype_as_tabletype(wasm_externtype_t * et)2478 wasm_tabletype_t* wasm_externtype_as_tabletype(wasm_externtype_t* et) {
2479 return et->kind() == wasm::EXTERN_TABLE
2480 ? hide_tabletype(
2481 static_cast<wasm::TableType*>(reveal_externtype(et)))
2482 : nullptr;
2483 }
wasm_externtype_as_memorytype(wasm_externtype_t * et)2484 wasm_memorytype_t* wasm_externtype_as_memorytype(wasm_externtype_t* et) {
2485 return et->kind() == wasm::EXTERN_MEMORY
2486 ? hide_memorytype(
2487 static_cast<wasm::MemoryType*>(reveal_externtype(et)))
2488 : nullptr;
2489 }
2490
wasm_externtype_as_functype_const(const wasm_externtype_t * et)2491 const wasm_functype_t* wasm_externtype_as_functype_const(
2492 const wasm_externtype_t* et) {
2493 return et->kind() == wasm::EXTERN_FUNC
2494 ? hide_functype(
2495 static_cast<const wasm::FuncType*>(reveal_externtype(et)))
2496 : nullptr;
2497 }
wasm_externtype_as_globaltype_const(const wasm_externtype_t * et)2498 const wasm_globaltype_t* wasm_externtype_as_globaltype_const(
2499 const wasm_externtype_t* et) {
2500 return et->kind() == wasm::EXTERN_GLOBAL
2501 ? hide_globaltype(
2502 static_cast<const wasm::GlobalType*>(reveal_externtype(et)))
2503 : nullptr;
2504 }
wasm_externtype_as_tabletype_const(const wasm_externtype_t * et)2505 const wasm_tabletype_t* wasm_externtype_as_tabletype_const(
2506 const wasm_externtype_t* et) {
2507 return et->kind() == wasm::EXTERN_TABLE
2508 ? hide_tabletype(
2509 static_cast<const wasm::TableType*>(reveal_externtype(et)))
2510 : nullptr;
2511 }
wasm_externtype_as_memorytype_const(const wasm_externtype_t * et)2512 const wasm_memorytype_t* wasm_externtype_as_memorytype_const(
2513 const wasm_externtype_t* et) {
2514 return et->kind() == wasm::EXTERN_MEMORY
2515 ? hide_memorytype(
2516 static_cast<const wasm::MemoryType*>(reveal_externtype(et)))
2517 : nullptr;
2518 }
2519
2520 // Import Types
2521
WASM_DEFINE_TYPE(importtype,wasm::ImportType)2522 WASM_DEFINE_TYPE(importtype, wasm::ImportType)
2523
2524 wasm_importtype_t* wasm_importtype_new(wasm_name_t* module, wasm_name_t* name,
2525 wasm_externtype_t* type) {
2526 return release_importtype(wasm::ImportType::make(
2527 adopt_byte_vec(module), adopt_byte_vec(name), adopt_externtype(type)));
2528 }
2529
wasm_importtype_module(const wasm_importtype_t * it)2530 const wasm_name_t* wasm_importtype_module(const wasm_importtype_t* it) {
2531 return hide_byte_vec(it->module());
2532 }
2533
wasm_importtype_name(const wasm_importtype_t * it)2534 const wasm_name_t* wasm_importtype_name(const wasm_importtype_t* it) {
2535 return hide_byte_vec(it->name());
2536 }
2537
wasm_importtype_type(const wasm_importtype_t * it)2538 const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t* it) {
2539 return hide_externtype(it->type());
2540 }
2541
2542 // Export Types
2543
WASM_DEFINE_TYPE(exporttype,wasm::ExportType)2544 WASM_DEFINE_TYPE(exporttype, wasm::ExportType)
2545
2546 wasm_exporttype_t* wasm_exporttype_new(wasm_name_t* name,
2547 wasm_externtype_t* type) {
2548 return release_exporttype(
2549 wasm::ExportType::make(adopt_byte_vec(name), adopt_externtype(type)));
2550 }
2551
wasm_exporttype_name(const wasm_exporttype_t * et)2552 const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t* et) {
2553 return hide_byte_vec(et->name());
2554 }
2555
wasm_exporttype_type(const wasm_exporttype_t * et)2556 const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t* et) {
2557 return hide_externtype(et->type());
2558 }
2559
2560 ///////////////////////////////////////////////////////////////////////////////
2561 // Runtime Values
2562
2563 // References
2564
2565 #define WASM_DEFINE_REF_BASE(name, Name) \
2566 WASM_DEFINE_OWN(name, Name) \
2567 \
2568 wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t* t) { \
2569 return release_##name(t->copy()); \
2570 } \
2571 \
2572 bool wasm_##name##_same(const wasm_##name##_t* t1, \
2573 const wasm_##name##_t* t2) { \
2574 return t1->same(t2); \
2575 } \
2576 \
2577 void* wasm_##name##_get_host_info(const wasm_##name##_t* r) { \
2578 return r->get_host_info(); \
2579 } \
2580 void wasm_##name##_set_host_info(wasm_##name##_t* r, void* info) { \
2581 r->set_host_info(info); \
2582 } \
2583 void wasm_##name##_set_host_info_with_finalizer( \
2584 wasm_##name##_t* r, void* info, void (*finalizer)(void*)) { \
2585 r->set_host_info(info, finalizer); \
2586 }
2587
2588 #define WASM_DEFINE_REF(name, Name) \
2589 WASM_DEFINE_REF_BASE(name, Name) \
2590 \
2591 wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t* r) { \
2592 return hide_ref(static_cast<wasm::Ref*>(reveal_##name(r))); \
2593 } \
2594 wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t* r) { \
2595 return hide_##name(static_cast<Name*>(reveal_ref(r))); \
2596 } \
2597 \
2598 const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t* r) { \
2599 return hide_ref(static_cast<const wasm::Ref*>(reveal_##name(r))); \
2600 } \
2601 const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t* r) { \
2602 return hide_##name(static_cast<const Name*>(reveal_ref(r))); \
2603 }
2604
2605 #define WASM_DEFINE_SHARABLE_REF(name, Name) \
2606 WASM_DEFINE_REF(name, Name) \
2607 WASM_DEFINE_OWN(shared_##name, wasm::Shared<Name>)
2608
WASM_DEFINE_REF_BASE(ref,wasm::Ref)2609 WASM_DEFINE_REF_BASE(ref, wasm::Ref)
2610
2611 // Values
2612
2613 extern "C++" {
2614
2615 inline auto is_empty(wasm_val_t v) -> bool {
2616 return !is_ref(reveal_valkind(v.kind)) || !v.of.ref;
2617 }
2618
2619 inline auto hide_val(wasm::Val v) -> wasm_val_t {
2620 wasm_val_t v2 = {hide_valkind(v.kind()), {}};
2621 switch (v.kind()) {
2622 case wasm::I32:
2623 v2.of.i32 = v.i32();
2624 break;
2625 case wasm::I64:
2626 v2.of.i64 = v.i64();
2627 break;
2628 case wasm::F32:
2629 v2.of.f32 = v.f32();
2630 break;
2631 case wasm::F64:
2632 v2.of.f64 = v.f64();
2633 break;
2634 case wasm::ANYREF:
2635 case wasm::FUNCREF:
2636 v2.of.ref = hide_ref(v.ref());
2637 break;
2638 default:
2639 UNREACHABLE();
2640 }
2641 return v2;
2642 }
2643
2644 inline auto release_val(wasm::Val v) -> wasm_val_t {
2645 wasm_val_t v2 = {hide_valkind(v.kind()), {}};
2646 switch (v.kind()) {
2647 case wasm::I32:
2648 v2.of.i32 = v.i32();
2649 break;
2650 case wasm::I64:
2651 v2.of.i64 = v.i64();
2652 break;
2653 case wasm::F32:
2654 v2.of.f32 = v.f32();
2655 break;
2656 case wasm::F64:
2657 v2.of.f64 = v.f64();
2658 break;
2659 case wasm::ANYREF:
2660 case wasm::FUNCREF:
2661 v2.of.ref = release_ref(v.release_ref());
2662 break;
2663 default:
2664 UNREACHABLE();
2665 }
2666 return v2;
2667 }
2668
2669 inline auto adopt_val(wasm_val_t v) -> wasm::Val {
2670 switch (reveal_valkind(v.kind)) {
2671 case wasm::I32:
2672 return wasm::Val(v.of.i32);
2673 case wasm::I64:
2674 return wasm::Val(v.of.i64);
2675 case wasm::F32:
2676 return wasm::Val(v.of.f32);
2677 case wasm::F64:
2678 return wasm::Val(v.of.f64);
2679 case wasm::ANYREF:
2680 case wasm::FUNCREF:
2681 return wasm::Val(adopt_ref(v.of.ref));
2682 default:
2683 UNREACHABLE();
2684 }
2685 }
2686
2687 struct borrowed_val {
2688 wasm::Val it;
2689 explicit borrowed_val(wasm::Val&& v) : it(std::move(v)) {}
2690 borrowed_val(borrowed_val&& that) : it(std::move(that.it)) {}
2691 ~borrowed_val() {
2692 if (it.is_ref()) it.release_ref().release();
2693 }
2694 };
2695
2696 inline auto borrow_val(const wasm_val_t* v) -> borrowed_val {
2697 wasm::Val v2;
2698 switch (reveal_valkind(v->kind)) {
2699 case wasm::I32:
2700 v2 = wasm::Val(v->of.i32);
2701 break;
2702 case wasm::I64:
2703 v2 = wasm::Val(v->of.i64);
2704 break;
2705 case wasm::F32:
2706 v2 = wasm::Val(v->of.f32);
2707 break;
2708 case wasm::F64:
2709 v2 = wasm::Val(v->of.f64);
2710 break;
2711 case wasm::ANYREF:
2712 case wasm::FUNCREF:
2713 v2 = wasm::Val(adopt_ref(v->of.ref));
2714 break;
2715 default:
2716 UNREACHABLE();
2717 }
2718 return borrowed_val(std::move(v2));
2719 }
2720
2721 } // extern "C++"
2722
2723 WASM_DEFINE_VEC_BASE(val, wasm::Val, wasm::vec, )
2724
wasm_val_vec_new(wasm_val_vec_t * out,size_t size,wasm_val_t const data[])2725 void wasm_val_vec_new(wasm_val_vec_t* out, size_t size,
2726 wasm_val_t const data[]) {
2727 auto v2 = wasm::vec<wasm::Val>::make_uninitialized(size);
2728 for (size_t i = 0; i < v2.size(); ++i) {
2729 v2[i] = adopt_val(data[i]);
2730 }
2731 *out = release_val_vec(std::move(v2));
2732 }
2733
wasm_val_vec_copy(wasm_val_vec_t * out,wasm_val_vec_t * v)2734 void wasm_val_vec_copy(wasm_val_vec_t* out, wasm_val_vec_t* v) {
2735 auto v2 = wasm::vec<wasm::Val>::make_uninitialized(v->size);
2736 for (size_t i = 0; i < v2.size(); ++i) {
2737 wasm_val_t val;
2738 wasm_val_copy(&v->data[i], &val);
2739 v2[i] = adopt_val(val);
2740 }
2741 *out = release_val_vec(std::move(v2));
2742 }
2743
wasm_val_delete(wasm_val_t * v)2744 void wasm_val_delete(wasm_val_t* v) {
2745 if (is_ref(reveal_valkind(v->kind))) {
2746 adopt_ref(v->of.ref);
2747 }
2748 }
2749
wasm_val_copy(wasm_val_t * out,const wasm_val_t * v)2750 void wasm_val_copy(wasm_val_t* out, const wasm_val_t* v) {
2751 *out = *v;
2752 if (is_ref(reveal_valkind(v->kind))) {
2753 out->of.ref = v->of.ref ? release_ref(v->of.ref->copy()) : nullptr;
2754 }
2755 }
2756
2757 ///////////////////////////////////////////////////////////////////////////////
2758 // Runtime Objects
2759
2760 // Frames
2761
WASM_DEFINE_OWN(frame,wasm::Frame)2762 WASM_DEFINE_OWN(frame, wasm::Frame)
2763 WASM_DEFINE_VEC_OWN(frame, wasm::Frame)
2764
2765 wasm_frame_t* wasm_frame_copy(const wasm_frame_t* frame) {
2766 return release_frame(frame->copy());
2767 }
2768
2769 wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame);
2770 // Defined below along with wasm_instance_t.
2771
wasm_frame_func_index(const wasm_frame_t * frame)2772 uint32_t wasm_frame_func_index(const wasm_frame_t* frame) {
2773 return reveal_frame(frame)->func_index();
2774 }
2775
wasm_frame_func_offset(const wasm_frame_t * frame)2776 size_t wasm_frame_func_offset(const wasm_frame_t* frame) {
2777 return reveal_frame(frame)->func_offset();
2778 }
2779
wasm_frame_module_offset(const wasm_frame_t * frame)2780 size_t wasm_frame_module_offset(const wasm_frame_t* frame) {
2781 return reveal_frame(frame)->module_offset();
2782 }
2783
2784 // Traps
2785
WASM_DEFINE_REF(trap,wasm::Trap)2786 WASM_DEFINE_REF(trap, wasm::Trap)
2787
2788 wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t* message) {
2789 auto message_ = borrow_byte_vec(message);
2790 return release_trap(wasm::Trap::make(store, message_.it));
2791 }
2792
wasm_trap_message(const wasm_trap_t * trap,wasm_message_t * out)2793 void wasm_trap_message(const wasm_trap_t* trap, wasm_message_t* out) {
2794 *out = release_byte_vec(reveal_trap(trap)->message());
2795 }
2796
wasm_trap_origin(const wasm_trap_t * trap)2797 wasm_frame_t* wasm_trap_origin(const wasm_trap_t* trap) {
2798 return release_frame(reveal_trap(trap)->origin());
2799 }
2800
wasm_trap_trace(const wasm_trap_t * trap,wasm_frame_vec_t * out)2801 void wasm_trap_trace(const wasm_trap_t* trap, wasm_frame_vec_t* out) {
2802 *out = release_frame_vec(reveal_trap(trap)->trace());
2803 }
2804
2805 // Foreign Objects
2806
WASM_DEFINE_REF(foreign,wasm::Foreign)2807 WASM_DEFINE_REF(foreign, wasm::Foreign)
2808
2809 wasm_foreign_t* wasm_foreign_new(wasm_store_t* store) {
2810 return release_foreign(wasm::Foreign::make(store));
2811 }
2812
2813 // Modules
2814
WASM_DEFINE_SHARABLE_REF(module,wasm::Module)2815 WASM_DEFINE_SHARABLE_REF(module, wasm::Module)
2816
2817 bool wasm_module_validate(wasm_store_t* store, const wasm_byte_vec_t* binary) {
2818 auto binary_ = borrow_byte_vec(binary);
2819 return wasm::Module::validate(store, binary_.it);
2820 }
2821
wasm_module_new(wasm_store_t * store,const wasm_byte_vec_t * binary)2822 wasm_module_t* wasm_module_new(wasm_store_t* store,
2823 const wasm_byte_vec_t* binary) {
2824 auto binary_ = borrow_byte_vec(binary);
2825 return release_module(wasm::Module::make(store, binary_.it));
2826 }
2827
wasm_module_imports(const wasm_module_t * module,wasm_importtype_vec_t * out)2828 void wasm_module_imports(const wasm_module_t* module,
2829 wasm_importtype_vec_t* out) {
2830 *out = release_importtype_vec(reveal_module(module)->imports());
2831 }
2832
wasm_module_exports(const wasm_module_t * module,wasm_exporttype_vec_t * out)2833 void wasm_module_exports(const wasm_module_t* module,
2834 wasm_exporttype_vec_t* out) {
2835 *out = release_exporttype_vec(reveal_module(module)->exports());
2836 }
2837
wasm_module_serialize(const wasm_module_t * module,wasm_byte_vec_t * out)2838 void wasm_module_serialize(const wasm_module_t* module, wasm_byte_vec_t* out) {
2839 *out = release_byte_vec(reveal_module(module)->serialize());
2840 }
2841
wasm_module_deserialize(wasm_store_t * store,const wasm_byte_vec_t * binary)2842 wasm_module_t* wasm_module_deserialize(wasm_store_t* store,
2843 const wasm_byte_vec_t* binary) {
2844 auto binary_ = borrow_byte_vec(binary);
2845 return release_module(wasm::Module::deserialize(store, binary_.it));
2846 }
2847
wasm_module_share(const wasm_module_t * module)2848 wasm_shared_module_t* wasm_module_share(const wasm_module_t* module) {
2849 return release_shared_module(reveal_module(module)->share());
2850 }
2851
wasm_module_obtain(wasm_store_t * store,const wasm_shared_module_t * shared)2852 wasm_module_t* wasm_module_obtain(wasm_store_t* store,
2853 const wasm_shared_module_t* shared) {
2854 return release_module(wasm::Module::obtain(store, shared));
2855 }
2856
2857 // Function Instances
2858
WASM_DEFINE_REF(func,wasm::Func)2859 WASM_DEFINE_REF(func, wasm::Func)
2860
2861 extern "C++" {
2862
2863 auto wasm_callback(void* env, const wasm::Val args[], wasm::Val results[])
2864 -> wasm::own<wasm::Trap> {
2865 auto f = reinterpret_cast<wasm_func_callback_t>(env);
2866 return adopt_trap(f(hide_val_vec(args), hide_val_vec(results)));
2867 }
2868
2869 struct wasm_callback_env_t {
2870 wasm_func_callback_with_env_t callback;
2871 void* env;
2872 void (*finalizer)(void*);
2873 };
2874
2875 auto wasm_callback_with_env(void* env, const wasm::Val args[],
2876 wasm::Val results[]) -> wasm::own<wasm::Trap> {
2877 auto t = static_cast<wasm_callback_env_t*>(env);
2878 return adopt_trap(
2879 t->callback(t->env, hide_val_vec(args), hide_val_vec(results)));
2880 }
2881
2882 void wasm_callback_env_finalizer(void* env) {
2883 auto t = static_cast<wasm_callback_env_t*>(env);
2884 if (t->finalizer) t->finalizer(t->env);
2885 delete t;
2886 }
2887
2888 } // extern "C++"
2889
wasm_func_new(wasm_store_t * store,const wasm_functype_t * type,wasm_func_callback_t callback)2890 wasm_func_t* wasm_func_new(wasm_store_t* store, const wasm_functype_t* type,
2891 wasm_func_callback_t callback) {
2892 return release_func(wasm::Func::make(store, type, wasm_callback,
2893 reinterpret_cast<void*>(callback)));
2894 }
2895
wasm_func_new_with_env(wasm_store_t * store,const wasm_functype_t * type,wasm_func_callback_with_env_t callback,void * env,void (* finalizer)(void *))2896 wasm_func_t* wasm_func_new_with_env(wasm_store_t* store,
2897 const wasm_functype_t* type,
2898 wasm_func_callback_with_env_t callback,
2899 void* env, void (*finalizer)(void*)) {
2900 auto env2 = new wasm_callback_env_t{callback, env, finalizer};
2901 return release_func(wasm::Func::make(store, type, wasm_callback_with_env,
2902 env2, wasm_callback_env_finalizer));
2903 }
2904
wasm_func_type(const wasm_func_t * func)2905 wasm_functype_t* wasm_func_type(const wasm_func_t* func) {
2906 return release_functype(func->type());
2907 }
2908
wasm_func_param_arity(const wasm_func_t * func)2909 size_t wasm_func_param_arity(const wasm_func_t* func) {
2910 return func->param_arity();
2911 }
2912
wasm_func_result_arity(const wasm_func_t * func)2913 size_t wasm_func_result_arity(const wasm_func_t* func) {
2914 return func->result_arity();
2915 }
2916
wasm_func_call(const wasm_func_t * func,const wasm_val_t args[],wasm_val_t results[])2917 wasm_trap_t* wasm_func_call(const wasm_func_t* func, const wasm_val_t args[],
2918 wasm_val_t results[]) {
2919 return release_trap(
2920 func->call(reveal_val_vec(args), reveal_val_vec(results)));
2921 }
2922
2923 // Global Instances
2924
WASM_DEFINE_REF(global,wasm::Global)2925 WASM_DEFINE_REF(global, wasm::Global)
2926
2927 wasm_global_t* wasm_global_new(wasm_store_t* store,
2928 const wasm_globaltype_t* type,
2929 const wasm_val_t* val) {
2930 auto val_ = borrow_val(val);
2931 return release_global(wasm::Global::make(store, type, val_.it));
2932 }
2933
wasm_global_type(const wasm_global_t * global)2934 wasm_globaltype_t* wasm_global_type(const wasm_global_t* global) {
2935 return release_globaltype(global->type());
2936 }
2937
wasm_global_get(const wasm_global_t * global,wasm_val_t * out)2938 void wasm_global_get(const wasm_global_t* global, wasm_val_t* out) {
2939 *out = release_val(global->get());
2940 }
2941
wasm_global_set(wasm_global_t * global,const wasm_val_t * val)2942 void wasm_global_set(wasm_global_t* global, const wasm_val_t* val) {
2943 auto val_ = borrow_val(val);
2944 global->set(val_.it);
2945 }
2946
2947 // Table Instances
2948
WASM_DEFINE_REF(table,wasm::Table)2949 WASM_DEFINE_REF(table, wasm::Table)
2950
2951 wasm_table_t* wasm_table_new(wasm_store_t* store, const wasm_tabletype_t* type,
2952 wasm_ref_t* ref) {
2953 return release_table(wasm::Table::make(store, type, ref));
2954 }
2955
wasm_table_type(const wasm_table_t * table)2956 wasm_tabletype_t* wasm_table_type(const wasm_table_t* table) {
2957 return release_tabletype(table->type());
2958 }
2959
wasm_table_get(const wasm_table_t * table,wasm_table_size_t index)2960 wasm_ref_t* wasm_table_get(const wasm_table_t* table, wasm_table_size_t index) {
2961 return release_ref(table->get(index));
2962 }
2963
wasm_table_set(wasm_table_t * table,wasm_table_size_t index,wasm_ref_t * ref)2964 bool wasm_table_set(wasm_table_t* table, wasm_table_size_t index,
2965 wasm_ref_t* ref) {
2966 return table->set(index, ref);
2967 }
2968
wasm_table_size(const wasm_table_t * table)2969 wasm_table_size_t wasm_table_size(const wasm_table_t* table) {
2970 return table->size();
2971 }
2972
wasm_table_grow(wasm_table_t * table,wasm_table_size_t delta,wasm_ref_t * ref)2973 bool wasm_table_grow(wasm_table_t* table, wasm_table_size_t delta,
2974 wasm_ref_t* ref) {
2975 return table->grow(delta, ref);
2976 }
2977
2978 // Memory Instances
2979
WASM_DEFINE_REF(memory,wasm::Memory)2980 WASM_DEFINE_REF(memory, wasm::Memory)
2981
2982 wasm_memory_t* wasm_memory_new(wasm_store_t* store,
2983 const wasm_memorytype_t* type) {
2984 return release_memory(wasm::Memory::make(store, type));
2985 }
2986
wasm_memory_type(const wasm_memory_t * memory)2987 wasm_memorytype_t* wasm_memory_type(const wasm_memory_t* memory) {
2988 return release_memorytype(memory->type());
2989 }
2990
wasm_memory_data(wasm_memory_t * memory)2991 wasm_byte_t* wasm_memory_data(wasm_memory_t* memory) { return memory->data(); }
2992
wasm_memory_data_size(const wasm_memory_t * memory)2993 size_t wasm_memory_data_size(const wasm_memory_t* memory) {
2994 return memory->data_size();
2995 }
2996
wasm_memory_size(const wasm_memory_t * memory)2997 wasm_memory_pages_t wasm_memory_size(const wasm_memory_t* memory) {
2998 return memory->size();
2999 }
3000
wasm_memory_grow(wasm_memory_t * memory,wasm_memory_pages_t delta)3001 bool wasm_memory_grow(wasm_memory_t* memory, wasm_memory_pages_t delta) {
3002 return memory->grow(delta);
3003 }
3004
3005 // Externals
3006
WASM_DEFINE_REF(extern,wasm::Extern)3007 WASM_DEFINE_REF(extern, wasm::Extern)
3008 WASM_DEFINE_VEC_OWN(extern, wasm::Extern)
3009
3010 wasm_externkind_t wasm_extern_kind(const wasm_extern_t* external) {
3011 return hide_externkind(external->kind());
3012 }
wasm_extern_type(const wasm_extern_t * external)3013 wasm_externtype_t* wasm_extern_type(const wasm_extern_t* external) {
3014 return release_externtype(external->type());
3015 }
3016
wasm_func_as_extern(wasm_func_t * func)3017 wasm_extern_t* wasm_func_as_extern(wasm_func_t* func) {
3018 return hide_extern(static_cast<wasm::Extern*>(reveal_func(func)));
3019 }
wasm_global_as_extern(wasm_global_t * global)3020 wasm_extern_t* wasm_global_as_extern(wasm_global_t* global) {
3021 return hide_extern(static_cast<wasm::Extern*>(reveal_global(global)));
3022 }
wasm_table_as_extern(wasm_table_t * table)3023 wasm_extern_t* wasm_table_as_extern(wasm_table_t* table) {
3024 return hide_extern(static_cast<wasm::Extern*>(reveal_table(table)));
3025 }
wasm_memory_as_extern(wasm_memory_t * memory)3026 wasm_extern_t* wasm_memory_as_extern(wasm_memory_t* memory) {
3027 return hide_extern(static_cast<wasm::Extern*>(reveal_memory(memory)));
3028 }
3029
wasm_func_as_extern_const(const wasm_func_t * func)3030 const wasm_extern_t* wasm_func_as_extern_const(const wasm_func_t* func) {
3031 return hide_extern(static_cast<const wasm::Extern*>(reveal_func(func)));
3032 }
wasm_global_as_extern_const(const wasm_global_t * global)3033 const wasm_extern_t* wasm_global_as_extern_const(const wasm_global_t* global) {
3034 return hide_extern(static_cast<const wasm::Extern*>(reveal_global(global)));
3035 }
wasm_table_as_extern_const(const wasm_table_t * table)3036 const wasm_extern_t* wasm_table_as_extern_const(const wasm_table_t* table) {
3037 return hide_extern(static_cast<const wasm::Extern*>(reveal_table(table)));
3038 }
wasm_memory_as_extern_const(const wasm_memory_t * memory)3039 const wasm_extern_t* wasm_memory_as_extern_const(const wasm_memory_t* memory) {
3040 return hide_extern(static_cast<const wasm::Extern*>(reveal_memory(memory)));
3041 }
3042
wasm_extern_as_func(wasm_extern_t * external)3043 wasm_func_t* wasm_extern_as_func(wasm_extern_t* external) {
3044 return hide_func(external->func());
3045 }
wasm_extern_as_global(wasm_extern_t * external)3046 wasm_global_t* wasm_extern_as_global(wasm_extern_t* external) {
3047 return hide_global(external->global());
3048 }
wasm_extern_as_table(wasm_extern_t * external)3049 wasm_table_t* wasm_extern_as_table(wasm_extern_t* external) {
3050 return hide_table(external->table());
3051 }
wasm_extern_as_memory(wasm_extern_t * external)3052 wasm_memory_t* wasm_extern_as_memory(wasm_extern_t* external) {
3053 return hide_memory(external->memory());
3054 }
3055
wasm_extern_as_func_const(const wasm_extern_t * external)3056 const wasm_func_t* wasm_extern_as_func_const(const wasm_extern_t* external) {
3057 return hide_func(external->func());
3058 }
wasm_extern_as_global_const(const wasm_extern_t * external)3059 const wasm_global_t* wasm_extern_as_global_const(
3060 const wasm_extern_t* external) {
3061 return hide_global(external->global());
3062 }
wasm_extern_as_table_const(const wasm_extern_t * external)3063 const wasm_table_t* wasm_extern_as_table_const(const wasm_extern_t* external) {
3064 return hide_table(external->table());
3065 }
wasm_extern_as_memory_const(const wasm_extern_t * external)3066 const wasm_memory_t* wasm_extern_as_memory_const(
3067 const wasm_extern_t* external) {
3068 return hide_memory(external->memory());
3069 }
3070
3071 // Module Instances
3072
WASM_DEFINE_REF(instance,wasm::Instance)3073 WASM_DEFINE_REF(instance, wasm::Instance)
3074
3075 wasm_instance_t* wasm_instance_new(wasm_store_t* store,
3076 const wasm_module_t* module,
3077 const wasm_extern_t* const imports[],
3078 wasm_trap_t** trap) {
3079 wasm::own<wasm::Trap> error;
3080 wasm_instance_t* instance = release_instance(wasm::Instance::make(
3081 store, module, reinterpret_cast<const wasm::Extern* const*>(imports),
3082 &error));
3083 if (trap) *trap = hide_trap(error.release());
3084 return instance;
3085 }
3086
wasm_instance_exports(const wasm_instance_t * instance,wasm_extern_vec_t * out)3087 void wasm_instance_exports(const wasm_instance_t* instance,
3088 wasm_extern_vec_t* out) {
3089 *out = release_extern_vec(instance->exports());
3090 }
3091
wasm_frame_instance(const wasm_frame_t * frame)3092 wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) {
3093 return hide_instance(reveal_frame(frame)->instance());
3094 }
3095
3096 #undef WASM_DEFINE_OWN
3097 #undef WASM_DEFINE_VEC_BASE
3098 #undef WASM_DEFINE_VEC_PLAIN
3099 #undef WASM_DEFINE_VEC_OWN
3100 #undef WASM_DEFINE_TYPE
3101 #undef WASM_DEFINE_REF_BASE
3102 #undef WASM_DEFINE_REF
3103 #undef WASM_DEFINE_SHARABLE_REF
3104
3105 } // extern "C"
3106