Ignore:
Timestamp:
Dec 8, 2016, 1:09:06 PM (9 years ago)
Author:
[email protected]
Message:

WebAssembly JS API: wire up Instance imports
https://bugs.webkit.org/show_bug.cgi?id=165118

Reviewed by Saam Barati.

JSTests:

  • wasm/js-api/test_Instance.js: add the test, disabled for now

Source/JavaScriptCore:

Change a bunch of the WebAssembly object model, and pipe the
necessary changes to be able to call JS imports from
WebAssembly. This will make it easier to call_indirect, and
unblock many other missing features.

As a follow-up I need to teach JSC::linkFor to live without a
CodeBlock: wasm doesn't have one and the IC patching is sad. We'll
switch on the callee (or its type?) and then use that as the owner
(because the callee is alive if the instance is alive, ditto
module, and module owns the CallLinkInfo).

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • interpreter/CallFrame.h:

(JSC::ExecState::callee): give access to the callee as a JSCell

  • jit/RegisterSet.cpp: dead code from previous WebAssembly implementation
  • jsc.cpp:

(callWasmFunction):
(functionTestWasmModuleFunctions):

  • runtime/JSCellInlines.h:

(JSC::ExecState::vm): check callee instead of jsCallee: wasm only has a JSCell and not a JSObject

  • runtime/VM.cpp:

(JSC::VM::VM): store the "top" WebAssembly.Instance on entry to WebAssembly (and restore the previous one on exit)

  • runtime/VM.h:
  • testWasm.cpp:

(runWasmTests):

  • wasm/JSWebAssembly.h:
  • wasm/WasmB3IRGenerator.cpp:

(JSC::Wasm::B3IRGenerator::B3IRGenerator): pass unlinked calls around to shorten their lifetime: they're ony needed until the Plan is done
(JSC::Wasm::B3IRGenerator::addCall):
(JSC::Wasm::createJSToWasmWrapper):
(JSC::Wasm::parseAndCompile): also pass in the function index space, so that imports can be signature-checked along with internal functions

  • wasm/WasmB3IRGenerator.h:
  • wasm/WasmBinding.cpp: Added.

(JSC::Wasm::importStubGenerator): stubs from wasm to JS

  • wasm/WasmBinding.h: Copied from Source/JavaScriptCore/wasm/WasmValidate.h.
  • wasm/WasmCallingConvention.h:

(JSC::Wasm::CallingConvention::setupFrameInPrologue):

  • wasm/WasmFormat.h: fix the object model

(JSC::Wasm::CallableFunction::CallableFunction):

  • wasm/WasmFunctionParser.h: simplify some of the failure condition checks

(JSC::Wasm::FunctionParser<Context>::FunctionParser): need function index space, not just internal functions
(JSC::Wasm::FunctionParser<Context>::parseExpression):

  • wasm/WasmModuleParser.cpp: early-create some of the structures which will be needed later

(JSC::Wasm::ModuleParser::parseImport):
(JSC::Wasm::ModuleParser::parseFunction):
(JSC::Wasm::ModuleParser::parseMemory):
(JSC::Wasm::ModuleParser::parseExport):
(JSC::Wasm::ModuleParser::parseCode):

  • wasm/WasmModuleParser.h:

(JSC::Wasm::ModuleParser::functionIndexSpace):
(JSC::Wasm::ModuleParser::functionLocations):

  • wasm/WasmParser.h:

(JSC::Wasm::Parser::consumeUTF8String):

  • wasm/WasmPlan.cpp: pass around the wasm objects at the right time, reducing their lifetime and making it easier to pass them around when needed

(JSC::Wasm::Plan::run):
(JSC::Wasm::Plan::initializeCallees):

  • wasm/WasmPlan.h:

(JSC::Wasm::Plan::exports):
(JSC::Wasm::Plan::internalFunctionCount):
(JSC::Wasm::Plan::jsToWasmEntryPointForFunction):
(JSC::Wasm::Plan::takeModuleInformation):
(JSC::Wasm::Plan::takeCallLinkInfos):
(JSC::Wasm::Plan::takeWasmToJSStubs):
(JSC::Wasm::Plan::takeFunctionIndexSpace):

  • wasm/WasmValidate.cpp: check function index space instead of only internal functions

(JSC::Wasm::Validate::addCall):
(JSC::Wasm::validateFunction):

  • wasm/WasmValidate.h:
  • wasm/js/JSWebAssemblyCallee.cpp:

(JSC::JSWebAssemblyCallee::finishCreation):

  • wasm/js/JSWebAssemblyCallee.h:

(JSC::JSWebAssemblyCallee::create):
(JSC::JSWebAssemblyCallee::jsToWasmEntryPoint):

  • wasm/js/JSWebAssemblyInstance.cpp:

(JSC::JSWebAssemblyInstance::create):
(JSC::JSWebAssemblyInstance::JSWebAssemblyInstance):
(JSC::JSWebAssemblyInstance::visitChildren):

  • wasm/js/JSWebAssemblyInstance.h: hold the import functions off the end of the Instance

