Changeset 189822 in webkit
- Timestamp:
- Sep 15, 2015 1:00:23 PM (9 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r189820 r189822 1 2015-09-15 Sukolsak Sakshuwong <sukolsak@gmail.com> 2 3 Implement calls to JavaScript functions in WebAssembly 4 https://bugs.webkit.org/show_bug.cgi?id=149093 5 6 Reviewed by Filip Pizlo. 7 8 This patch implements calls to JavaScript functions in WebAssembly. 9 WebAssembly functions can only call JavaScript functions that are 10 imported to their module via an object that is passed into 11 loadWebAssembly(). References to JavaScript functions are resolved at 12 the module's load time, just like asm.js. 13 14 * jsc.cpp: 15 (GlobalObject::finishCreation): 16 (functionLoadWebAssembly): 17 * tests/stress/wasm-calls.js: 18 * tests/stress/wasm/calls.wasm: 19 * wasm/JSWASMModule.cpp: 20 (JSC::JSWASMModule::visitChildren): 21 * wasm/JSWASMModule.h: 22 (JSC::JSWASMModule::importedFunctions): 23 * wasm/WASMFunctionCompiler.h: 24 (JSC::WASMFunctionCompiler::buildCallImport): 25 * wasm/WASMFunctionParser.cpp: 26 (JSC::WASMFunctionParser::parseExpressionI32): 27 (JSC::WASMFunctionParser::parseExpressionF64): 28 (JSC::WASMFunctionParser::parseCallImport): 29 * wasm/WASMFunctionParser.h: 30 * wasm/WASMFunctionSyntaxChecker.h: 31 (JSC::WASMFunctionSyntaxChecker::buildCallInternal): 32 (JSC::WASMFunctionSyntaxChecker::buildCallImport): 33 (JSC::WASMFunctionSyntaxChecker::updateTempStackHeightForCall): 34 * wasm/WASMModuleParser.cpp: 35 (JSC::WASMModuleParser::WASMModuleParser): 36 (JSC::WASMModuleParser::parse): 37 (JSC::WASMModuleParser::parseModule): 38 (JSC::WASMModuleParser::parseFunctionImportSection): 39 (JSC::WASMModuleParser::getImportedValue): 40 (JSC::parseWebAssembly): 41 * wasm/WASMModuleParser.h: 42 1 43 2015-09-15 Csaba Osztrogonác <ossy@webkit.org> 2 44 -
trunk/Source/JavaScriptCore/jsc.cpp
r189616 r189822 680 680 681 681 #if ENABLE(WEBASSEMBLY) 682 addFunction(vm, "loadWebAssembly", functionLoadWebAssembly, 1);682 addFunction(vm, "loadWebAssembly", functionLoadWebAssembly, 2); 683 683 #endif 684 684 addFunction(vm, "loadModule", functionLoadModule, 1); … … 1459 1459 RefPtr<WebAssemblySourceProvider> sourceProvider = WebAssemblySourceProvider::create(reinterpret_cast<Vector<uint8_t>&>(buffer), fileName); 1460 1460 SourceCode source(sourceProvider); 1461 JSObject* imports = exec->argument(1).getObject(); 1462 1461 1463 String errorMessage; 1462 JSWASMModule* module = parseWebAssembly(exec, source, errorMessage);1464 JSWASMModule* module = parseWebAssembly(exec, source, imports, errorMessage); 1463 1465 if (!module) 1464 1466 return JSValue::encode(exec->vm().throwException(exec, createSyntaxError(exec, errorMessage))); -
trunk/Source/JavaScriptCore/tests/stress/wasm-calls.js
r189563 r189822 9 9 wasm/calls.wasm is generated by pack-asmjs <https://github.com/WebAssembly/polyfill-prototype-1> from the following script: 10 10 11 function asmModule(global, env, buffer) {11 function asmModule(global, imports, buffer) { 12 12 "use asm"; 13 14 var sum = imports.sum; 15 var max = imports.max; 13 16 14 17 function fibonacci(x) { … … 33 36 } 34 37 38 function callSum(x, y) { 39 x = x | 0; 40 y = y | 0; 41 return sum(x, y) | 0; 42 } 43 44 function callMax(x, y) { 45 x = x | 0; 46 y = y | 0; 47 return max(x, y) | 0; 48 } 49 35 50 return { 36 51 fibonacci: fibonacci, 37 52 gcd: gcd, 38 53 lcm: lcm, 54 callSum: callSum, 55 callMax: callMax, 39 56 }; 40 57 } 41 58 */ 42 59 43 var module = loadWebAssembly("wasm/calls.wasm"); 60 var imports = { 61 sum: (x, y) => x + y, 62 max: Math.max, 63 }; 64 var module = loadWebAssembly("wasm/calls.wasm", imports); 44 65 45 66 shouldBe(module.fibonacci(10), 89); 46 67 shouldBe(module.gcd(15, 25), 5); 47 68 shouldBe(module.lcm(15, 25), 75); 69 70 shouldBe(module.callSum(1, 2), 3); 71 shouldBe(module.callMax(1, 2), 2); -
trunk/Source/JavaScriptCore/wasm/JSWASMModule.cpp
r188099 r189822 49 49 for (auto function : thisObject->m_functions) 50 50 visitor.append(&function); 51 for (auto importedFunction : thisObject->m_importedFunctions) 52 visitor.append(&importedFunction); 51 53 } 52 54 -
trunk/Source/JavaScriptCore/wasm/JSWASMModule.h
r189584 r189822 88 88 Vector<unsigned>& functionStackHeights() { return m_functionStackHeights; } 89 89 Vector<GlobalVariable>& globalVariables() { return m_globalVariables; } 90 Vector<WriteBarrier<JSFunction>>& importedFunctions() { return m_importedFunctions; } 90 91 91 92 private: … … 109 110 Vector<unsigned> m_functionStackHeights; 110 111 Vector<GlobalVariable> m_globalVariables; 112 Vector<WriteBarrier<JSFunction>> m_importedFunctions; 111 113 }; 112 114 -
trunk/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h
r189744 r189822 655 655 } 656 656 657 int buildCallImport(uint32_t functionImportIndex, int, const WASMSignature& signature, WASMExpressionType returnType) 658 { 659 boxArgumentsAndAdjustStackPointer(signature.arguments); 660 661 JSFunction* function = m_module->importedFunctions()[functionImportIndex].get(); 662 move(TrustedImmPtr(function), GPRInfo::regT0); 663 664 callAndUnboxResult(returnType); 665 return UNUSED; 666 } 667 657 668 void appendExpressionList(int&, int) { } 658 669 -
trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.cpp
r189744 r189822 531 531 case WASMOpExpressionI32::CallInternal: 532 532 return parseCallInternalExpressionI32(context); 533 case WASMOpExpressionI32::CallImport: 534 return parseCallImport(context, WASMExpressionType::I32); 533 535 case WASMOpExpressionI32::Negate: 534 536 case WASMOpExpressionI32::BitNot: … … 595 597 case WASMOpExpressionI32::StoreWithOffset32: 596 598 case WASMOpExpressionI32::CallIndirect: 597 case WASMOpExpressionI32::CallImport:598 599 case WASMOpExpressionI32::Conditional: 599 600 case WASMOpExpressionI32::Comma: … … 878 879 case WASMOpExpressionF64::GetGlobal: 879 880 return parseGetGlobalExpressionF64(context); 881 case WASMOpExpressionF64::CallImport: 882 return parseCallImport(context, WASMExpressionType::F64); 880 883 case WASMOpExpressionF64::SetLocal: 881 884 case WASMOpExpressionF64::SetGlobal: … … 886 889 case WASMOpExpressionF64::CallInternal: 887 890 case WASMOpExpressionF64::CallIndirect: 888 case WASMOpExpressionF64::CallImport:889 891 case WASMOpExpressionF64::Conditional: 890 892 case WASMOpExpressionF64::Comma: … … 1007 1009 } 1008 1010 1011 template <class Context> 1012 ContextExpression WASMFunctionParser::parseCallImport(Context& context, WASMExpressionType returnType) 1013 { 1014 uint32_t functionImportSignatureIndex; 1015 READ_COMPACT_UINT32_OR_FAIL(functionImportSignatureIndex, "Cannot read the function import signature index."); 1016 FAIL_IF_FALSE(functionImportSignatureIndex < m_module->functionImportSignatures().size(), "The function import signature index is incorrect."); 1017 const WASMFunctionImportSignature& functionImportSignature = m_module->functionImportSignatures()[functionImportSignatureIndex]; 1018 const WASMSignature& signature = m_module->signatures()[functionImportSignature.signatureIndex]; 1019 FAIL_IF_FALSE(signature.returnType == returnType, "Wrong return type."); 1020 1021 ContextExpressionList argumentList = parseCallArguments(context, signature.arguments); 1022 PROPAGATE_ERROR(); 1023 return context.buildCallImport(functionImportSignature.functionImportIndex, argumentList, signature, returnType); 1024 } 1025 1009 1026 } // namespace JSC 1010 1027 -
trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h
r189744 r189822 117 117 template <class Context> ContextExpressionList parseCallArguments(Context&, const Vector<WASMType>& arguments); 118 118 template <class Context> ContextExpression parseCallInternal(Context&, WASMExpressionType returnType); 119 template <class Context> ContextExpression parseCallImport(Context&, WASMExpressionType returnType); 119 120 120 121 JSWASMModule* m_module; -
trunk/Source/JavaScriptCore/wasm/WASMFunctionSyntaxChecker.h
r189744 r189822 145 145 { 146 146 size_t argumentCount = signature.arguments.size(); 147 148 // Boxed arguments + this argument + call frame header + padding. 149 m_tempStackTop += argumentCount + 1 + JSStack::CallFrameHeaderSize + 1; 150 updateTempStackHeight(); 151 m_tempStackTop -= argumentCount + 1 + JSStack::CallFrameHeaderSize + 1; 152 147 updateTempStackHeightForCall(argumentCount); 148 m_tempStackTop -= argumentCount; 149 if (returnType != WASMExpressionType::Void) { 150 m_tempStackTop++; 151 updateTempStackHeight(); 152 } 153 return UNUSED; 154 } 155 156 int buildCallImport(uint32_t, int, const WASMSignature& signature, WASMExpressionType returnType) 157 { 158 size_t argumentCount = signature.arguments.size(); 159 updateTempStackHeightForCall(argumentCount); 153 160 m_tempStackTop -= argumentCount; 154 161 if (returnType != WASMExpressionType::Void) { … … 197 204 } 198 205 206 void updateTempStackHeightForCall(size_t argumentCount) 207 { 208 // Boxed arguments + this argument + call frame header + maximum padding. 209 m_tempStackTop += argumentCount + 1 + JSStack::CallFrameHeaderSize + 1; 210 updateTempStackHeight(); 211 m_tempStackTop -= argumentCount + 1 + JSStack::CallFrameHeaderSize + 1; 212 } 213 199 214 unsigned m_numberOfLocals; 200 215 unsigned m_tempStackTop { 0 }; -
trunk/Source/JavaScriptCore/wasm/WASMModuleParser.cpp
r189584 r189822 50 50 namespace JSC { 51 51 52 WASMModuleParser::WASMModuleParser(VM& vm, JSGlobalObject* globalObject, const SourceCode& source )52 WASMModuleParser::WASMModuleParser(VM& vm, JSGlobalObject* globalObject, const SourceCode& source, JSObject* imports) 53 53 : m_vm(vm) 54 54 , m_globalObject(vm, globalObject) 55 55 , m_source(source) 56 , m_imports(vm, imports) 56 57 , m_reader(static_cast<WebAssemblySourceProvider*>(source.provider())->data()) 57 58 { 58 59 } 59 60 60 JSWASMModule* WASMModuleParser::parse( String& errorMessage)61 JSWASMModule* WASMModuleParser::parse(ExecState* exec, String& errorMessage) 61 62 { 62 63 m_module.set(m_vm, JSWASMModule::create(m_vm, m_globalObject->wasmModuleStructure())); 63 parseModule( );64 parseModule(exec); 64 65 if (!m_errorMessage.isNull()) { 65 66 errorMessage = m_errorMessage; … … 69 70 } 70 71 71 void WASMModuleParser::parseModule( )72 void WASMModuleParser::parseModule(ExecState* exec) 72 73 { 73 74 uint32_t magicNumber; … … 82 83 parseSignatureSection(); 83 84 PROPAGATE_ERROR(); 84 parseFunctionImportSection( );85 parseFunctionImportSection(exec); 85 86 PROPAGATE_ERROR(); 86 87 parseGlobalSection(); … … 144 145 } 145 146 146 void WASMModuleParser::parseFunctionImportSection( )147 void WASMModuleParser::parseFunctionImportSection(ExecState* exec) 147 148 { 148 149 uint32_t numberOfFunctionImports; … … 152 153 m_module->functionImports().reserveInitialCapacity(numberOfFunctionImports); 153 154 m_module->functionImportSignatures().reserveInitialCapacity(numberOfFunctionImportSignatures); 155 m_module->importedFunctions().reserveInitialCapacity(numberOfFunctionImports); 154 156 155 157 for (uint32_t functionImportIndex = 0; functionImportIndex < numberOfFunctionImports; ++functionImportIndex) { … … 169 171 m_module->functionImportSignatures().uncheckedAppend(functionImportSignature); 170 172 } 173 174 JSValue value; 175 getImportedValue(exec, functionImport.functionName, value); 176 PROPAGATE_ERROR(); 177 FAIL_IF_FALSE(value.isFunction(), "\"" + functionImport.functionName + "\" is not a function."); 178 JSFunction* function = jsCast<JSFunction*>(value.asCell()); 179 m_module->importedFunctions().uncheckedAppend(WriteBarrier<JSFunction>(m_vm, m_module.get(), function)); 171 180 } 172 181 FAIL_IF_FALSE(m_module->functionImportSignatures().size() == numberOfFunctionImportSignatures, "The number of function import signatures is incorrect."); … … 322 331 } 323 332 324 JSWASMModule* parseWebAssembly(ExecState* exec, const SourceCode& source, String& errorMessage) 325 { 326 WASMModuleParser moduleParser(exec->vm(), exec->lexicalGlobalObject(), source); 327 return moduleParser.parse(errorMessage); 333 void WASMModuleParser::getImportedValue(ExecState* exec, const String& importName, JSValue& value) 334 { 335 FAIL_IF_FALSE(m_imports, "Accessing property of non-object."); 336 Identifier identifier = Identifier::fromString(&m_vm, importName); 337 PropertySlot slot(m_imports.get()); 338 if (!m_imports->getPropertySlot(exec, identifier, slot)) 339 FAIL_WITH_MESSAGE("Can't find a property named \"" + importName + '"'); 340 FAIL_IF_FALSE(slot.isValue(), "\"" + importName + "\" is not a data property."); 341 // We only retrieve data properties. So, this does not cause any user-observable effect. 342 value = slot.getValue(exec, identifier); 343 } 344 345 JSWASMModule* parseWebAssembly(ExecState* exec, const SourceCode& source, JSObject* imports, String& errorMessage) 346 { 347 WASMModuleParser moduleParser(exec->vm(), exec->lexicalGlobalObject(), source, imports); 348 return moduleParser.parse(exec, errorMessage); 328 349 } 329 350 -
trunk/Source/JavaScriptCore/wasm/WASMModuleParser.h
r189123 r189822 43 43 class WASMModuleParser { 44 44 public: 45 WASMModuleParser(VM&, JSGlobalObject*, const SourceCode& );46 JSWASMModule* parse( String& errorMessage);45 WASMModuleParser(VM&, JSGlobalObject*, const SourceCode&, JSObject* imports); 46 JSWASMModule* parse(ExecState*, String& errorMessage); 47 47 48 48 private: 49 void parseModule( );49 void parseModule(ExecState*); 50 50 void parseConstantPoolSection(); 51 51 void parseSignatureSection(); 52 void parseFunctionImportSection( );52 void parseFunctionImportSection(ExecState*); 53 53 void parseGlobalSection(); 54 54 void parseFunctionDeclarationSection(); … … 57 57 void parseFunctionDefinition(size_t functionIndex); 58 58 void parseExportSection(); 59 void getImportedValue(ExecState*, const String& importName, JSValue&); 59 60 60 61 VM& m_vm; 61 62 Strong<JSGlobalObject> m_globalObject; 62 63 const SourceCode& m_source; 64 Strong<JSObject> m_imports; 63 65 WASMReader m_reader; 64 66 Strong<JSWASMModule> m_module; … … 66 68 }; 67 69 68 JS_EXPORT_PRIVATE JSWASMModule* parseWebAssembly(ExecState*, const SourceCode&, String& errorMessage);70 JS_EXPORT_PRIVATE JSWASMModule* parseWebAssembly(ExecState*, const SourceCode&, JSObject* imports, String& errorMessage); 69 71 70 72 } // namespace JSC
Note: See TracChangeset
for help on using the changeset viewer.