Changeset 275797 in webkit
- Timestamp:
- Apr 10, 2021, 9:12:19 AM (4 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 35 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r275653 r275797 1 2021-04-10 Mark Lam <mark.lam@apple.com> 2 3 Enable VMTraps checks in RETURN_IF_EXCEPTION. 4 https://bugs.webkit.org/show_bug.cgi?id=224078 5 rdar://75037057 6 7 Reviewed by Keith Miller. 8 9 * stress/watchdog-fire-while-in-forEachInIterable.js: Added. 10 1 11 2021-04-07 Yusuke Suzuki <ysuzuki@apple.com> 2 12 -
trunk/Source/JavaScriptCore/CMakeLists.txt
r275363 r275797 877 877 runtime/DateInstance.h 878 878 runtime/DateInstanceCache.h 879 runtime/DeferTermination.h 879 880 runtime/DeferredWorkTimer.h 880 881 runtime/DefinePropertyAttributes.h -
trunk/Source/JavaScriptCore/ChangeLog
r275788 r275797 1 2021-04-10 Mark Lam <mark.lam@apple.com> 2 3 Enable VMTraps checks in RETURN_IF_EXCEPTION. 4 https://bugs.webkit.org/show_bug.cgi?id=224078 5 rdar://75037057 6 7 Reviewed by Keith Miller. 8 9 In pre-existing code, termination of a VM's execution can already be requested 10 asynchronously (with respect to the mutator thread). For example, sources of such 11 a request can be a watchdog timer firing, or a request to stop execution issued 12 from a main web thread to a worker thread. 13 14 This request is made by firing the VMTraps::NeedTermination event on VMTraps. 15 Firing the event here only means setting a flag to indicate the presence of the 16 request. We still have to wait till the mutator thread reaches one of the 17 pre-designated polling check points to call VMTraps::handleTraps() in order to 18 service the request. As a result of this need to wait for a polling check point, 19 if the mutator is executing in a long running C++ loop, then a termination request 20 may not be serviced for a long time. 21 22 However, we observed that a lot of our C++ loops already have RETURN_IF_EXCEPTION 23 checks. Hence, if we can check VMTraps::needHandling() there, we can service the 24 VMTraps events more frequently even in a lot of C++ loops, and get a better response. 25 26 Full details of what this patch changes: 27 28 1. Shorten some type and methods names in the VMTraps class to make code easier to 29 read e.g. EventType => Event, needTrapHandling => needHandling. 30 31 2. Remove the VMTraps::Mask class. Mask was introduced so that we can express a 32 concatenation of multiple VMTraps events to form a bit mask in a simple way. 33 In the end, it isn't flexible enough but makes the code more complicated than 34 necessary. It is now replaced by the simpler solution of using macros to define 35 the Events as bit fields. Having Events as bit fields intrinsically make them 36 easy to concatenate (bitwise or) or filter (bitwise and). 37 38 Also removed the unused VMTraps::Error class. 39 40 3. Make VMTraps::BitField a uint32_t. There was always unused padding in VMTraps 41 to allow for this. So, we'll just extend it to a full 32-bit to make it easier 42 to add more events in the future for other uses. 43 44 4. Add NeedExceptionHandling as a VMTrap::Event. 45 46 5. Make VMTraps::m_trapBits Atomic. This makes it easier to set and clear the 47 NeedExceptionHandling bit from the mutator without a lock. 48 49 6. RETURN_IF_EXCEPTION now checks VMTraps::m_trapBits (via VMTraps::needHandling()) 50 instead of checking VM::m_exception. If the VMTraps::m_trapBits is non-null, 51 the macro will call VM:hasExceptionsAfterHandlingTraps() to service VMTraps 52 events as appropriate before returning whether an exception is being thrown. 53 The result of VM:hasExceptionsAfterHandlingTraps() will determine if 54 RETURN_IF_EXCEPTION returns or not. 55 56 VM:hasExceptionsAfterHandlingTraps() is intentionally designed to take a minimum 57 of arguments (just the VM as this pointer). This is because RETURN_IF_EXCEPTION 58 is called from many places, and we would like to minimize code size bloating 59 from this change. 60 61 7. Simplify paramaters of VMTraps::handleTraps(). 62 63 NeedDebuggerBreak's callFrame argument was always vm.topCallFrame anyway. 64 So, the patch makes it explicit, and removes the callFrame parameter. 65 66 NeedWatchdogCheck's globalObject argument should have always been 67 vm.entryScope->globalObject(), and we can remove the globalObject parameter. 68 69 Before this, we pass in whichever globalObject was convenient to grab hold of. 70 However, the idea of the watchdog is to time out the current script executing 71 on the stack. Hence, it makes sense to identify thay script by the globalObject 72 in use at VM entry. 73 74 So far, the only clients that uses the watchdog mechanism only operates in 75 scenarios with only one globalObject anyway. So this formalization to use 76 VMEntryScope's globalObject does not change the expected behavior. 77 78 8. Make the execution of termination more robust. Before reading this, please 79 read the description of the Events in VMTraps.h first, especially the section 80 on NeedTermination. 81 82 Here's the life cycle of a termination: 83 84 a. a client requests termination of the current execution stack by calling 85 VM::notifyNeedTermination(). notifyNeedTermination() does 2 things: 86 87 i. fire the NeedTermination event on VMTraps. 88 ii. set the VM::m_terminationInProgress flag. 89 90 b. Firing the NeedTermination event on VMTraps means setting the NeedTermination 91 bit on VMTraps::m_trapBits. This bit will be polled by the mutator thread 92 later at various designated points (including RETURN_IF_EXCEPTION, which we 93 added in this patch). 94 95 Once the mutator sees the NeedTermination bit is set, it will clear the bit 96 and throw the TerminationException (see VMTraps::handleTraps()). This is 97 unless the mutator thread is currently in a DeferTermination scope (see (8) 98 below). If in a DeferTermination scope, then it will not throw the 99 TerminationException. 100 101 Since the NeedTermination bit is cleared, the VM will no longer call 102 VMTraps::handleTraps() to service the event. If the mutator thread is in 103 a DeferTermination scope, then on exiting the scope (at scope destruction), 104 the scope will see that VM::m_terminationInProgress is set, and throw the 105 deferred TerminationException then. 106 107 c. The TerminationException will trigger unwinding out of the current stack 108 until we get to the outermost VMEntryScope. 109 110 d. At the the outermost VMEntryScope, we will clear VM::m_terminationInProgress 111 if the NeedTermination bit in VMtraps::m_trapBits is cleared. 112 113 If the NeedTermination bit is set, then that means we haven't thrown the 114 TerminationException yet. Currently, clients expect that we must throw the 115 TerminationException if NeedTermination was requested (again, read comments 116 at the top of VMTraps.h). 117 118 If the NeedTermination bit is set, we'll leave VM::m_terminationInProgress 119 set until the next time we re-enter the VM and exit to the outermost 120 VMEntryScope. 121 122 e. The purpose of VM::m_terminationInProgress is to provide a summary of the 123 fact that the VM is in a state of trying to terminate the current stack. 124 125 Note that this state is first indicated by the NeedTermination bit being set 126 in VMTraps::m_trapBits. Then, in VMTraps::handleTraps(), the state is 127 handed of with the NeedTermination bit being cleared, and the 128 TerminationException being thrown. 129 130 While the VM is in this termination state, we need to prevent new DFG/FTL 131 JIT code from being compiled and run. The reason is the firing of the 132 NeedTermination event has invalidated DFG/FTL code on the stack, thereby 133 allowing their baseline / LLInt versions which have VMTraps polling checks 134 to run. We don't want to compile new DFG / FTL code and possibly get stuck 135 in loops in there before the termination is complete. 136 137 In operationOptimize(), we check if VM::m_terminationInProgress is set, and 138 prevent new DFG (and therefore FTL) code from being compiled if needed. 139 Note: it is easier to check a single flag, VM::m_terminationInProgress, 140 then to check both if the NeedTermination bit is set or if the 141 TerminationException is being being thrown. 142 143 9. One complication of being able to service VMTraps in RETURN_IF_EXCEPTION checks 144 is that some of our code (usually for lengthier initializations and bootstrapping) 145 currently does not handle exceptions well, e.g. JSGlobalObject::init(). They 146 rely on the code crashing if an exception is thrown while still initializing. 147 148 However, for a worker thread, a TerminationException (requested by the main 149 thread) may arrive before the initialization is complete. This can lead to 150 crashes because part of the initialization may be aborted in the presence of 151 an exception, while other parts still expect everything prior to have been 152 initialized correctly. For resource exhaustion cases (which is abnormal), it 153 is OK to crash. For the TerminationException (which can be part of normal 154 operation), we should not be crashing. 155 156 To work around this, we introduce a DeferTermination RAII scope object that we 157 deploy in this type of initialization code. With the scope in effect, 158 159 a. if a TerminationException arrives but hasn't been thrown yet, it will be 160 deferred till the scope ends before being thrown. 161 b. if a TerminationException has already been thrown, the scope will stash 162 the exception, clear it from the VM so that the initialization code can 163 run to completion, and then re-throw the exception when the scope ends. 164 165 Currently, we only need to use the DeferTermination scope in a few places 166 where we know that initialization code will only run for a short period of time. 167 168 DeferTermination should not be used for code that can block waiting on an 169 external event for a long time. Obviously, doing so will prevent the VM 170 termination mechanism from working. 171 172 10. Replaced llint_slow_path_check_if_exception_is_uncatchable_and_notify_profiler 173 and operationCheckIfExceptionIsUncatchableAndNotifyProfiler with 174 llint_slow_path_retrieve_and_clear_exception_if_catchable and 175 operationRetrieveAndClearExceptionIfCatchable. 176 177 The 2 runtime functions doesn't actually do anything to notify a profiler. 178 So, we drop that part of the name. 179 180 After returning from these runtime functions respectively, the previous LLInt 181 and JIT code, which calls these runtimes functions, would go on to load 182 VM::m_exception, and then store a nullptr there to clear it. This is wasteful. 183 184 This patch changes the runtime function to clear and return the Exception 185 instead. As a result, the calling LLInt and JIT code is simplified a bit. 186 187 Note also that clearing an exception now also entails clearing the 188 NeedExceptionHandling bit in VMTraps::m_trapBits in an atomic way. The above 189 change makes it easy to do this clearing with C++ code. 190 191 11. Fix ScriptFunctionCall::call() to handle exceptions correctly. Previously, 192 it had one case where it propagates an exception, while another eats it. 193 Change this function to eat the exception in both cases. This is approproiate 194 because ScriptFunctionCall is only used to execute some Inspector instrumentation 195 calls. It doesn't make sense to propagate the exception back to user code. 196 197 12. Fix the lazy initialization of JSGlobalObject::m_defaultCollator to be able to 198 handle the TerminationException. 199 200 13. Not related to TerminationException, but this patch also fixes 201 MarkedArgumentBuffer::expandCapacity() to use Gigacage::tryMalloc() instead of 202 Gigacage::malloc(). This is needed as one of the fixes to make the 203 accompanying test case work. 204 205 This patch increases code size by 320K (144K for JSC, 176K for WebCore) measured 206 on x86_64. 207 208 * CMakeLists.txt: 209 * JavaScriptCore.xcodeproj/project.pbxproj: 210 * assembler/MacroAssemblerARM64.h: 211 (JSC::MacroAssemblerARM64::branchTest32): 212 * assembler/MacroAssemblerARMv7.h: 213 (JSC::MacroAssemblerARMv7::branchTest32): 214 * assembler/MacroAssemblerMIPS.h: 215 (JSC::MacroAssemblerMIPS::branchTest32): 216 * assembler/MacroAssemblerX86Common.h: 217 (JSC::MacroAssemblerX86Common::branchTest32): 218 * bindings/ScriptFunctionCall.cpp: 219 (Deprecated::ScriptFunctionCall::call): 220 * dfg/DFGSpeculativeJIT.cpp: 221 (JSC::DFG::SpeculativeJIT::compileCheckTraps): 222 * ftl/FTLLowerDFGToB3.cpp: 223 (JSC::FTL::DFG::LowerDFGToB3::compileCheckTraps): 224 * interpreter/Interpreter.cpp: 225 (JSC::Interpreter::executeProgram): 226 (JSC::Interpreter::executeCall): 227 (JSC::Interpreter::executeConstruct): 228 (JSC::Interpreter::execute): 229 (JSC::Interpreter::executeModuleProgram): 230 * interpreter/InterpreterInlines.h: 231 (JSC::Interpreter::execute): 232 * jit/JITOpcodes.cpp: 233 (JSC::JIT::emit_op_catch): 234 (JSC::JIT::emit_op_check_traps): 235 * jit/JITOpcodes32_64.cpp: 236 (JSC::JIT::emit_op_catch): 237 * jit/JITOperations.cpp: 238 (JSC::JSC_DEFINE_JIT_OPERATION): 239 * jit/JITOperations.h: 240 * llint/LLIntSlowPaths.cpp: 241 (JSC::LLInt::LLINT_SLOW_PATH_DECL): 242 * llint/LLIntSlowPaths.h: 243 * llint/LowLevelInterpreter.asm: 244 * llint/LowLevelInterpreter32_64.asm: 245 * llint/LowLevelInterpreter64.asm: 246 * runtime/ArgList.cpp: 247 (JSC::MarkedArgumentBuffer::expandCapacity): 248 * runtime/DeferTermination.h: Added. 249 (JSC::DeferTermination::DeferTermination): 250 (JSC::DeferTermination::~DeferTermination): 251 * runtime/ExceptionScope.h: 252 (JSC::ExceptionScope::exception const): 253 (JSC::ExceptionScope::exception): Deleted. 254 * runtime/JSGlobalObject.cpp: 255 (JSC::JSGlobalObject::init): 256 (JSC::JSGlobalObject::finishCreation): 257 * runtime/LazyPropertyInlines.h: 258 (JSC::ElementType>::callFunc): 259 * runtime/StringPrototype.cpp: 260 (JSC::JSC_DEFINE_HOST_FUNCTION): 261 * runtime/VM.cpp: 262 (JSC::VM::hasExceptionsAfterHandlingTraps): 263 (JSC::VM::clearException): 264 (JSC::VM::setException): 265 (JSC::VM::throwTerminationException): 266 (JSC::VM::throwException): 267 * runtime/VM.h: 268 (JSC::VM::terminationInProgress const): 269 (JSC::VM::setTerminationInProgress): 270 (JSC::VM::notifyNeedTermination): 271 (JSC::VM::DeferExceptionScope::DeferExceptionScope): 272 (JSC::VM::DeferExceptionScope::~DeferExceptionScope): 273 (JSC::VM::handleTraps): Deleted. 274 (JSC::VM::needTrapHandling): Deleted. 275 (JSC::VM::needTrapHandlingAddress): Deleted. 276 (JSC::VM::setException): Deleted. 277 (JSC::VM::clearException): Deleted. 278 * runtime/VMEntryScope.cpp: 279 (JSC::VMEntryScope::~VMEntryScope): 280 * runtime/VMTraps.cpp: 281 (JSC::VMTraps::tryInstallTrapBreakpoints): 282 (JSC::VMTraps::fireTrap): 283 (JSC::VMTraps::handleTraps): 284 (JSC::VMTraps::takeTopPriorityTrap): 285 (JSC::VMTraps::deferTermination): 286 (JSC::VMTraps::undoDeferTermination): 287 * runtime/VMTraps.h: 288 (JSC::VMTraps::onlyContainsAsyncEvents): 289 (JSC::VMTraps::needHandling const): 290 (JSC::VMTraps::trapBitsAddress): 291 (JSC::VMTraps::isDeferringTermination const): 292 (JSC::VMTraps::notifyGrabAllLocks): 293 (JSC::VMTraps::hasTrapBit): 294 (JSC::VMTraps::clearTrapBit): 295 (JSC::VMTraps::setTrapBit): 296 (JSC::VMTraps::Mask::Mask): Deleted. 297 (JSC::VMTraps::Mask::allEventTypes): Deleted. 298 (JSC::VMTraps::Mask::bits const): Deleted. 299 (JSC::VMTraps::Mask::init): Deleted. 300 (JSC::VMTraps::interruptingTraps): Deleted. 301 (JSC::VMTraps::needTrapHandling): Deleted. 302 (JSC::VMTraps::needTrapHandlingAddress): Deleted. 303 (JSC::VMTraps::hasTrapForEvent): Deleted. 304 (JSC::VMTraps::setTrapForEvent): Deleted. 305 (JSC::VMTraps::clearTrapForEvent): Deleted. 306 1 307 2021-04-09 Alexey Shvayka <shvaikalesh@gmail.com> 2 308 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r275363 r275797 1993 1993 FE99B2491C24C3D300C82159 /* JITNegGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FE99B2481C24B6D300C82159 /* JITNegGenerator.h */; }; 1994 1994 FE9F3FB92613C7890069E89F /* ResourceExhaustion.h in Headers */ = {isa = PBXBuildFile; fileRef = FE9F3FB82613C7880069E89F /* ResourceExhaustion.h */; }; 1995 FE9F3FC826163CA90069E89F /* DeferTermination.h in Headers */ = {isa = PBXBuildFile; fileRef = FE9F3FC626163CA90069E89F /* DeferTermination.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1995 1996 FEA08620182B7A0400F6D851 /* Breakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861E182B7A0400F6D851 /* Breakpoint.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1996 1997 FEA08621182B7A0400F6D851 /* DebuggerPrimitives.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 5364 5365 FE9F3FB82613C7880069E89F /* ResourceExhaustion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResourceExhaustion.h; sourceTree = "<group>"; }; 5365 5366 FE9F3FBA2613C87C0069E89F /* ResourceExhaustion.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ResourceExhaustion.cpp; sourceTree = "<group>"; }; 5367 FE9F3FC626163CA90069E89F /* DeferTermination.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeferTermination.h; sourceTree = "<group>"; }; 5366 5368 FEA0861E182B7A0400F6D851 /* Breakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakpoint.h; sourceTree = "<group>"; }; 5367 5369 FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerPrimitives.h; sourceTree = "<group>"; }; … … 7287 7289 BCD203470E17135E002C7E82 /* DatePrototype.cpp */, 7288 7290 BCD203480E17135E002C7E82 /* DatePrototype.h */, 7291 FE9F3FC626163CA90069E89F /* DeferTermination.h */, 7289 7292 534638761E71E06E00F12AC1 /* DeferredWorkTimer.cpp */, 7290 7293 534638741E70DDEC00F12AC1 /* DeferredWorkTimer.h */, … … 9664 9667 0FC20CB61852E2C600C9E954 /* DFGStrengthReductionPhase.h in Headers */, 9665 9668 0F63947815DCE34B006A597C /* DFGStructureAbstractValue.h in Headers */, 9669 FE9F3FC826163CA90069E89F /* DeferTermination.h in Headers */, 9666 9670 0F50AF3C193E8B3900674EE8 /* DFGStructureClobberState.h in Headers */, 9667 9671 0F2FCCFF18A60070001A27F8 /* DFGThreadData.h in Headers */, -
trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
r274401 r275797 1 1 /* 2 * Copyright (C) 2012-202 0Apple Inc. All rights reserved.2 * Copyright (C) 2012-2021 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 2943 2943 } 2944 2944 2945 Jump branchTest32(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) 2946 { 2947 move(TrustedImmPtr(address.m_ptr), getCachedMemoryTempRegisterIDAndInvalidate()); 2948 load32(Address(memoryTempRegister), memoryTempRegister); 2949 return branchTest32(cond, memoryTempRegister, mask); 2950 } 2951 2945 2952 Jump branchTest64(ResultCondition cond, RegisterID reg, RegisterID mask) 2946 2953 { -
trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
r269349 r275797 1 1 /* 2 * Copyright (C) 2009-20 19Apple Inc. All rights reserved.2 * Copyright (C) 2009-2021 Apple Inc. All rights reserved. 3 3 * Copyright (C) 2010 University of Szeged 4 4 * … … 1690 1690 } 1691 1691 1692 Jump branchTest32(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) 1693 { 1694 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/ 1695 move(TrustedImmPtr(address.m_ptr), addressTempRegister); 1696 load32(Address(addressTempRegister), addressTempRegister); 1697 return branchTest32(cond, addressTempRegister, mask); 1698 } 1699 1692 1700 Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1)) 1693 1701 { -
trunk/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
r269349 r275797 1 1 /* 2 * Copyright (C) 2008-20 19Apple Inc. All rights reserved.2 * Copyright (C) 2008-2021 Apple Inc. All rights reserved. 3 3 * Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved. 4 4 * … … 1962 1962 { 1963 1963 load32(address, dataTempRegister); 1964 return branchTest32(cond, dataTempRegister, mask); 1965 } 1966 1967 Jump branchTest32(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) 1968 { 1969 load32(address.m_ptr, dataTempRegister); 1964 1970 return branchTest32(cond, dataTempRegister, mask); 1965 1971 } -
trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
r270208 r275797 1 1 /* 2 * Copyright (C) 2008-20 19Apple Inc. All rights reserved.2 * Copyright (C) 2008-2021 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 2712 2712 m_assembler.testl_i32m(mask.m_value, address.offset, address.base, address.index, address.scale); 2713 2713 return Jump(m_assembler.jCC(x86Condition(cond))); 2714 } 2715 2716 Jump branchTest32(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) 2717 { 2718 move(TrustedImmPtr(address.m_ptr), scratchRegister()); 2719 return branchTest32(cond, Address(scratchRegister()), mask); 2714 2720 } 2715 2721 -
trunk/Source/JavaScriptCore/bindings/ScriptFunctionCall.cpp
r275648 r275797 109 109 VM& vm = m_globalObject->vm(); 110 110 JSLockHolder lock(vm); 111 auto scope = DECLARE_THROW_SCOPE(vm); 111 auto scope = DECLARE_CATCH_SCOPE(vm); 112 113 auto makeExceptionResult = [&] (Exception* exception) -> Expected<JSValue, NakedPtr<Exception>> { 114 // Do not treat a terminated execution exception as having an exception. Just treat it as an empty result. 115 if (!vm.isTerminationException(exception)) 116 return makeUnexpected(exception); 117 return { }; 118 }; 112 119 113 120 JSValue function = thisObject->get(m_globalObject, Identifier::fromString(vm, m_name)); 114 if (UNLIKELY(scope.exception())) 115 return makeUnexpected(scope.exception()); 121 Exception* exception = scope.exception(); 122 if (UNLIKELY(exception)) { 123 scope.clearException(); 124 return makeExceptionResult(exception); 125 } 116 126 117 127 auto callData = getCallData(vm, function); … … 120 130 121 131 JSValue result; 122 NakedPtr<Exception> exception;132 NakedPtr<Exception> uncaughtException; 123 133 if (m_callHandler) 124 result = m_callHandler(m_globalObject, function, callData, thisObject, m_arguments, exception);134 result = m_callHandler(m_globalObject, function, callData, thisObject, m_arguments, uncaughtException); 125 135 else 126 result = JSC::call(m_globalObject, function, callData, thisObject, m_arguments, exception);136 result = JSC::call(m_globalObject, function, callData, thisObject, m_arguments, uncaughtException); 127 137 128 if (exception) { 129 // Do not treat a terminated execution exception as having an exception. Just treat it as an empty result. 130 if (!vm.isTerminationException(exception)) 131 return makeUnexpected(exception); 132 return { }; 133 } 138 if (uncaughtException) 139 return makeExceptionResult(uncaughtException); 134 140 135 141 return result; -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r275597 r275797 1 1 /* 2 * Copyright (C) 2011-202 0Apple Inc. All rights reserved.2 * Copyright (C) 2011-2021 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 2223 2223 GPRReg unusedGPR = unused.gpr(); 2224 2224 2225 JITCompiler::Jump needTrapHandling = m_jit.branchTest8(JITCompiler::NonZero, 2226 JITCompiler::AbsoluteAddress(m_jit.vm().needTrapHandlingAddress())); 2225 JITCompiler::Jump needTrapHandling = m_jit.branchTest32(JITCompiler::NonZero, 2226 JITCompiler::AbsoluteAddress(m_jit.vm().traps().trapBitsAddress()), 2227 TrustedImm32(VMTraps::AsyncEvents)); 2227 2228 2228 2229 addSlowPathGenerator(slowPathCall(needTrapHandling, this, operationHandleTraps, unusedGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)))); -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r275650 r275797 1 1 /* 2 * Copyright (C) 2013-202 0Apple Inc. All rights reserved.2 * Copyright (C) 2013-2021 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 13401 13401 LBasicBlock continuation = m_out.newBlock(); 13402 13402 13403 LValue state = m_out.load8ZeroExt32(m_out.absolute(vm().needTrapHandlingAddress()));13404 m_out.branch(m_out. isZero32(state),13403 LValue trapBits = m_out.load32(m_out.absolute(vm().traps().trapBitsAddress())); 13404 m_out.branch(m_out.testIsZero32(trapBits, m_out.constInt32(VMTraps::AsyncEvents)), 13405 13405 usually(continuation), rarely(needTrapHandling)); 13406 13406 -
trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp
r275648 r275797 802 802 return checkedReturn(throwException(globalObject, throwScope, error)); 803 803 804 constexpr auto trapsMask = VMTraps::interruptingTraps(); 805 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 806 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 807 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 804 if (UNLIKELY(vm.traps().needHandling(VMTraps::NonDebuggerAsyncEvents))) { 805 if (vm.hasExceptionsAfterHandlingTraps()) 806 return throwScope.exception(); 808 807 } 809 808 … … 869 868 return checkedReturn(throwStackOverflowError(globalObject, throwScope)); 870 869 871 constexpr auto trapsMask = VMTraps::interruptingTraps(); 872 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 873 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 874 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 870 if (UNLIKELY(vm.traps().needHandling(VMTraps::NonDebuggerAsyncEvents))) { 871 if (vm.hasExceptionsAfterHandlingTraps()) 872 return throwScope.exception(); 875 873 } 876 874 … … 948 946 } 949 947 950 constexpr auto trapsMask = VMTraps::interruptingTraps(); 951 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 952 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 953 RETURN_IF_EXCEPTION(throwScope, nullptr); 948 if (UNLIKELY(vm.traps().needHandling(VMTraps::NonDebuggerAsyncEvents))) { 949 if (vm.hasExceptionsAfterHandlingTraps()) 950 return nullptr; 954 951 } 955 952 … … 1063 1060 } 1064 1061 1065 constexpr auto trapsMask = VMTraps::interruptingTraps(); 1066 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 1067 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 1068 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 1062 if (UNLIKELY(vm.traps().needHandling(VMTraps::NonDebuggerAsyncEvents))) { 1063 if (vm.hasExceptionsAfterHandlingTraps()) 1064 return throwScope.exception(); 1069 1065 } 1070 1066 … … 1221 1217 return checkedReturn(throwStackOverflowError(globalObject, throwScope)); 1222 1218 1223 constexpr auto trapsMask = VMTraps::interruptingTraps(); 1224 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 1225 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 1226 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 1219 if (UNLIKELY(vm.traps().needHandling(VMTraps::NonDebuggerAsyncEvents))) { 1220 if (vm.hasExceptionsAfterHandlingTraps()) 1221 return throwScope.exception(); 1227 1222 } 1228 1223 -
trunk/Source/JavaScriptCore/interpreter/InterpreterInlines.h
r269511 r275797 1 1 /* 2 2 * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com> 3 * Copyright (C) 2016-202 0Apple Inc. All rights reserved.3 * Copyright (C) 2016-2021 Apple Inc. All rights reserved. 4 4 * 5 5 * Redistribution and use in source and binary forms, with or without … … 81 81 StackStats::CheckPoint stackCheckPoint; 82 82 83 constexpr auto trapsMask = VMTraps::interruptingTraps();84 if (UNLIKELY(vm.needTrapHandling(trapsMask))) {85 vm.handleTraps(closure.protoCallFrame->globalObject, closure.oldCallFrame, trapsMask);86 RETURN_IF_EXCEPTION(throwScope, throwScope.exception());83 if (UNLIKELY(vm.traps().needHandling(VMTraps::NonDebuggerAsyncEvents))) { 84 ASSERT(vm.topCallFrame == closure.oldCallFrame); 85 if (vm.hasExceptionsAfterHandlingTraps()) 86 return throwScope.exception(); 87 87 } 88 88 -
trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp
r271489 r275797 843 843 addPtr(TrustedImm32(stackPointerOffsetFor(codeBlock()) * sizeof(Register)), callFrameRegister, stackPointerRegister); 844 844 845 callOperationNoExceptionCheck(operation CheckIfExceptionIsUncatchableAndNotifyProfiler, TrustedImmPtr(&vm()));846 Jump isCatchableException = branchTest32( Zero, returnValueGPR);845 callOperationNoExceptionCheck(operationRetrieveAndClearExceptionIfCatchable, TrustedImmPtr(&vm())); 846 Jump isCatchableException = branchTest32(NonZero, returnValueGPR); 847 847 jumpToExceptionHandler(vm()); 848 848 isCatchableException.link(this); 849 849 850 move(TrustedImmPtr(m_vm), regT3); 851 load64(Address(regT3, VM::exceptionOffset()), regT0); 852 store64(TrustedImm64(JSValue::encode(JSValue())), Address(regT3, VM::exceptionOffset())); 850 move(returnValueGPR, regT0); 853 851 emitPutVirtualRegister(bytecode.m_exception); 854 852 … … 1219 1217 void JIT::emit_op_check_traps(const Instruction*) 1220 1218 { 1221 addSlowCase(branchTest 8(NonZero, AbsoluteAddress(m_vm->needTrapHandlingAddress())));1219 addSlowCase(branchTest32(NonZero, AbsoluteAddress(m_vm->traps().trapBitsAddress()), TrustedImm32(VMTraps::AsyncEvents))); 1222 1220 } 1223 1221 -
trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
r271279 r275797 932 932 addPtr(TrustedImm32(stackPointerOffsetFor(codeBlock()) * sizeof(Register)), callFrameRegister, stackPointerRegister); 933 933 934 callOperationNoExceptionCheck(operation CheckIfExceptionIsUncatchableAndNotifyProfiler, TrustedImmPtr(&vm()));935 Jump isCatchableException = branchTest32( Zero, returnValueGPR);934 callOperationNoExceptionCheck(operationRetrieveAndClearExceptionIfCatchable, TrustedImmPtr(&vm())); 935 Jump isCatchableException = branchTest32(NonZero, returnValueGPR); 936 936 jumpToExceptionHandler(vm()); 937 937 isCatchableException.link(this); 938 938 939 move(TrustedImmPtr(m_vm), regT3);940 941 939 // Now store the exception returned by operationThrow. 942 load32(Address(regT3, VM::exceptionOffset()), regT2);940 move(returnValueGPR, regT2); 943 941 move(TrustedImm32(JSValue::CellTag), regT1); 944 945 store32(TrustedImm32(0), Address(regT3, VM::exceptionOffset()));946 942 947 943 emitStore(bytecode.m_exception, regT1, regT2); -
trunk/Source/JavaScriptCore/jit/JITOperations.cpp
r275648 r275797 1766 1766 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1767 1767 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1768 ASSERT(vm. needTrapHandling());1769 vm. handleTraps(globalObject, callFrame);1768 ASSERT(vm.traps().needHandling(VMTraps::AsyncEvents)); 1769 vm.traps().handleTraps(VMTraps::AsyncEvents); 1770 1770 return nullptr; 1771 1771 } … … 1842 1842 } 1843 1843 1844 if (UNLIKELY(vm.terminationInProgress())) { 1845 // If termination of the current stack of execution is in progress, 1846 // then we need to hold off on optimized compiles so that termination 1847 // checks will be called, and we can unwind out of the current stack. 1848 CODEBLOCK_LOG_EVENT(codeBlock, "delayOptimizeToDFG", ("Terminating current execution")); 1849 updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock); 1850 return encodeResult(nullptr, nullptr); 1851 } 1852 1844 1853 Debugger* debugger = codeBlock->globalObject()->debugger(); 1845 1854 if (UNLIKELY(debugger && (debugger->isStepping() || codeBlock->baselineAlternative()->hasDebuggerRequests()))) { … … 3512 3521 } 3513 3522 3514 JSC_DEFINE_JIT_OPERATION(operation CheckIfExceptionIsUncatchableAndNotifyProfiler, int32_t, (VM* vmPointer))3523 JSC_DEFINE_JIT_OPERATION(operationRetrieveAndClearExceptionIfCatchable, JSCell*, (VM* vmPointer)) 3515 3524 { 3516 3525 VM& vm = *vmPointer; … … 3520 3529 RELEASE_ASSERT(!!scope.exception()); 3521 3530 3522 if (vm.isTerminationException(scope.exception())) { 3531 Exception* exception = scope.exception(); 3532 if (vm.isTerminationException(exception)) { 3523 3533 genericUnwind(vm, callFrame); 3524 return 1; 3525 } 3526 return 0; 3534 return nullptr; 3535 } 3536 3537 // We want to clear the exception here rather than in the catch prologue 3538 // JIT code because clearing it also entails clearing a bit in an Atomic 3539 // bit field in VMTraps. 3540 scope.clearException(); 3541 return exception; 3527 3542 } 3528 3543 -
trunk/Source/JavaScriptCore/jit/JITOperations.h
r272580 r275797 1 1 /* 2 * Copyright (C) 2013-202 0Apple Inc. All rights reserved.2 * Copyright (C) 2013-2021 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 296 296 JSC_DECLARE_JIT_OPERATION(operationExceptionFuzzWithCallFrame, void, (VM*)); 297 297 298 JSC_DECLARE_JIT_OPERATION(operation CheckIfExceptionIsUncatchableAndNotifyProfiler, int32_t, (VM*));298 JSC_DECLARE_JIT_OPERATION(operationRetrieveAndClearExceptionIfCatchable, JSCell*, (VM*)); 299 299 JSC_DECLARE_JIT_OPERATION(operationInstanceOfCustom, size_t, (JSGlobalObject*, EncodedJSValue encodedValue, JSObject* constructor, EncodedJSValue encodedHasInstance)); 300 300 -
trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
r275648 r275797 2082 2082 { 2083 2083 LLINT_BEGIN_NO_SET_PC(); 2084 ASSERT(vm. needTrapHandling());2085 vm. handleTraps(globalObject, callFrame);2084 ASSERT(vm.traps().needHandling(VMTraps::AsyncEvents)); 2085 vm.traps().handleTraps(VMTraps::AsyncEvents); 2086 2086 UNUSED_PARAM(pc); 2087 2087 LLINT_RETURN_TWO(throwScope.exception(), globalObject); … … 2183 2183 } 2184 2184 2185 LLINT_SLOW_PATH_DECL(slow_path_ check_if_exception_is_uncatchable_and_notify_profiler)2185 LLINT_SLOW_PATH_DECL(slow_path_retrieve_and_clear_exception_if_catchable) 2186 2186 { 2187 2187 LLINT_BEGIN(); … … 2189 2189 RELEASE_ASSERT(!!throwScope.exception()); 2190 2190 2191 if (vm.isTerminationException(throwScope.exception())) 2192 LLINT_RETURN_TWO(pc, bitwise_cast<void*>(static_cast<uintptr_t>(1))); 2193 LLINT_RETURN_TWO(pc, nullptr); 2191 Exception* exception = throwScope.exception(); 2192 if (vm.isTerminationException(exception)) 2193 LLINT_RETURN_TWO(pc, nullptr); 2194 2195 // We want to clear the exception here rather than in the catch prologue 2196 // JIT code because clearing it also entails clearing a bit in an Atomic 2197 // bit field in VMTraps. 2198 throwScope.clearException(); 2199 LLINT_RETURN_TWO(pc, exception); 2194 2200 } 2195 2201 -
trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.h
r272580 r275797 1 1 /* 2 * Copyright (C) 2011-202 0Apple Inc. All rights reserved.2 * Copyright (C) 2011-2021 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 138 138 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_from_scope); 139 139 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_to_scope); 140 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_ check_if_exception_is_uncatchable_and_notify_profiler);140 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_retrieve_and_clear_exception_if_catchable); 141 141 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_profile_catch); 142 142 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_log_shadow_chicken_prologue); -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
r275626 r275797 1 # Copyright (C) 2011-202 0Apple Inc. All rights reserved.1 # Copyright (C) 2011-2021 Apple Inc. All rights reserved. 2 2 # 3 3 # Redistribution and use in source and binary forms, with or without … … 266 266 const NoPtrTag = constexpr NoPtrTag 267 267 268 # VMTraps data 269 const VMTrapsAsyncEvents = constexpr VMTraps::AsyncEvents 268 270 269 271 # Some register conventions. … … 2194 2196 loadp CodeBlock[cfr], t1 2195 2197 loadp CodeBlock::m_vm[t1], t1 2196 loadb VM::m_traps+VMTraps::m_needTrapHandling[t1], t0 2198 loadi VM::m_traps+VMTraps::m_trapBits[t1], t0 2199 andi VMTrapsAsyncEvents, t0 2197 2200 btpnz t0, .handleTraps 2198 2201 .afterHandlingTraps: -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
r275626 r275797 1 # Copyright (C) 2011-202 0Apple Inc. All rights reserved.1 # Copyright (C) 2011-2021 Apple Inc. All rights reserved. 2 2 # 3 3 # Redistribution and use in source and binary forms, with or without … … 2216 2216 subp PB, PC 2217 2217 2218 callSlowPath(_llint_slow_path_ check_if_exception_is_uncatchable_and_notify_profiler)2219 bp eq r1, 0, .isCatchableException2218 callSlowPath(_llint_slow_path_retrieve_and_clear_exception_if_catchable) 2219 bpneq r1, 0, .isCatchableException 2220 2220 jmp _llint_throw_from_slow_path_trampoline 2221 2221 2222 2222 .isCatchableException: 2223 loadp CodeBlock[cfr], t3 2224 loadp CodeBlock::m_vm[t3], t3 2225 2226 loadp VM::m_exception[t3], t0 2227 storep 0, VM::m_exception[t3] 2223 move r1, t0 2228 2224 get(size, OpCatch, m_exception, t2) 2229 2225 storei t0, PayloadOffset[cfr, t2, 8] -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
r275626 r275797 1 # Copyright (C) 2011-202 0Apple Inc. All rights reserved.1 # Copyright (C) 2011-2021 Apple Inc. All rights reserved. 2 2 # 3 3 # Redistribution and use in source and binary forms, with or without … … 2367 2367 subp PB, PC 2368 2368 2369 callSlowPath(_llint_slow_path_ check_if_exception_is_uncatchable_and_notify_profiler)2370 bp eq r1, 0, .isCatchableException2369 callSlowPath(_llint_slow_path_retrieve_and_clear_exception_if_catchable) 2370 bpneq r1, 0, .isCatchableException 2371 2371 jmp _llint_throw_from_slow_path_trampoline 2372 2372 2373 2373 .isCatchableException: 2374 loadp CodeBlock[cfr], t3 2375 loadp CodeBlock::m_vm[t3], t3 2376 2377 loadp VM::m_exception[t3], t0 2378 storep 0, VM::m_exception[t3] 2374 move r1, t0 2379 2375 get(size, OpCatch, m_exception, t2) 2380 2376 storeq t0, [cfr, t2, 8] -
trunk/Source/JavaScriptCore/runtime/ArgList.cpp
r273138 r275797 91 91 if (UNLIKELY(checkedSize.hasOverflowed())) 92 92 return this->overflowed(); 93 EncodedJSValue* newBuffer = static_cast<EncodedJSValue*>(Gigacage::malloc(Gigacage::JSValue, checkedSize.unsafeGet())); 93 EncodedJSValue* newBuffer = static_cast<EncodedJSValue*>(Gigacage::tryMalloc(Gigacage::JSValue, checkedSize.unsafeGet())); 94 if (!newBuffer) 95 return this->overflowed(); 94 96 for (int i = 0; i < m_size; ++i) { 95 97 newBuffer[i] = m_buffer[i]; -
trunk/Source/JavaScriptCore/runtime/ExceptionScope.h
r245646 r275797 1 1 /* 2 * Copyright (C) 2016-20 18Apple Inc. All rights reserved.2 * Copyright (C) 2016-2021 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 51 51 VM& vm() const { return m_vm; } 52 52 unsigned recursionDepth() const { return m_recursionDepth; } 53 Exception* exception() { return m_vm.exception(); }53 Exception* exception() const { return m_vm.exception(); } 54 54 55 55 ALWAYS_INLINE void assertNoException() { RELEASE_ASSERT_WITH_MESSAGE(!exception(), "%s", unexpectedExceptionMessage().data()); } … … 85 85 public: 86 86 ALWAYS_INLINE VM& vm() const { return m_vm; } 87 ALWAYS_INLINE Exception* exception() { return m_vm.exception(); }87 ALWAYS_INLINE Exception* exception() const { return m_vm.exception(); } 88 88 89 89 ALWAYS_INLINE void assertNoException() { ASSERT(!exception()); } … … 105 105 106 106 #define RETURN_IF_EXCEPTION(scope__, value__) do { \ 107 if (UNLIKELY((scope__).exception())) \ 108 return value__; \ 107 JSC::VM& vm = (scope__).vm(); \ 108 ASSERT(!!(scope__).exception() == vm.traps().needHandling(JSC::VMTraps::NeedExceptionHandling)); \ 109 if (UNLIKELY(vm.traps().needHandling(JSC::VMTraps::NonDebuggerEvents))) { \ 110 if (vm.hasExceptionsAfterHandlingTraps()) \ 111 return value__; \ 112 } \ 109 113 } while (false) 110 114 -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
r275439 r275797 60 60 #include "Debugger.h" 61 61 #include "DebuggerScope.h" 62 #include "DeferTermination.h" 62 63 #include "DirectArguments.h" 63 64 #include "ErrorConstructor.h" … … 1110 1111 JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner); 1111 1112 VM& vm = init.vm; 1112 auto scope = DECLARE_ CATCH_SCOPE(vm);1113 auto scope = DECLARE_THROW_SCOPE(vm); 1113 1114 IntlCollator* collator = IntlCollator::create(vm, globalObject->collatorStructure()); 1114 1115 collator->initializeCollator(globalObject, jsUndefined(), jsUndefined()); 1115 scope.releaseAssertNoException();1116 RETURN_IF_EXCEPTION(scope, void()); 1116 1117 init.set(collator); 1117 1118 }); … … 2404 2405 void JSGlobalObject::finishCreation(VM& vm) 2405 2406 { 2407 DeferTermination deferTermination(vm); 2406 2408 Base::finishCreation(vm); 2407 2409 structure(vm)->setGlobalObject(vm, this); … … 2414 2416 void JSGlobalObject::finishCreation(VM& vm, JSObject* thisValue) 2415 2417 { 2418 DeferTermination deferTermination(vm); 2416 2419 Base::finishCreation(vm); 2417 2420 structure(vm)->setGlobalObject(vm, this); -
trunk/Source/JavaScriptCore/runtime/LazyPropertyInlines.h
r273138 r275797 98 98 initializer.property.m_pointer |= initializingTag; 99 99 callStatelessLambda<void, Func>(initializer); 100 if (UNLIKELY(initializer.property.m_pointer & initializingTag)) { 101 VM& vm = initializer.vm; 102 Exception* exception = vm.exceptionForInspection(); 103 RELEASE_ASSERT(exception && vm.isTerminationException(exception)); 104 RELEASE_ASSERT(initializer.property.m_pointer & lazyTag); 105 return nullptr; 106 } 100 107 RELEASE_ASSERT(!(initializer.property.m_pointer & lazyTag)); 101 RELEASE_ASSERT(!(initializer.property.m_pointer & initializingTag));102 108 return bitwise_cast<ElementType*>(initializer.property.m_pointer); 103 109 } -
trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp
r272471 r275797 1 1 /* 2 2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 3 * Copyright (C) 2004-202 0Apple Inc. All rights reserved.3 * Copyright (C) 2004-2021 Apple Inc. All rights reserved. 4 4 * Copyright (C) 2009 Torch Mobile, Inc. 5 5 * Copyright (C) 2015 Jordan Harband (ljharb@gmail.com) … … 1540 1540 collator = IntlCollator::create(vm, globalObject->collatorStructure()); 1541 1541 collator->initializeCollator(globalObject, locales, options); 1542 RETURN_IF_EXCEPTION(scope, encodedJSValue());1543 }1542 } 1543 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1544 1544 RELEASE_AND_RETURN(scope, JSValue::encode(collator->compareStrings(globalObject, string, that))); 1545 1545 } -
trunk/Source/JavaScriptCore/runtime/VM.cpp
r275648 r275797 1 1 /* 2 * Copyright (C) 2008-202 0Apple Inc. All rights reserved.2 * Copyright (C) 2008-2021 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 959 959 } 960 960 961 bool VM::hasExceptionsAfterHandlingTraps() 962 { 963 if (UNLIKELY(traps().needHandling(VMTraps::NonDebuggerAsyncEvents))) 964 m_traps.handleTraps(VMTraps::NonDebuggerAsyncEvents); 965 return exception(); 966 } 967 968 void VM::clearException() 969 { 970 #if ENABLE(EXCEPTION_SCOPE_VERIFICATION) 971 m_needExceptionCheck = false; 972 m_nativeStackTraceOfLastThrow = nullptr; 973 m_throwingThread = nullptr; 974 #endif 975 m_exception = nullptr; 976 traps().clearTrapBit(VMTraps::NeedExceptionHandling); 977 } 978 979 void VM::setException(Exception* exception) 980 { 981 m_exception = exception; 982 m_lastException = exception; 983 if (exception) 984 traps().setTrapBit(VMTraps::NeedExceptionHandling); 985 } 986 961 987 void VM::throwTerminationException() 962 988 { 989 ASSERT(!m_traps.isDeferringTermination()); 963 990 setException(terminationException()); 964 991 } … … 966 993 Exception* VM::throwException(JSGlobalObject* globalObject, Exception* exceptionToThrow) 967 994 { 995 // The TerminationException should never be overridden. 996 if (m_exception && isTerminationException(m_exception)) 997 return m_exception; 998 968 999 // The TerminationException is not like ordinary exceptions that should be 969 1000 // reported to the debugger. The fact that the TerminationException uses the -
trunk/Source/JavaScriptCore/runtime/VM.h
r275648 r275797 338 338 WeakRandom& random() { return m_random; } 339 339 Integrity::Random& integrityRandom() { return m_integrityRandom; } 340 341 bool terminationInProgress() const { return m_terminationInProgress; } 342 void setTerminationInProgress(bool value) { m_terminationInProgress = value; } 340 343 341 344 JS_EXPORT_PRIVATE Exception* ensureTerminationException(); … … 1086 1089 VMTraps& traps() { return m_traps; } 1087 1090 1088 void handleTraps(JSGlobalObject* globalObject, CallFrame* callFrame, VMTraps::Mask mask = VMTraps::Mask::allEventTypes()) { m_traps.handleTraps(globalObject, callFrame, mask); } 1089 1090 bool needTrapHandling() { return m_traps.needTrapHandling(); } 1091 bool needTrapHandling(VMTraps::Mask mask) { return m_traps.needTrapHandling(mask); } 1092 void* needTrapHandlingAddress() { return m_traps.needTrapHandlingAddress(); } 1091 JS_EXPORT_PRIVATE bool hasExceptionsAfterHandlingTraps(); 1093 1092 1094 1093 // These may be called concurrently from another thread. 1095 1094 void notifyNeedDebuggerBreak() { m_traps.fireTrap(VMTraps::NeedDebuggerBreak); } 1096 1095 void notifyNeedShellTimeoutCheck() { m_traps.fireTrap(VMTraps::NeedShellTimeoutCheck); } 1097 void notifyNeedTermination() { m_traps.fireTrap(VMTraps::NeedTermination); } 1096 void notifyNeedTermination() 1097 { 1098 setTerminationInProgress(true); 1099 m_traps.fireTrap(VMTraps::NeedTermination); 1100 } 1098 1101 void notifyNeedWatchdogCheck() { m_traps.fireTrap(VMTraps::NeedWatchdogCheck); } 1099 1102 … … 1113 1116 public: 1114 1117 DeferExceptionScope(VM& vm) 1115 : m_savedException(vm.m_exception, nullptr) 1118 : m_vm(vm) 1119 , m_exceptionWasSet(vm.m_exception) 1120 , m_savedException(vm.m_exception, nullptr) 1116 1121 , m_savedLastException(vm.m_lastException, nullptr) 1117 1122 { 1123 if (m_exceptionWasSet) 1124 m_vm.traps().clearTrapBit(VMTraps::NeedExceptionHandling); 1118 1125 } 1119 1126 1127 ~DeferExceptionScope() 1128 { 1129 if (m_exceptionWasSet) 1130 m_vm.traps().setTrapBit(VMTraps::NeedExceptionHandling); 1131 } 1132 1120 1133 private: 1134 VM& m_vm; 1135 bool m_exceptionWasSet; 1121 1136 SetForScope<Exception*> m_savedException; 1122 1137 SetForScope<Exception*> m_savedLastException; … … 1146 1161 } 1147 1162 1148 void setException(Exception* exception)1149 {1150 m_exception = exception;1151 m_lastException = exception;1152 }1153 1163 Exception* exception() const 1154 1164 { … … 1158 1168 return m_exception; 1159 1169 } 1160 void clearException() 1161 { 1162 #if ENABLE(EXCEPTION_SCOPE_VERIFICATION) 1163 m_needExceptionCheck = false; 1164 m_nativeStackTraceOfLastThrow = nullptr; 1165 m_throwingThread = nullptr; 1166 #endif 1167 m_exception = nullptr; 1168 } 1170 1171 JS_EXPORT_PRIVATE void clearException(); 1172 JS_EXPORT_PRIVATE void setException(Exception*); 1169 1173 1170 1174 #if ENABLE(C_LOOP) … … 1255 1259 uintptr_t m_currentWeakRefVersion { 0 }; 1256 1260 1261 bool m_terminationInProgress { false }; 1262 1257 1263 Lock m_loopHintExecutionCountLock; 1258 1264 HashMap<const Instruction*, std::pair<unsigned, std::unique_ptr<uint64_t>>> m_loopHintExecutionCounts; -
trunk/Source/JavaScriptCore/runtime/VMEntryScope.cpp
r270861 r275797 1 1 /* 2 * Copyright (C) 2013-202 0Apple Inc. All rights reserved.2 * Copyright (C) 2013-2021 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 101 101 listener(); 102 102 103 // If the trap bit is still set at this point, then it means that VMTraps::handleTraps() 104 // has not yet been called for this termination request. As a result, we've not thrown a 105 // TerminationException yet. Some client code relies on detecting the presence of the 106 // TerminationException in order to signal that a termination was requested. As a result, 107 // we want to stay in the TerminationInProgress state until VMTraps::handleTraps() (which 108 // clears the trap bit) gets called, and the TerminationException gets thrown. 109 // 110 // Note: perhaps there's a better way for the client to know that a termination was 111 // requested (after all, the request came from the client). However, this is how the 112 // client code currently works. Changing that will take some significant effort to hunt 113 // down all the places in client code that currently rely on this behavior. 114 if (!m_vm.traps().needHandling(VMTraps::NeedTermination)) 115 m_vm.setTerminationInProgress(false); 103 116 m_vm.clearScratchBuffers(); 104 117 } -
trunk/Source/JavaScriptCore/runtime/VMTraps.cpp
r275648 r275797 146 146 return; // Let the SignalSender try again later. 147 147 148 if (!need TrapHandling()) {148 if (!needHandling(VMTraps::AsyncEvents)) { 149 149 // Too late. Someone else already handled the trap. 150 150 return; … … 253 253 return PollResult::Stop; 254 254 255 if (!traps().need TrapHandling())255 if (!traps().needHandling(VMTraps::AsyncEvents)) 256 256 return PollResult::Wait; 257 257 … … 323 323 } 324 324 325 void VMTraps::fireTrap(VMTraps::Event Type eventType)325 void VMTraps::fireTrap(VMTraps::Event event) 326 326 { 327 327 ASSERT(!vm().currentThreadIsHoldingAPILock()); 328 ASSERT(onlyContainsAsyncEvents(event)); 328 329 { 329 330 auto locker = holdLock(*m_lock); 330 331 ASSERT(!m_isShuttingDown); 331 setTrap ForEvent(locker, eventType);332 setTrapBit(event); 332 333 m_needToInvalidatedCodeBlocks = true; 333 334 } … … 346 347 } 347 348 348 void VMTraps::handleTraps( JSGlobalObject* globalObject, CallFrame* callFrame, VMTraps::Maskmask)349 void VMTraps::handleTraps(VMTraps::BitField mask) 349 350 { 350 351 VM& vm = this->vm(); 351 352 auto scope = DECLARE_THROW_SCOPE(vm); 353 ASSERT(onlyContainsAsyncEvents(mask)); 354 ASSERT(needHandling(mask)); 355 356 if (isDeferringTermination()) 357 mask &= ~NeedTermination; 352 358 353 359 { … … 360 366 } 361 367 362 ASSERT(needTrapHandling(mask)); 363 while (needTrapHandling(mask)) { 364 auto eventType = takeTopPriorityTrap(mask); 365 switch (eventType) { 368 while (needHandling(mask)) { 369 auto event = takeTopPriorityTrap(mask); 370 switch (event) { 366 371 case NeedDebuggerBreak: 367 372 dataLog("VM ", RawPointer(&vm), " on pid ", getCurrentProcessID(), " received NeedDebuggerBreak trap\n"); 368 invalidateCodeBlocksOnStack( callFrame);373 invalidateCodeBlocksOnStack(vm.topCallFrame); 369 374 break; 370 375 … … 376 381 case NeedWatchdogCheck: 377 382 ASSERT(vm.watchdog()); 378 if (LIKELY(!vm.watchdog()->shouldTerminate(globalObject))) 383 ASSERT(vm.entryScope->globalObject()); 384 if (LIKELY(!vm.watchdog()->shouldTerminate(vm.entryScope->globalObject()))) 379 385 continue; 386 vm.setTerminationInProgress(true); 380 387 FALLTHROUGH; 381 388 382 389 case NeedTermination: 383 RELEASE_AND_RETURN(scope, vm.throwTerminationException()); 384 390 ASSERT(vm.terminationInProgress()); 391 scope.release(); 392 if (!isDeferringTermination()) 393 vm.throwTerminationException(); 394 return; 395 396 case NeedExceptionHandling: 385 397 default: 386 398 RELEASE_ASSERT_NOT_REACHED(); … … 389 401 } 390 402 391 auto VMTraps::takeTopPriorityTrap(VMTraps:: Mask mask) -> EventType403 auto VMTraps::takeTopPriorityTrap(VMTraps::BitField mask) -> Event 392 404 { 393 405 auto locker = holdLock(*m_lock); 394 for (int i = 0; i < NumberOfEventTypes; ++i) { 395 EventType eventType = static_cast<EventType>(i); 396 if (hasTrapForEvent(locker, eventType, mask)) { 397 clearTrapForEvent(locker, eventType); 398 return eventType; 399 } 400 } 401 return Invalid; 406 407 // Note: the EventBitShift is already sorted in highest to lowest priority 408 // i.e. a bit shift of 0 is highest priority, etc. 409 for (int i = 0; i < NumberOfEvents; ++i) { 410 Event event = static_cast<Event>(1 << i); 411 if (hasTrapBit(event, mask)) { 412 clearTrapBit(event); 413 return event; 414 } 415 } 416 return NoEvent; 417 } 418 419 void VMTraps::deferTermination() 420 { 421 auto locker = holdLock(*m_lock); 422 m_deferTerminationCount++; 423 ASSERT(m_deferTerminationCount < UINT_MAX); 424 425 VM& vm = this->vm(); 426 Exception* pendingException = vm.exception(); 427 if (pendingException && vm.isTerminationException(pendingException)) { 428 vm.clearException(); 429 m_suspendedTerminationException = true; 430 } 431 } 432 433 void VMTraps::undoDeferTermination() 434 { 435 auto locker = holdLock(*m_lock); 436 ASSERT(m_deferTerminationCount > 0); 437 if (--m_deferTerminationCount == 0) { 438 VM& vm = this->vm(); 439 if (m_suspendedTerminationException || vm.terminationInProgress()) 440 vm.setException(vm.terminationException()); 441 } 402 442 } 403 443 -
trunk/Source/JavaScriptCore/runtime/VMTraps.h
r261538 r275797 1 1 /* 2 * Copyright (C) 2017-202 0Apple Inc. All rights reserved.2 * Copyright (C) 2017-2021 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 42 42 43 43 class VMTraps { 44 typedef uint8_t BitField;45 44 public: 46 enum class Error { 47 None, 48 LockUnavailable, 49 NotJITCode 45 using BitField = uint32_t; 46 static constexpr size_t bitsInBitField = sizeof(BitField) * CHAR_BIT; 47 48 // The following are the type of VMTrap events / signals that can be fired. 49 // This list should be sorted in servicing priority order from highest to 50 // lowest. 51 // 52 // The currently imlemented events are (in highest to lowest priority): 53 // 54 // NeedShellTimeoutCheck 55 // - Only used by the jsc shell to check if we need to force a hard shutdown. 56 // - This event may fire more than once before the jsc shell forces the 57 // shutdown (see NeedWatchdogCheck's discussion of CPU time for why 58 // this may be). 59 // 60 // NeedTermination 61 // - Used to request the termination of execution of the "current" stack. 62 // Note: "Termination" here simply means we terminate whatever is currently 63 // executing on the stack. It does not mean termination of the VM, and hence, 64 // is not permanent. Permanent VM termination mechanisms (like stopping the 65 // request to stop a woker thread) may use this Event to terminate the 66 // "current" stack, but it needs to do some additional work to prevent 67 // re-entry into the VM. 68 // 69 // - The mechanism for achieving this stack termination is by throwing the 70 // uncatchable TerminationException that piggy back on the VM's exception 71 // handling machinery to the unwind stack. The TerminationException is 72 // uncatchable in the sense that the VM will refuse to let JS code's 73 // catch handlers catch the exception. C++ code in the VM (that calls into 74 // JS) needs to do exception checks, and make sure to propagate the 75 // exception if it is the TerminationException. 76 // 77 // - Again, the termination request is not permanent. Once the VM unwinds out 78 // of the "current" execution state on the stack, the client may choose to 79 // clear the exception, and re-enter the VM to executing JS code again. 80 // See NeedWatchdogCheck below on why the VM watchdog needs this ability 81 // to re-enter the VM after terminating the current stack. 82 // 83 // - Many clients enter the VM via APIs that return an uncaught exception 84 // in a NakedPointer<Exception>&. Those APIs would automatically clear 85 // the uncaught TerminationException and return it via the 86 // NakedPointer<Exception>&. Hence, the VM is ready for re-entry upon 87 // returning to the client. 88 // 89 // - In the above notes, "current" (as in "current" stack) is in quotes because 90 // NeedTermination needs to guarantee that the TerminationException has 91 // been thrown in response to this event. If the event fires just before 92 // the VM exits and the TerminationException was not thrown yet, then we'll 93 // keep the NeedTermination trap bit set for the next VM entry. In this case, 94 // the termination will actual happen on the next stack of execution. 95 // 96 // This behavior is needed because some clients rely on seeing an uncaught 97 // TerminationException to know that a termination has been requested. 98 // Technically, there are better ways for the client to know about the 99 // termination request (after all, the termination is initiated by the 100 // client). However, this is how some current client code works. So, we need 101 // to retain this behavior until we can change all the clients that rely on 102 // it. 103 // 104 // NeedWatchdogCheck 105 // - Used to request a check as to whether the watchdog timer has expired. 106 // Note: the watchdog timeout is logically measured in CPU time. However, 107 // the real timer implementation (that fires this NeedWatchdogCheck event) 108 // has to operate on wall clock time. Hence, NeedWatchdogCheck firing does not 109 // necessarily mean that the watchdog timeout has expired, and we can expect 110 // to see NeedWatchdogCheck firing more than once for a single watchdog 111 // timeout. 112 // 113 // - The watchdog mechanism has the option to request termination of the 114 // the current execution stack on watchdog timeout (see 115 // Watchdog::shouldTerminate()). If termination is requested, it will 116 // be executed via the same mechanism as NeedTermination (see how the 117 // NeedWatchdogCheck case can fall through to the NeedTermination case in 118 // VMTraps::handleTraps()). 119 // 120 // - The watchdog timing out is not permanent i.e. after terminating the 121 // current stack, the client may choose to re-enter the VM to execute more 122 // JS. For example, a client may use the watchdog to ensure that an untrusted 123 // 3rd party script (that it runs) does not get trapped in an infinite loop. 124 // If so, the watchdog timeout can terminate that script. After terminating 125 // that bad script, the client may choose to allow other 3rd party scripts 126 // to execute, or even allow more tries on the current one that timed out. 127 // Hence, the timeout and termination must not be permanent. 128 // 129 // This is why termination via the NeedTermination event is not permanent, 130 // but only terminates the "current" stack. 131 // 132 // NeedDebuggerBreak 133 // - Services asynchronous debugger break requests. 134 // 135 // NeedExceptionHandling 136 // - Unlike the other events (which are asynchronous to the mutator thread), 137 // NeedExceptionHandling is set when the mutator thread throws a JS exception 138 // and cleared when the exception is handled / caught. 139 // 140 // - The reason why NeedExceptionHandling is a bit on VMTraps as well is so 141 // that we can piggy back on all the RETURN_IF_EXCEPTION checks in C++ code 142 // to service VMTraps as well. Having the NeedExceptionHandling event as 143 // part of VMTraps allows RETURN_IF_EXCEPTION to optimally only do a single 144 // check to determine if the VM possibly has a pending exception to handle, 145 // as well as if there are asynchronous VMTraps events to handle. 146 147 #define FOR_EACH_VMTRAPS_EVENTS(v) \ 148 v(NeedShellTimeoutCheck) \ 149 v(NeedTermination) \ 150 v(NeedWatchdogCheck) \ 151 v(NeedDebuggerBreak) \ 152 v(NeedExceptionHandling) 153 154 #define DECLARE_VMTRAPS_EVENT_BIT_SHIFT(event__) event__##BitShift, 155 enum EventBitShift { 156 FOR_EACH_VMTRAPS_EVENTS(DECLARE_VMTRAPS_EVENT_BIT_SHIFT) 157 NumberOfEvents, // This entry must be last in this list. 50 158 }; 51 52 enum EventType { 53 // Sorted in servicing priority order from highest to lowest. 54 NeedDebuggerBreak, 55 NeedShellTimeoutCheck, 56 NeedTermination, 57 NeedWatchdogCheck, 58 NumberOfEventTypes, // This entry must be last in this list. 59 Invalid 60 }; 61 62 class Mask { 63 public: 64 enum AllEventTypes { AllEventTypesTag }; 65 constexpr Mask(AllEventTypes) 66 : m_mask(std::numeric_limits<BitField>::max()) 67 { } 68 static constexpr Mask allEventTypes() { return Mask(AllEventTypesTag); } 69 70 constexpr Mask(const Mask&) = default; 71 constexpr Mask(Mask&&) = default; 72 73 template<typename... Arguments> 74 constexpr Mask(Arguments... args) 75 : m_mask(0) 76 { 77 init(args...); 78 } 79 80 BitField bits() const { return m_mask; } 81 82 private: 83 template<typename... Arguments> 84 constexpr void init(EventType eventType, Arguments... args) 85 { 86 ASSERT(eventType < NumberOfEventTypes); 87 m_mask |= (1 << eventType); 88 init(args...); 89 } 90 91 constexpr void init() { } 92 93 BitField m_mask; 94 }; 95 96 static constexpr Mask interruptingTraps() { return Mask(NeedShellTimeoutCheck, NeedTermination, NeedWatchdogCheck); } 159 #undef DECLARE_VMTRAPS_EVENT_BIT_SHIFT 160 161 using Event = BitField; 162 163 #define DECLARE_VMTRAPS_EVENT(event__) \ 164 static_assert(event__##BitShift < bitsInBitField); \ 165 static constexpr Event event__ = (1 << event__##BitShift); 166 FOR_EACH_VMTRAPS_EVENTS(DECLARE_VMTRAPS_EVENT) 167 #undef DECLARE_VMTRAPS_EVENT 168 169 #undef FOR_EACH_VMTRAPS_EVENTS 170 171 static constexpr Event NoEvent = 0; 172 173 static_assert(NumberOfEvents <= bitsInBitField); 174 static constexpr BitField AllEvents = (1ull << NumberOfEvents) - 1; 175 static constexpr BitField AsyncEvents = AllEvents & ~NeedExceptionHandling; 176 static constexpr BitField NonDebuggerEvents = AllEvents & ~NeedDebuggerBreak; 177 static constexpr BitField NonDebuggerAsyncEvents = AsyncEvents & ~NeedDebuggerBreak; 178 179 static constexpr bool onlyContainsAsyncEvents(BitField events) 180 { 181 return (AsyncEvents & events) && !(~AsyncEvents & events); 182 } 97 183 98 184 ~VMTraps(); … … 103 189 void willDestroyVM(); 104 190 105 bool needTrapHandling() { return m_needTrapHandling; } 106 bool needTrapHandling(Mask mask) { return m_needTrapHandling & mask.bits(); } 107 void* needTrapHandlingAddress() { return &m_needTrapHandling; } 191 bool needHandling(BitField mask) const { return m_trapBits.loadRelaxed() & mask; } 192 void* trapBitsAddress() { return &m_trapBits; } 193 194 bool isDeferringTermination() const { return m_deferTerminationCount; } 195 JS_EXPORT_PRIVATE void deferTermination(); 196 JS_EXPORT_PRIVATE void undoDeferTermination(); 108 197 109 198 void notifyGrabAllLocks() 110 199 { 111 if (need TrapHandling())200 if (needHandling(AsyncEvents)) 112 201 invalidateCodeBlocksOnStack(); 113 202 } 114 203 115 JS_EXPORT_PRIVATE void fireTrap(EventType); 116 117 void handleTraps(JSGlobalObject*, CallFrame*, VMTraps::Mask); 204 bool hasTrapBit(Event event, BitField mask) 205 { 206 BitField maskedBits = event & mask; 207 return m_trapBits.loadRelaxed() & maskedBits; 208 } 209 void clearTrapBit(Event event) { m_trapBits.exchangeAnd(~event); } 210 void setTrapBit(Event event) 211 { 212 ASSERT((event & ~AllEvents) == 0); 213 m_trapBits.exchangeOr(event); 214 } 215 216 JS_EXPORT_PRIVATE void fireTrap(Event); 217 void handleTraps(BitField mask = AsyncEvents); 118 218 119 219 void tryInstallTrapBreakpoints(struct SignalContext&, StackBounds); … … 122 222 VM& vm() const; 123 223 124 bool hasTrapForEvent(Locker<Lock>&, EventType eventType, Mask mask) 125 { 126 ASSERT(eventType < NumberOfEventTypes); 127 return (m_trapsBitField & mask.bits() & (1 << eventType)); 128 } 129 void setTrapForEvent(Locker<Lock>&, EventType eventType) 130 { 131 ASSERT(eventType < NumberOfEventTypes); 132 m_trapsBitField |= (1 << eventType); 133 } 134 void clearTrapForEvent(Locker<Lock>&, EventType eventType) 135 { 136 ASSERT(eventType < NumberOfEventTypes); 137 m_trapsBitField &= ~(1 << eventType); 138 } 139 140 EventType takeTopPriorityTrap(Mask); 224 Event takeTopPriorityTrap(BitField mask); 141 225 142 226 #if ENABLE(SIGNAL_BASED_VM_TRAPS) … … 155 239 #endif 156 240 241 static constexpr BitField NeedExceptionHandlingMask = ~(1 << NeedExceptionHandling); 242 157 243 Box<Lock> m_lock; 158 244 Ref<AutomaticThreadCondition> m_condition; 159 union { 160 BitField m_needTrapHandling { 0 }; 161 BitField m_trapsBitField; 162 }; 245 Atomic<BitField> m_trapBits { 0 }; 163 246 bool m_needToInvalidatedCodeBlocks { false }; 164 247 bool m_isShuttingDown { false }; 248 bool m_suspendedTerminationException { false }; 249 unsigned m_deferTerminationCount { 0 }; 165 250 166 251 #if ENABLE(SIGNAL_BASED_VM_TRAPS) -
trunk/Source/WebCore/ChangeLog
r275796 r275797 1 2021-04-10 Mark Lam <mark.lam@apple.com> 2 3 Enable VMTraps checks in RETURN_IF_EXCEPTION. 4 https://bugs.webkit.org/show_bug.cgi?id=224078 5 rdar://75037057 6 7 Reviewed by Keith Miller. 8 9 1. Add DeferTermination in WorkerOrWorkletScriptController::initScript(). 10 This allows us to avoid having to make all exception checking in 11 WorkerOrWorkletScriptController::initScript() very thorough and complete. 12 Currently, they aren't. 13 14 2. Fix WorkerOrWorkletScriptController::evaluate() to handle the TerminationException. 15 16 3. Fix JSEventListener::handleEvent() to handle the TerminationException correctly. 17 Previously, in one case, it was checking scope.exception() for the exception, 18 but the exception has already been taken out of there. 19 20 * bindings/js/JSEventListener.cpp: 21 (WebCore::JSEventListener::handleEvent): 22 * workers/WorkerOrWorkletScriptController.cpp: 23 (WebCore::WorkerOrWorkletScriptController::evaluate): 24 (WebCore::WorkerOrWorkletScriptController::initScript): 25 1 26 2021-04-10 Zalan Bujtas <zalan@apple.com> 2 27 -
trunk/Source/WebCore/bindings/js/JSEventListener.cpp
r275648 r275797 183 183 184 184 JSValue thisValue = handleEventFunction == jsFunction ? toJS(lexicalGlobalObject, globalObject, event.currentTarget()) : jsFunction; 185 NakedPtr<JSC::Exception> exception;186 JSValue retval = JSExecState::profiledCall(lexicalGlobalObject, JSC::ProfilingReason::Other, handleEventFunction, callData, thisValue, args, exception);185 NakedPtr<JSC::Exception> uncaughtException; 186 JSValue retval = JSExecState::profiledCall(lexicalGlobalObject, JSC::ProfilingReason::Other, handleEventFunction, callData, thisValue, args, uncaughtException); 187 187 188 188 InspectorInstrumentation::didCallFunction(&scriptExecutionContext); … … 191 191 jsFunctionWindow->setCurrentEvent(savedEvent.get()); 192 192 193 auto handleExceptionIfNeeded = [&] ( ) -> bool {193 auto handleExceptionIfNeeded = [&] (JSC::Exception* exception) -> bool { 194 194 if (is<WorkerGlobalScope>(scriptExecutionContext)) { 195 195 auto& scriptController = *downcast<WorkerGlobalScope>(scriptExecutionContext).script(); 196 bool terminatorCausedException = ( scope.exception() && vm.isTerminationException(scope.exception()));196 bool terminatorCausedException = (exception && vm.isTerminationException(exception)); 197 197 if (terminatorCausedException || scriptController.isTerminatingExecution()) 198 198 scriptController.forbidExecution(); … … 207 207 }; 208 208 209 if (handleExceptionIfNeeded( ))209 if (handleExceptionIfNeeded(uncaughtException)) 210 210 return; 211 211 … … 222 222 String resultStr = convert<IDLNullable<IDLDOMString>>(*lexicalGlobalObject, retval); 223 223 if (UNLIKELY(scope.exception())) { 224 exception = scope.exception(); 225 if (handleExceptionIfNeeded()) 224 if (handleExceptionIfNeeded(scope.exception())) 226 225 return; 227 226 } -
trunk/Source/WebCore/workers/WorkerOrWorkletScriptController.cpp
r275648 r275797 45 45 #include "WorkerScriptFetcher.h" 46 46 #include <JavaScriptCore/Completion.h> 47 #include <JavaScriptCore/DeferTermination.h> 47 48 #include <JavaScriptCore/DeferredWorkTimer.h> 48 49 #include <JavaScriptCore/Exception.h> … … 203 204 return; 204 205 205 NakedPtr<JSC::Exception> exception; 206 evaluate(sourceCode, exception, returnedExceptionMessage); 207 if (exception) { 208 JSLockHolder lock(vm()); 209 reportException(m_globalScopeWrapper.get(), exception); 206 VM& vm = this->vm(); 207 NakedPtr<JSC::Exception> uncaughtException; 208 evaluate(sourceCode, uncaughtException, returnedExceptionMessage); 209 if ((uncaughtException && vm.isTerminationException(uncaughtException)) || isTerminatingExecution()) { 210 forbidExecution(); 211 return; 212 } 213 if (uncaughtException) { 214 JSLockHolder lock(vm); 215 reportException(m_globalScopeWrapper.get(), uncaughtException); 210 216 } 211 217 } … … 518 524 void WorkerOrWorkletScriptController::initScript() 519 525 { 526 ASSERT(m_vm.get()); 527 JSC::DeferTermination deferTermination(*m_vm.get()); 528 520 529 if (is<DedicatedWorkerGlobalScope>(m_globalScope)) { 521 530 initScriptWithSubclass<JSDedicatedWorkerGlobalScopePrototype, JSDedicatedWorkerGlobalScope, DedicatedWorkerGlobalScope>();
Note:
See TracChangeset
for help on using the changeset viewer.