(JSC::JSWebAssemblyInstance::importFunction):
(JSC::JSWebAssemblyInstance::importFunctions):
(JSC::JSWebAssemblyInstance::setImportFunction):
(JSC::JSWebAssemblyInstance::offsetOfImportFunctions):
(JSC::JSWebAssemblyInstance::offsetOfImportFunction):
(JSC::JSWebAssemblyInstance::allocationSize):

  • wasm/js/JSWebAssemblyModule.cpp:

(JSC::JSWebAssemblyModule::create):
(JSC::JSWebAssemblyModule::JSWebAssemblyModule):
(JSC::JSWebAssemblyModule::visitChildren):

  • wasm/js/JSWebAssemblyModule.h: hold the link call info, the import function stubs, and the function index space

(JSC::JSWebAssemblyModule::signatureForFunctionIndexSpace):
(JSC::JSWebAssemblyModule::importCount):
(JSC::JSWebAssemblyModule::calleeFromFunctionIndexSpace):

  • wasm/js/WebAssemblyFunction.cpp:

(JSC::callWebAssemblyFunction): set top Instance on VM

  • wasm/js/WebAssemblyFunction.h:

(JSC::WebAssemblyFunction::instance):

  • wasm/js/WebAssemblyInstanceConstructor.cpp:

(JSC::constructJSWebAssemblyInstance): handle function imports

  • wasm/js/WebAssemblyModuleConstructor.cpp:

(JSC::constructJSWebAssemblyModule): generate the stubs for import functions

  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::link):

  • wasm/js/WebAssemblyToJSCallee.cpp: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyCallee.cpp.

