Changeset 207671 in webkit
- Timestamp:
- Oct 21, 2016 9:02:39 AM (7 years ago)
- Location:
- trunk
- Files:
-
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r207652 r207671 1 2016-10-20 Keith Miller <keith_miller@apple.com> 2 3 Add support for WASM calls 4 https://bugs.webkit.org/show_bug.cgi?id=161727 5 6 Reviewed by Filip Pizlo and Michael Saboff. 7 8 Add members of the Call category to the WASMOps special group. 9 10 * wasm/generate-wasmops-header.js: 11 1 12 2016-10-20 Yusuke Suzuki <utatane.tea@gmail.com> 2 13 -
trunk/JSTests/wasm/generate-wasmops-header.js
r207453 r207671 30 30 const defines = [ 31 31 "#define FOR_EACH_WASM_SPECIAL_OP(macro)", 32 ...opcodeMacroizer(op => op.category === "special" ),32 ...opcodeMacroizer(op => op.category === "special" || op.category === "call"), 33 33 "\n\n#define FOR_EACH_WASM_CONTROL_FLOW_OP(macro)", 34 34 ...opcodeMacroizer(op => op.category === "control"), -
trunk/Source/JavaScriptCore/ChangeLog
r207670 r207671 1 2016-10-20 Keith Miller <keith_miller@apple.com> 2 3 Add support for WASM calls 4 https://bugs.webkit.org/show_bug.cgi?id=161727 5 6 Reviewed by Filip Pizlo and Michael Saboff. 7 8 Add support for WASM calls. Since most of the work for this was already done when we added 9 WASM Memory, this is mostly just cleanup work. The main interesting part of this patch is 10 how we link calls to other WASM functions in the same module. Since a WASM callee may not 11 have been compiled by the time the current function has started compilation we don't know 12 what address we need to call to. For each callsite in the compiling function, WASM 13 remembers the CodeLocationCall and the target function index. Once all WASM functions are 14 compiled, each callsite is linked to the appropriate entrypoint. 15 16 * testWASM.cpp: 17 (runWASMTests): 18 * wasm/WASMB3IRGenerator.cpp: 19 (JSC::WASM::createJSWrapper): 20 (JSC::WASM::parseAndCompile): 21 * wasm/WASMB3IRGenerator.h: 22 * wasm/WASMCallingConvention.cpp: 23 (JSC::WASM::jscCallingConvention): 24 (JSC::WASM::wasmCallingConvention): 25 * wasm/WASMCallingConvention.h: 26 (JSC::WASM::CallingConvention::CallingConvention): 27 (JSC::WASM::CallingConvention::marshallArgumentImpl): 28 (JSC::WASM::CallingConvention::marshallArgument): 29 (JSC::WASM::CallingConvention::loadArguments): 30 (JSC::WASM::CallingConvention::setupCall): 31 (JSC::WASM::CallingConvention::iterate): Deleted. 32 * wasm/WASMFormat.h: 33 * wasm/WASMFunctionParser.h: 34 (JSC::WASM::FunctionParser<Context>::FunctionParser): 35 (JSC::WASM::FunctionParser<Context>::parseBlock): 36 (JSC::WASM::FunctionParser<Context>::parseExpression): 37 * wasm/WASMModuleParser.cpp: 38 (JSC::WASM::ModuleParser::parse): 39 * wasm/WASMOps.h: 40 * wasm/WASMParser.h: 41 (JSC::WASM::Parser::parseVarUInt32): 42 (JSC::WASM::Parser::parseVarUInt64): 43 * wasm/WASMPlan.cpp: 44 (JSC::WASM::Plan::Plan): 45 1 46 2016-10-21 Wenson Hsieh <wenson_hsieh@apple.com> 2 47 -
trunk/Source/JavaScriptCore/testWASM.cpp
r207453 r207671 136 136 size_t offset = startOffset; \ 137 137 uint32_t result; \ 138 bool status = decodeUInt32(vector.data(), vector.size(), offset, result); \138 bool status = WTF::LEBDecoder::decodeUInt32(vector.data(), vector.size(), offset, result); \ 139 139 CHECK_EQ(status, expectedStatus); \ 140 140 if (expectedStatus) { \ … … 184 184 size_t offset = startOffset; \ 185 185 int32_t result; \ 186 bool status = decodeInt32(vector.data(), vector.size(), offset, result); \186 bool status = WTF::LEBDecoder::decodeInt32(vector.data(), vector.size(), offset, result); \ 187 187 CHECK_EQ(status, expectedStatus); \ 188 188 if (expectedStatus) { \ … … 243 243 static void runWASMTests() 244 244 { 245 { 246 // Generated from: 247 // (module 248 // (memory 1) 249 // (func $sum12 (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (result i32) (return (i32.add (get_local 0) (i32.add (get_local 1) (i32.add (get_local 2) (i32.add (get_local 3) (i32.add (get_local 4) (i32.add (get_local 5) (i32.add (get_local 6) (i32.add (get_local 7) (i32.add (get_local 8) (i32.add (get_local 9) (i32.add (get_local 10) (get_local 11)))))))))))))) 250 // (func (export "mult12") (param i32) (result i32) (return (call $sum12 (get_local 0) (get_local 0) (get_local 0) (get_local 0) (get_local 0) (get_local 0) (get_local 0) (get_local 0) (get_local 0) (get_local 0) (get_local 0) (get_local 0)))) 251 // ) 252 253 Vector<uint8_t> vector = { 254 0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x96, 0x80, 0x80, 0x80, 0x00, 0x02, 0x40, 255 0x0c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 256 0x01, 0x01, 0x01, 0x01, 0x03, 0x83, 0x80, 0x80, 0x80, 0x00, 0x02, 0x00, 0x01, 0x05, 0x83, 0x80, 257 0x80, 0x80, 0x00, 0x01, 0x00, 0x01, 0x07, 0x8a, 0x80, 0x80, 0x80, 0x00, 0x01, 0x06, 0x6d, 0x75, 258 0x6c, 0x74, 0x31, 0x32, 0x00, 0x01, 0x0a, 0xce, 0x80, 0x80, 0x80, 0x00, 0x02, 0xa6, 0x80, 0x80, 259 0x80, 0x00, 0x00, 0x14, 0x00, 0x14, 0x01, 0x14, 0x02, 0x14, 0x03, 0x14, 0x04, 0x14, 0x05, 0x14, 260 0x06, 0x14, 0x07, 0x14, 0x08, 0x14, 0x09, 0x14, 0x0a, 0x14, 0x0b, 0x40, 0x40, 0x40, 0x40, 0x40, 261 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x09, 0x0f, 0x9d, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x00, 262 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 263 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x16, 0x00, 0x09, 0x0f 264 }; 265 266 Plan plan(*vm, vector); 267 if (plan.result.size() != 2 || !plan.result[0] || !plan.result[1]) { 268 dataLogLn("Module failed to compile correctly."); 269 CRASH(); 270 } 271 272 // Test this doesn't crash. 273 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(0) }), 0); 274 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(100) }), 1200); 275 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(1) }), 12); 276 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2), box(3), box(4), box(5), box(6), box(7), box(8), box(9), box(10), box(11), box(12) }), 78); 277 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1), box(2), box(3), box(4), box(5), box(6), box(7), box(8), box(9), box(10), box(11), box(100) }), 166); 278 } 279 280 { 281 // Generated from: 282 // (module 283 // (memory 1) 284 // (func $fac (export "fac") (param i64) (result i64) 285 // (if (i64.eqz (get_local 0)) 286 // (return (i64.const 1)) 287 // ) 288 // (return (i64.mul (get_local 0) (call $fac (i64.sub (get_local 0) (i64.const 1))))) 289 // ) 290 // ) 291 Vector<uint8_t> vector = { 292 0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x86, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40, 293 0x01, 0x02, 0x01, 0x02, 0x03, 0x82, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x05, 0x83, 0x80, 0x80, 294 0x80, 0x00, 0x01, 0x00, 0x01, 0x07, 0x87, 0x80, 0x80, 0x80, 0x00, 0x01, 0x03, 0x66, 0x61, 0x63, 295 0x00, 0x00, 0x0a, 0x9e, 0x80, 0x80, 0x80, 0x00, 0x01, 0x98, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 296 0x00, 0x11, 0x00, 0x68, 0x03, 0x00, 0x11, 0x01, 0x09, 0x0f, 0x14, 0x00, 0x14, 0x00, 0x11, 0x01, 297 0x5c, 0x16, 0x00, 0x5d, 0x09, 0x0f 298 }; 299 300 Plan plan(*vm, vector); 301 if (plan.result.size() != 1 || !plan.result[0]) { 302 dataLogLn("Module failed to compile correctly."); 303 CRASH(); 304 } 305 306 // Test this doesn't crash. 307 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 1); 308 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1); 309 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(2) }), 2); 310 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(4) }), 24); 311 } 312 313 { 314 // Generated from: 315 // (module 316 // (memory 1) 317 // (func (export "double") (param i64) (result i64) (return (call 1 (get_local 0) (get_local 0)))) 318 // (func $sum (param i64) (param i64) (result i64) (return (i64.add (get_local 0) (get_local 1)))) 319 // ) 320 Vector<uint8_t> vector = { 321 0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x8c, 0x80, 0x80, 0x80, 0x00, 0x02, 0x40, 322 0x01, 0x02, 0x01, 0x02, 0x40, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x83, 0x80, 0x80, 0x80, 0x00, 323 0x02, 0x00, 0x01, 0x05, 0x83, 0x80, 0x80, 0x80, 0x00, 0x01, 0x00, 0x01, 0x07, 0x8a, 0x80, 0x80, 324 0x80, 0x00, 0x01, 0x06, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x00, 0x00, 0x0a, 0x9c, 0x80, 0x80, 325 0x80, 0x00, 0x02, 0x89, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x16, 0x01, 0x09, 326 0x0f, 0x88, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x00, 0x14, 0x01, 0x5b, 0x09, 0x0f 327 }; 328 329 Plan plan(*vm, vector); 330 if (plan.result.size() != 2 || !plan.result[0] || !plan.result[1]) { 331 dataLogLn("Module failed to compile correctly."); 332 CRASH(); 333 } 334 335 // Test this doesn't crash. 336 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(0), box(0) }), 0); 337 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(100), box(0) }), 100); 338 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(1), box(15) }), 16); 339 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0); 340 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 200); 341 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 2); 342 } 343 344 { 345 // Generated from: 346 // (module 347 // (memory 1) 348 // (func $id (param $value i32) (result i32) (return (get_local $value))) 349 // (func (export "id-call") (param $value i32) (result i32) (return (call $id (get_local $value)))) 350 // ) 351 Vector<uint8_t> vector = { 352 0x00, 0x61, 0x73, 0x6d, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x86, 0x80, 0x80, 0x80, 0x00, 0x01, 0x40, 353 0x01, 0x01, 0x01, 0x01, 0x03, 0x83, 0x80, 0x80, 0x80, 0x00, 0x02, 0x00, 0x00, 0x05, 0x83, 0x80, 354 0x80, 0x80, 0x00, 0x01, 0x01, 0x01, 0x07, 0x8b, 0x80, 0x80, 0x80, 0x00, 0x01, 0x07, 0x69, 0x64, 355 0x2d, 0x63, 0x61, 0x6c, 0x6c, 0x00, 0x01, 0x0a, 0x97, 0x80, 0x80, 0x80, 0x00, 0x02, 0x85, 0x80, 356 0x80, 0x80, 0x00, 0x00, 0x14, 0x00, 0x09, 0x0f, 0x87, 0x80, 0x80, 0x80, 0x00, 0x00, 0x14, 0x00, 357 0x16, 0x00, 0x09, 0x0f 358 }; 359 360 Plan plan(*vm, vector); 361 if (plan.result.size() != 2 || !plan.result[0] || !plan.result[1]) { 362 dataLogLn("Module failed to compile correctly."); 363 CRASH(); 364 } 365 366 // Test this doesn't crash. 367 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(0) }), 0); 368 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(100) }), 100); 369 CHECK_EQ(invoke<int>(*plan.result[1]->jsEntryPoint, { box(1) }), 1); 370 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(0) }), 0); 371 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(100) }), 100); 372 CHECK_EQ(invoke<int>(*plan.result[0]->jsEntryPoint, { box(1) }), 1); 373 } 374 245 375 { 246 376 // Generated from: -
trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.cpp
r207453 r207671 171 171 static constexpr ExpressionType emptyExpression = nullptr; 172 172 173 B3IRGenerator(Memory*, Procedure& );173 B3IRGenerator(Memory*, Procedure&, Vector<UnlinkedCall>& unlinkedCalls); 174 174 175 175 void addArguments(const Vector<Type>&); … … 199 199 bool WARN_UNUSED_RETURN endBlock(ControlData&, ExpressionList& expressionStack); 200 200 201 bool WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const FunctionInformation&, Vector<ExpressionType>& args, ExpressionType& result); 202 201 203 bool isContinuationReachable(ControlData&); 202 204 … … 215 217 BasicBlock* m_currentBlock; 216 218 Vector<Variable*> m_locals; 219 // m_unlikedCalls is list of each call site and the function index whose address it should be patched with. 220 Vector<UnlinkedCall>& m_unlinkedCalls; 217 221 GPRReg m_memoryBaseGPR; 218 222 GPRReg m_memorySizeGPR; 219 223 }; 220 224 221 B3IRGenerator::B3IRGenerator(Memory* memory, Procedure& procedure )225 B3IRGenerator::B3IRGenerator(Memory* memory, Procedure& procedure, Vector<UnlinkedCall>& unlinkedCalls) 222 226 : m_memory(memory) 223 227 , m_proc(procedure) 228 , m_unlinkedCalls(unlinkedCalls) 224 229 { 225 230 m_currentBlock = m_proc.addBlock(); … … 232 237 for (const PinnedSizeRegisterInfo& info : m_memory->pinnedRegisters().sizeRegisters) 233 238 m_proc.pinRegister(info.sizeRegister); 234 } 235 236 m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR, unsigned) {237 ASSERT_UNUSED(pinnedGPR, m_memorySizeGPR == pinnedGPR);238 // FIXME: This should unwind the stack and throw a JS exception. See: https://bugs.webkit.org/show_bug.cgi?id=163351239 jit.breakpoint();240 } );239 240 m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR, unsigned) { 241 ASSERT_UNUSED(pinnedGPR, m_memorySizeGPR == pinnedGPR); 242 // FIXME: This should unwind the stack and throw a JS exception. See: https://bugs.webkit.org/show_bug.cgi?id=163351 243 jit.breakpoint(); 244 }); 245 } 241 246 } 242 247 … … 252 257 ASSERT(!m_locals.size()); 253 258 m_locals.grow(types.size()); 254 jscCallingConvention().iterate(types, m_proc, m_currentBlock, Origin(),259 wasmCallingConvention().loadArguments(types, m_proc, m_currentBlock, Origin(), 255 260 [&] (ExpressionType argument, unsigned i) { 256 261 Variable* argumentVariable = m_proc.addVariable(argument->type()); … … 562 567 } 563 568 569 bool B3IRGenerator::addCall(unsigned functionIndex, const FunctionInformation& info, Vector<ExpressionType>& args, ExpressionType& result) 570 { 571 ASSERT(info.signature->arguments.size() == args.size()); 572 573 Type returnType = info.signature->returnType; 574 575 size_t callIndex = m_unlinkedCalls.size(); 576 m_unlinkedCalls.grow(callIndex + 1); 577 result = wasmCallingConvention().setupCall(m_proc, m_currentBlock, Origin(), args, toB3Type(returnType), 578 [&] (PatchpointValue* patchpoint) { 579 patchpoint->effects.writesPinned = true; 580 patchpoint->effects.readsPinned = true; 581 582 patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) { 583 AllowMacroScratchRegisterUsage allowScratch(jit); 584 585 CCallHelpers::Call call = jit.call(); 586 587 jit.addLinkTask([=] (LinkBuffer& linkBuffer) { 588 m_unlinkedCalls[callIndex] = { linkBuffer.locationOf(call), functionIndex }; 589 }); 590 }); 591 }); 592 return true; 593 } 594 564 595 bool B3IRGenerator::isContinuationReachable(ControlData& data) 565 596 { … … 643 674 // Get our arguments. 644 675 Vector<Value*> arguments; 645 jscCallingConvention(). iterate(signature->arguments, proc, block, Origin(), [&] (Value* argument, unsigned) {676 jscCallingConvention().loadArguments(signature->arguments, proc, block, Origin(), [&] (Value* argument, unsigned) { 646 677 arguments.append(argument); 647 678 }); 648 679 649 680 // Move the arguments into place. 650 Value* result = jscCallingConvention().setupCall(proc, block, Origin(), mainFunction, arguments, toB3Type(signature->returnType), [&] (PatchpointValue* patchpoint) {681 Value* result = wasmCallingConvention().setupCall(proc, block, Origin(), arguments, toB3Type(signature->returnType), [&] (PatchpointValue* patchpoint) { 651 682 if (memory) { 652 683 ASSERT(sizes.size() == memory->pinnedRegisters().sizeRegisters.size()); … … 655 686 patchpoint->append(ConstrainedValue(sizes[i], ValueRep::reg(memory->pinnedRegisters().sizeRegisters[i].sizeRegister))); 656 687 } 688 689 patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) { 690 AllowMacroScratchRegisterUsage allowScratch(jit); 691 692 CCallHelpers::Call call = jit.call(); 693 jit.addLinkTask([=] (LinkBuffer& linkBuffer) { 694 linkBuffer.link(call, FunctionPtr(mainFunction.executableAddress())); 695 }); 696 }); 657 697 }); 658 698 … … 666 706 } 667 707 668 std::unique_ptr<FunctionCompilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, Memory* memory, FunctionInformation info, unsigned optLevel) 669 { 708 std::unique_ptr<FunctionCompilation> parseAndCompile(VM& vm, Vector<uint8_t>& source, Memory* memory, FunctionInformation info, const Vector<FunctionInformation>& functions, unsigned optLevel) 709 { 710 auto result = std::make_unique<FunctionCompilation>(); 711 670 712 Procedure procedure; 671 B3IRGenerator context(memory, procedure );672 FunctionParser<B3IRGenerator> parser(context, source, info );713 B3IRGenerator context(memory, procedure, result->unlinkedCalls); 714 FunctionParser<B3IRGenerator> parser(context, source, info, functions); 673 715 if (!parser.parse()) 674 716 RELEASE_ASSERT_NOT_REACHED(); … … 680 722 if (verbose) 681 723 dataLog("Post SSA: ", procedure); 682 auto result = std::make_unique<FunctionCompilation>();683 724 684 725 result->code = std::make_unique<Compilation>(vm, procedure, optLevel); -
trunk/Source/JavaScriptCore/wasm/WASMB3IRGenerator.h
r207453 r207671 38 38 class Memory; 39 39 40 std::unique_ptr<FunctionCompilation> parseAndCompile(VM&, Vector<uint8_t>&, Memory*, FunctionInformation, unsigned optLevel = 1);40 std::unique_ptr<FunctionCompilation> parseAndCompile(VM&, Vector<uint8_t>&, Memory*, FunctionInformation, const Vector<FunctionInformation>&, unsigned optLevel = 1); 41 41 42 42 } } // namespace JSC::WASM -
trunk/Source/JavaScriptCore/wasm/WASMCallingConvention.cpp
r205552 r207671 38 38 static std::once_flag staticJSCCallingConventionFlag; 39 39 std::call_once(staticJSCCallingConventionFlag, [] () { 40 staticJSCCallingConvention.construct(Vector< GPRReg>(), RegisterSet::calleeSaveRegisters());40 staticJSCCallingConvention.construct(Vector<Reg>(), Vector<Reg>(), RegisterSet::calleeSaveRegisters()); 41 41 }); 42 42 … … 44 44 } 45 45 46 const WASMCallingConvention& wasmCallingConvention() 47 { 48 static LazyNeverDestroyed<JSCCallingConvention> staticWASMCallingConvention; 49 static std::once_flag staticWASMCallingConventionFlag; 50 std::call_once(staticWASMCallingConventionFlag, [] () { 51 Vector<Reg> gprArgumentRegisters(GPRInfo::numberOfArgumentRegisters); 52 for (unsigned i = 0; i < GPRInfo::numberOfArgumentRegisters; ++i) 53 gprArgumentRegisters[i] = GPRInfo::toArgumentRegister(i); 54 55 Vector<Reg> fprArgumentRegisters(FPRInfo::numberOfArgumentRegisters); 56 for (unsigned i = 0; i < FPRInfo::numberOfArgumentRegisters; ++i) 57 fprArgumentRegisters[i] = FPRInfo::toArgumentRegister(i); 58 59 staticWASMCallingConvention.construct(WTFMove(gprArgumentRegisters), WTFMove(fprArgumentRegisters), RegisterSet::calleeSaveRegisters()); 60 }); 61 62 return staticWASMCallingConvention; 63 } 64 46 65 } } // namespace JSC::WASM 47 66 -
trunk/Source/JavaScriptCore/wasm/WASMCallingConvention.h
r207453 r207671 49 49 class CallingConvention { 50 50 public: 51 CallingConvention(Vector<GPRReg>&& registerArguments, RegisterSet&& calleeSaveRegisters) 52 : m_registerArguments(registerArguments) 51 CallingConvention(Vector<Reg>&& gprArgs, Vector<Reg>&& fprArgs, RegisterSet&& calleeSaveRegisters) 52 : m_gprArgs(gprArgs) 53 , m_fprArgs(fprArgs) 53 54 , m_calleeSaveRegisters(calleeSaveRegisters) 54 55 { 55 56 } 56 57 58 private: 59 B3::ValueRep marshallArgumentImpl(Vector<Reg> regArgs, B3::Type type, size_t& count, size_t& stackOffset) const 60 { 61 if (count < regArgs.size()) 62 return B3::ValueRep::reg(regArgs[count++]); 63 64 count++; 65 B3::ValueRep result = B3::ValueRep::stackArgument(stackOffset); 66 stackOffset = updateOffset(stackOffset, type); 67 return result; 68 } 69 70 B3::ValueRep marshallArgument(B3::Type type, size_t& gpArgumentCount, size_t& fpArgumentCount, size_t& stackOffset) const 71 { 72 switch (type) { 73 case B3::Int32: 74 case B3::Int64: 75 return marshallArgumentImpl(m_gprArgs, type, gpArgumentCount, stackOffset); 76 case B3::Float: 77 case B3::Double: 78 return marshallArgumentImpl(m_fprArgs, type, fpArgumentCount, stackOffset); 79 case Void: 80 break; 81 } 82 RELEASE_ASSERT_NOT_REACHED(); 83 } 84 85 public: 57 86 template<typename Functor> 58 void iterate(const Vector<Type>& argumentTypes, B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, const Functor& functor) const87 void loadArguments(const Vector<Type>& argumentTypes, B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, const Functor& functor) const 59 88 { 60 unsigned currentOffset = headerSize;61 89 B3::Value* framePointer = block->appendNew<B3::Value>(proc, B3::FramePointer, origin); 62 90 63 for (unsigned i = 0; i < argumentTypes.size(); ++i) { 91 size_t gpArgumentCount = 0; 92 size_t fpArgumentCount = 0; 93 size_t stackOffset = headerSize; 94 95 for (size_t i = 0; i < argumentTypes.size(); ++i) { 96 B3::Type type = toB3Type(argumentTypes[i]); 64 97 B3::Value* argument; 65 if (i < m_registerArguments.size()) 66 argument = block->appendNew<B3::ArgumentRegValue>(proc, origin, m_registerArguments[i]); 67 else { 98 B3::ValueRep rep = marshallArgument(type, gpArgumentCount, fpArgumentCount, stackOffset); 99 if (rep.isReg()) { 100 argument = block->appendNew<B3::ArgumentRegValue>(proc, origin, rep.reg()); 101 if (type == B3::Int32) 102 argument = block->appendNew<B3::Value>(proc, B3::Trunc, origin, argument); 103 // FIXME: How do I get a float from a FPR? We don't support floating points yet so it's not a big deal... yet. 104 // see: https://bugs.webkit.org/show_bug.cgi?id=163770 105 } else { 106 ASSERT(rep.isStackArgument()); 68 107 B3::Value* address = block->appendNew<B3::Value>(proc, B3::Add, origin, framePointer, 69 block->appendNew<B3::Const64Value>(proc, origin, currentOffset)); 70 argument = block->appendNew<B3::MemoryValue>(proc, B3::Load, toB3Type(argumentTypes[i]), origin, address); 71 currentOffset = updateOffset(currentOffset, toB3Type(argumentTypes[i])); 108 block->appendNew<B3::Const64Value>(proc, origin, rep.offsetFromSP())); 109 argument = block->appendNew<B3::MemoryValue>(proc, B3::Load, type, origin, address); 72 110 } 73 111 functor(argument, i); … … 75 113 } 76 114 115 // It's expected that the pachpointFunctor sets the generator for the call operation. 77 116 template<typename Functor> 78 B3::Value* setupCall(B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, MacroAssemblerCodePtr target,const Vector<B3::Value*>& arguments, B3::Type returnType, const Functor& patchpointFunctor) const117 B3::Value* setupCall(B3::Procedure& proc, B3::BasicBlock* block, B3::Origin origin, const Vector<B3::Value*>& arguments, B3::Type returnType, const Functor& patchpointFunctor) const 79 118 { 80 size_t stackArgumentCount = arguments.size() < m_registerArguments.size() ? 0 : arguments.size() - m_registerArguments.size(); 81 unsigned offset = headerSize - sizeof(CallerFrameAndPC); 119 size_t gpArgumentCount = 0; 120 size_t fpArgumentCount = 0; 121 size_t stackOffset = headerSize - sizeof(CallerFrameAndPC); 82 122 83 proc.requestCallArgAreaSizeInBytes(WTF::roundUpToMultipleOf(stackAlignmentBytes(), headerSize + (stackArgumentCount * sizeof(Register))));84 123 Vector<B3::ConstrainedValue> constrainedArguments; 85 for (unsigned i = 0; i < arguments.size(); ++i) { 86 B3::ValueRep rep; 87 if (i < m_registerArguments.size()) 88 rep = B3::ValueRep::reg(m_registerArguments[i]); 89 else 90 rep = B3::ValueRep::stackArgument(offset); 91 constrainedArguments.append(B3::ConstrainedValue(arguments[i], rep)); 92 offset = updateOffset(offset, arguments[i]->type()); 124 for (B3::Value* argument : arguments) { 125 B3::ValueRep rep = marshallArgument(argument->type(), gpArgumentCount, fpArgumentCount, stackOffset); 126 constrainedArguments.append(B3::ConstrainedValue(argument, rep)); 93 127 } 94 128 129 proc.requestCallArgAreaSizeInBytes(WTF::roundUpToMultipleOf(stackAlignmentBytes(), stackOffset)); 130 95 131 B3::PatchpointValue* patchpoint = block->appendNew<B3::PatchpointValue>(proc, returnType, origin); 132 patchpoint->clobberEarly(RegisterSet::macroScratchRegisters()); 133 patchpoint->clobberLate(RegisterSet::volatileRegistersForJSCall()); 96 134 patchpoint->appendVector(constrainedArguments); 97 135 patchpointFunctor(patchpoint); 98 patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {99 AllowMacroScratchRegisterUsage allowScratch(jit);100 101 CCallHelpers::Call call = jit.call();102 jit.addLinkTask([=] (LinkBuffer& linkBuffer) {103 linkBuffer.link(call, FunctionPtr(target.executableAddress()));104 });105 });106 136 107 137 if (returnType == B3::Void) … … 112 142 } 113 143 114 const Vector<GPRReg> m_registerArguments; 144 const Vector<Reg> m_gprArgs; 145 const Vector<Reg> m_fprArgs; 115 146 const RegisterSet m_calleeSaveRegisters; 116 147 const RegisterSet m_callerSaveRegisters; … … 125 156 typedef CallingConvention<jscHeaderSize, nextJSCOffset> JSCCallingConvention; 126 157 158 typedef JSCCallingConvention WASMCallingConvention; 159 127 160 const JSCCallingConvention& jscCallingConvention(); 161 const WASMCallingConvention& wasmCallingConvention(); 128 162 129 163 } } // namespace JSC::WASM -
trunk/Source/JavaScriptCore/wasm/WASMFormat.h
r207453 r207671 47 47 #include "B3Compilation.h" 48 48 #include "B3Type.h" 49 #include "CodeLocation.h" 49 50 #include <wtf/Vector.h> 50 51 #include <wtf/text/WTFString.h> … … 128 129 }; 129 130 131 struct UnlinkedCall { 132 CodeLocationCall callLocation; 133 size_t functionIndex; 134 }; 135 130 136 struct FunctionCompilation { 137 Vector<UnlinkedCall> unlinkedCalls; 131 138 std::unique_ptr<B3::Compilation> code; 132 139 std::unique_ptr<B3::Compilation> jsEntryPoint; -
trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h
r207453 r207671 45 45 typedef typename Context::ControlType ControlType; 46 46 47 FunctionParser(Context&, const Vector<uint8_t>& sourceBuffer, const FunctionInformation& );47 FunctionParser(Context&, const Vector<uint8_t>& sourceBuffer, const FunctionInformation&, const Vector<FunctionInformation>& functions); 48 48 49 49 bool WARN_UNUSED_RETURN parse(); … … 61 61 Vector<ControlType> m_controlStack; 62 62 const Signature& m_signature; 63 const Vector<FunctionInformation>& m_functions; 63 64 unsigned m_unreachableBlocks { 0 }; 64 65 }; 65 66 66 67 template<typename Context> 67 FunctionParser<Context>::FunctionParser(Context& context, const Vector<uint8_t>& sourceBuffer, const FunctionInformation& info )68 FunctionParser<Context>::FunctionParser(Context& context, const Vector<uint8_t>& sourceBuffer, const FunctionInformation& info, const Vector<FunctionInformation>& functions) 68 69 : Parser(sourceBuffer, info.start, info.end) 69 70 , m_context(context) 70 71 , m_signature(*info.signature) 72 , m_functions(functions) 71 73 { 72 74 if (verbose) … … 102 104 while (true) { 103 105 uint8_t op; 104 if (!parseUInt7(op) || !isValidOpType(op)) 105 return false; 106 if (!parseUInt7(op) || !isValidOpType(op)) { 107 if (verbose) 108 WTF::dataLogLn("attempted to decode invalid op: ", RawPointer(reinterpret_cast<void*>(op)), " at offset: ", RawPointer(reinterpret_cast<void*>(m_offset))); 109 return false; 110 } 106 111 107 112 if (verbose) { … … 194 199 } 195 200 201 case OpType::I64Const: { 202 uint64_t constant; 203 if (!parseVarUInt64(constant)) 204 return false; 205 m_expressionStack.append(m_context.addConstant(I64, constant)); 206 return true; 207 } 208 196 209 case OpType::GetLocal: { 197 210 uint32_t index; … … 212 225 ExpressionType value = m_expressionStack.takeLast(); 213 226 return m_context.setLocal(index, value); 227 } 228 229 case OpType::Call: { 230 uint32_t functionIndex; 231 if (!parseVarUInt32(functionIndex)) 232 return false; 233 234 if (functionIndex >= m_functions.size()) 235 return false; 236 237 const FunctionInformation& info = m_functions[functionIndex]; 238 239 Vector<ExpressionType> args; 240 for (unsigned i = 0; i < info.signature->arguments.size(); ++i) 241 args.append(m_expressionStack.takeLast()); 242 243 ExpressionType result = Context::emptyExpression; 244 if (!m_context.addCall(functionIndex, info, args, result)) 245 return false; 246 247 if (result != Context::emptyExpression) 248 m_expressionStack.append(result); 249 250 return true; 214 251 } 215 252 … … 282 319 case OpType::Nop: 283 320 case OpType::Drop: 284 case OpType::I64Const:285 321 case OpType::F32Const: 286 322 case OpType::F64Const: … … 288 324 case OpType::GetGlobal: 289 325 case OpType::SetGlobal: 326 case OpType::CallIndirect: 290 327 // FIXME: Not yet implemented. 291 328 return false; -
trunk/Source/JavaScriptCore/wasm/WASMModuleParser.cpp
r207453 r207671 83 83 84 84 // Make sure we can read up to the section's size. 85 if (m_offset + sectionNameLength + maxLEBByteLength >= m_sourceLength)85 if (m_offset + sectionNameLength + WTF::LEBDecoder::max32BitLEBByteLength >= m_sourceLength) 86 86 return false; 87 87 -
trunk/Source/JavaScriptCore/wasm/WASMOps.h
r207453 r207671 43 43 macro(TeeLocal, 0x19, Oops) \ 44 44 macro(GetGlobal, 0xbb, Oops) \ 45 macro(SetGlobal, 0xbc, Oops) 45 macro(SetGlobal, 0xbc, Oops) \ 46 macro(Call, 0x16, Oops) \ 47 macro(CallIndirect, 0x17, Oops) 46 48 47 49 #define FOR_EACH_WASM_CONTROL_FLOW_OP(macro) \ -
trunk/Source/JavaScriptCore/wasm/WASMParser.h
r206794 r207671 47 47 bool WARN_UNUSED_RETURN parseUInt7(uint8_t& result); 48 48 bool WARN_UNUSED_RETURN parseUInt32(uint32_t& result); 49 bool WARN_UNUSED_RETURN parseVarUInt32(uint32_t& result) { return decodeUInt32(m_source.data(), m_sourceLength, m_offset, result); } 49 bool WARN_UNUSED_RETURN parseVarUInt32(uint32_t& result) { return WTF::LEBDecoder::decodeUInt32(m_source.data(), m_sourceLength, m_offset, result); } 50 bool WARN_UNUSED_RETURN parseVarUInt64(uint64_t& result) { return WTF::LEBDecoder::decodeUInt64(m_source.data(), m_sourceLength, m_offset, result); } 50 51 51 52 -
trunk/Source/JavaScriptCore/wasm/WASMPlan.cpp
r207453 r207671 55 55 if (verbose) 56 56 dataLogLn("Processing funcion starting at: ", info.start, " and ending at: ", info.end); 57 result.append(parseAndCompile(vm, source, moduleParser.memory().get(), info ));57 result.append(parseAndCompile(vm, source, moduleParser.memory().get(), info, moduleParser.functionInformation())); 58 58 } 59 60 // Patch the call sites for each function. 61 for (std::unique_ptr<FunctionCompilation>& functionPtr : result) { 62 FunctionCompilation* function = functionPtr.get(); 63 for (auto& call : function->unlinkedCalls) 64 MacroAssembler::repatchCall(call.callLocation, CodeLocationLabel(result[call.functionIndex]->code->code())); 65 } 66 59 67 memory = WTFMove(moduleParser.memory()); 60 68 } -
trunk/Source/WTF/ChangeLog
r207653 r207671 1 2016-10-20 Keith Miller <keith_miller@apple.com> 2 3 Add support for WASM calls 4 https://bugs.webkit.org/show_bug.cgi?id=161727 5 6 Reviewed by Filip Pizlo and Michael Saboff. 7 8 Added a new decodeUInt64. Also, added WTF::LEBDecoder namespace. 9 10 * wtf/LEBDecoder.h: 11 (WTF::LEBDecoder::decodeUInt): 12 (WTF::LEBDecoder::decodeUInt32): 13 (WTF::LEBDecoder::decodeUInt64): 14 (WTF::LEBDecoder::decodeInt32): 15 (decodeUInt32): Deleted. 16 (decodeInt32): Deleted. 17 1 18 2016-10-20 Filip Pizlo <fpizlo@apple.com> 2 19 -
trunk/Source/WTF/wtf/LEBDecoder.h
r204484 r207671 33 33 // LEB format. 34 34 35 const size_t maxLEBByteLength = 5; 35 namespace WTF { namespace LEBDecoder { 36 36 37 inline bool WARN_UNUSED_RETURN decodeUInt32(const uint8_t* bytes, size_t length, size_t& offset, uint32_t& result) 37 template<size_t maxByteLength, typename T> 38 inline bool WARN_UNUSED_RETURN decodeUInt(const uint8_t* bytes, size_t length, size_t& offset, T& result) 38 39 { 39 40 ASSERT(length > offset); 40 41 result = 0; 41 42 unsigned shift = 0; 42 size_t last = std::min(max LEBByteLength, length - offset - 1);43 size_t last = std::min(maxByteLength, length - offset - 1); 43 44 for (unsigned i = 0; true; ++i) { 44 45 uint8_t byte = bytes[offset++]; … … 54 55 } 55 56 57 const size_t max32BitLEBByteLength = 5; 58 const size_t max64BitLEBByteLength = 10; 59 60 inline bool WARN_UNUSED_RETURN decodeUInt32(const uint8_t* bytes, size_t length, size_t& offset, uint32_t& result) 61 { 62 return decodeUInt<max32BitLEBByteLength, uint32_t>(bytes, length, offset, result); 63 } 64 65 inline bool WARN_UNUSED_RETURN decodeUInt64(const uint8_t* bytes, size_t length, size_t& offset, uint64_t& result) 66 { 67 return decodeUInt<max64BitLEBByteLength, uint64_t>(bytes, length, offset, result); 68 } 69 56 70 inline bool WARN_UNUSED_RETURN decodeInt32(const uint8_t* bytes, size_t length, size_t& offset, int32_t& result) 57 71 { … … 59 73 result = 0; 60 74 unsigned shift = 0; 61 size_t last = std::min(max LEBByteLength, length - offset - 1);75 size_t last = std::min(max32BitLEBByteLength, length - offset - 1); 62 76 uint8_t byte; 63 77 for (unsigned i = 0; true; ++i) { … … 75 89 return true; 76 90 } 91 92 } } // WTF::LEBDecoder
Note: See TracChangeset
for help on using the changeset viewer.