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