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