Changeset 207266 in webkit
- Timestamp:
- Oct 12, 2016 6:42:53 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 17 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/CMakeLists.txt
r207004 r207266 173 173 b3/B3Variable.cpp 174 174 b3/B3VariableValue.cpp 175 b3/B3WasmBoundsCheckValue.cpp 175 176 176 177 bindings/ScriptFunctionCall.cpp -
trunk/Source/JavaScriptCore/ChangeLog
r207263 r207266 1 2016-10-12 Keith Miller <keith_miller@apple.com> 2 3 B3 needs a special WasmBoundsCheck Opcode 4 https://bugs.webkit.org/show_bug.cgi?id=163246 5 6 Reviewed by Filip Pizlo. 7 8 This patch adds a new Opcode, WasmBoundsCheck, as well as a B3::Value subclass for it, 9 WasmBoundsCheckValue. WasmBoundsCheckValue takes three pieces of information. The first is 10 the Int32 pointer value used to be used by the Load. Next is the pinned register. The 11 pinned register must be pinned by calling proc.setPinned() prior to compiling the 12 Procedure. Lastly, the WasmBoundsCheckValue takes an offset. The WasmBoundsCheckValue is 13 will then emit code that side-exits if the Int64 sum of the offset and pointer is greater 14 than or equal to the value in the pinnedRegister. Instead of taking a generator for each 15 value like Check/Patchpoint, WasmBoundsCheck gets its generator directly off Air::Code. In 16 Air this patch adds a new Custom opcode, WasmBoundsCheck. 17 18 In the future we should add WasmBoundsCheck to CSE so it can eliminate redundant bounds 19 checks. At the first cut, we can remove any WasmBoundsCheck dominated by another 20 WasmBoundsCheck with the same pointer and pinnedGPR, and a larger offset. 21 22 * CMakeLists.txt: 23 * JavaScriptCore.xcodeproj/project.pbxproj: 24 * b3/B3LowerToAir.cpp: 25 (JSC::B3::Air::LowerToAir::imm): 26 (JSC::B3::Air::LowerToAir::lower): 27 * b3/B3Opcode.cpp: 28 (WTF::printInternal): 29 * b3/B3Opcode.h: 30 * b3/B3Procedure.cpp: 31 (JSC::B3::Procedure::setWasmBoundsCheckGenerator): 32 * b3/B3Procedure.h: 33 (JSC::B3::Procedure::setWasmBoundsCheckGenerator): 34 * b3/B3Validate.cpp: 35 * b3/B3Value.cpp: 36 (JSC::B3::Value::effects): 37 (JSC::B3::Value::typeFor): 38 * b3/B3WasmBoundsCheckValue.cpp: Added. 39 (JSC::B3::WasmBoundsCheckValue::~WasmBoundsCheckValue): 40 (JSC::B3::WasmBoundsCheckValue::WasmBoundsCheckValue): 41 (JSC::B3::WasmBoundsCheckValue::dumpMeta): 42 * b3/B3WasmBoundsCheckValue.h: Added. 43 (JSC::B3::WasmBoundsCheckValue::accepts): 44 (JSC::B3::WasmBoundsCheckValue::pinnedGPR): 45 (JSC::B3::WasmBoundsCheckValue::offset): 46 * b3/air/AirCode.h: 47 (JSC::B3::Air::Code::setWasmBoundsCheckGenerator): 48 (JSC::B3::Air::Code::wasmBoundsCheckGenerator): 49 * b3/air/AirCustom.cpp: 50 (JSC::B3::Air::WasmBoundsCheckCustom::isValidForm): 51 * b3/air/AirCustom.h: 52 (JSC::B3::Air::WasmBoundsCheckCustom::forEachArg): 53 (JSC::B3::Air::WasmBoundsCheckCustom::isValidFormStatic): 54 (JSC::B3::Air::WasmBoundsCheckCustom::admitsStack): 55 (JSC::B3::Air::WasmBoundsCheckCustom::isTerminal): 56 (JSC::B3::Air::WasmBoundsCheckCustom::hasNonArgNonControlEffects): 57 (JSC::B3::Air::WasmBoundsCheckCustom::generate): 58 * b3/air/AirOpcode.opcodes: 59 * b3/testb3.cpp: 60 (JSC::B3::testWasmBoundsCheck): 61 (JSC::B3::run): 62 1 63 2016-10-12 Filip Pizlo <fpizlo@apple.com> 2 64 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r207239 r207266 1207 1207 531374BD1D5CE67600AF7A0B /* WASMPlan.h in Headers */ = {isa = PBXBuildFile; fileRef = 531374BC1D5CE67600AF7A0B /* WASMPlan.h */; }; 1208 1208 531374BF1D5CE95000AF7A0B /* WASMPlan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 531374BE1D5CE95000AF7A0B /* WASMPlan.cpp */; }; 1209 5341FC701DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5341FC6F1DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp */; }; 1210 5341FC721DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */; }; 1209 1211 53486BB71C1795C300F6F3AF /* JSTypedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 53486BB61C1795C300F6F3AF /* JSTypedArray.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1210 1212 53486BBB1C18E84500F6F3AF /* JSTypedArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53486BBA1C18E84500F6F3AF /* JSTypedArray.cpp */; }; … … 3442 3444 531374BC1D5CE67600AF7A0B /* WASMPlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WASMPlan.h; sourceTree = "<group>"; }; 3443 3445 531374BE1D5CE95000AF7A0B /* WASMPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WASMPlan.cpp; sourceTree = "<group>"; }; 3446 5341FC6F1DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3WasmBoundsCheckValue.cpp; path = b3/B3WasmBoundsCheckValue.cpp; sourceTree = "<group>"; }; 3447 5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3WasmBoundsCheckValue.h; path = b3/B3WasmBoundsCheckValue.h; sourceTree = "<group>"; }; 3444 3448 53486BB61C1795C300F6F3AF /* JSTypedArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypedArray.h; sourceTree = "<group>"; }; 3445 3449 53486BBA1C18E84500F6F3AF /* JSTypedArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSTypedArray.cpp; sourceTree = "<group>"; }; … … 4858 4862 0FEC84BA1BDACDAC0080FF74 /* B3BlockWorklist.h */, 4859 4863 DCFDFBD71D1F5D9800FE3D72 /* B3BottomProvider.h */, 4864 5341FC6F1DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp */, 4865 5341FC711DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h */, 4860 4866 0F6B8ADE1C4EFE1700969052 /* B3BreakCriticalEdges.cpp */, 4861 4867 0F6B8ADF1C4EFE1700969052 /* B3BreakCriticalEdges.h */, … … 7651 7657 0F1E3A67153A21E2000F9456 /* DFGSilentRegisterSavePlan.h in Headers */, 7652 7658 0FFB921D16D02F300055A5DB /* DFGSlowPathGenerator.h in Headers */, 7659 5341FC721DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h in Headers */, 7653 7660 86EC9DD31328DF82002B2AD7 /* DFGSpeculativeJIT.h in Headers */, 7654 7661 0F682FB319BCB36400FA3BAD /* DFGSSACalculator.h in Headers */, … … 9366 9373 0F766D2F15A8DCE0008F363E /* GCAwareJITStubRoutine.cpp in Sources */, 9367 9374 2ADFA26318EF3540004F9FCC /* GCLogging.cpp in Sources */, 9375 5341FC701DAC33E500E7E4D7 /* B3WasmBoundsCheckValue.cpp in Sources */, 9368 9376 0F93329F14CA7DCA0085F3C6 /* GetByIdStatus.cpp in Sources */, 9369 9377 0F0332C318B01763005F979A /* GetByIdVariant.cpp in Sources */, -
trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp
r207163 r207266 569 569 } 570 570 571 Arg imm(int64_t intValue) 572 { 573 if (Arg::isValidImmForm(intValue)) 574 return Arg::imm(intValue); 575 return Arg(); 576 } 577 571 578 Arg imm(Value* value) 572 579 { 573 if (value->hasInt()) { 574 int64_t intValue = value->asInt(); 575 if (Arg::isValidImmForm(intValue)) 576 return Arg::imm(intValue); 577 } 580 if (value->hasInt()) 581 return imm(value->asInt()); 578 582 return Arg(); 579 583 } … … 2628 2632 } 2629 2633 2634 case B3::WasmBoundsCheck: { 2635 WasmBoundsCheckValue* value = m_value->as<WasmBoundsCheckValue>(); 2636 2637 Value* ptr = value->child(0); 2638 2639 Arg temp = m_code.newTmp(Arg::GP); 2640 append(Inst(Move32, value, tmp(ptr), temp)); 2641 if (value->offset()) { 2642 if (imm(value->offset())) 2643 append(Add64, imm(value->offset()), temp); 2644 else { 2645 Arg bigImm = m_code.newTmp(Arg::GP); 2646 append(Move, Arg::bigImm(value->offset()), bigImm); 2647 append(Add64, bigImm, temp); 2648 } 2649 } 2650 append(Inst(Air::WasmBoundsCheck, value, temp, Arg(value->pinnedGPR()))); 2651 return; 2652 } 2653 2630 2654 case Upsilon: { 2631 2655 Value* value = m_value->child(0); -
trunk/Source/JavaScriptCore/b3/B3Opcode.cpp
r206595 r207266 273 273 out.print("Check"); 274 274 return; 275 case WasmBoundsCheck: 276 out.print("WasmBoundsCheck"); 277 return; 275 278 case Upsilon: 276 279 out.print("Upsilon"); -
trunk/Source/JavaScriptCore/b3/B3Opcode.h
r206595 r207266 210 210 Check, 211 211 212 // Special Wasm opcode that takes a Int32, a special pinned gpr and an offset. This node exists 213 // to allow us to CSE WasmBoundsChecks if both use the same pointer and one dominates the other. 214 // Without some such node B3 would not have enough information about the inner workings of wasm 215 // to be able to perform such optimizations. 216 WasmBoundsCheck, 217 212 218 // SSA support, in the style of DFG SSA. 213 219 Upsilon, // This uses the UpsilonValue class. -
trunk/Source/JavaScriptCore/b3/B3Procedure.cpp
r207004 r207266 349 349 } 350 350 351 void Procedure::setWasmBoundsCheckGenerator(RefPtr<WasmBoundsCheckGenerator> generator) 352 { 353 code().setWasmBoundsCheckGenerator(generator); 354 } 355 351 356 } } // namespace JSC::B3 352 357 -
trunk/Source/JavaScriptCore/b3/B3Procedure.h
r207004 r207266 59 59 namespace Air { class Code; } 60 60 61 typedef void WasmBoundsCheckGeneratorFunction(CCallHelpers&, GPRReg, unsigned); 62 typedef SharedTask<WasmBoundsCheckGeneratorFunction> WasmBoundsCheckGenerator; 63 61 64 // This represents B3's view of a piece of code. Note that this object must exist in a 1:1 62 65 // relationship with Air::Code. B3::Procedure and Air::Code are just different facades of the B3 … … 221 224 PCToOriginMap& pcToOriginMap() { return m_pcToOriginMap; } 222 225 PCToOriginMap releasePCToOriginMap() { return WTFMove(m_pcToOriginMap); } 226 227 JS_EXPORT_PRIVATE void setWasmBoundsCheckGenerator(RefPtr<WasmBoundsCheckGenerator>); 228 229 template<typename Functor> 230 void setWasmBoundsCheckGenerator(const Functor& functor) 231 { 232 setWasmBoundsCheckGenerator(RefPtr<WasmBoundsCheckGenerator>(createSharedTask<WasmBoundsCheckGeneratorFunction>(functor))); 233 } 223 234 224 235 private: -
trunk/Source/JavaScriptCore/b3/B3Validate.cpp
r206694 r207266 29 29 #if ENABLE(B3_JIT) 30 30 31 #include "AirCode.h" 31 32 #include "B3ArgumentRegValue.h" 32 33 #include "B3BasicBlockInlines.h" … … 41 42 #include "B3Variable.h" 42 43 #include "B3VariableValue.h" 44 #include "B3WasmBoundsCheckValue.h" 43 45 #include <wtf/HashSet.h> 44 46 #include <wtf/StringPrintStream.h> … … 413 415 VALIDATE(value->as<StackmapValue>()->constrainedChild(0).rep() == ValueRep::WarmAny, ("At ", *value)); 414 416 validateStackmap(value); 417 break; 418 case WasmBoundsCheck: 419 VALIDATE(!value->kind().hasExtraBits(), ("At ", *value)); 420 VALIDATE(value->numChildren() == 1, ("At ", *value)); 421 VALIDATE(value->child(0)->type() == Int32, ("At ", *value)); 422 VALIDATE(m_procedure.code().isPinned(value->as<WasmBoundsCheckValue>()->pinnedGPR()), ("At ", *value)); 423 VALIDATE(m_procedure.code().wasmBoundsCheckGenerator(), ("At ", *value)); 415 424 break; 416 425 case Upsilon: -
trunk/Source/JavaScriptCore/b3/B3Value.cpp
r206846 r207266 616 616 case Check: 617 617 result = Effects::forCheck(); 618 break; 619 case WasmBoundsCheck: 620 result.readsPinned = true; 621 result.exitsSideways = true; 618 622 break; 619 623 case Upsilon: … … 810 814 case Oops: 811 815 case EntrySwitch: 816 case WasmBoundsCheck: 812 817 return Void; 813 818 case Select: -
trunk/Source/JavaScriptCore/b3/air/AirCode.h
r207004 r207266 53 53 class CCallSpecial; 54 54 55 typedef void WasmBoundsCheckGeneratorFunction(CCallHelpers&, GPRReg, unsigned); 56 typedef SharedTask<WasmBoundsCheckGeneratorFunction> WasmBoundsCheckGenerator; 57 55 58 // This is an IR that is very close to the bare metal. It requires about 40x more bytes than the 56 59 // generated machine code - for example if you're generating 1MB of machine code, you need about … … 261 264 262 265 const char* lastPhaseName() const { return m_lastPhaseName; } 266 267 void setWasmBoundsCheckGenerator(RefPtr<WasmBoundsCheckGenerator> generator) 268 { 269 m_wasmBoundsCheckGenerator = generator; 270 } 271 272 RefPtr<WasmBoundsCheckGenerator> wasmBoundsCheckGenerator() const { return m_wasmBoundsCheckGenerator; } 263 273 264 274 // This is a hash of the code. You can use this if you want to put code into a hashtable, but … … 299 309 Vector<FrequentedBlock> m_entrypoints; // This is empty until after lowerEntrySwitch(). 300 310 Vector<CCallHelpers::Label> m_entrypointLabels; // This is empty until code generation. 311 RefPtr<WasmBoundsCheckGenerator> m_wasmBoundsCheckGenerator; 301 312 const char* m_lastPhaseName; 302 313 }; -
trunk/Source/JavaScriptCore/b3/air/AirCustom.cpp
r195298 r207266 179 179 } 180 180 181 bool WasmBoundsCheckCustom::isValidForm(Inst& inst) 182 { 183 if (inst.args.size() != 2) 184 return false; 185 if (!inst.args[0].isTmp() && !inst.args[0].isSomeImm()) 186 return false; 187 188 return inst.args[1].isReg(); 189 } 190 191 181 192 } } } // namespace JSC::B3::Air 182 193 -
trunk/Source/JavaScriptCore/b3/air/AirCustom.h
r206525 r207266 28 28 #if ENABLE(B3_JIT) 29 29 30 #include "AirCode.h" 31 #include "AirGenerationContext.h" 30 32 #include "AirInst.h" 31 33 #include "AirSpecial.h" 32 #include "B3Value.h" 34 #include "B3ValueInlines.h" 35 #include "B3WasmBoundsCheckValue.h" 33 36 34 37 namespace JSC { namespace B3 { namespace Air { … … 274 277 }; 275 278 279 struct WasmBoundsCheckCustom : public CommonCustomBase<WasmBoundsCheckCustom> { 280 template<typename Func> 281 static void forEachArg(Inst& inst, const Func& functor) 282 { 283 functor(inst.args[0], Arg::Use, Arg::GP, Arg::Width64); 284 functor(inst.args[1], Arg::Use, Arg::GP, Arg::Width64); 285 } 286 287 template<typename... Arguments> 288 static bool isValidFormStatic(Arguments...) 289 { 290 return false; 291 } 292 293 static bool isValidForm(Inst&); 294 295 static bool admitsStack(Inst&, unsigned) 296 { 297 return false; 298 } 299 300 static bool isTerminal(Inst&) 301 { 302 return false; 303 } 304 305 static bool hasNonArgNonControlEffects(Inst&) 306 { 307 return true; 308 } 309 310 static CCallHelpers::Jump generate(Inst& inst, CCallHelpers& jit, GenerationContext& context) 311 { 312 WasmBoundsCheckValue* value = inst.origin->as<WasmBoundsCheckValue>(); 313 CCallHelpers::Jump outOfBounds = Inst(Air::Branch64, value, Arg::relCond(CCallHelpers::AboveOrEqual), inst.args[0], inst.args[1]).generate(jit, context); 314 315 context.latePaths.append(createSharedTask<GenerationContext::LatePathFunction>( 316 [=] (CCallHelpers& jit, Air::GenerationContext&) { 317 outOfBounds.link(&jit); 318 context.code->wasmBoundsCheckGenerator()->run(jit, value->pinnedGPR(), value->offset()); 319 })); 320 321 // We said we were not a terminal. 322 return CCallHelpers::Jump(); 323 } 324 }; 325 276 326 } } } // namespace JSC::B3::Air 277 327 -
trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes
r207039 r207266 890 890 custom ColdCCall 891 891 892 892 # This is a special wasm opcode that branches to a trap handler. This uses the generator located to Air::Code 893 # to produce the side-exit code. 894 custom WasmBoundsCheck 895 -
trunk/Source/JavaScriptCore/b3/testb3.cpp
r207164 r207266 55 55 #include "B3ValueInlines.h" 56 56 #include "B3VariableValue.h" 57 #include "B3WasmBoundsCheckValue.h" 57 58 #include "CCallHelpers.h" 58 59 #include "FPRInfo.h" … … 13728 13729 } 13729 13730 CHECK(found); 13731 } 13732 13733 void testWasmBoundsCheck(unsigned offset) 13734 { 13735 Procedure proc; 13736 GPRReg pinned = GPRInfo::argumentGPR1; 13737 proc.pinRegister(pinned); 13738 13739 proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR, unsigned actualOffset) { 13740 CHECK_EQ(pinnedGPR, pinned); 13741 CHECK_EQ(actualOffset, offset); 13742 13743 // This should always work because a function this simple should never have callee 13744 // saves. 13745 jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR); 13746 jit.emitFunctionEpilogue(); 13747 jit.ret(); 13748 }); 13749 13750 BasicBlock* root = proc.addBlock(); 13751 Value* left = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); 13752 if (pointerType() != Int32) 13753 left = root->appendNew<Value>(proc, Trunc, Origin(), left); 13754 root->appendNew<WasmBoundsCheckValue>(proc, Origin(), left, pinned, offset); 13755 Value* result = root->appendNew<Const32Value>(proc, Origin(), 0x42); 13756 root->appendNewControlValue(proc, Return, Origin(), result); 13757 13758 auto code = compile(proc); 13759 CHECK_EQ(invoke<int32_t>(*code, 1, 2 + offset), 0x42); 13760 CHECK_EQ(invoke<int32_t>(*code, 3, 2 + offset), 42); 13761 CHECK_EQ(invoke<int32_t>(*code, 2, 2 + offset), 42); 13730 13762 } 13731 13763 … … 15149 15181 RUN(testPatchpointTerminalReturnValue(true)); 15150 15182 RUN(testPatchpointTerminalReturnValue(false)); 15151 15183 15152 15184 RUN(testMemoryFence()); 15153 15185 RUN(testStoreFence()); … … 15169 15201 RUN(testLoadBaseIndexShift32()); 15170 15202 RUN(testOptimizeMaterialization()); 15171 15203 15204 RUN(testWasmBoundsCheck(0)); 15205 RUN(testWasmBoundsCheck(100)); 15206 RUN(testWasmBoundsCheck(10000)); 15207 RUN(testWasmBoundsCheck(std::numeric_limits<unsigned>::max() - 5)); 15208 15172 15209 if (isX86()) { 15173 15210 RUN(testBranchBitAndImmFusion(Identity, Int64, 1, Air::BranchTest32, Air::Arg::Tmp)); -
trunk/Websites/webkit.org/ChangeLog
r206973 r207266 1 2016-10-12 Keith Miller <keith_miller@apple.com> 2 3 B3 needs a special WasmBoundsCheck Opcode 4 https://bugs.webkit.org/show_bug.cgi?id=163246 5 6 Reviewed by Filip Pizlo. 7 8 Update the docs for the new WasmBoundsCheck opcode. 9 10 * docs/b3/intermediate-representation.html: 11 1 12 2016-10-09 Simon Fraser <simon.fraser@apple.com> 2 13 -
trunk/Websites/webkit.org/docs/b3/intermediate-representation.html
r206739 r207266 537 537 to an instruction that branches to the exit if @a >= @b or if either @a or @b are 538 538 NaN. Must use the CheckValue class.</dd> 539 540 <dt>Void WasmBoundsCheck(Int32, pinnedGPR, offset)</dt> 541 <dd>Special Wasm opcode. This branches on the first child. If the first child plus the offset 542 produces a Int64 less than to the pinnedGPR this falls through. Otherwise, it branches to 543 the exit path generated by the passed generator. Unlike the Patch/Check family, the 544 generator used by WasmBoundsCheck sould be set on the Procuder itself. The GRPReg passed in 545 pinnedGPR must also be marked as pinned by calling the Procedure's pinning API. B3 assumes 546 the WasmBoundsCheck will side-exit when the it branches, so the generator must do some kind 547 of termination. In Wasm this is used to trap and unwind back to JS. Must use the 548 WasmBoundsCheckValue class.</dd> 539 549 540 550 <dt>Void Upsilon(T, ^phi)</dt>
Note: See TracChangeset
for help on using the changeset viewer.