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