static EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncSet(ExecState* exec) { VM& vm = exec->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue()); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); JSValue value = exec->argument(1); WebAssemblyFunction* wasmFunction; WebAssemblyWrapperFunction* wasmWrapperFunction; if (!value.isNull() && !isWebAssemblyHostFunction(vm, value, wasmFunction, wasmWrapperFunction)) return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, "WebAssembly.Table.prototype.set expects the second argument to be null or an instance of WebAssembly.Function"_s))); uint32_t index = toNonWrappingUint32(exec, exec->argument(0)); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); if (index >= table->length()) return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, "WebAssembly.Table.prototype.set expects an integer less than the length of the table"_s))); if (value.isNull()) table->clearFunction(index); else { ASSERT(value.isObject() && isWebAssemblyHostFunction(vm, jsCast<JSObject*>(value), wasmFunction, wasmWrapperFunction)); ASSERT(!!wasmFunction || !!wasmWrapperFunction); if (wasmFunction) table->setFunction(vm, index, wasmFunction); else table->setFunction(vm, index, wasmWrapperFunction); } return JSValue::encode(jsUndefined()); }
JSValue WebAssemblyModuleRecord::evaluate(ExecState* state) { VM& vm = state->vm(); auto scope = DECLARE_THROW_SCOPE(vm); { JSWebAssemblyModule* module = m_instance->module(); const Wasm::ModuleInformation& moduleInformation = module->moduleInformation(); JSWebAssemblyTable* table = m_instance->table(); for (const Wasm::Element& element : moduleInformation.elements) { // It should be a validation error to have any elements without a table. // Also, it could be that a table wasn't imported, or that the table // imported wasn't compatible. However, those should error out before // getting here. ASSERT(!!table); if (!element.functionIndices.size()) continue; uint32_t tableIndex = element.offset; uint64_t lastWrittenIndex = static_cast<uint64_t>(tableIndex) + static_cast<uint64_t>(element.functionIndices.size()) - 1; if (lastWrittenIndex >= table->size()) return throwException(state, scope, createJSWebAssemblyLinkError(state, vm, ASCIILiteral("Element is trying to set an out of bounds table index"))); for (uint32_t i = 0; i < element.functionIndices.size(); ++i) { // FIXME: This essentially means we're exporting an import. // We need a story here. We need to create a WebAssemblyFunction // for the import. // https://bugs.webkit.org/show_bug.cgi?id=165510 uint32_t functionIndex = element.functionIndices[i]; if (functionIndex < module->functionImportCount()) { return JSValue::decode( throwVMRangeError(state, scope, ASCIILiteral("Element is setting the table value with an import. This is not yet implemented. FIXME."))); } JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(functionIndex); JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(functionIndex); Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(functionIndex); const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex); // FIXME: Say we export local function "foo" at funciton index 0. // What if we also set it to the table an Element w/ index 0. // Does (new Instance(...)).exports.foo === table.get(0)? // https://bugs.webkit.org/show_bug.cgi?id=165825 WebAssemblyFunction* function = WebAssemblyFunction::create( vm, m_instance->globalObject(), signature->argumentCount(), String(), m_instance.get(), jsEntrypointCallee, wasmEntrypointCallee, signatureIndex); table->setFunction(vm, tableIndex, function); ++tableIndex; } } } { const Vector<Wasm::Segment::Ptr>& data = m_instance->module()->moduleInformation().data; JSWebAssemblyMemory* jsMemory = m_instance->memory(); if (!data.isEmpty()) { uint8_t* memory = reinterpret_cast<uint8_t*>(jsMemory->memory()->memory()); uint64_t sizeInBytes = jsMemory->memory()->size(); for (auto& segment : data) { if (segment->sizeInBytes) { uint32_t offset; if (segment->offset.isGlobalImport()) offset = static_cast<uint32_t>(m_instance->loadI32Global(segment->offset.globalImportIndex())); else offset = segment->offset.constValue(); if (UNLIKELY(sizeInBytes < segment->sizeInBytes)) return dataSegmentFail(state, vm, scope, sizeInBytes, segment->sizeInBytes, offset, ASCIILiteral(", segment is too big")); if (UNLIKELY(offset > sizeInBytes - segment->sizeInBytes)) return dataSegmentFail(state, vm, scope, sizeInBytes, segment->sizeInBytes, offset, ASCIILiteral(", segment writes outside of memory")); RELEASE_ASSERT(memory); memcpy(memory + offset, &segment->byte(0), segment->sizeInBytes); } } } } if (JSCell* startFunction = m_startFunction.get()) { CallData callData; CallType callType = JSC::getCallData(startFunction, callData); call(state, startFunction, callType, callData, jsUndefined(), state->emptyList()); RETURN_IF_EXCEPTION(scope, { }); } return jsUndefined(); }