c5708bcba4a58a0803f6429c2f7583c9db27257c
[WebKit-https.git] / Source / JavaScriptCore / wasm / js / WebAssemblyModuleRecord.cpp
1 /*
2  * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WebAssemblyModuleRecord.h"
28
29 #if ENABLE(WEBASSEMBLY)
30
31 #include "Error.h"
32 #include "JSCInlines.h"
33 #include "JSLexicalEnvironment.h"
34 #include "JSModuleEnvironment.h"
35 #include "JSWebAssemblyHelpers.h"
36 #include "JSWebAssemblyInstance.h"
37 #include "JSWebAssemblyLinkError.h"
38 #include "JSWebAssemblyModule.h"
39 #include "ProtoCallFrame.h"
40 #include "WasmSignatureInlines.h"
41 #include "WebAssemblyFunction.h"
42 #include <limits>
43
44 namespace JSC {
45
46 const ClassInfo WebAssemblyModuleRecord::s_info = { "WebAssemblyModuleRecord", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(WebAssemblyModuleRecord) };
47
48 Structure* WebAssemblyModuleRecord::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
49 {
50     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
51 }
52
53 WebAssemblyModuleRecord* WebAssemblyModuleRecord::create(ExecState* exec, VM& vm, Structure* structure, const Identifier& moduleKey, const Wasm::ModuleInformation& moduleInformation)
54 {
55     WebAssemblyModuleRecord* instance = new (NotNull, allocateCell<WebAssemblyModuleRecord>(vm.heap)) WebAssemblyModuleRecord(vm, structure, moduleKey);
56     instance->finishCreation(exec, vm, moduleInformation);
57     return instance;
58 }
59
60 WebAssemblyModuleRecord::WebAssemblyModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey)
61     : Base(vm, structure, moduleKey)
62 {
63 }
64
65 void WebAssemblyModuleRecord::destroy(JSCell* cell)
66 {
67     WebAssemblyModuleRecord* thisObject = static_cast<WebAssemblyModuleRecord*>(cell);
68     thisObject->WebAssemblyModuleRecord::~WebAssemblyModuleRecord();
69 }
70
71 void WebAssemblyModuleRecord::finishCreation(ExecState* exec, VM& vm, const Wasm::ModuleInformation& moduleInformation)
72 {
73     Base::finishCreation(exec, vm);
74     ASSERT(inherits(vm, info()));
75     for (const auto& exp : moduleInformation.exports) {
76         Identifier field = Identifier::fromString(&vm, String::fromUTF8(exp.field));
77         addExportEntry(ExportEntry::createLocal(field, field));
78     }
79 }
80
81 void WebAssemblyModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
82 {
83     WebAssemblyModuleRecord* thisObject = jsCast<WebAssemblyModuleRecord*>(cell);
84     Base::visitChildren(thisObject, visitor);
85     visitor.append(thisObject->m_instance);
86     visitor.append(thisObject->m_startFunction);
87 }
88
89 void WebAssemblyModuleRecord::prepareLink(VM& vm, JSWebAssemblyInstance* instance)
90 {
91     RELEASE_ASSERT(!m_instance);
92     m_instance.set(vm, this, instance);
93 }
94
95 void WebAssemblyModuleRecord::link(ExecState* exec, JSValue, JSObject* importObject, Wasm::CreationMode creationMode)
96 {
97     VM& vm = exec->vm();
98     auto scope = DECLARE_THROW_SCOPE(vm);
99     UNUSED_PARAM(scope);
100     auto* globalObject = exec->lexicalGlobalObject();
101
102     RELEASE_ASSERT(m_instance);
103
104     Wasm::CodeBlock* codeBlock = m_instance->instance().codeBlock();
105     JSWebAssemblyModule* module = m_instance->module();
106     const Wasm::ModuleInformation& moduleInformation = module->moduleInformation();
107
108     auto exception = [&] (JSObject* error) {
109         throwException(exec, scope, error);
110     };
111
112     auto importFailMessage = [&] (const Wasm::Import& import, const char* before, const char* after) {
113         return makeString(before, " ", String::fromUTF8(import.module), ":", String::fromUTF8(import.field), " ", after);
114     };
115
116     bool hasTableImport = false;
117
118     for (const auto& import : moduleInformation.imports) {
119         // Validation and linking other than Wasm::ExternalKind::Function is already done in JSWebAssemblyInstance.
120         // Eventually we will move all the linking code in JSWebAssemblyInstance here and remove this switch statement.
121         switch (import.kind) {
122         case Wasm::ExternalKind::Function:
123         case Wasm::ExternalKind::Global:
124         case Wasm::ExternalKind::Table:
125             break;
126         case Wasm::ExternalKind::Memory:
127             continue;
128         }
129
130         Identifier moduleName = Identifier::fromString(&vm, String::fromUTF8(import.module));
131         Identifier fieldName = Identifier::fromString(&vm, String::fromUTF8(import.field));
132         JSValue value;
133         if (creationMode == Wasm::CreationMode::FromJS) {
134             // 1. Let o be the resultant value of performing Get(importObject, i.module_name).
135             JSValue importModuleValue = importObject->get(exec, moduleName);
136             RETURN_IF_EXCEPTION(scope, void());
137             // 2. If Type(o) is not Object, throw a TypeError.
138             if (!importModuleValue.isObject())
139                 return exception(createTypeError(exec, importFailMessage(import, "import", "must be an object"), defaultSourceAppender, runtimeTypeForValue(vm, importModuleValue)));
140
141             // 3. Let v be the value of performing Get(o, i.item_name)
142             JSObject* object = jsCast<JSObject*>(importModuleValue);
143             value = object->get(exec, fieldName);
144             RETURN_IF_EXCEPTION(scope, void());
145         } else {
146             AbstractModuleRecord* importedModule = hostResolveImportedModule(exec, moduleName);
147             RETURN_IF_EXCEPTION(scope, void());
148             Resolution resolution = importedModule->resolveExport(exec, fieldName);
149             RETURN_IF_EXCEPTION(scope, void());
150             switch (resolution.type) {
151             case Resolution::Type::NotFound:
152                 throwSyntaxError(exec, scope, makeString("Importing binding name '", String(fieldName.impl()), "' is not found."));
153                 return;
154
155             case Resolution::Type::Ambiguous:
156                 throwSyntaxError(exec, scope, makeString("Importing binding name '", String(fieldName.impl()), "' cannot be resolved due to ambiguous multiple bindings."));
157                 return;
158
159             case Resolution::Type::Error:
160                 throwSyntaxError(exec, scope, makeString("Importing binding name 'default' cannot be resolved by star export entries."));
161                 return;
162
163             case Resolution::Type::Resolved:
164                 break;
165             }
166
167             AbstractModuleRecord* importedRecord = resolution.moduleRecord;
168             JSModuleEnvironment* importedEnvironment = importedRecord->moduleEnvironmentMayBeNull();
169             // It means that target module is not linked yet. In wasm loading, we allow this since we do not solve cyclic resolution as if JS's bindings.
170             // At that time, error occurs since |value| is an empty, and later |value| becomes an undefined.
171             // https://github.com/WebAssembly/esm-integration/tree/master/proposals/esm-integration#js---wasm-cycle-where-js-is-higher-in-the-module-graph
172             if (importedEnvironment) {
173                 SymbolTable* symbolTable = importedEnvironment->symbolTable();
174                 ConcurrentJSLocker locker(symbolTable->m_lock);
175                 auto iter = symbolTable->find(locker, resolution.localName.impl());
176                 ASSERT(iter != symbolTable->end(locker));
177                 SymbolTableEntry& entry = iter->value;
178                 ASSERT(!entry.isNull());
179                 ASSERT(importedEnvironment->isValidScopeOffset(entry.scopeOffset()));
180
181                 // Snapshotting a value.
182                 value = importedEnvironment->variableAt(entry.scopeOffset()).get();
183             }
184         }
185         if (!value)
186             value = jsUndefined();
187
188         switch (import.kind) {
189         case Wasm::ExternalKind::Function: {
190             // 4. If i is a function import:
191             // i. If IsCallable(v) is false, throw a WebAssembly.LinkError.
192             if (!value.isFunction(vm))
193                 return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "import function", "must be callable")));
194
195             Wasm::Instance* calleeInstance = nullptr;
196             WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation = nullptr;
197             JSObject* function = jsCast<JSObject*>(value);
198
199             // ii. If v is an Exported Function Exotic Object:
200             WebAssemblyFunction* wasmFunction;
201             WebAssemblyWrapperFunction* wasmWrapperFunction;
202             if (isWebAssemblyHostFunction(vm, function, wasmFunction, wasmWrapperFunction)) {
203                 // a. If the signature of v does not match the signature of i, throw a WebAssembly.LinkError.
204                 Wasm::SignatureIndex importedSignatureIndex;
205                 if (wasmFunction) {
206                     importedSignatureIndex = wasmFunction->signatureIndex();
207                     calleeInstance = &wasmFunction->instance()->instance();
208                     entrypointLoadLocation = wasmFunction->entrypointLoadLocation();
209                 } else {
210                     importedSignatureIndex = wasmWrapperFunction->signatureIndex();
211                     // b. Let closure be v.[[Closure]].
212                     function = wasmWrapperFunction->function();
213                 }
214                 Wasm::SignatureIndex expectedSignatureIndex = moduleInformation.importFunctionSignatureIndices[import.kindIndex];
215                 if (importedSignatureIndex != expectedSignatureIndex)
216                     return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported function", "signature doesn't match the provided WebAssembly function's signature")));
217             }
218             // iii. Otherwise:
219             // a. Let closure be a new host function of the given signature which calls v by coercing WebAssembly arguments to JavaScript arguments via ToJSValue and returns the result, if any, by coercing via ToWebAssemblyValue.
220             // Note: done as part of Plan compilation.
221             // iv. Append v to funcs.
222             // Note: adding the JSCell to the instance list fulfills closure requirements b. above (the WebAssembly.Instance wil be kept alive) and v. below (the JSFunction).
223
224             auto* info = m_instance->instance().importFunctionInfo(import.kindIndex);
225             info->targetInstance = calleeInstance;
226             info->wasmEntrypointLoadLocation = entrypointLoadLocation;
227             m_instance->instance().importFunction<JSWebAssemblyInstance::PoisonedBarrier<JSObject>>(import.kindIndex)->set(vm, m_instance.get(), function);
228             break;
229         }
230
231         case Wasm::ExternalKind::Global: {
232             // 5. If i is a global import:
233             // i. If i is not an immutable global, throw a TypeError.
234             ASSERT(moduleInformation.globals[import.kindIndex].mutability == Wasm::Global::Immutable);
235             // ii. If the global_type of i is i64 or Type(v) is not Number, throw a WebAssembly.LinkError.
236             if (moduleInformation.globals[import.kindIndex].type == Wasm::I64)
237                 return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "cannot be an i64")));
238             if (!value.isNumber())
239                 return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "must be a number")));
240             // iii. Append ToWebAssemblyValue(v) to imports.
241             switch (moduleInformation.globals[import.kindIndex].type) {
242             case Wasm::I32:
243                 m_instance->instance().setGlobal(import.kindIndex, value.toInt32(exec));
244                 break;
245             case Wasm::F32:
246                 m_instance->instance().setGlobal(import.kindIndex, bitwise_cast<uint32_t>(value.toFloat(exec)));
247                 break;
248             case Wasm::F64:
249                 m_instance->instance().setGlobal(import.kindIndex, bitwise_cast<uint64_t>(value.asNumber()));
250                 break;
251             default:
252                 RELEASE_ASSERT_NOT_REACHED();
253             }
254             scope.assertNoException();
255             break;
256         }
257
258         case Wasm::ExternalKind::Table: {
259             RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
260             // 7. Otherwise (i is a table import):
261             hasTableImport = true;
262             JSWebAssemblyTable* table = jsDynamicCast<JSWebAssemblyTable*>(vm, value);
263             // i. If v is not a WebAssembly.Table object, throw a WebAssembly.LinkError.
264             if (!table)
265                 return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "is not an instance of WebAssembly.Table")));
266
267             uint32_t expectedInitial = moduleInformation.tableInformation.initial();
268             uint32_t actualInitial = table->length();
269             if (actualInitial < expectedInitial)
270                 return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "provided an 'initial' that is too small")));
271
272             if (Optional<uint32_t> expectedMaximum = moduleInformation.tableInformation.maximum()) {
273                 Optional<uint32_t> actualMaximum = table->maximum();
274                 if (!actualMaximum)
275                     return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "does not have a 'maximum' but the module requires that it does")));
276                 if (*actualMaximum > *expectedMaximum)
277                     return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Imported Table", "'maximum' is larger than the module's expected 'maximum'")));
278             }
279
280             // ii. Append v to tables.
281             // iii. Append v.[[Table]] to imports.
282             m_instance->setTable(vm, table);
283             RETURN_IF_EXCEPTION(scope, void());
284             break;
285         }
286
287         case Wasm::ExternalKind::Memory:
288             break;
289         }
290     }
291
292     {
293         if (!!moduleInformation.tableInformation && moduleInformation.tableInformation.isImport()) {
294             // We should either have a Table import or we should have thrown an exception.
295             RELEASE_ASSERT(hasTableImport);
296         }
297
298         if (!!moduleInformation.tableInformation && !hasTableImport) {
299             RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
300             // We create a Table when it's a Table definition.
301             RefPtr<Wasm::Table> wasmTable = Wasm::Table::tryCreate(moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum());
302             if (!wasmTable)
303                 return exception(createJSWebAssemblyLinkError(exec, vm, "couldn't create Table"));
304             JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, globalObject->WebAssemblyTableStructure(), wasmTable.releaseNonNull());
305             // We should always be able to allocate a JSWebAssemblyTable we've defined.
306             // If it's defined to be too large, we should have thrown a validation error.
307             scope.assertNoException();
308             ASSERT(table);
309             m_instance->setTable(vm, table);
310             RETURN_IF_EXCEPTION(scope, void());
311         }
312     }
313
314     // Globals
315     {
316         for (size_t globalIndex = moduleInformation.firstInternalGlobal; globalIndex < moduleInformation.globals.size(); ++globalIndex) {
317             const auto& global = moduleInformation.globals[globalIndex];
318             ASSERT(global.initializationType != Wasm::Global::IsImport);
319             if (global.initializationType == Wasm::Global::FromGlobalImport) {
320                 ASSERT(global.initialBitsOrImportNumber < moduleInformation.firstInternalGlobal);
321                 m_instance->instance().setGlobal(globalIndex, m_instance->instance().loadI64Global(global.initialBitsOrImportNumber));
322             } else
323                 m_instance->instance().setGlobal(globalIndex, global.initialBitsOrImportNumber);
324         }
325     }
326
327     SymbolTable* exportSymbolTable = module->exportSymbolTable();
328     unsigned functionImportCount = codeBlock->functionImportCount();
329
330     // Let exports be a list of (string, JS value) pairs that is mapped from each external value e in instance.exports as follows:
331     JSModuleEnvironment* moduleEnvironment = JSModuleEnvironment::create(vm, globalObject, nullptr, exportSymbolTable, JSValue(), this);
332     for (const auto& exp : moduleInformation.exports) {
333         JSValue exportedValue;
334         switch (exp.kind) {
335         case Wasm::ExternalKind::Function: {
336             // 1. If e is a closure c:
337             //   i. If there is an Exported Function Exotic Object func in funcs whose func.[[Closure]] equals c, then return func.
338             //   ii. (Note: At most one wrapper is created for any closure, so func is unique, even if there are multiple occurrances in the list. Moreover, if the item was an import that is already an Exported Function Exotic Object, then the original function object will be found. For imports that are regular JS functions, a new wrapper will be created.)
339             if (exp.kindIndex < functionImportCount) {
340                 unsigned functionIndex = exp.kindIndex;
341                 JSObject* functionImport = m_instance->instance().importFunction<JSWebAssemblyInstance::PoisonedBarrier<JSObject>>(functionIndex)->get();
342                 if (isWebAssemblyHostFunction(vm, functionImport))
343                     exportedValue = functionImport;
344                 else {
345                     Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(functionIndex);
346                     exportedValue = WebAssemblyWrapperFunction::create(vm, globalObject, functionImport, functionIndex, m_instance.get(), signatureIndex);
347                 }
348             } else {
349                 //   iii. Otherwise:
350                 //     a. Let func be an Exported Function Exotic Object created from c.
351                 //     b. Append func to funcs.
352                 //     c. Return func.
353                 Wasm::Callee& embedderEntrypointCallee = codeBlock->embedderEntrypointCalleeFromFunctionIndexSpace(exp.kindIndex);
354                 Wasm::WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation = codeBlock->entrypointLoadLocationFromFunctionIndexSpace(exp.kindIndex);
355                 Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(exp.kindIndex);
356                 const Wasm::Signature& signature = Wasm::SignatureInformation::get(signatureIndex);
357                 WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature.argumentCount(), String::fromUTF8(exp.field), m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
358                 exportedValue = function;
359             }
360             break;
361         }
362         case Wasm::ExternalKind::Table: {
363             // This should be guaranteed by module verification.
364             RELEASE_ASSERT(m_instance->table()); 
365             ASSERT(exp.kindIndex == 0);
366
367             exportedValue = m_instance->table();
368             break;
369         }
370         case Wasm::ExternalKind::Memory: {
371             ASSERT(exp.kindIndex == 0);
372
373             exportedValue = m_instance->memory();
374             break;
375         }
376         case Wasm::ExternalKind::Global: {
377             // Assert: the global is immutable by MVP validation constraint.
378             const Wasm::Global& global = moduleInformation.globals[exp.kindIndex];
379             ASSERT(global.mutability == Wasm::Global::Immutable);
380             // Return ToJSValue(v).
381             switch (global.type) {
382             case Wasm::I32:
383                 exportedValue = JSValue(m_instance->instance().loadI32Global(exp.kindIndex));
384                 break;
385
386             case Wasm::I64:
387                 throwException(exec, scope, createJSWebAssemblyLinkError(exec, vm, "exported global cannot be an i64"_s));
388                 return;
389
390             case Wasm::F32:
391                 exportedValue = jsNumber(purifyNaN(m_instance->instance().loadF32Global(exp.kindIndex)));
392                 break;
393
394             case Wasm::F64:
395                 exportedValue = jsNumber(purifyNaN(m_instance->instance().loadF64Global(exp.kindIndex)));
396                 break;
397
398             default:
399                 RELEASE_ASSERT_NOT_REACHED();
400             }
401             break;
402         }
403         }
404
405         bool shouldThrowReadOnlyError = false;
406         bool ignoreReadOnlyErrors = true;
407         bool putResult = false;
408         symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, Identifier::fromString(&vm, String::fromUTF8(exp.field)), exportedValue, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult);
409         scope.assertNoException();
410         RELEASE_ASSERT(putResult);
411     }
412
413     bool hasStart = !!moduleInformation.startFunctionIndexSpace;
414     if (hasStart) {
415         auto startFunctionIndexSpace = moduleInformation.startFunctionIndexSpace.value_or(0);
416         Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(startFunctionIndexSpace);
417         const Wasm::Signature& signature = Wasm::SignatureInformation::get(signatureIndex);
418         // The start function must not take any arguments or return anything. This is enforced by the parser.
419         ASSERT(!signature.argumentCount());
420         ASSERT(signature.returnType() == Wasm::Void);
421         if (startFunctionIndexSpace < codeBlock->functionImportCount()) {
422             JSObject* startFunction = m_instance->instance().importFunction<JSWebAssemblyInstance::PoisonedBarrier<JSObject>>(startFunctionIndexSpace)->get();
423             m_startFunction.set(vm, this, startFunction);
424         } else {
425             Wasm::Callee& embedderEntrypointCallee = codeBlock->embedderEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
426             Wasm::WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation = codeBlock->entrypointLoadLocationFromFunctionIndexSpace(startFunctionIndexSpace);
427             WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature.argumentCount(), "start", m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
428             m_startFunction.set(vm, this, function);
429         }
430     }
431     m_moduleEnvironment.set(vm, this, moduleEnvironment);
432 }
433
434 template <typename Scope, typename M, typename N, typename ...Args>
435 NEVER_INLINE static JSValue dataSegmentFail(ExecState* exec, VM& vm, Scope& scope, M memorySize, N segmentSize, N offset, Args... args)
436 {
437     return throwException(exec, scope, createJSWebAssemblyLinkError(exec, vm, makeString("Invalid data segment initialization: segment of "_s, String::number(segmentSize), " bytes memory of "_s, String::number(memorySize), " bytes, at offset "_s, String::number(offset), args...)));
438 }
439
440 JSValue WebAssemblyModuleRecord::evaluate(ExecState* exec)
441 {
442     VM& vm = exec->vm();
443     auto scope = DECLARE_THROW_SCOPE(vm);
444
445     Wasm::Module& module = m_instance->instance().module();
446     Wasm::CodeBlock* codeBlock = m_instance->instance().codeBlock();
447     const Wasm::ModuleInformation& moduleInformation = module.moduleInformation();
448     JSWebAssemblyTable* table = m_instance->table();
449
450     const Vector<Wasm::Segment::Ptr>& data = moduleInformation.data;
451     
452     Optional<JSValue> exception;
453
454     auto forEachElement = [&] (auto fn) {
455         for (const Wasm::Element& element : moduleInformation.elements) {
456             // It should be a validation error to have any elements without a table.
457             // Also, it could be that a table wasn't imported, or that the table
458             // imported wasn't compatible. However, those should error out before
459             // getting here.
460             ASSERT(!!table);
461
462             if (!element.functionIndices.size())
463                 continue;
464
465             uint32_t tableIndex = element.offset.isGlobalImport()
466                 ? static_cast<uint32_t>(m_instance->instance().loadI32Global(element.offset.globalImportIndex()))
467                 : element.offset.constValue();
468
469             fn(element, tableIndex);
470
471             if (exception)
472                 break;
473         }
474     };
475
476     auto forEachSegment = [&] (auto fn) {
477         uint8_t* memory = reinterpret_cast<uint8_t*>(m_instance->instance().cachedMemory());
478         uint64_t sizeInBytes = m_instance->instance().cachedMemorySize();
479
480         for (const Wasm::Segment::Ptr& segment : data) {
481             uint32_t offset = segment->offset.isGlobalImport()
482                 ? static_cast<uint32_t>(m_instance->instance().loadI32Global(segment->offset.globalImportIndex()))
483                 : segment->offset.constValue();
484
485             fn(memory, sizeInBytes, segment, offset);
486
487             if (exception)
488                 break;
489         }
490     };
491
492     // Validation of all element ranges comes before all Table and Memory initialization.
493     forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex) {
494         uint64_t lastWrittenIndex = static_cast<uint64_t>(tableIndex) + static_cast<uint64_t>(element.functionIndices.size()) - 1;
495         if (UNLIKELY(lastWrittenIndex >= table->length()))
496             exception = JSValue(throwException(exec, scope, createJSWebAssemblyLinkError(exec, vm, "Element is trying to set an out of bounds table index"_s)));
497     });
498
499     if (UNLIKELY(exception))
500         return exception.value();
501
502     // Validation of all segment ranges comes before all Table and Memory initialization.
503     forEachSegment([&] (uint8_t*, uint64_t sizeInBytes, const Wasm::Segment::Ptr& segment, uint32_t offset) {
504         if (UNLIKELY(sizeInBytes < segment->sizeInBytes))
505             exception = dataSegmentFail(exec, vm, scope, sizeInBytes, segment->sizeInBytes, offset, ", segment is too big"_s);
506         else if (UNLIKELY(offset > sizeInBytes - segment->sizeInBytes))
507             exception = dataSegmentFail(exec, vm, scope, sizeInBytes, segment->sizeInBytes, offset, ", segment writes outside of memory"_s);
508     });
509
510     if (UNLIKELY(exception))
511         return exception.value();
512
513     JSGlobalObject* globalObject = m_instance->globalObject(vm);
514     forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex) {
515         for (uint32_t i = 0; i < element.functionIndices.size(); ++i) {
516             // FIXME: This essentially means we're exporting an import.
517             // We need a story here. We need to create a WebAssemblyFunction
518             // for the import.
519             // https://bugs.webkit.org/show_bug.cgi?id=165510
520             uint32_t functionIndex = element.functionIndices[i];
521             Wasm::SignatureIndex signatureIndex = module.signatureIndexFromFunctionIndexSpace(functionIndex);
522             if (functionIndex < codeBlock->functionImportCount()) {
523                 JSObject* functionImport = m_instance->instance().importFunction<JSWebAssemblyInstance::PoisonedBarrier<JSObject>>(functionIndex)->get();
524                 if (isWebAssemblyHostFunction(vm, functionImport)) {
525                     WebAssemblyFunction* wasmFunction = jsDynamicCast<WebAssemblyFunction*>(vm, functionImport);
526                     // If we ever import a WebAssemblyWrapperFunction, we set the import as the unwrapped value.
527                     // Because a WebAssemblyWrapperFunction can never wrap another WebAssemblyWrapperFunction,
528                     // the only type this could be is WebAssemblyFunction.
529                     RELEASE_ASSERT(wasmFunction);
530                     table->setFunction(vm, tableIndex, wasmFunction);
531                     ++tableIndex;
532                     continue;
533                 }
534
535                 table->setFunction(vm, tableIndex,
536                     WebAssemblyWrapperFunction::create(vm, globalObject, functionImport, functionIndex, m_instance.get(), signatureIndex));
537                 ++tableIndex;
538                 continue;
539             }
540
541             Wasm::Callee& embedderEntrypointCallee = codeBlock->embedderEntrypointCalleeFromFunctionIndexSpace(functionIndex);
542             Wasm::WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation = codeBlock->entrypointLoadLocationFromFunctionIndexSpace(functionIndex);
543             const Wasm::Signature& signature = Wasm::SignatureInformation::get(signatureIndex);
544             // FIXME: Say we export local function "foo" at function index 0.
545             // What if we also set it to the table an Element w/ index 0.
546             // Does (new Instance(...)).exports.foo === table.get(0)?
547             // https://bugs.webkit.org/show_bug.cgi?id=165825
548             WebAssemblyFunction* function = WebAssemblyFunction::create(
549                 vm, globalObject, signature.argumentCount(), String(), m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
550
551             table->setFunction(vm, tableIndex, function);
552             ++tableIndex;
553         }
554     });
555
556     ASSERT(!exception);
557
558     forEachSegment([&] (uint8_t* memory, uint64_t, const Wasm::Segment::Ptr& segment, uint32_t offset) {
559         // Empty segments are valid, but only if memory isn't present, which would be undefined behavior in memcpy.
560         if (segment->sizeInBytes) {
561             RELEASE_ASSERT(memory);
562             memcpy(memory + offset, &segment->byte(0), segment->sizeInBytes);
563         }
564     });
565
566     ASSERT(!exception);
567
568     if (JSObject* startFunction = m_startFunction.get()) {
569         CallData callData;
570         CallType callType = JSC::getCallData(vm, startFunction, callData);
571         call(exec, startFunction, callType, callData, jsUndefined(), *vm.emptyList);
572         RETURN_IF_EXCEPTION(scope, { });
573     }
574
575     return jsUndefined();
576 }
577
578 } // namespace JSC
579
580 #endif // ENABLE(WEBASSEMBLY)