Changeset 241849 in webkit
- Timestamp:
- Feb 20, 2019 4:10:43 PM (5 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r241841 r241849 1 2019-02-20 Mark Lam <mark.lam@apple.com> 2 3 Add code to validate expected GC activity modelled by doesGC() against what the runtime encounters. 4 https://bugs.webkit.org/show_bug.cgi?id=193938 5 <rdar://problem/47616277> 6 7 Reviewed by Michael Saboff, Saam Barati, and Robin Morisset. 8 9 In DFG::SpeculativeJIT::compile() and FTL::LowerDFGToB3::compileNode(), before 10 emitting code / B3IR for each DFG node, we emit a write to set Heap::m_expectDoesGC 11 to the value returned by doesGC() for that node. In the runtime (i.e. in allocateCell() 12 and functions that can resolve a rope), we assert that Heap::m_expectDoesGC is 13 true. 14 15 This validation code is currently only enabled for debug builds. It is disabled 16 for release builds by default, but it can easily be made to run on release builds 17 as well by forcing ENABLE_DFG_DOES_GC_VALIDATION to 1 in Heap.h. 18 19 To allow this validation code to run on release builds as well, the validation uses 20 RELEASE_ASSERT instead of ASSERT. 21 22 To ensure that Heap.h is #include'd for all files that needs to do this validation 23 (so that the validation code is accidentally disabled), we guard the validation 24 code with an if conditional on constexpr bool validateDFGDoesGC (instead of using 25 a #if ENABLE(DFG_DOES_GC_VALIDATION)). This way, if Heap.h isn't #include'd, the 26 validation code will fail to build (no silent failures). 27 28 Currently, all JSC tests and Layout tests should pass with this validation enabled 29 in debug builds. We'll only see new failures if there's a regression or if new 30 tests reveal a previously untested code path that has an undetected issue. 31 32 * dfg/DFGOSRExit.cpp: 33 (JSC::DFG::OSRExit::executeOSRExit): 34 (JSC::DFG::OSRExit::compileExit): 35 * dfg/DFGSpeculativeJIT64.cpp: 36 (JSC::DFG::SpeculativeJIT::compile): 37 * ftl/FTLLowerDFGToB3.cpp: 38 (JSC::FTL::DFG::LowerDFGToB3::compileNode): 39 * ftl/FTLOSRExitCompiler.cpp: 40 (JSC::FTL::compileStub): 41 * heap/Heap.h: 42 (JSC::Heap::expectDoesGC const): 43 (JSC::Heap::setExpectDoesGC): 44 (JSC::Heap::addressOfExpectDoesGC): 45 * jit/JITArithmetic.cpp: 46 (JSC::JIT::emit_compareAndJump): 47 * runtime/JSCellInlines.h: 48 (JSC::tryAllocateCellHelper): 49 * runtime/JSString.h: 50 (JSC::jsSingleCharacterString): 51 (JSC::JSString::toAtomicString const): 52 (JSC::JSString::toExistingAtomicString const): 53 (JSC::JSString::value const): 54 (JSC::JSString::tryGetValue const): 55 (JSC::JSRopeString::unsafeView const): 56 (JSC::JSRopeString::viewWithUnderlyingString const): 57 (JSC::JSString::unsafeView const): 58 1 59 2019-02-20 Andy Estes <aestes@apple.com> 2 60 -
trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp
r241222 r241849 1 1 /* 2 * Copyright (C) 2011-201 8Apple Inc. All rights reserved.2 * Copyright (C) 2011-2019 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 338 338 ASSERT(&exec->vm() == &vm); 339 339 auto& cpu = context.cpu; 340 341 if (validateDFGDoesGC) { 342 // We're about to exit optimized code. So, there's no longer any optimized 343 // code running that expects no GC. 344 vm.heap.setExpectDoesGC(true); 345 } 340 346 341 347 if (vm.callFrameForCatch) { … … 1390 1396 } 1391 1397 1398 if (validateDFGDoesGC) { 1399 // We're about to exit optimized code. So, there's no longer any optimized 1400 // code running that expects no GC. We need to set this before arguments 1401 // materialization below (see emitRestoreArguments()). 1402 jit.store8(CCallHelpers::TrustedImm32(true), vm.heap.addressOfExpectDoesGC()); 1403 } 1404 1392 1405 // Need to ensure that the stack pointer accounts for the worst-case stack usage at exit. This 1393 1406 // could toast some stack that the DFG used. We need to do it before storing to stack offsets -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r241210 r241849 1 1 /* 2 * Copyright (C) 2011-201 8Apple Inc. All rights reserved.2 * Copyright (C) 2011-2019 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 34 34 #include "DFGAbstractInterpreterInlines.h" 35 35 #include "DFGCallArrayAllocatorSlowPathGenerator.h" 36 #include "DFGDoesGC.h" 36 37 #include "DFGOperations.h" 37 38 #include "DFGSlowPathGenerator.h" … … 1900 1901 { 1901 1902 NodeType op = node->op(); 1902 1903 1904 if (validateDFGDoesGC) { 1905 bool expectDoesGC = doesGC(m_jit.graph(), node); 1906 m_jit.store8(TrustedImm32(expectDoesGC), m_jit.vm()->heap.addressOfExpectDoesGC()); 1907 } 1908 1903 1909 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION) 1904 1910 m_jit.clearRegisterAllocationOffsets(); -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r241228 r241849 1 1 /* 2 * Copyright (C) 2013-201 8Apple Inc. All rights reserved.2 * Copyright (C) 2013-2019 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 44 44 #include "DFGAbstractInterpreterInlines.h" 45 45 #include "DFGCapabilities.h" 46 #include "DFGDoesGC.h" 46 47 #include "DFGDominators.h" 47 48 #include "DFGInPlaceAbstractState.h" … … 526 527 m_interpreter.startExecuting(); 527 528 m_interpreter.executeKnownEdgeTypes(m_node); 528 529 530 if (validateDFGDoesGC) { 531 bool expectDoesGC = doesGC(m_graph, m_node); 532 m_out.store(m_out.constBool(expectDoesGC), m_out.absolute(vm().heap.addressOfExpectDoesGC())); 533 } 534 529 535 switch (m_node->op()) { 530 536 case DFG::Upsilon: -
trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp
r241222 r241849 1 1 /* 2 * Copyright (C) 2013-201 8Apple Inc. All rights reserved.2 * Copyright (C) 2013-2019 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 245 245 saveAllRegisters(jit, registerScratch); 246 246 247 if (validateDFGDoesGC) { 248 // We're about to exit optimized code. So, there's no longer any optimized 249 // code running that expects no GC. We need to set this before object 250 // materialization below. 251 jit.store8(CCallHelpers::TrustedImm32(true), vm->heap.addressOfExpectDoesGC()); 252 } 253 247 254 // Bring the stack back into a sane form and assert that it's sane. 248 255 jit.popToRestore(GPRInfo::regT0); -
trunk/Source/JavaScriptCore/heap/Heap.h
r240216 r241849 2 2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) 3 3 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 4 * Copyright (C) 2003-201 7Apple Inc. All rights reserved.4 * Copyright (C) 2003-2019 Apple Inc. All rights reserved. 5 5 * 6 6 * This library is free software; you can redistribute it and/or … … 96 96 } 97 97 98 #if !ASSERT_DISABLED 99 #define ENABLE_DFG_DOES_GC_VALIDATION 1 100 #else 101 #define ENABLE_DFG_DOES_GC_VALIDATION 0 102 #endif 103 constexpr bool validateDFGDoesGC = ENABLE_DFG_DOES_GC_VALIDATION; 104 98 105 typedef HashCountedSet<JSCell*> ProtectCountSet; 99 106 typedef HashCountedSet<const char*> TypeCountSet; … … 294 301 unsigned barrierThreshold() const { return m_barrierThreshold; } 295 302 const unsigned* addressOfBarrierThreshold() const { return &m_barrierThreshold; } 303 304 #if ENABLE(DFG_DOES_GC_VALIDATION) 305 bool expectDoesGC() const { return m_expectDoesGC; } 306 void setExpectDoesGC(bool value) { m_expectDoesGC = value; } 307 bool* addressOfExpectDoesGC() { return &m_expectDoesGC; } 308 #else 309 bool expectDoesGC() const { UNREACHABLE_FOR_PLATFORM(); return true; } 310 void setExpectDoesGC(bool) { UNREACHABLE_FOR_PLATFORM(); } 311 bool* addressOfExpectDoesGC() { UNREACHABLE_FOR_PLATFORM(); return nullptr; } 312 #endif 296 313 297 314 // If true, the GC believes that the mutator is currently messing with the heap. We call this … … 582 599 Markable<CollectionScope, EnumMarkableTraits<CollectionScope>> m_lastCollectionScope; 583 600 Lock m_raceMarkStackLock; 601 #if ENABLE(DFG_DOES_GC_VALIDATION) 602 bool m_expectDoesGC { true }; 603 #endif 584 604 585 605 StructureIDTable m_structureIDTable; -
trunk/Source/JavaScriptCore/jit/JITArithmetic.cpp
r240138 r241849 180 180 int op2 = bytecode.m_rhs.offset(); 181 181 unsigned target = jumpTarget(instruction, bytecode.m_targetLabel); 182 bool disallowAllocation = false; 182 183 if (isOperandConstantChar(op1)) { 183 184 emitGetVirtualRegister(op2, regT0); … … 186 187 emitLoadCharacterString(regT0, regT0, failures); 187 188 addSlowCase(failures); 188 addJump(branch32(commute(condition), regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue( )[0])), target);189 addJump(branch32(commute(condition), regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue(disallowAllocation)[0])), target); 189 190 return; 190 191 } … … 195 196 emitLoadCharacterString(regT0, regT0, failures); 196 197 addSlowCase(failures); 197 addJump(branch32(condition, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue( )[0])), target);198 addJump(branch32(condition, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue(disallowAllocation)[0])), target); 198 199 return; 199 200 } -
trunk/Source/JavaScriptCore/runtime/JSCellInlines.h
r240965 r241849 1 1 /* 2 * Copyright (C) 2012-201 8Apple Inc. All rights reserved.2 * Copyright (C) 2012-2019 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 167 167 { 168 168 VM& vm = *heap.vm(); 169 if (validateDFGDoesGC) 170 RELEASE_ASSERT(heap.expectDoesGC()); 171 169 172 ASSERT(deferralContext || !DisallowGC::isInEffectOnCurrentThread()); 170 173 ASSERT(size >= sizeof(T)); -
trunk/Source/JavaScriptCore/runtime/JSString.h
r241493 r241849 2 2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 3 3 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 4 * Copyright (C) 2003-201 8Apple Inc. All rights reserved.4 * Copyright (C) 2003-2019 Apple Inc. All rights reserved. 5 5 * 6 6 * This library is free software; you can redistribute it and/or … … 164 164 inline bool equal(ExecState*, JSString* other) const; 165 165 const String& value(ExecState*) const; 166 inline const String& tryGetValue( ) const;166 inline const String& tryGetValue(bool allocationAllowed = true) const; 167 167 const StringImpl* tryGetValueImpl() const; 168 168 ALWAYS_INLINE unsigned length() const { return m_length; } … … 516 516 ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c) 517 517 { 518 if (validateDFGDoesGC) 519 RELEASE_ASSERT(vm->heap.expectDoesGC()); 518 520 if (c <= maxSingleCharacterString) 519 521 return vm->smallStrings.singleCharacterString(c); … … 540 542 ALWAYS_INLINE AtomicString JSString::toAtomicString(ExecState* exec) const 541 543 { 544 if (validateDFGDoesGC) 545 RELEASE_ASSERT(vm()->heap.expectDoesGC()); 542 546 if (isRope()) 543 547 static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec); … … 547 551 ALWAYS_INLINE RefPtr<AtomicStringImpl> JSString::toExistingAtomicString(ExecState* exec) const 548 552 { 553 if (validateDFGDoesGC) 554 RELEASE_ASSERT(vm()->heap.expectDoesGC()); 549 555 if (isRope()) 550 556 return static_cast<const JSRopeString*>(this)->resolveRopeToExistingAtomicString(exec); … … 556 562 inline const String& JSString::value(ExecState* exec) const 557 563 { 564 if (validateDFGDoesGC) 565 RELEASE_ASSERT(vm()->heap.expectDoesGC()); 558 566 if (isRope()) 559 567 static_cast<const JSRopeString*>(this)->resolveRope(exec); … … 561 569 } 562 570 563 inline const String& JSString::tryGetValue() const 564 { 565 if (isRope()) { 566 // Pass nullptr for the ExecState so that resolveRope does not throw in the event of an OOM error. 567 static_cast<const JSRopeString*>(this)->resolveRope(nullptr); 568 } 571 inline const String& JSString::tryGetValue(bool allocationAllowed) const 572 { 573 if (allocationAllowed) { 574 if (validateDFGDoesGC) 575 RELEASE_ASSERT(vm()->heap.expectDoesGC()); 576 if (isRope()) { 577 // Pass nullptr for the ExecState so that resolveRope does not throw in the event of an OOM error. 578 static_cast<const JSRopeString*>(this)->resolveRope(nullptr); 579 } 580 } else 581 RELEASE_ASSERT(!isRope()); 569 582 return m_value; 570 583 } … … 740 753 ALWAYS_INLINE StringView JSRopeString::unsafeView(ExecState* exec) const 741 754 { 755 if (validateDFGDoesGC) 756 RELEASE_ASSERT(vm()->heap.expectDoesGC()); 742 757 if (isSubstring()) { 743 758 if (is8Bit()) … … 751 766 ALWAYS_INLINE StringViewWithUnderlyingString JSRopeString::viewWithUnderlyingString(ExecState* exec) const 752 767 { 768 if (validateDFGDoesGC) 769 RELEASE_ASSERT(vm()->heap.expectDoesGC()); 753 770 if (isSubstring()) { 754 771 auto& base = substringBase()->m_value; … … 763 780 ALWAYS_INLINE StringView JSString::unsafeView(ExecState* exec) const 764 781 { 782 if (validateDFGDoesGC) 783 RELEASE_ASSERT(vm()->heap.expectDoesGC()); 765 784 if (isRope()) 766 785 return static_cast<const JSRopeString*>(this)->unsafeView(exec);
Note: See TracChangeset
for help on using the changeset viewer.