(JSC::WebAssemblyToJSCallee::create): dummy JSCell singleton which lives on the VM, and is put as the callee in the import stub's frame to identified it when unwinding
(JSC::WebAssemblyToJSCallee::createStructure):
(JSC::WebAssemblyToJSCallee::WebAssemblyToJSCallee):
(JSC::WebAssemblyToJSCallee::finishCreation):
(JSC::WebAssemblyToJSCallee::destroy):

  • wasm/js/WebAssemblyToJSCallee.h: Copied from Source/JavaScriptCore/wasm/WasmB3IRGenerator.h.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp

    r209312 r209560  
    3434#include "JSWebAssemblyCallee.h"
    3535#include "WasmB3IRGenerator.h"
     36#include "WasmBinding.h"
    3637#include "WasmCallingConvention.h"
    3738#include "WasmMemory.h"
     
    3940#include "WasmValidate.h"
    4041#include <wtf/DataLog.h>
     42#include <wtf/StdLibExtras.h>
    4143#include <wtf/text/StringBuilder.h>
    4244
     
    7072        }
    7173        m_moduleInformation = WTFMove(moduleParser.moduleInformation());
     74        m_functionLocationInBinary = WTFMove(moduleParser.functionLocationInBinary());
     75        m_functionIndexSpace = WTFMove(moduleParser.functionIndexSpace());
    7276    }
    7377    if (verbose)
    7478        dataLogLn("Parsed module.");
    7579
    76     if (!m_compiledFunctions.tryReserveCapacity(m_moduleInformation->functions.size())) {
    77         StringBuilder builder;
    78         builder.appendLiteral("Failed allocating enough space for ");
    79         builder.appendNumber(m_moduleInformation->functions.size());
    80         builder.appendLiteral(" compiled functions");
    81         m_errorMessage = builder.toString();
     80    auto tryReserveCapacity = [this] (auto& vector, size_t size, const char* what) {
     81        if (UNLIKELY(!vector.tryReserveCapacity(size))) {
     82            StringBuilder builder;
     83            builder.appendLiteral("Failed allocating enough space for ");
     84            builder.appendNumber(size);
     85            builder.append(what);
     86            m_errorMessage = builder.toString();
     87            return false;
     88        }
     89        return true;
     90    };
     91    Vector<Vector<UnlinkedWasmToWasmCall>> unlinkedWasmToWasmCalls;
     92    if (!tryReserveCapacity(m_wasmToJSStubs, m_moduleInformation->importFunctions.size(), " WebAssembly to JavaScript stubs")
     93        || !tryReserveCapacity(unlinkedWasmToWasmCalls, m_functionLocationInBinary.size(), " unlinked WebAssembly to WebAssembly calls")
     94        || !tryReserveCapacity(m_wasmInternalFunctions, m_functionLocationInBinary.size(), " WebAssembly functions"))
    8295        return;
     96
     97    for (unsigned importIndex = 0; importIndex < m_moduleInformation->imports.size(); ++importIndex) {
     98        Import* import = &m_moduleInformation->imports[importIndex];
     99        if (import->kind != External::Function)
     100            continue;
     101        unsigned importFunctionIndex = m_wasmToJSStubs.size();
     102        if (verbose)
     103            dataLogLn("Processing import function number ", importFunctionIndex, ": ", import->module, ": ", import->field);
     104        Signature* signature = m_moduleInformation->importFunctions.at(import->kindIndex);
     105        m_wasmToJSStubs.uncheckedAppend(importStubGenerator(m_vm, m_callLinkInfos, signature, importFunctionIndex));
     106        m_functionIndexSpace[importFunctionIndex].code = m_wasmToJSStubs[importFunctionIndex].code().executableAddress();
    83107    }
    84108
    85     for (const FunctionInformation& info : m_moduleInformation->functions) {
     109    for (unsigned functionIndex = 0; functionIndex < m_functionLocationInBinary.size(); ++functionIndex) {
    86110        if (verbose)
    87             dataLogLn("Processing function starting at: ", info.start, " and ending at: ", info.end);
    88         const uint8_t* functionStart = m_source + info.start;
    89         size_t functionLength = info.end - info.start;
     111            dataLogLn("Processing function starting at: ", m_functionLocationInBinary[functionIndex].start, " and ending at: ", m_functionLocationInBinary[functionIndex].end);
     112        const uint8_t* functionStart = m_source + m_functionLocationInBinary[functionIndex].start;
     113        size_t functionLength = m_functionLocationInBinary[functionIndex].end - m_functionLocationInBinary[functionIndex].start;
    90114        ASSERT(functionLength <= m_sourceLength);
     115        Signature* signature = m_moduleInformation->internalFunctionSignatures[functionIndex];
     116        unsigned functionIndexSpace = m_wasmToJSStubs.size() + functionIndex;
     117        ASSERT(m_functionIndexSpace[functionIndexSpace].signature == signature);
    91118
    92         String error = validateFunction(functionStart, functionLength, info.signature, m_moduleInformation->functions);
     119        String error = validateFunction(functionStart, functionLength, signature, m_functionIndexSpace);
    93120        if (!error.isNull()) {
    94121            if (verbose) {
     
    101128        }
    102129
    103         m_compiledFunctions.uncheckedAppend(parseAndCompile(*m_vm, functionStart, functionLength, m_moduleInformation->memory.get(), info.signature, m_moduleInformation->functions));
     130        unlinkedWasmToWasmCalls.uncheckedAppend(Vector<UnlinkedWasmToWasmCall>());
     131        m_wasmInternalFunctions.uncheckedAppend(parseAndCompile(*m_vm, functionStart, functionLength, m_moduleInformation->memory.get(), signature, unlinkedWasmToWasmCalls.at(functionIndex), m_functionIndexSpace));
     132        m_functionIndexSpace[functionIndexSpace].code = m_wasmInternalFunctions[functionIndex]->code->code().executableAddress();
    104133    }
    105134
    106     // Patch the call sites for each function.
    107     for (std::unique_ptr<FunctionCompilation>& functionPtr : m_compiledFunctions) {
    108         FunctionCompilation* function = functionPtr.get();
    109         for (auto& call : function->unlinkedCalls)
    110             MacroAssembler::repatchCall(call.callLocation, CodeLocationLabel(m_compiledFunctions[call.functionIndex]->code->code()));
     135    // Patch the call sites for each WebAssembly function.
     136    for (auto& unlinked : unlinkedWasmToWasmCalls) {
     137        for (auto& call : unlinked)
     138            MacroAssembler::repatchCall(call.callLocation, CodeLocationLabel(m_functionIndexSpace[call.functionIndex].code));
    111139    }
    112140
     
    117145{
    118146    ASSERT(!failed());
    119     for (unsigned i = 0; i < m_compiledFunctions.size(); i++) {
    120         std::unique_ptr<FunctionCompilation>& compilation = m_compiledFunctions[i];
    121         CodeLocationDataLabelPtr calleeMoveLocation = compilation->calleeMoveLocation;
    122         JSWebAssemblyCallee* callee = JSWebAssemblyCallee::create(globalObject->vm(), WTFMove(compilation));
     147    for (unsigned internalFunctionIndex = 0; internalFunctionIndex < m_wasmInternalFunctions.size(); ++internalFunctionIndex) {
     148        WasmInternalFunction* function = m_wasmInternalFunctions[internalFunctionIndex].get();
     149        CodeLocationDataLabelPtr calleeMoveLocation = function->calleeMoveLocation;
     150        JSWebAssemblyCallee* callee = JSWebAssemblyCallee::create(globalObject->vm(), WTFMove(function->code), WTFMove(function->jsToWasmEntryPoint));
    123151
    124152        MacroAssembler::repatchPointer(calleeMoveLocation, callee);
     
    127155            dataLogLn("Made Wasm callee: ", RawPointer(callee));
    128156
    129         callback(i, callee);
     157        callback(internalFunctionIndex, callee);
    130158    }
    131159}
Note: See TracChangeset for help on using the changeset viewer.