Changeset 252800 in webkit
- Timestamp:
- Nov 22, 2019 2:13:28 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r252789 r252800 1 2019-11-22 Tadeu Zagallo <tzagallo@apple.com> 2 3 [WebAssembly] Improve Wasm::LLIntGenerator 4 https://bugs.webkit.org/show_bug.cgi?id=204092 5 6 Reviewed by Saam Barati. 7 8 * wasm/stress/set-local-enclosed-stack.js: Added. 9 (assert.eq.instance.exports.foo): 10 (assert.eq): 11 1 12 2019-11-22 Yusuke Suzuki <ysuzuki@apple.com> 2 13 -
trunk/Source/JavaScriptCore/ChangeLog
r252789 r252800 1 2019-11-22 Tadeu Zagallo <tzagallo@apple.com> 2 3 [WebAssembly] Improve Wasm::LLIntGenerator 4 https://bugs.webkit.org/show_bug.cgi?id=204092 5 6 Reviewed by Saam Barati. 7 8 This improves the Wasm::LLIntGenerator by: 9 - Changing LLIntGenerator::ExpressionType from RefPtr<RegisterID> to VirtualRegister: Instead of allocating and retaining 10 RegisterIDs we use VirtualRegisters directly and ensure that they match the WebAssembly stack, i.e. the parser's expression 11 stack should match the virtual registers. 12 - Removing redundant moves when materializing constants and performing local.get: instead of creating a new temporary 13 for each constant and local.get, we return the VirtualRegister for the constant/local slot directly. In order for this 14 to work, we still allocate the stack slot for the temporaries, since we have to materialize them before loops and branches. 15 - Adding a constructor to ControlType that takes the results ExpressionList as an rvalue instead of copying it 16 - Optimizing callInformationFor, which is now split into two functions. The callee does not care about arguments, and should 17 never allocate temporaries, and the caller case was optimized by avoiding unnecessary calls to newTemporary 18 - Delay holding the lock in LLintPlan::compileFunction, since we do not need to hold it while compiling the js-to-wasm entrypoint 19 20 * bytecode/BytecodeList.rb: 21 * bytecompiler/Label.h: 22 (JSC::GenericLabel::location const): 23 (JSC::GenericLabel::unresolvedJumps const): 24 * generator/Wasm.rb: 25 * llint/WebAssembly.asm: 26 * wasm/WasmAirIRGenerator.cpp: 27 (JSC::Wasm::AirIRGenerator::endTopLevel): 28 (JSC::Wasm::AirIRGenerator::didPopValueFromStack): 29 * wasm/WasmB3IRGenerator.cpp: 30 (JSC::Wasm::B3IRGenerator::endTopLevel): 31 (JSC::Wasm::B3IRGenerator::didPopValueFromStack): 32 * wasm/WasmFunctionCodeBlock.cpp: 33 (JSC::Wasm::FunctionCodeBlock::addJumpTable): 34 * wasm/WasmFunctionCodeBlock.h: 35 * wasm/WasmFunctionParser.h: 36 (JSC::Wasm::FunctionParser::expressionStack): 37 (JSC::Wasm::FunctionParser<Context>::parseBody): 38 (JSC::Wasm::FunctionParser<Context>::parseExpression): 39 * wasm/WasmLLIntGenerator.cpp: 40 (JSC::Wasm::LLIntGenerator::ControlType::loop): 41 (JSC::Wasm::LLIntGenerator::ControlType::topLevel): 42 (JSC::Wasm::LLIntGenerator::ControlType::block): 43 (JSC::Wasm::LLIntGenerator::ControlType::if_): 44 (JSC::Wasm::LLIntGenerator::ControlType::targetArity const): 45 (JSC::Wasm::LLIntGenerator::ControlType::stackSize const): 46 (JSC::Wasm::LLIntGenerator::ControlType::ControlType): 47 (JSC::Wasm::LLIntGenerator::unifyValuesWithBlock): 48 (JSC::Wasm::LLIntGenerator::push): 49 (JSC::Wasm::LLIntGenerator::didPopValueFromStack): 50 (JSC::Wasm::LLIntGenerator::emptyExpression): 51 (JSC::Wasm::LLIntGenerator::addEndToUnreachable): 52 (JSC::Wasm::LLIntGenerator::dump): 53 (JSC::Wasm::LLIntGenerator::virtualRegisterForWasmLocal): 54 (JSC::Wasm::LLIntGenerator::jsNullConstant): 55 (JSC::Wasm::LLIntGenerator::zeroConstant): 56 (JSC::Wasm::LLIntGenerator::getDropKeepCount): 57 (JSC::Wasm::LLIntGenerator::dropKeep): 58 (JSC::Wasm::LLIntGenerator::walkExpressionStack): 59 (JSC::Wasm::LLIntGenerator::checkConsistency): 60 (JSC::Wasm::LLIntGenerator::materializeConstantsAndLocals): 61 (JSC::Wasm::LLIntGenerator::materializeLocals): 62 (JSC::Wasm::LLIntGenerator::ConstantMapHashTraits::constructDeletedValue): 63 (JSC::Wasm::LLIntGenerator::ConstantMapHashTraits::isDeletedValue): 64 (JSC::Wasm::LLIntGenerator::LLIntGenerator): 65 (JSC::Wasm::LLIntGenerator::finalize): 66 (JSC::Wasm::LLIntGenerator::callInformationForCaller): 67 (JSC::Wasm::LLIntGenerator::callInformationForCallee): 68 (JSC::Wasm::LLIntGenerator::addArguments): 69 (JSC::Wasm::LLIntGenerator::addLocal): 70 (JSC::Wasm::LLIntGenerator::didFinishParsingLocals): 71 (JSC::Wasm::LLIntGenerator::addConstant): 72 (JSC::Wasm::LLIntGenerator::getLocal): 73 (JSC::Wasm::LLIntGenerator::setLocal): 74 (JSC::Wasm::LLIntGenerator::getGlobal): 75 (JSC::Wasm::LLIntGenerator::addLoop): 76 (JSC::Wasm::LLIntGenerator::addTopLevel): 77 (JSC::Wasm::LLIntGenerator::addBlock): 78 (JSC::Wasm::LLIntGenerator::addIf): 79 (JSC::Wasm::LLIntGenerator::addElse): 80 (JSC::Wasm::LLIntGenerator::addElseToUnreachable): 81 (JSC::Wasm::LLIntGenerator::addReturn): 82 (JSC::Wasm::LLIntGenerator::addBranch): 83 (JSC::Wasm::LLIntGenerator::addSwitch): 84 (JSC::Wasm::LLIntGenerator::endBlock): 85 (JSC::Wasm::LLIntGenerator::endTopLevel): 86 (JSC::Wasm::LLIntGenerator::addCall): 87 (JSC::Wasm::LLIntGenerator::addCallIndirect): 88 (JSC::Wasm::LLIntGenerator::addRefIsNull): 89 (JSC::Wasm::LLIntGenerator::addRefFunc): 90 (JSC::Wasm::LLIntGenerator::addTableGet): 91 (JSC::Wasm::LLIntGenerator::addTableSize): 92 (JSC::Wasm::LLIntGenerator::addTableGrow): 93 (JSC::Wasm::LLIntGenerator::addCurrentMemory): 94 (JSC::Wasm::LLIntGenerator::addGrowMemory): 95 (JSC::Wasm::LLIntGenerator::addSelect): 96 (JSC::Wasm::LLIntGenerator::load): 97 (JSC::GenericLabel<Wasm::GeneratorTraits>::setLocation): 98 * wasm/WasmLLIntPlan.cpp: 99 (JSC::Wasm::LLIntPlan::compileFunction): 100 * wasm/WasmValidate.cpp: 101 (JSC::Wasm::Validate::endTopLevel): 102 (JSC::Wasm::Validate::didPopValueFromStack): 103 1 104 2019-11-22 Yusuke Suzuki <ysuzuki@apple.com> 2 105 -
trunk/Source/JavaScriptCore/bytecode/BytecodeList.rb
r252680 r252800 1300 1300 scrutinee: VirtualRegister, 1301 1301 tableIndex: unsigned, 1302 defaultTarget: WasmBoundLabel,1303 1302 } 1304 1303 … … 1307 1306 op :unreachable 1308 1307 op :ret_void 1308 1309 op :drop_keep, 1310 args: { 1311 startOffset: unsigned, 1312 dropCount: unsigned, 1313 keepCount: unsigned, 1314 } 1309 1315 1310 1316 op :ref_is_null, -
trunk/Source/JavaScriptCore/bytecompiler/Label.h
r251886 r252800 129 129 using BytecodeGenerator = BytecodeGeneratorBase<Traits>; 130 130 using BoundLabel = GenericBoundLabel<Traits>; 131 using JumpVector = Vector<int, 8>; 131 132 132 133 public: … … 171 172 bool isBound() const { return m_bound; } 172 173 174 unsigned location() const 175 { 176 ASSERT(!isForward()); 177 m_bound = true; 178 return m_location; 179 }; 180 181 const JumpVector& unresolvedJumps() const { return m_unresolvedJumps; } 182 173 183 private: 174 184 friend BoundLabel; 175 176 typedef Vector<int, 8> JumpVector;177 185 178 186 static constexpr unsigned invalidLocation = UINT_MAX; -
trunk/Source/JavaScriptCore/generator/Wasm.rb
r252231 r252800 59 59 auto LLIntGenerator::addOp<#{op_type(op)}>(ExpressionType lhs, ExpressionType rhs, ExpressionType& result) -> PartialResult 60 60 { 61 result = lhs;61 result = push(); 62 62 #{op.capitalized_name}::emit(this, result, lhs, rhs); 63 63 return { }; … … 71 71 auto LLIntGenerator::addOp<#{op_type(op)}>(ExpressionType operand, ExpressionType& result) -> PartialResult 72 72 { 73 result = operand;73 result = push(); 74 74 #{op.capitalized_name}::emit(this, result, operand); 75 75 return { }; -
trunk/Source/JavaScriptCore/llint/WebAssembly.asm
r252231 r252800 298 298 negi ws1 299 299 sxi2q ws1, ws1 300 leap (NumberOfWasmArguments + CalleeSaveSpaceAsVirtualRegisters ) * -8[cfr], ws0300 leap (NumberOfWasmArguments + CalleeSaveSpaceAsVirtualRegisters + 1) * -8[cfr], ws0 301 301 .zeroInitializeLocalsLoop: 302 302 addq 1, ws1 … … 589 589 590 590 loadi VectorSizeOffset[t2], t3 591 biaeq t0, t3, .default 591 bib t0, t3, .inBounds 592 593 .outOfBounds: 594 subi t3, 1, t0 595 596 .inBounds: 592 597 loadp VectorBufferOffset[t2], t2 593 loadi [t2, t0, 4], t3 598 muli sizeof Wasm::FunctionCodeBlock::JumpTableEntry, t0 599 600 loadi Wasm::FunctionCodeBlock::JumpTableEntry::startOffset[t2, t0], t1 601 loadi Wasm::FunctionCodeBlock::JumpTableEntry::dropCount[t2, t0], t3 602 loadi Wasm::FunctionCodeBlock::JumpTableEntry::keepCount[t2, t0], t5 603 dropKeep(t1, t3, t5) 604 605 loadis Wasm::FunctionCodeBlock::JumpTableEntry::target[t2, t0], t3 594 606 assert(macro(ok) btinz t3, .ok end) 595 607 wasmDispatchIndirect(t3) 596 597 .default:598 jump(ctx, m_defaultTarget)599 608 end) 600 609 … … 1994 2003 returnq(ctx, t0) 1995 2004 end) 2005 2006 macro dropKeep(startOffset, drop, keep) 2007 lshifti 3, startOffset 2008 subp cfr, startOffset, startOffset 2009 negi drop 2010 sxi2q drop, drop 2011 2012 .copyLoop: 2013 btiz keep, .done 2014 loadq [startOffset, drop, 8], t6 2015 storeq t6, [startOffset] 2016 subi 1, keep 2017 subp 8, startOffset 2018 jmp .copyLoop 2019 2020 .done: 2021 end 2022 2023 wasmOp(drop_keep, WasmDropKeep, macro(ctx) 2024 wgetu(ctx, m_startOffset, t0) 2025 wgetu(ctx, m_dropCount, t1) 2026 wgetu(ctx, m_keepCount, t2) 2027 2028 dropKeep(t0, t1, t2) 2029 2030 dispatch(ctx) 2031 end) -
trunk/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp
r251978 r252800 286 286 PartialResult WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&, const Stack& expressionStack = { }); 287 287 288 PartialResult WARN_UNUSED_RETURN endTopLevel(BlockSignature, const Stack&) { return { }; } 289 288 290 // Calls 289 291 PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, Vector<ExpressionType, 1>& results); … … 300 302 void setParser(FunctionParser<AirIRGenerator>* parser) { m_parser = parser; }; 301 303 void didFinishParsingLocals() { } 304 void didPopValueFromStack() { } 302 305 303 306 static Vector<Tmp> toTmpVector(const Vector<TypedTmp>& vector) -
trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
r252306 r252800 236 236 PartialResult WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&, const Stack& = { }); 237 237 238 PartialResult WARN_UNUSED_RETURN endTopLevel(BlockSignature, const Stack&) { return { }; } 239 238 240 // Calls 239 241 PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, ResultList& results); … … 245 247 void setParser(FunctionParser<B3IRGenerator>* parser) { m_parser = parser; }; 246 248 void didFinishParsingLocals() { } 249 void didPopValueFromStack() { } 247 250 248 251 Value* constant(B3::Type, uint64_t bits, Optional<Origin> = WTF::nullopt); -
trunk/Source/JavaScriptCore/wasm/WasmFunctionCodeBlock.cpp
r252310 r252800 76 76 auto FunctionCodeBlock::addJumpTable(size_t numberOfEntries) -> JumpTable& 77 77 { 78 #if !ASSERT_DISABLED79 m_jumpTables.append(JumpTable(numberOfEntries, 0));80 #else81 78 m_jumpTables.append(JumpTable(numberOfEntries)); 82 #endif83 79 return m_jumpTables.last(); 84 80 } -
trunk/Source/JavaScriptCore/wasm/WasmFunctionCodeBlock.h
r252310 r252800 106 106 const Signature& signature(unsigned index) const; 107 107 108 using JumpTable = Vector<InstructionStream::Offset>; 108 struct JumpTableEntry { 109 int target { 0 }; 110 unsigned startOffset; 111 unsigned dropCount; 112 unsigned keepCount; 113 }; 114 115 using JumpTable = Vector<JumpTableEntry>; 109 116 JumpTable& addJumpTable(size_t numberOfEntries); 110 117 const JumpTable& jumpTable(unsigned tableIndex) const; -
trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h
r251978 r252800 78 78 79 79 Vector<ControlEntry>& controlStack() { return m_controlStack; } 80 Stack& expressionStack() { return m_expressionStack; } 80 81 81 82 private: … … 90 91 WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't pop empty stack in " what); \ 91 92 result = m_expressionStack.takeLast(); \ 93 m_context.didPopValueFromStack(); \ 92 94 } while (0) 93 95 … … 177 179 } 178 180 } 181 WASM_FAIL_IF_HELPER_FAILS(m_context.endTopLevel(&m_signature, m_expressionStack)); 179 182 180 183 ASSERT(op == OpType::End); … … 439 442 Vector<ExpressionType> args; 440 443 WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(calleeSignature.argumentCount()), "can't allocate enough memory for call's ", calleeSignature.argumentCount(), " arguments"); 441 for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i) 444 for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i) { 442 445 args.uncheckedAppend(m_expressionStack.at(i)); 446 m_context.didPopValueFromStack(); 447 } 443 448 m_expressionStack.shrink(firstArgumentIndex); 444 449 … … 468 473 WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(argumentCount), "can't allocate enough memory for ", argumentCount, " call_indirect arguments"); 469 474 size_t firstArgumentIndex = m_expressionStack.size() - argumentCount; 470 for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i) 475 for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i) { 471 476 args.uncheckedAppend(m_expressionStack.at(i)); 477 m_context.didPopValueFromStack(); 478 } 472 479 m_expressionStack.shrink(firstArgumentIndex); 473 480 … … 609 616 WASM_PARSER_FAIL_IF(!m_expressionStack.size(), "can't drop on empty stack"); 610 617 m_expressionStack.takeLast(); 618 m_context.didPopValueFromStack(); 611 619 return { }; 612 620 } -
trunk/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp
r252310 r252800 33 33 #include "InstructionStream.h" 34 34 #include "Label.h" 35 #include "RegisterID.h"36 35 #include "WasmCallingConvention.h" 37 36 #include "WasmContextInlines.h" … … 40 39 #include "WasmGeneratorTraits.h" 41 40 #include "WasmThunks.h" 41 #include <wtf/CompletionHandler.h> 42 42 #include <wtf/RefPtr.h> 43 43 #include <wtf/StdUnorderedMap.h> … … 48 48 class LLIntGenerator : public BytecodeGeneratorBase<GeneratorTraits> { 49 49 public: 50 using ExpressionType = RefPtr<RegisterID>;50 using ExpressionType = VirtualRegister; 51 51 using ExpressionList = Vector<ExpressionType, 1>; 52 using Stack = ExpressionList;52 using Stack = Vector<ExpressionType, 16, UnsafeVectorOverflow>; 53 53 54 54 struct ControlLoop { … … 74 74 } 75 75 76 static ControlType loop(BlockSignature signature, const ExpressionList& results, Ref<Label> body, RefPtr<Label>continuation)76 static ControlType loop(BlockSignature signature, unsigned stackSize, Ref<Label>&& body, RefPtr<Label>&& continuation) 77 77 { 78 return ControlType(signature, results, WTFMove(continuation), ControlLoop { WTFMove(body) });79 } 80 81 static ControlType topLevel(BlockSignature signature, const ExpressionList& results, RefPtr<Label>continuation)78 return ControlType(signature, stackSize - signature->argumentCount(), WTFMove(continuation), ControlLoop { WTFMove(body) }); 79 } 80 81 static ControlType topLevel(BlockSignature signature, unsigned stackSize, RefPtr<Label>&& continuation) 82 82 { 83 return ControlType(signature, results, WTFMove(continuation), ControlTopLevel { });84 } 85 86 static ControlType block(BlockSignature signature, const ExpressionList& results, RefPtr<Label>continuation)83 return ControlType(signature, stackSize, WTFMove(continuation), ControlTopLevel { }); 84 } 85 86 static ControlType block(BlockSignature signature, unsigned stackSize, RefPtr<Label>&& continuation) 87 87 { 88 return ControlType(signature, results, WTFMove(continuation), ControlBlock { });89 } 90 91 static ControlType if_(BlockSignature signature, const ExpressionList& results, Ref<Label> alternate, RefPtr<Label>continuation)88 return ControlType(signature, stackSize - signature->argumentCount(), WTFMove(continuation), ControlBlock { }); 89 } 90 91 static ControlType if_(BlockSignature signature, unsigned stackSize, Ref<Label>&& alternate, RefPtr<Label>&& continuation) 92 92 { 93 return ControlType(signature, results, WTFMove(continuation), ControlIf { WTFMove(alternate) });93 return ControlType(signature, stackSize - signature->argumentCount(), WTFMove(continuation), ControlIf { WTFMove(alternate) }); 94 94 } 95 95 … … 101 101 } 102 102 103 unsigned targetArity() const 104 { 105 if (WTF::holds_alternative<ControlLoop>(*this)) 106 return m_signature->argumentCount(); 107 return m_signature->returnCount(); 108 } 109 110 unsigned stackSize() const { return m_stackSize; } 111 103 112 BlockSignature m_signature; 104 ExpressionList m_results;113 unsigned m_stackSize; 105 114 RefPtr<Label> m_continuation; 106 115 107 116 private: 108 117 template<typename T> 109 ControlType(BlockSignature signature, const ExpressionList& results, RefPtr<Label> continuation, Tt)118 ControlType(BlockSignature signature, unsigned stackSize, RefPtr<Label>&& continuation, T&& t) 110 119 : Base(WTFMove(t)) 111 120 , m_signature(signature) 112 , m_ results(results)121 , m_stackSize(stackSize) 113 122 , m_continuation(WTFMove(continuation)) 114 123 { … … 138 147 { 139 148 ASSERT(destinations.size() <= values.size()); 149 auto offset = values.size() - destinations.size(); 140 150 for (size_t i = 0; i < destinations.size(); ++i) 141 WasmMov::emit(this, destinations[destinations.size() - i - 1], values[values.size() - i - 1]); 142 } 143 144 145 static ExpressionType emptyExpression() { return nullptr; }; 151 WasmMov::emit(this, destinations[i], values[offset + i]); 152 } 153 154 enum NoConsistencyCheckTag { NoConsistencyCheck }; 155 ExpressionType push(NoConsistencyCheckTag) 156 { 157 m_maxStackSize = std::max(m_maxStackSize, ++m_stackSize); 158 return virtualRegisterForLocal(m_stackSize - 1); 159 } 160 161 ExpressionType push() 162 { 163 checkConsistency(); 164 return push(NoConsistencyCheck); 165 } 166 167 void didPopValueFromStack() { --m_stackSize; } 168 169 static ExpressionType emptyExpression() { return VirtualRegister { }; }; 146 170 Stack createStack() { return Stack(); } 147 171 bool isControlTypeIf(const ControlType& control) { return WTF::holds_alternative<ControlIf>(control); } … … 149 173 PartialResult WARN_UNUSED_RETURN addArguments(const Signature&); 150 174 PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t); 151 ExpressionType addConstant(Type, uint64_t);175 ExpressionType addConstant(Type, int64_t); 152 176 153 177 // References … … 188 212 PartialResult WARN_UNUSED_RETURN addLoop(BlockSignature, Stack& enclosingStack, ControlType& block, Stack& newStack, uint32_t loopIndex); 189 213 PartialResult WARN_UNUSED_RETURN addIf(ExpressionType condition, BlockSignature, Stack& enclosingStack, ControlType& result, Stack& newStack); 190 PartialResult WARN_UNUSED_RETURN addElse(ControlType&, const ExpressionList&);214 PartialResult WARN_UNUSED_RETURN addElse(ControlType&, Stack&); 191 215 PartialResult WARN_UNUSED_RETURN addElseToUnreachable(ControlType&); 192 216 193 PartialResult WARN_UNUSED_RETURN addReturn(const ControlType&, const ExpressionList& returnValues); 194 PartialResult WARN_UNUSED_RETURN addBranch(ControlType&, ExpressionType condition, const ExpressionList& returnValues); 195 PartialResult WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlType*>& targets, ControlType& defaultTargets, const ExpressionList& expressionStack); 196 PartialResult WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack); 197 PartialResult WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&, const Stack& expressionStack = { }); 217 PartialResult WARN_UNUSED_RETURN addReturn(const ControlType&, Stack& returnValues); 218 PartialResult WARN_UNUSED_RETURN addBranch(ControlType&, ExpressionType condition, Stack& returnValues); 219 PartialResult WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlType*>& targets, ControlType& defaultTargets, Stack& expressionStack); 220 PartialResult WARN_UNUSED_RETURN endBlock(ControlEntry&, Stack& expressionStack); 221 PartialResult WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&, const Stack& expressionStack = { }, bool unreachable = true); 222 PartialResult WARN_UNUSED_RETURN endTopLevel(BlockSignature, const Stack&); 198 223 199 224 // Calls … … 206 231 void setParser(FunctionParser<LLIntGenerator>* parser) { m_parser = parser; }; 207 232 208 void dump(const Vector<ControlEntry>&, const ExpressionList*) { }233 void dump(const Vector<ControlEntry>&, const Stack*) { } 209 234 210 235 private: … … 215 240 unsigned numberOfStackArguments; 216 241 ExpressionList arguments; 217 ExpressionList results;242 CompletionHandler<void(ExpressionList&)> commitResults; 218 243 }; 219 244 220 LLIntCallInformation callInformationFor(const Signature&, CallRole = CallRole::Caller); 221 222 VirtualRegister virtualRegisterForLocal(uint32_t index) 245 LLIntCallInformation callInformationForCaller(const Signature&); 246 Vector<VirtualRegister, 2> callInformationForCallee(const Signature&); 247 248 VirtualRegister virtualRegisterForWasmLocal(uint32_t index) 223 249 { 224 250 if (index < m_codeBlock->m_numArguments) … … 228 254 const uint32_t gprCount = callingConvention.gprArgs.size(); 229 255 const uint32_t fprCount = callingConvention.fprArgs.size(); 230 return ::JSC::virtualRegisterForLocal(index - m_codeBlock->m_numArguments + gprCount + fprCount + numberOfLLIntCalleeSaveRegisters); 231 } 232 233 ExpressionList tmpsForSignature(BlockSignature signature) 234 { 235 ExpressionList result(signature->returnCount()); 236 for (unsigned i = 0; i < signature->returnCount(); ++i) 237 result[i] = newTemporary(); 256 return virtualRegisterForLocal(index - m_codeBlock->m_numArguments + gprCount + fprCount + numberOfLLIntCalleeSaveRegisters); 257 } 258 259 ExpressionType jsNullConstant() 260 { 261 if (UNLIKELY(!m_jsNullConstant.isValid())) { 262 m_jsNullConstant = VirtualRegister(FirstConstantRegisterIndex + m_codeBlock->m_constants.size()); 263 m_codeBlock->m_constants.append(JSValue::encode(jsNull())); 264 if (UNLIKELY(Options::dumpGeneratedWasmBytecodes())) 265 m_codeBlock->m_constantTypes.append(Type::Anyref); 266 } 267 return m_jsNullConstant; 268 } 269 270 ExpressionType zeroConstant() 271 { 272 if (UNLIKELY(!m_zeroConstant.isValid())) { 273 m_zeroConstant = VirtualRegister(FirstConstantRegisterIndex + m_codeBlock->m_constants.size()); 274 m_codeBlock->m_constants.append(0); 275 if (UNLIKELY(Options::dumpGeneratedWasmBytecodes())) 276 m_codeBlock->m_constantTypes.append(Type::I32); 277 } 278 return m_zeroConstant; 279 } 280 281 void getDropKeepCount(const ControlType& target, unsigned& startOffset, unsigned& drop, unsigned& keep) 282 { 283 startOffset = target.stackSize() + 1; 284 keep = target.targetArity(); 285 drop = m_stackSize - target.stackSize() - target.targetArity(); 286 } 287 288 void dropKeep(Stack& values, const ControlType& target, bool dropValues) 289 { 290 unsigned startOffset; 291 unsigned keep; 292 unsigned drop; 293 294 getDropKeepCount(target, startOffset, drop, keep); 295 296 if (dropValues) 297 values.shrink(keep); 298 299 if (!drop) 300 return; 301 302 if (keep) 303 WasmDropKeep::emit(this, startOffset, drop, keep); 304 } 305 306 template<typename Functor> 307 void walkExpressionStack(Stack& expressionStack, unsigned stackSize, const Functor& functor) 308 { 309 for (unsigned i = expressionStack.size(); i > 0; --i) { 310 VirtualRegister slot = virtualRegisterForLocal(stackSize - i); 311 functor(expressionStack[expressionStack.size() - i], slot); 312 } 313 } 314 315 template<typename Functor> 316 void walkExpressionStack(Stack& expressionStack, const Functor& functor) 317 { 318 walkExpressionStack(expressionStack, m_stackSize, functor); 319 } 320 321 template<typename Functor> 322 void walkExpressionStack(ControlEntry& entry, const Functor& functor) 323 { 324 walkExpressionStack(entry.enclosedExpressionStack, entry.controlData.stackSize(), functor); 325 } 326 327 void checkConsistency() 328 { 329 #if !ASSERT_DISABLED 330 // The rules for locals and constants in the stack are: 331 // 1) Locals have to be materialized whenever a control entry is pushed to the control stack (i.e. every time we splitStack) 332 // NOTE: This is a trade-off so that set_local does not have to walk up the control stack looking for delayed get_locals 333 // 2) If the control entry is a loop, we also need to materialize constants in the newStack, since those slots will be written 334 // to from loop back edges 335 // 3) Both locals and constants have to be materialized before branches, since multiple branches might share the same target, 336 // we can't make any assumptions about the stack state at that point, so we materialize the stack. 337 for (ControlEntry& controlEntry : m_parser->controlStack()) { 338 walkExpressionStack(controlEntry, [&](VirtualRegister expression, VirtualRegister slot) { 339 ASSERT(expression == slot || expression.isConstant()); 340 }); 341 } 342 walkExpressionStack(m_parser->expressionStack(), [&](VirtualRegister expression, VirtualRegister slot) { 343 ASSERT(expression == slot || expression.isConstant() || expression.isArgument() || expression.toLocal() < m_codeBlock->m_numVars); 344 }); 345 #endif 346 } 347 348 void materializeConstantsAndLocals(Stack& expressionStack) 349 { 350 if (expressionStack.isEmpty()) 351 return; 352 353 checkConsistency(); 354 walkExpressionStack(expressionStack, [&](VirtualRegister& expression, VirtualRegister slot) { 355 ASSERT(expression == slot || expression.isConstant() || expression.isArgument() || expression.toLocal() < m_codeBlock->m_numVars); 356 if (expression == slot) 357 return; 358 WasmMov::emit(this, slot, expression); 359 expression = slot; 360 }); 361 checkConsistency(); 362 } 363 364 Stack splitStack(BlockSignature signature, Stack& stack) 365 { 366 Stack result = JSC::Wasm::splitStack(signature, stack); 367 368 m_stackSize -= result.size(); 369 checkConsistency(); 370 walkExpressionStack(stack, [&](VirtualRegister& expression, VirtualRegister slot) { 371 ASSERT(expression == slot || expression.isConstant() || expression.isArgument() || expression.toLocal() < m_codeBlock->m_numVars); 372 if (expression == slot || expression.isConstant()) 373 return; 374 WasmMov::emit(this, slot, expression); 375 expression = slot; 376 }); 377 checkConsistency(); 378 m_stackSize += result.size(); 238 379 return result; 239 }240 241 ExpressionType jsNullConstant()242 {243 if (!m_jsNullConstant)244 m_jsNullConstant = addConstant(Type::Anyref, JSValue::encode(jsNull()));245 return m_jsNullConstant;246 380 } 247 381 248 382 struct SwitchEntry { 249 383 InstructionStream::Offset offset; 250 InstructionStream::Offset* jumpTarget; 384 int* jumpTarget; 385 }; 386 387 struct ConstantMapHashTraits : WTF::GenericHashTraits<EncodedJSValue> { 388 static constexpr bool emptyValueIsZero = true; 389 static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(jsNull()); } 390 static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(jsNull()); } 251 391 }; 252 392 … … 257 397 HashMap<Label*, Vector<SwitchEntry>> m_switches; 258 398 ExpressionType m_jsNullConstant; 399 ExpressionType m_zeroConstant; 259 400 ExpressionList m_unitializedLocals; 260 StdUnorderedMap<uint64_t, VirtualRegister> m_constantMap; 401 HashMap<EncodedJSValue, VirtualRegister, WTF::IntHash<EncodedJSValue>, ConstantMapHashTraits> m_constantMap; 402 Vector<VirtualRegister, 2> m_results; 403 unsigned m_stackSize { 0 }; 404 unsigned m_maxStackSize { 0 }; 261 405 }; 262 406 … … 271 415 272 416 LLIntGenerator::LLIntGenerator(const ModuleInformation& info, unsigned functionIndex, ThrowWasmException throwWasmException, const Signature&) 273 : BytecodeGeneratorBase(makeUnique<FunctionCodeBlock>(functionIndex), numberOfLLIntCalleeSaveRegisters)417 : BytecodeGeneratorBase(makeUnique<FunctionCodeBlock>(functionIndex), 0) 274 418 , m_info(info) 275 419 , m_functionIndex(functionIndex) 276 420 { 421 m_codeBlock->m_numVars = numberOfLLIntCalleeSaveRegisters; 422 m_stackSize = numberOfLLIntCalleeSaveRegisters; 423 m_maxStackSize = numberOfLLIntCalleeSaveRegisters; 424 277 425 if (throwWasmException) 278 426 Thunks::singleton().setThrowWasmException(throwWasmException); … … 284 432 { 285 433 RELEASE_ASSERT(m_codeBlock); 434 m_codeBlock->m_numCalleeLocals = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_maxStackSize); 286 435 m_codeBlock->setInstructions(m_writer.finalize()); 287 436 return WTFMove(m_codeBlock); … … 291 440 #include "WasmLLIntGeneratorInlines.h" 292 441 293 auto LLIntGenerator::callInformationFor(const Signature& signature, CallRole role) -> LLIntCallInformation 294 { 442 auto LLIntGenerator::callInformationForCaller(const Signature& signature) -> LLIntCallInformation 443 { 444 // This function sets up the stack layout for calls. The desired stack layout is: 445 446 // FPRn 447 // ... 448 // FPR1 449 // FPR0 450 // --- 451 // GPRn 452 // ... 453 // GPR1 454 // GPR0 455 // ---- 456 // stackN 457 // ... 458 // stack1 459 // stack0 460 // --- 461 // call frame header 462 463 // We need to allocate at least space for all GPRs and FPRs. 464 // Return values use the same allocation layout. 465 466 const auto initialStackSize = m_stackSize; 467 295 468 const auto& callingConvention = wasmCallingConvention(); 296 469 const uint32_t gprCount = callingConvention.gprArgs.size(); … … 300 473 uint32_t gprIndex = 0; 301 474 uint32_t fprIndex = 0; 302 303 Vector<RefPtr<RegisterID>, 16> registers; 304 305 ExpressionList arguments(signature.argumentCount()); 306 ExpressionList results(signature.returnCount()); 475 uint32_t stackIndex = 0; 307 476 308 477 auto allocateStackRegister = [&](Type type) { 309 ASSERT(role == CallRole::Caller);310 478 switch (type) { 311 479 case Type::I32: … … 315 483 if (gprIndex < gprCount) 316 484 ++gprIndex; 317 else { 318 registers.append(newTemporary()); 485 else if (stackIndex++ >= stackCount) 319 486 ++stackCount; 320 }321 487 break; 322 488 case Type::F32: … … 324 490 if (fprIndex < fprCount) 325 491 ++fprIndex; 326 else { 327 registers.append(newTemporary()); 492 else if (stackIndex++ >= stackCount) 328 493 ++stackCount; 329 }330 494 break; 331 495 case Void: … … 336 500 337 501 338 if (role == CallRole::Callee) { 339 // Reuse the slots we allocated to spill the registers in addArguments 340 for (uint32_t i = gprCount + fprCount; i--;) 341 registers.append(new RegisterID(::JSC::virtualRegisterForLocal(numberOfLLIntCalleeSaveRegisters + i))); 342 } else { 343 for (uint32_t i = 0; i < gprCount; i++) 344 registers.append(newTemporary()); 345 for (uint32_t i = 0; i < fprCount; i++) 346 registers.append(newTemporary()); 347 348 for (uint32_t i = 0; i < signature.argumentCount(); i++) 349 allocateStackRegister(signature.argument(i)); 350 gprIndex = 0; 351 fprIndex = 0; 352 for (uint32_t i = 0; i < signature.returnCount(); i++) 353 allocateStackRegister(signature.returnType(i)); 354 } 355 356 unsigned stackOffset; 357 if (role == CallRole::Callee) 358 stackOffset = static_cast<unsigned>(-registers.last()->index()); 359 else { 360 // Align the stack 361 auto computeStackOffset = [&] { 362 return static_cast<unsigned>(-registers.last()->index()) + CallFrame::headerSizeInRegisters; 363 }; 364 while (computeStackOffset() % stackAlignmentRegisters()) 365 registers.append(newTemporary()); 366 stackOffset = computeStackOffset(); 367 } 368 369 ASSERT(role == CallRole::Caller || !stackCount); 370 const uint32_t maxGPRIndex = stackCount + gprCount; 502 for (uint32_t i = 0; i < signature.argumentCount(); i++) 503 allocateStackRegister(signature.argument(i)); 504 505 gprIndex = 0; 506 fprIndex = 0; 507 stackIndex = 0; 508 for (uint32_t i = 0; i < signature.returnCount(); i++) 509 allocateStackRegister(signature.returnType(i)); 510 511 // FIXME: we are allocating the extra space for the argument/return count in order to avoid interference, but we could do better 512 // NOTE: We increase arg count by 1 for the case of indirect calls 513 m_stackSize += std::max(signature.argumentCount() + 1, signature.returnCount()) + gprCount + fprCount + stackCount + CallFrame::headerSizeInRegisters; 514 if (m_stackSize % stackAlignmentRegisters()) 515 ++m_stackSize; 516 if (m_maxStackSize < m_stackSize) 517 m_maxStackSize = m_stackSize; 518 519 520 ExpressionList arguments(signature.argumentCount()); 521 ExpressionList temporaryResults(signature.returnCount()); 522 523 const unsigned stackOffset = m_stackSize; 524 const unsigned base = stackOffset - CallFrame::headerSizeInRegisters; 525 526 const uint32_t gprLimit = base - stackCount - gprCount; 527 const uint32_t fprLimit = gprLimit - fprCount; 528 529 stackIndex = base; 530 gprIndex = base - stackCount; 531 fprIndex = gprIndex - gprCount; 532 for (uint32_t i = 0; i < signature.argumentCount(); i++) { 533 switch (signature.argument(i)) { 534 case Type::I32: 535 case Type::I64: 536 case Type::Anyref: 537 case Type::Funcref: 538 if (gprIndex > gprLimit) 539 arguments[i] = virtualRegisterForLocal(--gprIndex); 540 else 541 arguments[i] = virtualRegisterForLocal(--stackIndex); 542 break; 543 case Type::F32: 544 case Type::F64: 545 if (fprIndex > fprLimit) 546 arguments[i] = virtualRegisterForLocal(--fprIndex); 547 else 548 arguments[i] = virtualRegisterForLocal(--stackIndex); 549 break; 550 case Void: 551 case Func: 552 RELEASE_ASSERT_NOT_REACHED(); 553 } 554 } 555 556 stackIndex = base; 557 gprIndex = base - stackCount; 558 fprIndex = gprIndex - gprCount; 559 for (uint32_t i = 0; i < signature.returnCount(); i++) { 560 switch (signature.returnType(i)) { 561 case Type::I32: 562 case Type::I64: 563 case Type::Anyref: 564 case Type::Funcref: 565 if (gprIndex > gprLimit) 566 temporaryResults[i] = virtualRegisterForLocal(--gprIndex); 567 else 568 temporaryResults[i] = virtualRegisterForLocal(--stackIndex); 569 break; 570 case Type::F32: 571 case Type::F64: 572 if (fprIndex > fprLimit) 573 temporaryResults[i] = virtualRegisterForLocal(--fprIndex); 574 else 575 temporaryResults[i] = virtualRegisterForLocal(--stackIndex); 576 break; 577 case Void: 578 case Func: 579 RELEASE_ASSERT_NOT_REACHED(); 580 } 581 } 582 583 m_stackSize = initialStackSize; 584 585 auto commitResults = [this, temporaryResults = WTFMove(temporaryResults)](ExpressionList& results) { 586 for (auto temporaryResult : temporaryResults) { 587 ExpressionType result = push(); 588 WasmMov::emit(this, result, temporaryResult); 589 results.append(result); 590 } 591 }; 592 593 return LLIntCallInformation { stackOffset, stackCount, WTFMove(arguments), WTFMove(commitResults) }; 594 } 595 596 auto LLIntGenerator::callInformationForCallee(const Signature& signature) -> Vector<VirtualRegister, 2> 597 { 598 if (m_results.size()) 599 return m_results; 600 601 m_results.reserveInitialCapacity(signature.returnCount()); 602 603 const auto& callingConvention = wasmCallingConvention(); 604 const uint32_t gprCount = callingConvention.gprArgs.size(); 605 const uint32_t fprCount = callingConvention.fprArgs.size(); 606 607 uint32_t gprIndex = 0; 608 uint32_t fprIndex = gprCount; 609 uint32_t stackIndex = 0; 610 const uint32_t maxGPRIndex = gprCount; 371 611 const uint32_t maxFPRIndex = maxGPRIndex + fprCount; 372 uint32_t stackIndex = 0; 373 auto appendForType = [&](Type type, unsigned index, auto& vector) {374 switch ( type) {612 613 for (uint32_t i = 0; i < signature.returnCount(); i++) { 614 switch (signature.returnType(i)) { 375 615 case Type::I32: 376 616 case Type::I64: … … 378 618 case Type::Funcref: 379 619 if (gprIndex < maxGPRIndex) 380 vector[index] = registers[registers.size() - gprIndex++ - 1]; 381 else { 382 if (role == CallRole::Caller) 383 vector[index] = registers[registers.size() - stackIndex++ - 1]; 384 else 385 vector[index] = new RegisterID(virtualRegisterForArgument(stackIndex++)); 386 } 620 m_results.append(virtualRegisterForLocal(numberOfLLIntCalleeSaveRegisters + gprIndex++)); 621 else 622 m_results.append(virtualRegisterForArgument(stackIndex++)); 387 623 break; 388 624 case Type::F32: 389 625 case Type::F64: 390 626 if (fprIndex < maxFPRIndex) 391 vector[index] = registers[registers.size() - fprIndex++ - 1]; 392 else { 393 if (role == CallRole::Caller) 394 vector[index] = registers[registers.size() - stackIndex++ - 1]; 395 else 396 vector[index] = new RegisterID(virtualRegisterForArgument(stackIndex++)); 397 } 627 m_results.append(virtualRegisterForLocal(numberOfLLIntCalleeSaveRegisters + fprIndex++)); 628 else 629 m_results.append(virtualRegisterForArgument(stackIndex++)); 398 630 break; 399 631 case Void: … … 401 633 RELEASE_ASSERT_NOT_REACHED(); 402 634 } 403 }; 404 405 gprIndex = stackCount; 406 fprIndex = maxGPRIndex; 407 for (uint32_t i = 0; i < signature.argumentCount(); i++) 408 appendForType(signature.argument(i), i, arguments); 409 gprIndex = stackCount; 410 fprIndex = maxGPRIndex; 411 for (uint32_t i = 0; i < signature.returnCount(); i++) 412 appendForType(signature.returnType(i), i, results); 413 414 if (role == CallRole::Caller) { 415 // Reserve space for call frame. 416 Vector<RefPtr<RegisterID>, CallFrame::headerSizeInRegisters + 2, UnsafeVectorOverflow> callFrame; 417 for (int i = 0; i < CallFrame::headerSizeInRegisters; ++i) 418 callFrame.append(newTemporary()); 419 } 420 421 return LLIntCallInformation { stackOffset, stackCount, WTFMove(arguments), WTFMove(results) }; 635 } 636 637 return m_results; 422 638 } 423 639 … … 436 652 uint32_t stackIndex = 0; 437 653 438 Vector< RefPtr<RegisterID>> registerArguments(gprCount + fprCount);654 Vector<VirtualRegister> registerArguments(gprCount + fprCount); 439 655 for (uint32_t i = 0; i < gprCount + fprCount; i++) 440 registerArguments[i] = addVar();656 registerArguments[i] = push(); 441 657 442 658 const auto addArgument = [&](uint32_t index, uint32_t& count, uint32_t max) { … … 465 681 } 466 682 683 m_codeBlock->m_numVars += gprCount + fprCount; 684 467 685 return { }; 468 686 } … … 470 688 auto LLIntGenerator::addLocal(Type type, uint32_t count) -> PartialResult 471 689 { 690 m_codeBlock->m_numVars += count; 472 691 while (count--) { 473 auto local = addVar();692 auto local = push(); 474 693 switch (type) { 475 694 case Type::Anyref: … … 486 705 void LLIntGenerator::didFinishParsingLocals() 487 706 { 707 if (m_unitializedLocals.isEmpty()) 708 return; 709 488 710 auto null = jsNullConstant(); 489 711 for (auto local : m_unitializedLocals) … … 492 714 } 493 715 494 auto LLIntGenerator::addConstant(Type type, uint64_t value) -> ExpressionType 495 { 496 VirtualRegister source(FirstConstantRegisterIndex + m_codeBlock->m_constants.size()); 497 auto result = m_constantMap.emplace(value, source); 498 if (result.second) { 716 auto LLIntGenerator::addConstant(Type type, int64_t value) -> ExpressionType 717 { 718 auto constant = [&] { 719 if (!value) 720 return zeroConstant(); 721 722 if (value == JSValue::encode(jsNull())) 723 return jsNullConstant(); 724 725 VirtualRegister source(FirstConstantRegisterIndex + m_codeBlock->m_constants.size()); 726 auto result = m_constantMap.add(value, source); 727 if (!result.isNewEntry) 728 return result.iterator->value; 499 729 m_codeBlock->m_constants.append(value); 500 730 if (UNLIKELY(Options::dumpGeneratedWasmBytecodes())) 501 731 m_codeBlock->m_constantTypes.append(type); 502 } else503 source = result.first->second;504 auto target = newTemporary();505 WasmMov::emit(this, target, source);506 return target;732 return source; 733 }; 734 // leave a hole if we need to materialize the constant 735 push(); 736 return constant(); 507 737 } 508 738 509 739 auto LLIntGenerator::getLocal(uint32_t index, ExpressionType& result) -> PartialResult 510 740 { 511 // FIXME: Remove unnecessary moves 512 // https://bugs.webkit.org/show_bug.cgi?id=203657 513 result = newTemporary(); 514 WasmMov::emit(this, result, virtualRegisterForLocal(index)); 741 // leave a hole if we need to materialize the local 742 push(); 743 result = virtualRegisterForWasmLocal(index); 515 744 return { }; 516 745 } … … 518 747 auto LLIntGenerator::setLocal(uint32_t index, ExpressionType value) -> PartialResult 519 748 { 520 WasmMov::emit(this, virtualRegisterForLocal(index), value); 749 VirtualRegister target = virtualRegisterForWasmLocal(index); 750 751 // If this local is currently on the stack we need to materialize it, otherwise it'll see the new value instead of the old one 752 walkExpressionStack(m_parser->expressionStack(), [&](VirtualRegister& expression, VirtualRegister slot) { 753 if (expression != target) 754 return; 755 WasmMov::emit(this, slot, expression); 756 expression = slot; 757 }); 758 759 WasmMov::emit(this, target, value); 760 521 761 return { }; 522 762 } … … 524 764 auto LLIntGenerator::getGlobal(uint32_t index, ExpressionType& result) -> PartialResult 525 765 { 526 result = newTemporary();766 result = push(); 527 767 WasmGetGlobal::emit(this, result, index); 528 768 return { }; … … 541 781 auto LLIntGenerator::addLoop(BlockSignature signature, Stack& enclosingStack, ControlType& block, Stack& newStack, uint32_t loopIndex) -> PartialResult 542 782 { 783 newStack = splitStack(signature, enclosingStack); 784 materializeConstantsAndLocals(newStack); 785 543 786 Ref<Label> body = newEmittedLabel(); 544 787 Ref<Label> continuation = newLabel(); 545 788 546 newStack = splitStack(signature, enclosingStack); 547 block = ControlType::loop(signature, newStack, WTFMove(body), WTFMove(continuation)); 789 block = ControlType::loop(signature, m_stackSize, WTFMove(body), WTFMove(continuation)); 548 790 549 791 Vector<VirtualRegister> osrEntryData; … … 555 797 const uint32_t fprCount = callingConvention.fprArgs.size(); 556 798 for (int32_t i = gprCount + fprCount + numberOfLLIntCalleeSaveRegisters; i < m_codeBlock->m_numVars; i++) 557 osrEntryData.append( ::JSC::virtualRegisterForLocal(i));799 osrEntryData.append(virtualRegisterForLocal(i)); 558 800 for (unsigned controlIndex = 0; controlIndex < m_parser->controlStack().size(); ++controlIndex) { 559 ExpressionList& expressionStack = m_parser->controlStack()[controlIndex].enclosedExpressionStack;801 Stack& expressionStack = m_parser->controlStack()[controlIndex].enclosedExpressionStack; 560 802 for (auto& expression : expressionStack) 561 osrEntryData.append(expression ->virtualRegister());803 osrEntryData.append(expression); 562 804 } 563 805 … … 571 813 auto LLIntGenerator::addTopLevel(BlockSignature signature) -> ControlType 572 814 { 573 return ControlType::topLevel(signature, tmpsForSignature(signature), newLabel());815 return ControlType::topLevel(signature, m_stackSize, newLabel()); 574 816 } 575 817 … … 577 819 { 578 820 newStack = splitStack(signature, enclosingStack); 579 newBlock = ControlType::block(signature, tmpsForSignature(signature), newLabel());821 newBlock = ControlType::block(signature, m_stackSize, newLabel()); 580 822 return { }; 581 823 } … … 586 828 Ref<Label> continuation = newLabel(); 587 829 830 newStack = splitStack(signature, enclosingStack); 831 588 832 WasmJfalse::emit(this, condition, alternate->bind(this)); 589 833 590 newStack = splitStack(signature, enclosingStack); 591 result = ControlType::if_(signature, tmpsForSignature(signature), WTFMove(alternate), WTFMove(continuation)); 592 return { }; 593 } 594 595 auto LLIntGenerator::addElse(ControlType& data, const ExpressionList& currentStack) -> PartialResult 834 result = ControlType::if_(signature, m_stackSize, WTFMove(alternate), WTFMove(continuation)); 835 return { }; 836 } 837 838 auto LLIntGenerator::addElse(ControlType& data, Stack& expressionStack) -> PartialResult 596 839 { 597 840 ASSERT(WTF::holds_alternative<ControlIf>(data)); 598 unifyValuesWithBlock(data.m_results, currentStack);841 materializeConstantsAndLocals(expressionStack); 599 842 WasmJmp::emit(this, data.m_continuation->bind(this)); 600 843 return addElseToUnreachable(data); … … 603 846 auto LLIntGenerator::addElseToUnreachable(ControlType& data) -> PartialResult 604 847 { 848 m_stackSize = data.stackSize() + data.m_signature->argumentCount(); 849 605 850 ControlIf& control = WTF::get<ControlIf>(data); 606 851 emitLabel(control.m_alternate.get()); 607 data = ControlType::block(data.m_signature, WTFMove(data.m_results), WTFMove(data.m_continuation));608 return { }; 609 } 610 611 auto LLIntGenerator::addReturn(const ControlType& data, const ExpressionList& returnValues) -> PartialResult852 data = ControlType::block(data.m_signature, m_stackSize, WTFMove(data.m_continuation)); 853 return { }; 854 } 855 856 auto LLIntGenerator::addReturn(const ControlType& data, Stack& returnValues) -> PartialResult 612 857 { 613 858 if (!data.m_signature->returnCount()) { … … 616 861 } 617 862 618 LLIntCallInformation info = callInformationFor(*data.m_signature, CallRole::Callee);619 unifyValuesWithBlock( info.results, returnValues);863 // no need to drop keep here, since we have to move anyway 864 unifyValuesWithBlock(callInformationForCallee(*data.m_signature), returnValues); 620 865 WasmRet::emit(this); 621 866 … … 623 868 } 624 869 625 auto LLIntGenerator::addBranch(ControlType& data, ExpressionType condition, const ExpressionList& returnValues) -> PartialResult 626 { 627 unifyValuesWithBlock(data.m_results, returnValues); 628 870 auto LLIntGenerator::addBranch(ControlType& data, ExpressionType condition, Stack& returnValues) -> PartialResult 871 { 629 872 RefPtr<Label> target = data.targetLabelForBranch(); 630 if (condition) 631 WasmJtrue::emit(this, condition, target->bind(this)); 632 else 633 WasmJmp::emit(this, target->bind(this)); 634 635 return { }; 636 } 637 638 auto LLIntGenerator::addSwitch(ExpressionType condition, const Vector<ControlType*>& targets, ControlType& defaultTarget, const ExpressionList& expressionStack) -> PartialResult 639 { 873 RefPtr<Label> skip = nullptr; 874 875 materializeConstantsAndLocals(returnValues); 876 877 if (condition.isValid()) { 878 skip = newLabel(); 879 WasmJfalse::emit(this, condition, skip->bind(this)); 880 } 881 882 dropKeep(returnValues, data, !skip); 883 WasmJmp::emit(this, target->bind(this)); 884 885 if (skip) 886 emitLabel(*skip); 887 888 return { }; 889 } 890 891 auto LLIntGenerator::addSwitch(ExpressionType condition, const Vector<ControlType*>& targets, ControlType& defaultTarget, Stack& expressionStack) -> PartialResult 892 { 893 materializeConstantsAndLocals(expressionStack); 894 640 895 unsigned tableIndex = m_codeBlock->numberOfJumpTables(); 641 FunctionCodeBlock::JumpTable& jumpTable = m_codeBlock->addJumpTable(targets.size()); 642 643 for (const auto& target : targets) 644 unifyValuesWithBlock(target->m_results, expressionStack); 645 unifyValuesWithBlock(defaultTarget.m_results, expressionStack); 646 647 WasmSwitch::emit(this, condition, tableIndex, defaultTarget.targetLabelForBranch()->bind(this)); 896 FunctionCodeBlock::JumpTable& jumpTable = m_codeBlock->addJumpTable(targets.size() + 1); 897 898 WasmSwitch::emit(this, condition, tableIndex); 648 899 649 900 unsigned index = 0; 650 901 InstructionStream::Offset offset = m_lastInstruction.offset(); 651 for (const auto& target : targets) { 652 RefPtr<Label> targetLabel = target->targetLabelForBranch(); 902 903 auto addTarget = [&](ControlType& target) { 904 RefPtr<Label> targetLabel = target.targetLabelForBranch(); 905 906 getDropKeepCount(target, jumpTable[index].startOffset, jumpTable[index].dropCount, jumpTable[index].keepCount); 907 653 908 if (targetLabel->isForward()) { 654 909 auto result = m_switches.add(targetLabel.get(), Vector<SwitchEntry>()); 655 ASSERT(!jumpTable[index] );656 result.iterator->value.append( { offset, &jumpTable[index++]});910 ASSERT(!jumpTable[index].target); 911 result.iterator->value.append(SwitchEntry { offset, &jumpTable[index++].target }); 657 912 } else { 658 int jumpTarget = targetLabel-> bind(this).target();913 int jumpTarget = targetLabel->location() - offset; 659 914 ASSERT(jumpTarget); 660 jumpTable[index++] = jumpTarget; 661 } 662 } 663 664 665 return { }; 666 } 667 668 auto LLIntGenerator::endBlock(ControlEntry& entry, ExpressionList& expressionStack) -> PartialResult 915 jumpTable[index++].target = jumpTarget; 916 } 917 }; 918 919 for (const auto& target : targets) 920 addTarget(*target); 921 addTarget(defaultTarget); 922 923 return { }; 924 } 925 926 auto LLIntGenerator::endBlock(ControlEntry& entry, Stack& expressionStack) -> PartialResult 927 { 928 // FIXME: We only need to materialize constants here if there exists a jump to this label 929 // https://bugs.webkit.org/show_bug.cgi?id=203657 930 materializeConstantsAndLocals(expressionStack); 931 return addEndToUnreachable(entry, expressionStack, false); 932 } 933 934 935 auto LLIntGenerator::addEndToUnreachable(ControlEntry& entry, const Stack& expressionStack, bool unreachable) -> PartialResult 669 936 { 670 937 ControlType& data = entry.controlData; 671 938 672 if (!WTF::holds_alternative<ControlLoop>(data)) 673 unifyValuesWithBlock(data.m_results, expressionStack); 674 675 return addEndToUnreachable(entry, expressionStack); 676 } 677 678 679 auto LLIntGenerator::addEndToUnreachable(ControlEntry& entry, const Stack& expressionStack) -> PartialResult 680 { 681 ControlType& data = entry.controlData; 682 683 emitLabel(*data.m_continuation); 684 685 if (!WTF::holds_alternative<ControlLoop>(data)) 686 entry.enclosedExpressionStack.appendVector(data.m_results); 687 else { 688 for (unsigned i = 0; i < data.m_signature->returnCount(); ++i) { 689 if (i < expressionStack.size()) 690 entry.enclosedExpressionStack.append(expressionStack[i]); 691 else 692 entry.enclosedExpressionStack.append(newTemporary()); 693 } 694 } 695 696 // TopLevel does not have any code after this so we need to make sure we emit a return here. 697 if (WTF::holds_alternative<ControlTopLevel>(data)) 698 return addReturn(data, entry.enclosedExpressionStack); 939 RELEASE_ASSERT(unreachable || m_stackSize == data.stackSize() + data.m_signature->returnCount()); 940 941 m_stackSize = data.stackSize(); 942 943 for (unsigned i = 0; i < data.m_signature->returnCount(); ++i) { 944 // We don't want to do a consistency check here because we just reset the stack size 945 // are pushing new values, while we already have the same values in the stack. 946 // The only reason we do things this way is so that it also works for unreachable blocks, 947 // since they might not have the right number of values in the expression stack. 948 // Instead, we do a stricter consistency check below. 949 auto tmp = push(NoConsistencyCheck); 950 ASSERT_UNUSED(expressionStack, unreachable || tmp == expressionStack[i]); 951 entry.enclosedExpressionStack.append(tmp); 952 } 953 954 if (m_lastOpcodeID == wasm_jmp && data.m_continuation->unresolvedJumps().size() == 1 && data.m_continuation->unresolvedJumps()[0] == static_cast<int>(m_lastInstruction.offset())) { 955 m_lastOpcodeID = wasm_unreachable; 956 m_writer.rewind(m_lastInstruction); 957 } else 958 emitLabel(*data.m_continuation); 959 960 return { }; 961 } 962 963 auto LLIntGenerator::endTopLevel(BlockSignature signature, const Stack& expressionStack) -> PartialResult 964 { 965 RELEASE_ASSERT(expressionStack.size() == signature->returnCount()); 966 967 if (!signature->returnCount()) { 968 WasmRetVoid::emit(this); 969 return { }; 970 } 971 972 checkConsistency(); 973 unifyValuesWithBlock(callInformationForCallee(*signature), expressionStack); 974 WasmRet::emit(this); 699 975 700 976 return { }; … … 704 980 { 705 981 ASSERT(signature.argumentCount() == args.size()); 706 LLIntCallInformation info = callInformationFor (signature);982 LLIntCallInformation info = callInformationForCaller(signature); 707 983 unifyValuesWithBlock(info.arguments, args); 708 results = WTFMove(info.results);709 984 if (Context::useFastTLS()) 710 985 WasmCall::emit(this, functionIndex, info.stackOffset, info.numberOfStackArguments); 711 986 else 712 987 WasmCallNoTls::emit(this, functionIndex, info.stackOffset, info.numberOfStackArguments); 988 info.commitResults(results); 713 989 714 990 return { }; … … 723 999 ASSERT(m_info.tables[tableIndex].type() == TableElementType::Funcref); 724 1000 725 LLIntCallInformation info = callInformationFor (signature);1001 LLIntCallInformation info = callInformationForCaller(signature); 726 1002 unifyValuesWithBlock(info.arguments, args); 727 results = WTFMove(info.results);728 1003 if (Context::useFastTLS()) 729 1004 WasmCallIndirect::emit(this, calleeIndex, m_codeBlock->addSignature(signature), info.stackOffset, info.numberOfStackArguments, tableIndex); 730 1005 else 731 1006 WasmCallIndirectNoTls::emit(this, calleeIndex, m_codeBlock->addSignature(signature), info.stackOffset, info.numberOfStackArguments, tableIndex); 1007 info.commitResults(results); 732 1008 733 1009 return { }; … … 736 1012 auto LLIntGenerator::addRefIsNull(ExpressionType value, ExpressionType& result) -> PartialResult 737 1013 { 738 result = value;1014 result = push(); 739 1015 WasmRefIsNull::emit(this, result, value); 740 1016 … … 744 1020 auto LLIntGenerator::addRefFunc(uint32_t index, ExpressionType& result) -> PartialResult 745 1021 { 746 result = newTemporary();1022 result = push(); 747 1023 WasmRefFunc::emit(this, result, index); 748 1024 … … 752 1028 auto LLIntGenerator::addTableGet(unsigned tableIndex, ExpressionType index, ExpressionType& result) -> PartialResult 753 1029 { 754 result = index;1030 result = push(); 755 1031 WasmTableGet::emit(this, result, index, tableIndex); 756 1032 … … 767 1043 auto LLIntGenerator::addTableSize(unsigned tableIndex, ExpressionType& result) -> PartialResult 768 1044 { 769 result = newTemporary();1045 result = push(); 770 1046 WasmTableSize::emit(this, result, tableIndex); 771 1047 … … 775 1051 auto LLIntGenerator::addTableGrow(unsigned tableIndex, ExpressionType fill, ExpressionType delta, ExpressionType& result) -> PartialResult 776 1052 { 777 result = fill;1053 result = push(); 778 1054 WasmTableGrow::emit(this, result, fill, delta, tableIndex); 779 1055 … … 797 1073 auto LLIntGenerator::addCurrentMemory(ExpressionType& result) -> PartialResult 798 1074 { 799 result = newTemporary();1075 result = push(); 800 1076 WasmCurrentMemory::emit(this, result); 801 1077 … … 805 1081 auto LLIntGenerator::addGrowMemory(ExpressionType delta, ExpressionType& result) -> PartialResult 806 1082 { 807 result = delta;1083 result = push(); 808 1084 WasmGrowMemory::emit(this, result, delta); 809 1085 … … 813 1089 auto LLIntGenerator::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) -> PartialResult 814 1090 { 815 result = condition;1091 result = push(); 816 1092 WasmSelect::emit(this, result, condition, nonZero, zero); 817 1093 … … 821 1097 auto LLIntGenerator::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t offset) -> PartialResult 822 1098 { 823 result = p ointer;1099 result = push(); 824 1100 switch (op) { 825 1101 case LoadOpType::I32Load8S: … … 933 1209 CASE(WasmJtrue) 934 1210 CASE(WasmJfalse) 935 case WasmSwitch::opcodeID: {936 ASSERT((!instruction->as<WasmSwitch, WasmOpcodeTraits>().m_defaultTarget));937 instruction->cast<WasmSwitch, WasmOpcodeTraits>()->setDefaultTarget(BoundLabel(target), [&]() {938 generator.m_codeBlock->addOutOfLineJumpTarget(instruction.offset(), target);939 return BoundLabel();940 });941 break;942 }943 1211 default: 944 ASSERT_NOT_REACHED();1212 RELEASE_ASSERT_NOT_REACHED(); 945 1213 } 946 1214 #undef CASE -
trunk/Source/JavaScriptCore/wasm/WasmLLIntPlan.cpp
r252310 r252800 81 81 82 82 if (m_exportedFunctionIndices.contains(functionIndex) || m_moduleInformation->referencedFunctions().contains(functionIndex)) { 83 auto locker = holdLock(m_lock);84 83 EmbederToWasmFunction entry; 85 84 entry.jit = makeUnique<CCallHelpers>(); 86 85 entry.function = m_createEmbedderWrapper(*entry.jit, signature, &m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, functionIndex); 86 auto locker = holdLock(m_lock); 87 87 auto result = m_embedderToWasmInternalFunctions.add(functionIndex, WTFMove(entry)); 88 88 ASSERT_UNUSED(result, result.isNewEntry); -
trunk/Source/JavaScriptCore/wasm/WasmValidate.cpp
r251978 r252800 162 162 163 163 Result WARN_UNUSED_RETURN addUnreachable() { return { }; } 164 Result WARN_UNUSED_RETURN endTopLevel(BlockSignature, const Stack&) { return { }; } 164 165 165 166 // Calls … … 177 178 void setParser(FunctionParser<Validate>*) { } 178 179 void didFinishParsingLocals() { } 180 void didPopValueFromStack() { } 179 181 180 182 private:
Note: See TracChangeset
for help on using the changeset viewer.