Changeset 287801 in webkit
- Timestamp:
- Jan 7, 2022, 5:57:04 PM (5 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 1 added
- 12 edited
-
ChangeLog (modified) (1 diff)
-
JavaScriptCore.xcodeproj/project.pbxproj (modified) (4 diffs)
-
b3/air/AirAllocateRegistersAndStackAndGenerateCode.cpp (modified) (5 diffs)
-
wasm/WasmAirIRGenerator.cpp (modified) (40 diffs)
-
wasm/WasmB3IRGenerator.cpp (modified) (10 diffs)
-
wasm/WasmB3IRGenerator.h (modified) (1 diff)
-
wasm/WasmBBQPlan.cpp (modified) (2 diffs)
-
wasm/WasmIRGeneratorHelpers.h (added)
-
wasm/WasmLLIntGenerator.cpp (modified) (1 diff)
-
wasm/WasmModuleInformation.h (modified) (1 diff)
-
wasm/WasmOMGPlan.cpp (modified) (1 diff)
-
wasm/WasmOSREntryPlan.cpp (modified) (1 diff)
-
wasm/WasmStreamingParser.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r287800 r287801 1 2022-01-07 Saam Barati <sbarati@apple.com> 2 3 Add support for Wasm exceptions in the Air generator 4 https://bugs.webkit.org/show_bug.cgi?id=231211 5 <rdar://problem/84132861> 6 7 Reviewed by Filip Pizlo. 8 9 This patch adds support to Air for Wasm exceptions. The implementation 10 is very similar to how we implement it in the B3 Wasm tier. This patch 11 shares code with the B3 tier where it can. 12 13 This patch also fixes a bug where you the early clobbered registers 14 of a patchpoint could prevent the prior instruction from register allocating. 15 For example, you can have the instructions I1, I2. Where I2 clobbers the 16 entire register file. It doesn't mean I1 shouldn't be able to allocate 17 registers. Instead, the clobber should occur after I1 executes. This patch 18 fixes the issue. 19 20 * JavaScriptCore.xcodeproj/project.pbxproj: 21 * b3/air/AirAllocateRegistersAndStackAndGenerateCode.cpp: 22 (JSC::B3::Air::GenerateAndAllocateRegisters::generate): 23 * wasm/WasmAirIRGenerator.cpp: 24 (JSC::Wasm::AirIRGenerator::ControlData::ControlData): 25 (JSC::Wasm::AirIRGenerator::ControlData::isTry): 26 (JSC::Wasm::AirIRGenerator::ControlData::isCatch): 27 (JSC::Wasm::AirIRGenerator::ControlData::convertTryToCatch): 28 (JSC::Wasm::AirIRGenerator::ControlData::convertTryToCatchAll): 29 (JSC::Wasm::AirIRGenerator::ControlData::tryStart const): 30 (JSC::Wasm::AirIRGenerator::ControlData::tryEnd const): 31 (JSC::Wasm::AirIRGenerator::ControlData::tryDepth const): 32 (JSC::Wasm::AirIRGenerator::ControlData::catchKind const): 33 (JSC::Wasm::AirIRGenerator::ControlData::exception const): 34 (JSC::Wasm::AirIRGenerator::emitCallPatchpoint): 35 (JSC::Wasm::AirIRGenerator::addStackMap): 36 (JSC::Wasm::AirIRGenerator::takeStackmaps): 37 (JSC::Wasm::AirIRGenerator::takeExceptionHandlers): 38 (JSC::Wasm::AirIRGenerator::newTmp): 39 (JSC::Wasm::AirIRGenerator::emitPatchpoint): 40 (JSC::Wasm::AirIRGenerator::emitLoad): 41 (JSC::Wasm::AirIRGenerator::AirIRGenerator): 42 (JSC::Wasm::AirIRGenerator::finalizeEntrypoints): 43 (JSC::Wasm::AirIRGenerator::forEachLiveValue): 44 (JSC::Wasm::AirIRGenerator::emitLoopTierUpCheck): 45 (JSC::Wasm::AirIRGenerator::addTry): 46 (JSC::Wasm::AirIRGenerator::addCatch): 47 (JSC::Wasm::AirIRGenerator::addCatchAll): 48 (JSC::Wasm::AirIRGenerator::addCatchToUnreachable): 49 (JSC::Wasm::AirIRGenerator::addCatchAllToUnreachable): 50 (JSC::Wasm::AirIRGenerator::emitCatchImpl): 51 (JSC::Wasm::AirIRGenerator::addDelegate): 52 (JSC::Wasm::AirIRGenerator::addDelegateToUnreachable): 53 (JSC::Wasm::AirIRGenerator::addThrow): 54 (JSC::Wasm::AirIRGenerator::addRethrow): 55 (JSC::Wasm::AirIRGenerator::addEndToUnreachable): 56 (JSC::Wasm::AirIRGenerator::addCall): 57 (JSC::Wasm::AirIRGenerator::emitIndirectCall): 58 (JSC::Wasm::parseAndCompileAir): 59 (JSC::Wasm::AirIRGenerator::preparePatchpointForExceptions): 60 * wasm/WasmB3IRGenerator.cpp: 61 (JSC::Wasm::B3IRGenerator::insertEntrySwitch): 62 (JSC::Wasm::B3IRGenerator::emitCatchImpl): 63 (JSC::Wasm::B3IRGenerator::addThrow): 64 (JSC::Wasm::B3IRGenerator::addRethrow): 65 (JSC::Wasm::PatchpointExceptionHandle::generate const): Deleted. 66 (JSC::Wasm::buildEntryBufferForCatch): Deleted. 67 (JSC::Wasm::computeExceptionHandlerLocations): Deleted. 68 * wasm/WasmB3IRGenerator.h: 69 * wasm/WasmBBQPlan.cpp: 70 (JSC::Wasm::BBQPlan::compileFunction): 71 * wasm/WasmIRGeneratorHelpers.h: Added. 72 (JSC::Wasm::PatchpointExceptionHandle::generate const): 73 (JSC::Wasm::computeExceptionHandlerLocations): 74 (JSC::Wasm::emitRethrowImpl): 75 (JSC::Wasm::emitThrowImpl): 76 (JSC::Wasm::buildEntryBufferForCatch): 77 (JSC::Wasm::emitCatchPrologueShared): 78 * wasm/WasmLLIntGenerator.cpp: 79 (JSC::Wasm::LLIntGenerator::finalize): 80 * wasm/WasmModuleInformation.h: 81 * wasm/WasmOMGPlan.cpp: 82 * wasm/WasmOSREntryPlan.cpp: 83 * wasm/WasmStreamingParser.cpp: 84 (JSC::Wasm::StreamingParser::parseCodeSectionSize): 85 1 86 2022-01-07 Alexey Shvayka <ashvayka@apple.com> 2 87 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r287582 r287801 901 901 52EED7942492B870008F4C93 /* FunctionAllowlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 52EED7932492B868008F4C93 /* FunctionAllowlist.h */; }; 902 902 52F6C35E1E71EB080081F4CC /* WebAssemblyWrapperFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 52F6C35C1E71EB080081F4CC /* WebAssemblyWrapperFunction.h */; }; 903 52FDABC32788076B00C15B59 /* WasmIRGeneratorHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 52FDABC22788076900C15B59 /* WasmIRGeneratorHelpers.h */; }; 903 904 530A66B91FA3E78B0026A545 /* UnifiedSource3-mm.mm in Sources */ = {isa = PBXBuildFile; fileRef = 530A66B11FA3E77A0026A545 /* UnifiedSource3-mm.mm */; }; 904 905 530A66BA1FA3E78B0026A545 /* UnifiedSource4-mm.mm in Sources */ = {isa = PBXBuildFile; fileRef = 530A66B81FA3E77E0026A545 /* UnifiedSource4-mm.mm */; }; … … 3761 3762 52F6C35B1E71EB080081F4CC /* WebAssemblyWrapperFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebAssemblyWrapperFunction.cpp; path = js/WebAssemblyWrapperFunction.cpp; sourceTree = "<group>"; }; 3762 3763 52F6C35C1E71EB080081F4CC /* WebAssemblyWrapperFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebAssemblyWrapperFunction.h; path = js/WebAssemblyWrapperFunction.h; sourceTree = "<group>"; }; 3764 52FDABC22788076900C15B59 /* WasmIRGeneratorHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WasmIRGeneratorHelpers.h; sourceTree = "<group>"; }; 3763 3765 5300740C22DD6F6600B9ACB3 /* JSFinalizationRegistry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSFinalizationRegistry.cpp; sourceTree = "<group>"; }; 3764 3766 530A63401FA3E31C0026A545 /* SourcesCocoa.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SourcesCocoa.txt; sourceTree = "<group>"; }; … … 7306 7308 148521D526EAEBDF00CC1D1A /* WasmHandlerInfo.cpp */, 7307 7309 148521D726EAEBFE00CC1D1A /* WasmHandlerInfo.h */, 7310 52FDABC22788076900C15B59 /* WasmIRGeneratorHelpers.h */, 7308 7311 AD8FF3961EB5BD850087FF82 /* WasmIndexOrName.cpp */, 7309 7312 AD8FF3951EB5BD850087FF82 /* WasmIndexOrName.h */, … … 11161 11164 E393ADD81FE702D00022D681 /* WeakMapImplInlines.h in Headers */, 11162 11165 A7CA3AE617DA41AE006538AF /* WeakMapPrototype.h in Headers */, 11166 52FDABC32788076B00C15B59 /* WasmIRGeneratorHelpers.h in Headers */, 11163 11167 539930C822AD3B9A0051CDE2 /* WeakObjectRefConstructor.h in Headers */, 11164 11168 539BFBAE22AD3C3A0023F4C0 /* WeakObjectRefPrototype.h in Headers */, -
trunk/Source/JavaScriptCore/b3/air/AirAllocateRegistersAndStackAndGenerateCode.cpp
r280650 r287801 1 1 /* 2 * Copyright (C) 2019 Apple Inc. All rights reserved.2 * Copyright (C) 2019-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 613 613 614 614 RegisterSet clobberedRegisters; 615 RegisterSet earlyNextClobberedRegisters; 615 616 { 616 617 Inst* nextInst = block->get(instIndex + 1); … … 619 620 clobberedRegisters.merge(inst.extraClobberedRegs()); 620 621 if (nextInst && nextInst->kind.opcode == Patch) 621 clobberedRegisters.merge(nextInst->extraEarlyClobberedRegs());622 earlyNextClobberedRegisters.merge(nextInst->extraEarlyClobberedRegs()); 622 623 623 624 clobberedRegisters.filter(m_allowedRegisters); 624 625 clobberedRegisters.exclude(m_namedDefdRegs); 626 earlyNextClobberedRegisters.filter(m_allowedRegisters); 625 627 626 628 m_namedDefdRegs.merge(clobberedRegisters); … … 740 742 } 741 743 742 if (inst.isTerminal() && block->numSuccessors()) { 743 // By default, we spill everything between block boundaries. However, we have a small 744 // heuristic to pass along register state. We should eventually make this better. 745 // What we do now is if we have a successor with a single predecessor (us), and we 746 // haven't yet generated code for it, we give it our register state. If all our successors 747 // can take on our register state, we don't flush at the end of this block. 748 749 bool everySuccessorGetsOurRegisterState = true; 750 for (unsigned i = 0; i < block->numSuccessors(); ++i) { 751 BasicBlock* successor = block->successorBlock(i); 752 if (successor->numPredecessors() == 1 && !context.blockLabels[successor]->isSet()) 753 currentAllocationMap[successor] = currentAllocation; 754 else 755 everySuccessorGetsOurRegisterState = false; 756 } 757 if (!everySuccessorGetsOurRegisterState) { 758 for (Tmp tmp : m_liveness->liveAtTail(block)) { 759 if (tmp.isReg() && isDisallowedRegister(tmp.reg())) 760 continue; 761 if (Reg reg = m_map[tmp].reg) 762 flush(tmp, reg); 763 } 764 } 765 } 744 auto clobber = [&] (const RegisterSet& set) { 745 for (Reg reg : set) { 746 Tmp tmp(reg); 747 ASSERT(currentAllocation[reg] == tmp); 748 m_availableRegs[tmp.bank()].set(reg); 749 m_currentAllocation->at(reg) = Tmp(); 750 m_map[tmp].reg = Reg(); 751 } 752 }; 766 753 767 754 if (!inst.isTerminal()) { … … 771 758 ASSERT_UNUSED(jump, !jump.isSet()); 772 759 773 for (Reg reg : clobberedRegisters) { 774 Tmp tmp(reg); 775 ASSERT(currentAllocation[reg] == tmp); 776 m_availableRegs[tmp.bank()].set(reg); 777 m_currentAllocation->at(reg) = Tmp(); 778 m_map[tmp].reg = Reg(); 779 } 760 allocNamed(earlyNextClobberedRegisters, true); 761 clobber(clobberedRegisters); 762 clobber(earlyNextClobberedRegisters); 780 763 } else { 781 764 ASSERT(needsToGenerate); 765 766 clobber(clobberedRegisters); 767 ASSERT(earlyNextClobberedRegisters.isEmpty()); 768 769 if (block->numSuccessors()) { 770 // By default, we spill everything between block boundaries. However, we have a small 771 // heuristic to pass along register state. We should eventually make this better. 772 // What we do now is if we have a successor with a single predecessor (us), and we 773 // haven't yet generated code for it, we give it our register state. If all our successors 774 // can take on our register state, we don't flush at the end of this block. 775 776 777 bool everySuccessorGetsOurRegisterState = true; 778 for (unsigned i = 0; i < block->numSuccessors(); ++i) { 779 BasicBlock* successor = block->successorBlock(i); 780 if (successor->numPredecessors() == 1 && !context.blockLabels[successor]->isSet()) 781 currentAllocationMap[successor] = currentAllocation; 782 else 783 everySuccessorGetsOurRegisterState = false; 784 } 785 if (!everySuccessorGetsOurRegisterState) { 786 for (Tmp tmp : m_liveness->liveAtTail(block)) { 787 if (tmp.isReg() && isDisallowedRegister(tmp.reg())) 788 continue; 789 if (Reg reg = m_map[tmp].reg) 790 flush(tmp, reg); 791 } 792 } 793 } 794 782 795 if (inst.kind.opcode == Jump && block->successorBlock(0) == m_code.findNextBlock(block)) 783 796 needsToGenerate = false; -
trunk/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp
r287160 r287801 1 1 /* 2 * Copyright (C) 2019-202 1Apple Inc. All rights reserved.2 * Copyright (C) 2019-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 49 49 #include "WasmExceptionType.h" 50 50 #include "WasmFunctionParser.h" 51 #include "WasmIRGeneratorHelpers.h" 51 52 #include "WasmInstance.h" 52 53 #include "WasmMemory.h" … … 133 134 134 135 struct ControlData { 135 ControlData(B3::Origin origin, BlockSignature result, ResultList resultTmps, BlockType type, BasicBlock* continuation, BasicBlock* special = nullptr)136 ControlData(B3::Origin, BlockSignature result, ResultList resultTmps, BlockType type, BasicBlock* continuation, BasicBlock* special = nullptr) 136 137 : controlBlockType(type) 137 138 , continuation(continuation) … … 140 141 , returnType(result) 141 142 { 142 UNUSED_PARAM(origin); 143 } 144 145 ControlData(B3::Origin, BlockSignature result, ResultList resultTmps, BlockType type, BasicBlock* continuation, unsigned tryStart, unsigned tryDepth) 146 : controlBlockType(type) 147 , continuation(continuation) 148 , special(nullptr) 149 , results(resultTmps) 150 , returnType(result) 151 , m_tryStart(tryStart) 152 , m_tryCatchDepth(tryDepth) 153 { 143 154 } 144 155 … … 149 160 static bool isIf(const ControlData& control) { return control.blockType() == BlockType::If; } 150 161 static bool isTry(const ControlData& control) { return control.blockType() == BlockType::Try; } 151 static bool isCatch(const ControlData& control) { return control.blockType() == BlockType::Catch; }152 162 static bool isAnyCatch(const ControlData& control) { return control.blockType() == BlockType::Catch; } 163 static bool isCatch(const ControlData& control) { return isAnyCatch(control) && control.catchKind() == CatchKind::Catch; } 153 164 static bool isTopLevel(const ControlData& control) { return control.blockType() == BlockType::TopLevel; } 154 165 static bool isLoop(const ControlData& control) { return control.blockType() == BlockType::Loop; } … … 222 233 } 223 234 235 void convertTryToCatch(unsigned tryEndCallSiteIndex, TypedTmp exception) 236 { 237 ASSERT(blockType() == BlockType::Try); 238 controlBlockType = BlockType::Catch; 239 m_catchKind = CatchKind::Catch; 240 m_tryEnd = tryEndCallSiteIndex; 241 m_exception = exception; 242 } 243 244 void convertTryToCatchAll(unsigned tryEndCallSiteIndex, TypedTmp exception) 245 { 246 ASSERT(blockType() == BlockType::Try); 247 controlBlockType = BlockType::Catch; 248 m_catchKind = CatchKind::CatchAll; 249 m_tryEnd = tryEndCallSiteIndex; 250 m_exception = exception; 251 } 252 253 unsigned tryStart() const 254 { 255 ASSERT(controlBlockType == BlockType::Try || controlBlockType == BlockType::Catch); 256 return m_tryStart; 257 } 258 259 unsigned tryEnd() const 260 { 261 ASSERT(controlBlockType == BlockType::Catch); 262 return m_tryEnd; 263 } 264 265 unsigned tryDepth() const 266 { 267 ASSERT(controlBlockType == BlockType::Try || controlBlockType == BlockType::Catch); 268 return m_tryCatchDepth; 269 } 270 271 CatchKind catchKind() const 272 { 273 ASSERT(controlBlockType == BlockType::Catch); 274 return m_catchKind; 275 } 276 277 TypedTmp exception() const 278 { 279 ASSERT(controlBlockType == BlockType::Catch); 280 return m_exception; 281 } 282 224 283 private: 225 284 friend class AirIRGenerator; … … 229 288 ResultList results; 230 289 BlockSignature returnType; 290 unsigned m_tryStart; 291 unsigned m_tryEnd; 292 unsigned m_tryCatchDepth; 293 CatchKind m_catchKind; 294 TypedTmp m_exception; 231 295 }; 232 296 … … 260 324 261 325 AirIRGenerator(const ModuleInformation&, B3::Procedure&, InternalFunction*, Vector<UnlinkedWasmToWasmCall>&, MemoryMode, unsigned functionIndex, TierUpCount*, const Signature&); 326 327 void finalizeEntrypoints(); 262 328 263 329 PartialResult WARN_UNUSED_RETURN addArguments(const Signature&); … … 350 416 PartialResult WARN_UNUSED_RETURN addUnreachable(); 351 417 PartialResult WARN_UNUSED_RETURN emitIndirectCall(TypedTmp calleeInstance, ExpressionType calleeCode, const Signature&, const Vector<ExpressionType>& args, ResultList&); 352 B3::PatchpointValue* WARN_UNUSED_RETURN emitCallPatchpoint(BasicBlock*, const Signature&, const ResultList& results, const Vector<TypedTmp>& args, Vector<ConstrainedTmp>&&extraArgs = { });418 std::pair<B3::PatchpointValue*, PatchpointExceptionHandle> WARN_UNUSED_RETURN emitCallPatchpoint(BasicBlock*, const Signature&, const ResultList& results, const Vector<TypedTmp>& args, Vector<ConstrainedTmp> extraArgs = { }); 353 419 354 420 PartialResult addShift(Type, B3::Air::Opcode, ExpressionType value, ExpressionType shift, ExpressionType& result); … … 362 428 void didPopValueFromStack() { } 363 429 430 Tmp emitCatchImpl(CatchKind, ControlType&, unsigned exceptionIndex = 0); 431 template <size_t inlineCapacity> 432 PatchpointExceptionHandle preparePatchpointForExceptions(B3::PatchpointValue*, Vector<ConstrainedTmp, inlineCapacity>& args); 433 364 434 const Bag<B3::PatchpointValue*>& patchpoints() const 365 435 { 366 436 return m_patchpoints; 437 } 438 439 void addStackMap(unsigned callSiteIndex, StackMap&& stackmap) 440 { 441 m_stackmaps.add(CallSiteIndex(callSiteIndex), WTFMove(stackmap)); 442 } 443 444 StackMaps&& takeStackmaps() 445 { 446 return WTFMove(m_stackmaps); 447 } 448 449 Vector<UnlinkedHandlerInfo>&& takeExceptionHandlers() 450 { 451 return WTFMove(m_exceptionHandlers); 367 452 } 368 453 … … 418 503 Tmp newTmp(B3::Bank bank) 419 504 { 420 switch (bank) {421 case B3::GP:422 if (m_freeGPs.size())423 return m_freeGPs.takeLast();424 break;425 case B3::FP:426 if (m_freeFPs.size())427 return m_freeFPs.takeLast();428 break;429 }430 505 return m_code.newTmp(bank); 431 506 } … … 497 572 } 498 573 574 template <size_t inlineSize> 575 void emitPatchpoint(BasicBlock* basicBlock, B3::PatchpointValue* patch, Tmp result, Vector<ConstrainedTmp, inlineSize>&& args) 576 { 577 emitPatchpoint(basicBlock, patch, Vector<Tmp, 8> { result }, WTFMove(args)); 578 } 579 499 580 template <typename ResultTmpType, size_t inlineSize> 500 void emitPatchpoint(BasicBlock* basicBlock, B3::PatchpointValue* patch, const Vector<ResultTmpType, 8>& results, Vector<ConstrainedTmp, inlineSize>&& args)581 void emitPatchpoint(BasicBlock* basicBlock, B3::PatchpointValue* patch, const Vector<ResultTmpType, 8>& results, Vector<ConstrainedTmp, inlineSize>&& args) 501 582 { 502 583 if (!m_patchpointSpecial) … … 550 631 patch->append(dummyValue, tmp.rep); 551 632 switch (tmp.rep.kind()) { 552 case B3::ValueRep::ColdAny: // B3::Value propagates ColdAny information and later Air will allocate appropriate stack. 633 // B3::Value propagates (Late)ColdAny information and later Air will allocate appropriate stack. 634 case B3::ValueRep::ColdAny: 635 case B3::ValueRep::LateColdAny: 553 636 case B3::ValueRep::SomeRegister: 554 637 inst.args.append(tmp.tmp); … … 560 643 break; 561 644 case B3::ValueRep::StackArgument: { 562 ASSERT(!patch->effects.terminal);563 645 Arg arg = Arg::callArg(tmp.rep.offsetFromSP()); 564 646 append(basicBlock, tmp.tmp.isGP() ? Move : MoveDouble, tmp.tmp, arg); … … 690 772 } 691 773 774 void emitLoad(B3::Air::Opcode op, B3::Type type, Tmp base, size_t offset, Tmp result) 775 { 776 if (Arg::isValidAddrForm(offset, B3::widthForType(type))) 777 append(op, Arg::addr(base, offset), result); 778 else { 779 auto temp2 = g64(); 780 append(Move, Arg::bigImm(offset), temp2); 781 append(Add64, temp2, base, temp2); 782 append(op, Arg::addr(temp2), result); 783 } 784 } 785 786 void emitLoad(Tmp base, size_t offset, TypedTmp result) 787 { 788 emitLoad(moveOpForValueType(result.type()), toB3Type(result.type()), base, offset, result.tmp()); 789 } 790 692 791 void emitThrowException(CCallHelpers&, ExceptionType); 693 792 … … 738 837 } 739 838 839 template <typename Function> 840 void forEachLiveValue(Function); 841 740 842 FunctionParser<AirIRGenerator>* m_parser { nullptr }; 741 843 const ModuleInformation& m_info; … … 749 851 BasicBlock* m_currentBlock { nullptr }; 750 852 BasicBlock* m_rootBlock { nullptr }; 853 BasicBlock* m_mainEntrypointStart { nullptr }; 751 854 Vector<TypedTmp> m_locals; 752 855 Vector<UnlinkedWasmToWasmCall>& m_unlinkedWasmToWasmCalls; // List each call site and the function index whose address it should be patched with. … … 754 857 GPRReg m_boundsCheckingSizeGPR { InvalidGPRReg }; 755 858 GPRReg m_wasmContextInstanceGPR { InvalidGPRReg }; 859 GPRReg m_prologueWasmContextGPR { InvalidGPRReg }; 756 860 bool m_makesCalls { false }; 757 758 Vector<Tmp, 8> m_freeGPs;759 Vector<Tmp, 8> m_freeFPs;760 861 761 862 HashMap<BlockSignature, B3::Type> m_tupleMap; … … 775 876 776 877 B3::PatchpointSpecial* m_patchpointSpecial { nullptr }; 878 879 RefPtr<B3::Air::PrologueGenerator> m_prologueGenerator; 880 881 Vector<BasicBlock*> m_catchEntrypoints; 882 883 Checked<unsigned> m_tryCatchDepth { 0 }; 884 Checked<unsigned> m_callSiteIndex { 0 }; 885 StackMaps m_stackmaps; 886 Vector<UnlinkedHandlerInfo> m_exceptionHandlers; 777 887 }; 778 888 … … 848 958 } 849 959 850 m_code.setNumEntrypoints(1); 851 852 GPRReg contextInstance = Context::useFastTLS() ? wasmCallingConvention().prologueScratchGPRs[1] : m_wasmContextInstanceGPR; 853 854 Ref<B3::Air::PrologueGenerator> prologueGenerator = createSharedTask<B3::Air::PrologueGeneratorFunction>([=] (CCallHelpers& jit, B3::Air::Code& code) { 960 m_prologueWasmContextGPR = Context::useFastTLS() ? wasmCallingConvention().prologueScratchGPRs[1] : m_wasmContextInstanceGPR; 961 962 m_prologueGenerator = createSharedTask<B3::Air::PrologueGeneratorFunction>([=] (CCallHelpers& jit, B3::Air::Code& code) { 855 963 AllowMacroScratchRegisterUsage allowScratch(jit); 856 964 code.emitDefaultPrologue(jit); … … 892 1000 893 1001 if (Context::useFastTLS()) 894 jit.loadWasmContextInstance( contextInstance);1002 jit.loadWasmContextInstance(m_prologueWasmContextGPR); 895 1003 896 1004 jit.addPtr(CCallHelpers::TrustedImm32(-checkSize), GPRInfo::callFrameRegister, scratch); … … 898 1006 if (UNLIKELY(needUnderflowCheck)) 899 1007 overflow.append(jit.branchPtr(CCallHelpers::Above, scratch, GPRInfo::callFrameRegister)); 900 overflow.append(jit.branchPtr(CCallHelpers::Below, scratch, CCallHelpers::Address( contextInstance, Instance::offsetOfCachedStackLimit())));1008 overflow.append(jit.branchPtr(CCallHelpers::Below, scratch, CCallHelpers::Address(m_prologueWasmContextGPR, Instance::offsetOfCachedStackLimit()))); 901 1009 jit.addLinkTask([overflow] (LinkBuffer& linkBuffer) { 902 1010 linkBuffer.link(overflow, CodeLocationLabel<JITThunkPtrTag>(Thunks::singleton().stub(throwStackOverflowFromWasmThunkGenerator).code())); … … 904 1012 } else if (m_usesInstanceValue && Context::useFastTLS()) { 905 1013 // No overflow check is needed, but the instance values still needs to be correct. 906 jit.loadWasmContextInstance( contextInstance);1014 jit.loadWasmContextInstance(m_prologueWasmContextGPR); 907 1015 } 908 } 909 }); 910 911 m_code.setPrologueForEntrypoint(0, WTFMove(prologueGenerator)); 1016 1017 if (m_catchEntrypoints.size()) { 1018 GPRReg scratch = wasmCallingConvention().prologueScratchGPRs[0]; 1019 jit.loadPtr(CCallHelpers::Address(m_prologueWasmContextGPR, Instance::offsetOfOwner()), scratch); 1020 jit.store64(scratch, CCallHelpers::Address(GPRInfo::callFrameRegister, CallFrameSlot::thisArgument * sizeof(Register))); 1021 } 1022 } 1023 }); 912 1024 913 1025 if (Context::useFastTLS()) { 914 1026 m_instanceValue = g64(); 915 1027 // FIXME: Would be nice to only do this if we use instance value. 916 append(Move, Tmp( contextInstance), m_instanceValue);1028 append(Move, Tmp(m_prologueWasmContextGPR), m_instanceValue); 917 1029 } else 918 m_instanceValue = { Tmp(contextInstance), Types::I64 }; 1030 m_instanceValue = { Tmp(m_prologueWasmContextGPR), Types::I64 }; 1031 1032 append(EntrySwitch); 1033 m_mainEntrypointStart = m_code.addBlock(); 1034 m_currentBlock = m_mainEntrypointStart; 919 1035 920 1036 ASSERT(!m_locals.size()); … … 955 1071 } 956 1072 1073 void AirIRGenerator::finalizeEntrypoints() 1074 { 1075 unsigned numEntrypoints = 1 + m_catchEntrypoints.size(); 1076 m_proc.setNumEntrypoints(numEntrypoints); 1077 m_code.setPrologueForEntrypoint(0, Ref<B3::Air::PrologueGenerator>(*m_prologueGenerator)); 1078 1079 if (m_catchEntrypoints.size()) { 1080 Ref<B3::Air::PrologueGenerator> catchPrologueGenerator = createSharedTask<B3::Air::PrologueGeneratorFunction>([this] (CCallHelpers& jit, B3::Air::Code& code) { 1081 AllowMacroScratchRegisterUsage allowScratch(jit); 1082 emitCatchPrologueShared(code, jit); 1083 1084 if (Context::useFastTLS()) { 1085 // Shared prologue expects this in this register when entering the function using fast TLS. 1086 jit.loadWasmContextInstance(m_prologueWasmContextGPR); 1087 } 1088 }); 1089 1090 for (unsigned i = 0; i < m_catchEntrypoints.size(); ++i) 1091 m_code.setPrologueForEntrypoint(1 + i, catchPrologueGenerator.copyRef()); 1092 } 1093 1094 BasicBlock::SuccessorList successors; 1095 successors.append(m_mainEntrypointStart); 1096 successors.appendVector(m_catchEntrypoints); 1097 1098 RELEASE_ASSERT(numEntrypoints == successors.size()); 1099 m_rootBlock->successors() = successors; 1100 } 1101 957 1102 B3::Type AirIRGenerator::toB3ResultType(BlockSignature returnType) 958 1103 { … … 1026 1171 linkBuffer.link(jumpToExceptionStub, CodeLocationLabel<JITThunkPtrTag>(Thunks::singleton().stub(throwExceptionFromWasmThunkGenerator).code())); 1027 1172 }); 1173 } 1174 1175 template <typename Function> 1176 void AirIRGenerator::forEachLiveValue(Function function) 1177 { 1178 for (const auto& local : m_locals) 1179 function(local); 1180 for (unsigned controlIndex = 0; controlIndex < m_parser->controlStack().size(); ++controlIndex) { 1181 ControlData& data = m_parser->controlStack()[controlIndex].controlData; 1182 Stack& expressionStack = m_parser->controlStack()[controlIndex].enclosedExpressionStack; 1183 for (const auto& tmp : expressionStack) 1184 function(tmp.value()); 1185 if (ControlType::isAnyCatch(data)) 1186 function(data.exception()); 1187 } 1028 1188 } 1029 1189 … … 2904 3064 patchArgs.append(countdownPtr); 2905 3065 2906 for (auto& local : m_locals) 2907 patchArgs.append(ConstrainedTmp(local, B3::ValueRep::ColdAny)); 2908 for (unsigned controlIndex = 0; controlIndex < m_parser->controlStack().size(); ++controlIndex) { 2909 Stack& expressionStack = m_parser->controlStack()[controlIndex].enclosedExpressionStack; 2910 for (TypedExpression value : expressionStack) 2911 patchArgs.append(ConstrainedTmp(value.value(), B3::ValueRep::ColdAny)); 2912 } 3066 forEachLiveValue([&] (Tmp tmp) { 3067 patchArgs.append(ConstrainedTmp(tmp, B3::ValueRep::ColdAny)); 3068 }); 2913 3069 for (TypedExpression value : enclosingStack) 2914 3070 patchArgs.append(ConstrainedTmp(value.value(), B3::ValueRep::ColdAny)); … … 3013 3169 } 3014 3170 3015 // FIXME: Add support for Wasm exceptions in the Air generator 3016 // https://bugs.webkit.org/show_bug.cgi?id=231211 3017 auto AirIRGenerator::addTry(BlockSignature, Stack&, ControlType&, Stack&) -> PartialResult 3018 { 3019 return { }; 3020 } 3021 3022 auto AirIRGenerator::addCatch(unsigned, const Signature&, Stack&, ControlType&, ResultList&) -> PartialResult 3023 { 3024 RELEASE_ASSERT_NOT_REACHED(); 3025 return { }; 3026 } 3027 3028 auto AirIRGenerator::addCatchToUnreachable(unsigned, const Signature&, ControlType&, ResultList&) -> PartialResult 3029 { 3030 RELEASE_ASSERT_NOT_REACHED(); 3031 return { }; 3032 } 3033 3034 auto AirIRGenerator::addCatchAll(Stack&, ControlType&) -> PartialResult 3035 { 3036 RELEASE_ASSERT_NOT_REACHED(); 3037 return { }; 3038 } 3039 3040 auto AirIRGenerator::addCatchAllToUnreachable(ControlType&) -> PartialResult 3041 { 3042 RELEASE_ASSERT_NOT_REACHED(); 3043 return { }; 3044 } 3045 3046 auto AirIRGenerator::addDelegate(ControlType&, ControlType&) -> PartialResult 3047 { 3048 RELEASE_ASSERT_NOT_REACHED(); 3049 return { }; 3050 } 3051 3052 auto AirIRGenerator::addDelegateToUnreachable(ControlType&, ControlType&) -> PartialResult 3053 { 3054 RELEASE_ASSERT_NOT_REACHED(); 3055 return { }; 3056 } 3057 3058 auto AirIRGenerator::addThrow(unsigned exceptionIndex, Vector<ExpressionType>&, Stack&) -> PartialResult 3059 { 3060 UNUSED_PARAM(exceptionIndex); 3061 return { }; 3062 } 3063 3064 auto AirIRGenerator::addRethrow(unsigned, ControlType&) -> PartialResult 3065 { 3171 auto AirIRGenerator::addTry(BlockSignature signature, Stack& enclosingStack, ControlType& result, Stack& newStack) -> PartialResult 3172 { 3173 ++m_tryCatchDepth; 3174 3175 BasicBlock* continuation = m_code.addBlock(); 3176 splitStack(signature, enclosingStack, newStack); 3177 result = ControlData(origin(), signature, tmpsForSignature(signature), BlockType::Try, continuation, ++m_callSiteIndex, m_tryCatchDepth); 3178 return { }; 3179 } 3180 3181 auto AirIRGenerator::addCatch(unsigned exceptionIndex, const Signature& signature, Stack& currentStack, ControlType& data, ResultList& results) -> PartialResult 3182 { 3183 unifyValuesWithBlock(currentStack, data.results); 3184 append(Jump); 3185 m_currentBlock->setSuccessors(data.continuation); 3186 return addCatchToUnreachable(exceptionIndex, signature, data, results); 3187 } 3188 3189 auto AirIRGenerator::addCatchAll(Stack& currentStack, ControlType& data) -> PartialResult 3190 { 3191 unifyValuesWithBlock(currentStack, data.results); 3192 append(Jump); 3193 m_currentBlock->setSuccessors(data.continuation); 3194 return addCatchAllToUnreachable(data); 3195 } 3196 3197 auto AirIRGenerator::addCatchToUnreachable(unsigned exceptionIndex, const Signature& signature, ControlType& data, ResultList& results) -> PartialResult 3198 { 3199 Tmp buffer = emitCatchImpl(CatchKind::Catch, data, exceptionIndex); 3200 for (unsigned i = 0; i < signature.argumentCount(); ++i) { 3201 Type type = signature.argument(i); 3202 TypedTmp tmp = tmpForType(type); 3203 emitLoad(buffer, i * sizeof(uint64_t), tmp); 3204 results.append(tmp); 3205 } 3206 return { }; 3207 } 3208 3209 auto AirIRGenerator::addCatchAllToUnreachable(ControlType& data) -> PartialResult 3210 { 3211 emitCatchImpl(CatchKind::CatchAll, data); 3212 return { }; 3213 } 3214 3215 Tmp AirIRGenerator::emitCatchImpl(CatchKind kind, ControlType& data, unsigned exceptionIndex) 3216 { 3217 m_currentBlock = m_code.addBlock(); 3218 m_catchEntrypoints.append(m_currentBlock); 3219 3220 if (ControlType::isTry(data)) { 3221 if (kind == CatchKind::Catch) 3222 data.convertTryToCatch(++m_callSiteIndex, g64()); 3223 else 3224 data.convertTryToCatchAll(++m_callSiteIndex, g64()); 3225 } 3226 // We convert from "try" to "catch" ControlType above. This doesn't 3227 // happen if ControlType is already a "catch". This can happen when 3228 // we have multiple catches like "try {} catch(A){} catch(B){}...CatchAll(E){}". 3229 // We just convert the first ControlType to a catch, then the others will 3230 // use its fields. 3231 ASSERT(ControlType::isAnyCatch(data)); 3232 3233 HandlerType handlerType = kind == CatchKind::Catch ? HandlerType::Catch : HandlerType::CatchAll; 3234 m_exceptionHandlers.append({ handlerType, data.tryStart(), data.tryEnd(), 0, m_tryCatchDepth, exceptionIndex }); 3235 3236 restoreWebAssemblyGlobalState(RestoreCachedStackLimit::Yes, m_info.memory, instanceValue(), m_currentBlock); 3237 3238 unsigned indexInBuffer = 0; 3239 auto loadFromScratchBuffer = [&] (TypedTmp result) { 3240 size_t offset = sizeof(uint64_t) * indexInBuffer; 3241 ++indexInBuffer; 3242 Tmp bufferPtr = Tmp(GPRInfo::argumentGPR0); 3243 emitLoad(bufferPtr, offset, result); 3244 }; 3245 forEachLiveValue([&] (TypedTmp tmp) { 3246 // We set our current ControlEntry's exception below after the patchpoint, it's 3247 // not in the incoming buffer of live values. 3248 auto toIgnore = data.exception(); 3249 if (tmp.tmp() != toIgnore.tmp()) 3250 loadFromScratchBuffer(tmp); 3251 }); 3252 3253 B3::PatchpointValue* patch = addPatchpoint(m_proc.addTuple({ B3::pointerType(), B3::pointerType() })); 3254 patch->effects.exitsSideways = true; 3255 patch->clobber(RegisterSet::macroScratchRegisters()); 3256 RegisterSet clobberLate = RegisterSet::volatileRegistersForJSCall(); 3257 clobberLate.add(GPRInfo::argumentGPR0); 3258 patch->clobberLate(clobberLate); 3259 patch->resultConstraints.append(B3::ValueRep::reg(GPRInfo::returnValueGPR)); 3260 patch->resultConstraints.append(B3::ValueRep::reg(GPRInfo::returnValueGPR2)); 3261 patch->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) { 3262 AllowMacroScratchRegisterUsage allowScratch(jit); 3263 jit.move(params[2].gpr(), GPRInfo::argumentGPR0); 3264 CCallHelpers::Call call = jit.call(OperationPtrTag); 3265 jit.addLinkTask([call] (LinkBuffer& linkBuffer) { 3266 linkBuffer.link(call, FunctionPtr<OperationPtrTag>(operationWasmRetrieveAndClearExceptionIfCatchable)); 3267 }); 3268 }); 3269 3270 Tmp exception = Tmp(GPRInfo::returnValueGPR); 3271 Tmp buffer = Tmp(GPRInfo::returnValueGPR2); 3272 emitPatchpoint(m_currentBlock, patch, Vector<Tmp, 8>::from(exception, buffer), Vector<ConstrainedTmp, 1>::from(instanceValue())); 3273 append(Move, exception, data.exception()); 3274 3275 return buffer; 3276 } 3277 3278 auto AirIRGenerator::addDelegate(ControlType& target, ControlType& data) -> PartialResult 3279 { 3280 return addDelegateToUnreachable(target, data); 3281 } 3282 3283 auto AirIRGenerator::addDelegateToUnreachable(ControlType& target, ControlType& data) -> PartialResult 3284 { 3285 unsigned targetDepth = 0; 3286 if (ControlType::isTry(target)) 3287 targetDepth = target.tryDepth(); 3288 3289 m_exceptionHandlers.append({ HandlerType::Delegate, data.tryStart(), ++m_callSiteIndex, 0, m_tryCatchDepth, targetDepth }); 3290 return { }; 3291 } 3292 3293 auto AirIRGenerator::addThrow(unsigned exceptionIndex, Vector<ExpressionType>& args, Stack&) -> PartialResult 3294 { 3295 B3::PatchpointValue* patch = addPatchpoint(B3::Void); 3296 patch->effects.terminal = true; 3297 patch->clobber(RegisterSet::volatileRegistersForJSCall()); 3298 3299 Vector<ConstrainedTmp, 8> patchArgs; 3300 patchArgs.append(ConstrainedTmp(instanceValue(), B3::ValueRep::reg(GPRInfo::argumentGPR0))); 3301 patchArgs.append(ConstrainedTmp(Tmp(GPRInfo::callFrameRegister), B3::ValueRep::reg(GPRInfo::argumentGPR1))); 3302 for (unsigned i = 0; i < args.size(); ++i) 3303 patchArgs.append(ConstrainedTmp(args[i], B3::ValueRep::stackArgument(i * sizeof(EncodedJSValue)))); 3304 3305 PatchpointExceptionHandle handle = preparePatchpointForExceptions(patch, patchArgs); 3306 3307 patch->setGenerator([this, exceptionIndex, handle] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) { 3308 AllowMacroScratchRegisterUsage allowScratch(jit); 3309 handle.generate(jit, params, this); 3310 emitThrowImpl(jit, exceptionIndex); 3311 }); 3312 3313 emitPatchpoint(m_currentBlock, patch, Tmp(), WTFMove(patchArgs)); 3314 3315 return { }; 3316 } 3317 3318 auto AirIRGenerator::addRethrow(unsigned, ControlType& data) -> PartialResult 3319 { 3320 B3::PatchpointValue* patch = addPatchpoint(B3::Void); 3321 patch->clobber(RegisterSet::volatileRegistersForJSCall()); 3322 patch->effects.terminal = true; 3323 3324 Vector<ConstrainedTmp, 3> patchArgs; 3325 patchArgs.append(ConstrainedTmp(instanceValue(), B3::ValueRep::reg(GPRInfo::argumentGPR0))); 3326 patchArgs.append(ConstrainedTmp(Tmp(GPRInfo::callFrameRegister), B3::ValueRep::reg(GPRInfo::argumentGPR1))); 3327 patchArgs.append(ConstrainedTmp(data.exception(), B3::ValueRep::reg(GPRInfo::argumentGPR2))); 3328 3329 PatchpointExceptionHandle handle = preparePatchpointForExceptions(patch, patchArgs); 3330 patch->setGenerator([this, handle] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) { 3331 AllowMacroScratchRegisterUsage allowScratch(jit); 3332 handle.generate(jit, params, this); 3333 emitRethrowImpl(jit); 3334 }); 3335 3336 emitPatchpoint(m_currentBlock, patch, Tmp(), WTFMove(patchArgs)); 3337 3066 3338 return { }; 3067 3339 } … … 3210 3482 append(data.special, Jump); 3211 3483 data.special->setSuccessors(m_currentBlock); 3212 } 3484 } else if (data.blockType() == BlockType::Try || data.blockType() == BlockType::Catch) 3485 --m_tryCatchDepth; 3213 3486 3214 3487 if (data.blockType() == BlockType::Loop) { … … 3234 3507 } 3235 3508 3236 B3::PatchpointValue* AirIRGenerator::emitCallPatchpoint(BasicBlock* block, const Signature& signature, const ResultList& results, const Vector<TypedTmp>& args, Vector<ConstrainedTmp>&&patchArgs)3509 std::pair<B3::PatchpointValue*, PatchpointExceptionHandle> AirIRGenerator::emitCallPatchpoint(BasicBlock* block, const Signature& signature, const ResultList& results, const Vector<TypedTmp>& args, Vector<ConstrainedTmp> patchArgs) 3237 3510 { 3238 3511 auto* patchpoint = addPatchpoint(toB3ResultType(&signature)); … … 3259 3532 patchpoint->resultConstraints = WTFMove(resultConstraints); 3260 3533 } 3534 PatchpointExceptionHandle exceptionHandle = preparePatchpointForExceptions(patchpoint, patchArgs); 3261 3535 emitPatchpoint(block, patchpoint, results, WTFMove(patchArgs)); 3262 return patchpoint;3536 return { patchpoint, exceptionHandle }; 3263 3537 } 3264 3538 … … 3296 3570 3297 3571 { 3298 auto* patchpoint = emitCallPatchpoint(isWasmBlock, signature, results, args); 3572 auto pair = emitCallPatchpoint(isWasmBlock, signature, results, args); 3573 auto* patchpoint = pair.first; 3574 auto exceptionHandle = pair.second; 3299 3575 // We need to clobber all potential pinned registers since we might be leaving the instance. 3300 3576 // We pessimistically assume we could be calling to something that is bounds checking. … … 3302 3578 patchpoint->clobberLate(PinnedRegisterInfo::get().toSave(MemoryMode::BoundsChecking)); 3303 3579 3304 patchpoint->setGenerator([ unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {3580 patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) { 3305 3581 AllowMacroScratchRegisterUsage allowScratch(jit); 3582 exceptionHandle.generate(jit, params, this); 3306 3583 CCallHelpers::Call call = jit.threadSafePatchableNearCall(); 3307 3584 jit.addLinkTask([unlinkedWasmToWasmCalls, call, functionIndex] (LinkBuffer& linkBuffer) { … … 3322 3599 Vector<ConstrainedTmp> jumpArgs; 3323 3600 jumpArgs.append({ jumpDestination, B3::ValueRep::SomeRegister }); 3324 auto* patchpoint = emitCallPatchpoint(isEmbedderBlock, signature, results, args, WTFMove(jumpArgs)); 3601 auto pair = emitCallPatchpoint(isEmbedderBlock, signature, results, args, WTFMove(jumpArgs)); 3602 auto* patchpoint = pair.first; 3603 auto exceptionHandle = pair.second; 3604 3325 3605 // We need to clobber all potential pinned registers since we might be leaving the instance. 3326 3606 // We pessimistically assume we could be calling to something that is bounds checking. 3327 3607 // FIXME: We shouldn't have to do this: https://bugs.webkit.org/show_bug.cgi?id=172181 3328 3608 patchpoint->clobberLate(PinnedRegisterInfo::get().toSave(MemoryMode::BoundsChecking)); 3329 patchpoint->setGenerator([ ] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {3609 patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) { 3330 3610 AllowMacroScratchRegisterUsage allowScratch(jit); 3611 exceptionHandle.generate(jit, params, this); 3331 3612 jit.call(params[params.proc().resultCount(params.value()->type())].gpr(), WasmEntryPtrTag); 3332 3613 }); … … 3340 3621 restoreWebAssemblyGlobalState(RestoreCachedStackLimit::Yes, m_info.memory, currentInstance, continuation); 3341 3622 } else { 3342 auto* patchpoint = emitCallPatchpoint(m_currentBlock, signature, results, args); 3623 auto pair = emitCallPatchpoint(m_currentBlock, signature, results, args); 3624 auto* patchpoint = pair.first; 3625 auto exceptionHandle = pair.second; 3343 3626 // We need to clobber the size register since the LLInt always bounds checks 3344 3627 if (m_mode == MemoryMode::Signaling || m_info.memory.isShared()) 3345 3628 patchpoint->clobberLate(RegisterSet { PinnedRegisterInfo::get().boundsCheckingSizeRegister }); 3346 patchpoint->setGenerator([ unlinkedWasmToWasmCalls, functionIndex] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {3629 patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) { 3347 3630 AllowMacroScratchRegisterUsage allowScratch(jit); 3631 exceptionHandle.generate(jit, params, this); 3348 3632 CCallHelpers::Call call = jit.threadSafePatchableNearCall(); 3349 3633 jit.addLinkTask([unlinkedWasmToWasmCalls, call, functionIndex] (LinkBuffer& linkBuffer) { … … 3524 3808 results.append(tmpForType(signature.returnType(i))); 3525 3809 3526 auto* patchpoint = emitCallPatchpoint(m_currentBlock, signature, results, args, WTFMove(extraArgs)); 3810 auto pair = emitCallPatchpoint(m_currentBlock, signature, results, args, WTFMove(extraArgs)); 3811 auto* patchpoint = pair.first; 3812 auto exceptionHandle = pair.second; 3527 3813 3528 3814 // We need to clobber all potential pinned registers since we might be leaving the instance. … … 3536 3822 patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) { 3537 3823 AllowMacroScratchRegisterUsage allowScratch(jit); 3824 exceptionHandle.generate(jit, params, this); 3538 3825 jit.call(params[params.proc().resultCount(params.value()->type())].gpr(), WasmEntryPtrTag); 3539 3826 }); … … 3596 3883 compilationContext.wasmEntrypointJIT = makeUnique<CCallHelpers>(); 3597 3884 3598 B3::Procedure procedure; 3885 compilationContext.procedure = makeUnique<B3::Procedure>(); 3886 auto& procedure = *compilationContext.procedure; 3599 3887 Code& code = procedure.code(); 3600 3888 … … 3616 3904 WASM_FAIL_IF_HELPER_FAILS(parser.parse()); 3617 3905 3906 irGenerator.finalizeEntrypoints(); 3618 3907 3619 3908 for (BasicBlock* block : code) { … … 3622 3911 } 3623 3912 3624 { 3625 if (UNLIKELY(shouldDumpIRAtEachPhase(B3::AirMode))) { 3626 dataLogLn("Generated patchpoints"); 3627 for (B3::PatchpointValue** patch : irGenerator.patchpoints()) 3628 dataLogLn(deepDump(procedure, *patch)); 3629 } 3630 3631 B3::Air::prepareForGeneration(code); 3632 B3::Air::generate(code, *compilationContext.wasmEntrypointJIT); 3633 compilationContext.wasmEntrypointByproducts = procedure.releaseByproducts(); 3634 result->entrypoint.calleeSaveRegisters = code.calleeSaveRegisterAtOffsetList(); 3635 } 3913 if (UNLIKELY(shouldDumpIRAtEachPhase(B3::AirMode))) { 3914 dataLogLn("Generated patchpoints"); 3915 for (B3::PatchpointValue** patch : irGenerator.patchpoints()) 3916 dataLogLn(deepDump(procedure, *patch)); 3917 } 3918 3919 B3::Air::prepareForGeneration(code); 3920 B3::Air::generate(code, *compilationContext.wasmEntrypointJIT); 3921 3922 compilationContext.wasmEntrypointByproducts = procedure.releaseByproducts(); 3923 result->entrypoint.calleeSaveRegisters = code.calleeSaveRegisterAtOffsetList(); 3924 result->stackmaps = irGenerator.takeStackmaps(); 3925 result->exceptionHandlers = irGenerator.takeExceptionHandlers(); 3636 3926 3637 3927 return result; … … 5179 5469 } 5180 5470 5471 template <size_t inlineCapacity> 5472 PatchpointExceptionHandle AirIRGenerator::preparePatchpointForExceptions(B3::PatchpointValue* patch, Vector<ConstrainedTmp, inlineCapacity>& args) 5473 { 5474 ++m_callSiteIndex; 5475 if (!m_tryCatchDepth) 5476 return { }; 5477 5478 unsigned numLiveValues = 0; 5479 forEachLiveValue([&] (Tmp tmp) { 5480 ++numLiveValues; 5481 args.append(ConstrainedTmp(tmp, B3::ValueRep::LateColdAny)); 5482 }); 5483 5484 patch->effects.exitsSideways = true; 5485 5486 return PatchpointExceptionHandle { m_callSiteIndex, numLiveValues }; 5487 } 5488 5181 5489 } } // namespace JSC::Wasm 5182 5490 -
trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
r287738 r287801 1 1 /* 2 * Copyright (C) 2016-202 1Apple Inc. All rights reserved.2 * Copyright (C) 2016-2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 58 58 #include "WasmExceptionType.h" 59 59 #include "WasmFunctionParser.h" 60 #include "WasmIRGeneratorHelpers.h" 60 61 #include "WasmInstance.h" 61 62 #include "WasmMemory.h" … … 87 88 } 88 89 } 89 90 class B3IRGenerator;91 struct PatchpointExceptionHandle {92 void generate(CCallHelpers&, const B3::StackmapGenerationParams&, B3IRGenerator*) const;93 94 static constexpr unsigned s_invalidCallSiteIndex = std::numeric_limits<unsigned>::max();95 96 unsigned m_callSiteIndex { s_invalidCallSiteIndex };97 unsigned m_numLiveValues;98 };99 90 100 91 class B3IRGenerator { … … 579 570 }; 580 571 581 void PatchpointExceptionHandle::generate(CCallHelpers& jit, const B3::StackmapGenerationParams& params, B3IRGenerator* generator) const582 {583 if (m_callSiteIndex == s_invalidCallSiteIndex)584 return;585 586 StackMap values(m_numLiveValues);587 unsigned paramsOffset = params.size() - m_numLiveValues;588 unsigned childrenOffset = params.value()->numChildren() - m_numLiveValues;589 for (unsigned i = 0; i < m_numLiveValues; ++i)590 values[i] = OSREntryValue(params[i + paramsOffset], params.value()->child(i + childrenOffset)->type());591 592 generator->addStackMap(m_callSiteIndex, WTFMove(values));593 jit.store32(CCallHelpers::TrustedImm32(m_callSiteIndex), CCallHelpers::tagFor(CallFrameSlot::argumentCountIncludingThis));594 }595 596 572 // Memory accesses in WebAssembly have unsigned 32-bit offsets, whereas they have signed 32-bit offsets in B3. 597 573 int32_t B3IRGenerator::fixupPointerPlusOffset(Value*& ptr, uint32_t offset) … … 858 834 } 859 835 860 static void buildEntryBufferForCatch(Probe::Context& context)861 {862 CallFrame* callFrame = context.fp<CallFrame*>();863 CallSiteIndex callSiteIndex = callFrame->callSiteIndex();864 OptimizingJITCallee* callee = bitwise_cast<OptimizingJITCallee*>(callFrame->callee().asWasmCallee());865 const StackMap& stackmap = callee->stackmap(callSiteIndex);866 VM* vm = context.gpr<VM*>(GPRInfo::regT0);867 uint64_t* buffer = vm->wasmContext.scratchBufferForSize(stackmap.size() * 8);868 loadValuesIntoBuffer(context, stackmap, buffer);869 870 context.gpr(GPRInfo::argumentGPR0) = bitwise_cast<uintptr_t>(buffer);871 }872 873 836 void B3IRGenerator::insertEntrySwitch() 874 837 { … … 877 840 Ref<B3::Air::PrologueGenerator> catchPrologueGenerator = createSharedTask<B3::Air::PrologueGeneratorFunction>([] (CCallHelpers& jit, B3::Air::Code& code) { 878 841 AllowMacroScratchRegisterUsage allowScratch(jit); 879 880 jit.emitGetFromCallFrameHeaderPtr(CallFrameSlot::callee, GPRInfo::regT0); 881 { 882 // FIXME: Handling precise allocations in WasmB3IRGenerator catch entrypoints might be unnecessary 883 // https://bugs.webkit.org/show_bug.cgi?id=231213 884 auto preciseAllocationCase = jit.branchTestPtr(CCallHelpers::NonZero, GPRInfo::regT0, CCallHelpers::TrustedImm32(PreciseAllocation::halfAlignment)); 885 jit.andPtr(CCallHelpers::TrustedImmPtr(MarkedBlock::blockMask), GPRInfo::regT0); 886 jit.loadPtr(CCallHelpers::Address(GPRInfo::regT0, MarkedBlock::offsetOfFooter + MarkedBlock::Footer::offsetOfVM()), GPRInfo::regT0); 887 auto loadedCase = jit.jump(); 888 889 preciseAllocationCase.link(&jit); 890 jit.loadPtr(CCallHelpers::Address(GPRInfo::regT0, PreciseAllocation::offsetOfWeakSet() + WeakSet::offsetOfVM() - PreciseAllocation::headerSize()), GPRInfo::regT0); 891 892 loadedCase.link(&jit); 893 } 894 jit.restoreCalleeSavesFromVMEntryFrameCalleeSavesBuffer(GPRInfo::regT0, GPRInfo::regT3); 895 896 jit.loadPtr(CCallHelpers::Address(GPRInfo::regT0, VM::calleeForWasmCatchOffset()), GPRInfo::regT3); 897 jit.storePtr(CCallHelpers::TrustedImmPtr(nullptr), CCallHelpers::Address(GPRInfo::regT0, VM::calleeForWasmCatchOffset())); 898 jit.emitPutToCallFrameHeader(GPRInfo::regT3, CallFrameSlot::callee); 899 900 jit.load64(CCallHelpers::Address(GPRInfo::regT0, VM::callFrameForCatchOffset()), GPRInfo::callFrameRegister); 901 jit.storePtr(CCallHelpers::TrustedImmPtr(nullptr), CCallHelpers::Address(GPRInfo::regT0, VM::callFrameForCatchOffset())); 902 903 jit.loadPtr(CCallHelpers::Address(GPRInfo::callFrameRegister, CallFrameSlot::thisArgument * sizeof(Register)), GPRInfo::regT3); 904 jit.loadPtr(CCallHelpers::Address(GPRInfo::regT3, JSWebAssemblyInstance::offsetOfInstance()), GPRInfo::regT3); 905 jit.storeWasmContextInstance(GPRInfo::regT3); 906 907 jit.probe(tagCFunction<JITProbePtrTag>(buildEntryBufferForCatch), nullptr); 908 909 jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister); 842 emitCatchPrologueShared(code, jit); 910 843 }); 911 844 … … 2653 2586 data.convertTryToCatchAll(++m_callSiteIndex, m_proc.addVariable(pointerType())); 2654 2587 } 2588 // We convert from "try" to "catch" ControlType above. This doesn't 2589 // happen if ControlType is already a "catch". This can happen when 2590 // we have multiple catches like "try {} catch(A){} catch(B){}...CatchAll(E){}" 2591 ASSERT(ControlType::isAnyCatch(data)); 2655 2592 2656 2593 HandlerType handlerType = kind == CatchKind::Catch ? HandlerType::Catch : HandlerType::CatchAll; … … 2723 2660 patch->setGenerator([this, exceptionIndex, handle] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) { 2724 2661 AllowMacroScratchRegisterUsage allowScratch(jit); 2725 GPRReg scratch = GPRInfo::nonPreservedNonArgumentGPR0;2726 2662 handle.generate(jit, params, this); 2727 2728 jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR0, Instance::offsetOfOwner()), scratch); 2729 { 2730 auto preciseAllocationCase = jit.branchTestPtr(CCallHelpers::NonZero, scratch, CCallHelpers::TrustedImm32(PreciseAllocation::halfAlignment)); 2731 jit.andPtr(CCallHelpers::TrustedImmPtr(MarkedBlock::blockMask), scratch); 2732 jit.loadPtr(CCallHelpers::Address(scratch, MarkedBlock::offsetOfFooter + MarkedBlock::Footer::offsetOfVM()), scratch); 2733 auto loadedCase = jit.jump(); 2734 2735 preciseAllocationCase.link(&jit); 2736 jit.loadPtr(CCallHelpers::Address(scratch, PreciseAllocation::offsetOfWeakSet() + WeakSet::offsetOfVM() - PreciseAllocation::headerSize()), scratch); 2737 2738 loadedCase.link(&jit); 2739 } 2740 jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(scratch); 2741 2742 jit.move(MacroAssembler::TrustedImm32(exceptionIndex), GPRInfo::argumentGPR2); 2743 jit.move(MacroAssembler::stackPointerRegister, GPRInfo::argumentGPR3); 2744 CCallHelpers::Call call = jit.call(OperationPtrTag); 2745 jit.farJump(GPRInfo::returnValueGPR, ExceptionHandlerPtrTag); 2746 jit.addLinkTask([call] (LinkBuffer& linkBuffer) { 2747 linkBuffer.link(call, FunctionPtr<OperationPtrTag>(operationWasmThrow)); 2748 }); 2663 emitThrowImpl(jit, exceptionIndex); 2749 2664 }); 2750 2665 m_currentBlock->append(patch); … … 2764 2679 patch->setGenerator([this, handle] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) { 2765 2680 AllowMacroScratchRegisterUsage allowScratch(jit); 2766 2767 GPRReg scratch = GPRInfo::nonPreservedNonArgumentGPR0;2768 jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR0, Instance::offsetOfOwner()), scratch);2769 {2770 auto preciseAllocationCase = jit.branchTestPtr(CCallHelpers::NonZero, scratch, CCallHelpers::TrustedImm32(PreciseAllocation::halfAlignment));2771 jit.andPtr(CCallHelpers::TrustedImmPtr(MarkedBlock::blockMask), scratch);2772 jit.loadPtr(CCallHelpers::Address(scratch, MarkedBlock::offsetOfFooter + MarkedBlock::Footer::offsetOfVM()), scratch);2773 auto loadedCase = jit.jump();2774 2775 preciseAllocationCase.link(&jit);2776 jit.loadPtr(CCallHelpers::Address(scratch, PreciseAllocation::offsetOfWeakSet() + WeakSet::offsetOfVM() - PreciseAllocation::headerSize()), scratch);2777 2778 loadedCase.link(&jit);2779 }2780 jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(scratch);2781 2782 2681 handle.generate(jit, params, this); 2783 CCallHelpers::Call call = jit.call(OperationPtrTag); 2784 jit.farJump(GPRInfo::returnValueGPR, ExceptionHandlerPtrTag); 2785 jit.addLinkTask([call] (LinkBuffer& linkBuffer) { 2786 linkBuffer.link(call, FunctionPtr<OperationPtrTag>(operationWasmRethrow)); 2787 }); 2682 emitRethrowImpl(jit); 2788 2683 }); 2789 2684 m_currentBlock->append(patch); … … 3321 3216 } 3322 3217 3323 void computeExceptionHandlerLocations(Vector<CodeLocationLabel<ExceptionHandlerPtrTag>>& handlers, const InternalFunction* function, const CompilationContext& context, LinkBuffer& linkBuffer)3324 {3325 if (!context.procedure)3326 return;3327 3328 unsigned entrypointIndex = 0;3329 unsigned numEntrypoints = context.procedure->numEntrypoints();3330 for (const UnlinkedHandlerInfo& handlerInfo : function->exceptionHandlers) {3331 RELEASE_ASSERT(entrypointIndex < numEntrypoints);3332 if (handlerInfo.m_type == HandlerType::Delegate) {3333 handlers.append({ });3334 continue;3335 }3336 3337 ++entrypointIndex;3338 handlers.append(linkBuffer.locationOf<ExceptionHandlerPtrTag>(context.procedure->code().entrypointLabel(entrypointIndex)));3339 }3340 RELEASE_ASSERT(entrypointIndex == numEntrypoints - 1);3341 }3342 3343 3218 // Custom wasm ops. These are the ones too messy to do in wasm.json. 3344 3219 -
trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h
r286920 r287801 60 60 Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext&, const FunctionData&, const Signature&, Vector<UnlinkedWasmToWasmCall>&, unsigned& osrEntryScratchBufferSize, const ModuleInformation&, MemoryMode, CompilationMode, uint32_t functionIndex, uint32_t loopIndexForOSREntry, TierUpCount* = nullptr); 61 61 62 void computeExceptionHandlerLocations(Vector<CodeLocationLabel<ExceptionHandlerPtrTag>>& handlers, const InternalFunction*, const CompilationContext&, LinkBuffer&);63 62 void computePCToCodeOriginMap(CompilationContext&, LinkBuffer&); 64 63 -
trunk/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
r287221 r287801 37 37 #include "WasmCalleeGroup.h" 38 38 #include "WasmCalleeRegistry.h" 39 #include "WasmIRGeneratorHelpers.h" 39 40 #include "WasmSignatureInlines.h" 40 41 #include "WasmTierUpCount.h" … … 204 205 if (Options::webAssemblyBBQAirModeThreshold() && m_moduleInformation->codeSectionSize >= Options::webAssemblyBBQAirModeThreshold()) 205 206 forceUsingB3 = true; 206 else if (!m_moduleInformation->m_functionDoesNotUseExceptions.quickGet(functionIndex))207 forceUsingB3 = true;208 207 else if (!Options::wasmBBQUsesAir()) 209 208 forceUsingB3 = true; -
trunk/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp
r287459 r287801 559 559 RELEASE_ASSERT(usedBuffer.capacity() == oldCapacity); 560 560 *threadSpecific = WTFMove(usedBuffer); 561 562 if (!m_usesExceptions)563 m_info.m_functionDoesNotUseExceptions.quickSet(m_functionIndex);564 561 565 562 return WTFMove(m_codeBlock); -
trunk/Source/JavaScriptCore/wasm/WasmModuleInformation.h
r286992 r287801 120 120 BitVector m_declaredFunctions; 121 121 BitVector m_declaredExceptions; 122 BitVector m_functionDoesNotUseExceptions;123 122 mutable BitVector m_referencedFunctions; 124 123 }; -
trunk/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp
r287221 r287801 34 34 #include "WasmCallee.h" 35 35 #include "WasmCalleeRegistry.h" 36 #include "WasmIRGeneratorHelpers.h" 36 37 #include "WasmNameSection.h" 37 38 #include "WasmSignatureInlines.h" -
trunk/Source/JavaScriptCore/wasm/WasmOSREntryPlan.cpp
r287379 r287801 33 33 #include "WasmB3IRGenerator.h" 34 34 #include "WasmCallee.h" 35 #include "WasmIRGeneratorHelpers.h" 35 36 #include "WasmMachineThreads.h" 36 37 #include "WasmNameSection.h" -
trunk/Source/JavaScriptCore/wasm/WasmStreamingParser.cpp
r283852 r287801 118 118 m_functionIndex = 0; 119 119 m_codeOffset = m_offset; 120 m_info->m_functionDoesNotUseExceptions.ensureSize(functionCount);121 120 122 121 WASM_PARSER_FAIL_IF(functionCount == std::numeric_limits<uint32_t>::max(), "Code section's count is too big ", functionCount);
Note:
See TracChangeset
for help on using the changeset viewer.