Skip to content

Commit 342fdba

Browse files
author
Mark Lam
committed
Enable VMTraps checks in RETURN_IF_EXCEPTION.
https://bugs.webkit.org/show_bug.cgi?id=224078 rdar://75037057 Reviewed by Keith Miller. JSTests: * stress/watchdog-fire-while-in-forEachInIterable.js: Added. Source/JavaScriptCore: In pre-existing code, termination of a VM's execution can already be requested asynchronously (with respect to the mutator thread). For example, sources of such a request can be a watchdog timer firing, or a request to stop execution issued from a main web thread to a worker thread. This request is made by firing the VMTraps::NeedTermination event on VMTraps. Firing the event here only means setting a flag to indicate the presence of the request. We still have to wait till the mutator thread reaches one of the pre-designated polling check points to call VMTraps::handleTraps() in order to service the request. As a result of this need to wait for a polling check point, if the mutator is executing in a long running C++ loop, then a termination request may not be serviced for a long time. However, we observed that a lot of our C++ loops already have RETURN_IF_EXCEPTION checks. Hence, if we can check VMTraps::needHandling() there, we can service the VMTraps events more frequently even in a lot of C++ loops, and get a better response. Full details of what this patch changes: 1. Shorten some type and methods names in the VMTraps class to make code easier to read e.g. EventType => Event, needTrapHandling => needHandling. 2. Remove the VMTraps::Mask class. Mask was introduced so that we can express a concatenation of multiple VMTraps events to form a bit mask in a simple way. In the end, it isn't flexible enough but makes the code more complicated than necessary. It is now replaced by the simpler solution of using macros to define the Events as bit fields. Having Events as bit fields intrinsically make them easy to concatenate (bitwise or) or filter (bitwise and). Also removed the unused VMTraps::Error class. 3. Make VMTraps::BitField a uint32_t. There was always unused padding in VMTraps to allow for this. So, we'll just extend it to a full 32-bit to make it easier to add more events in the future for other uses. 4. Add NeedExceptionHandling as a VMTrap::Event. 5. Make VMTraps::m_trapBits Atomic. This makes it easier to set and clear the NeedExceptionHandling bit from the mutator without a lock. 6. RETURN_IF_EXCEPTION now checks VMTraps::m_trapBits (via VMTraps::needHandling()) instead of checking VM::m_exception. If the VMTraps::m_trapBits is non-null, the macro will call VM:hasExceptionsAfterHandlingTraps() to service VMTraps events as appropriate before returning whether an exception is being thrown. The result of VM:hasExceptionsAfterHandlingTraps() will determine if RETURN_IF_EXCEPTION returns or not. VM:hasExceptionsAfterHandlingTraps() is intentionally designed to take a minimum of arguments (just the VM as this pointer). This is because RETURN_IF_EXCEPTION is called from many places, and we would like to minimize code size bloating from this change. 7. Simplify paramaters of VMTraps::handleTraps(). NeedDebuggerBreak's callFrame argument was always vm.topCallFrame anyway. So, the patch makes it explicit, and removes the callFrame parameter. NeedWatchdogCheck's globalObject argument should have always been vm.entryScope->globalObject(), and we can remove the globalObject parameter. Before this, we pass in whichever globalObject was convenient to grab hold of. However, the idea of the watchdog is to time out the current script executing on the stack. Hence, it makes sense to identify thay script by the globalObject in use at VM entry. So far, the only clients that uses the watchdog mechanism only operates in scenarios with only one globalObject anyway. So this formalization to use VMEntryScope's globalObject does not change the expected behavior. 8. Make the execution of termination more robust. Before reading this, please read the description of the Events in VMTraps.h first, especially the section on NeedTermination. Here's the life cycle of a termination: a. a client requests termination of the current execution stack by calling VM::notifyNeedTermination(). notifyNeedTermination() does 2 things: i. fire the NeedTermination event on VMTraps. ii. set the VM::m_terminationInProgress flag. b. Firing the NeedTermination event on VMTraps means setting the NeedTermination bit on VMTraps::m_trapBits. This bit will be polled by the mutator thread later at various designated points (including RETURN_IF_EXCEPTION, which we added in this patch). Once the mutator sees the NeedTermination bit is set, it will clear the bit and throw the TerminationException (see VMTraps::handleTraps()). This is unless the mutator thread is currently in a DeferTermination scope (see (8) below). If in a DeferTermination scope, then it will not throw the TerminationException. Since the NeedTermination bit is cleared, the VM will no longer call VMTraps::handleTraps() to service the event. If the mutator thread is in a DeferTermination scope, then on exiting the scope (at scope destruction), the scope will see that VM::m_terminationInProgress is set, and throw the deferred TerminationException then. c. The TerminationException will trigger unwinding out of the current stack until we get to the outermost VMEntryScope. d. At the the outermost VMEntryScope, we will clear VM::m_terminationInProgress if the NeedTermination bit in VMtraps::m_trapBits is cleared. If the NeedTermination bit is set, then that means we haven't thrown the TerminationException yet. Currently, clients expect that we must throw the TerminationException if NeedTermination was requested (again, read comments at the top of VMTraps.h). If the NeedTermination bit is set, we'll leave VM::m_terminationInProgress set until the next time we re-enter the VM and exit to the outermost VMEntryScope. e. The purpose of VM::m_terminationInProgress is to provide a summary of the fact that the VM is in a state of trying to terminate the current stack. Note that this state is first indicated by the NeedTermination bit being set in VMTraps::m_trapBits. Then, in VMTraps::handleTraps(), the state is handed of with the NeedTermination bit being cleared, and the TerminationException being thrown. While the VM is in this termination state, we need to prevent new DFG/FTL JIT code from being compiled and run. The reason is the firing of the NeedTermination event has invalidated DFG/FTL code on the stack, thereby allowing their baseline / LLInt versions which have VMTraps polling checks to run. We don't want to compile new DFG / FTL code and possibly get stuck in loops in there before the termination is complete. In operationOptimize(), we check if VM::m_terminationInProgress is set, and prevent new DFG (and therefore FTL) code from being compiled if needed. Note: it is easier to check a single flag, VM::m_terminationInProgress, then to check both if the NeedTermination bit is set or if the TerminationException is being being thrown. 9. One complication of being able to service VMTraps in RETURN_IF_EXCEPTION checks is that some of our code (usually for lengthier initializations and bootstrapping) currently does not handle exceptions well, e.g. JSGlobalObject::init(). They rely on the code crashing if an exception is thrown while still initializing. However, for a worker thread, a TerminationException (requested by the main thread) may arrive before the initialization is complete. This can lead to crashes because part of the initialization may be aborted in the presence of an exception, while other parts still expect everything prior to have been initialized correctly. For resource exhaustion cases (which is abnormal), it is OK to crash. For the TerminationException (which can be part of normal operation), we should not be crashing. To work around this, we introduce a DeferTermination RAII scope object that we deploy in this type of initialization code. With the scope in effect, a. if a TerminationException arrives but hasn't been thrown yet, it will be deferred till the scope ends before being thrown. b. if a TerminationException has already been thrown, the scope will stash the exception, clear it from the VM so that the initialization code can run to completion, and then re-throw the exception when the scope ends. Currently, we only need to use the DeferTermination scope in a few places where we know that initialization code will only run for a short period of time. DeferTermination should not be used for code that can block waiting on an external event for a long time. Obviously, doing so will prevent the VM termination mechanism from working. 10. Replaced llint_slow_path_check_if_exception_is_uncatchable_and_notify_profiler and operationCheckIfExceptionIsUncatchableAndNotifyProfiler with llint_slow_path_retrieve_and_clear_exception_if_catchable and operationRetrieveAndClearExceptionIfCatchable. The 2 runtime functions doesn't actually do anything to notify a profiler. So, we drop that part of the name. After returning from these runtime functions respectively, the previous LLInt and JIT code, which calls these runtimes functions, would go on to load VM::m_exception, and then store a nullptr there to clear it. This is wasteful. This patch changes the runtime function to clear and return the Exception instead. As a result, the calling LLInt and JIT code is simplified a bit. Note also that clearing an exception now also entails clearing the NeedExceptionHandling bit in VMTraps::m_trapBits in an atomic way. The above change makes it easy to do this clearing with C++ code. 11. Fix ScriptFunctionCall::call() to handle exceptions correctly. Previously, it had one case where it propagates an exception, while another eats it. Change this function to eat the exception in both cases. This is approproiate because ScriptFunctionCall is only used to execute some Inspector instrumentation calls. It doesn't make sense to propagate the exception back to user code. 12. Fix the lazy initialization of JSGlobalObject::m_defaultCollator to be able to handle the TerminationException. 13. Not related to TerminationException, but this patch also fixes MarkedArgumentBuffer::expandCapacity() to use Gigacage::tryMalloc() instead of Gigacage::malloc(). This is needed as one of the fixes to make the accompanying test case work. This patch increases code size by 320K (144K for JSC, 176K for WebCore) measured on x86_64. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/MacroAssemblerARM64.h: (JSC::MacroAssemblerARM64::branchTest32): * assembler/MacroAssemblerARMv7.h: (JSC::MacroAssemblerARMv7::branchTest32): * assembler/MacroAssemblerMIPS.h: (JSC::MacroAssemblerMIPS::branchTest32): * assembler/MacroAssemblerX86Common.h: (JSC::MacroAssemblerX86Common::branchTest32): * bindings/ScriptFunctionCall.cpp: (Deprecated::ScriptFunctionCall::call): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::compileCheckTraps): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileCheckTraps): * interpreter/Interpreter.cpp: (JSC::Interpreter::executeProgram): (JSC::Interpreter::executeCall): (JSC::Interpreter::executeConstruct): (JSC::Interpreter::execute): (JSC::Interpreter::executeModuleProgram): * interpreter/InterpreterInlines.h: (JSC::Interpreter::execute): * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_catch): (JSC::JIT::emit_op_check_traps): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_catch): * jit/JITOperations.cpp: (JSC::JSC_DEFINE_JIT_OPERATION): * jit/JITOperations.h: * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LLIntSlowPaths.h: * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/ArgList.cpp: (JSC::MarkedArgumentBuffer::expandCapacity): * runtime/DeferTermination.h: Added. (JSC::DeferTermination::DeferTermination): (JSC::DeferTermination::~DeferTermination): * runtime/ExceptionScope.h: (JSC::ExceptionScope::exception const): (JSC::ExceptionScope::exception): Deleted. * runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::init): (JSC::JSGlobalObject::finishCreation): * runtime/LazyPropertyInlines.h: (JSC::ElementType>::callFunc): * runtime/StringPrototype.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/VM.cpp: (JSC::VM::hasExceptionsAfterHandlingTraps): (JSC::VM::clearException): (JSC::VM::setException): (JSC::VM::throwTerminationException): (JSC::VM::throwException): * runtime/VM.h: (JSC::VM::terminationInProgress const): (JSC::VM::setTerminationInProgress): (JSC::VM::notifyNeedTermination): (JSC::VM::DeferExceptionScope::DeferExceptionScope): (JSC::VM::DeferExceptionScope::~DeferExceptionScope): (JSC::VM::handleTraps): Deleted. (JSC::VM::needTrapHandling): Deleted. (JSC::VM::needTrapHandlingAddress): Deleted. (JSC::VM::setException): Deleted. (JSC::VM::clearException): Deleted. * runtime/VMEntryScope.cpp: (JSC::VMEntryScope::~VMEntryScope): * runtime/VMTraps.cpp: (JSC::VMTraps::tryInstallTrapBreakpoints): (JSC::VMTraps::fireTrap): (JSC::VMTraps::handleTraps): (JSC::VMTraps::takeTopPriorityTrap): (JSC::VMTraps::deferTermination): (JSC::VMTraps::undoDeferTermination): * runtime/VMTraps.h: (JSC::VMTraps::onlyContainsAsyncEvents): (JSC::VMTraps::needHandling const): (JSC::VMTraps::trapBitsAddress): (JSC::VMTraps::isDeferringTermination const): (JSC::VMTraps::notifyGrabAllLocks): (JSC::VMTraps::hasTrapBit): (JSC::VMTraps::clearTrapBit): (JSC::VMTraps::setTrapBit): (JSC::VMTraps::Mask::Mask): Deleted. (JSC::VMTraps::Mask::allEventTypes): Deleted. (JSC::VMTraps::Mask::bits const): Deleted. (JSC::VMTraps::Mask::init): Deleted. (JSC::VMTraps::interruptingTraps): Deleted. (JSC::VMTraps::needTrapHandling): Deleted. (JSC::VMTraps::needTrapHandlingAddress): Deleted. (JSC::VMTraps::hasTrapForEvent): Deleted. (JSC::VMTraps::setTrapForEvent): Deleted. (JSC::VMTraps::clearTrapForEvent): Deleted. Source/WebCore: 1. Add DeferTermination in WorkerOrWorkletScriptController::initScript(). This allows us to avoid having to make all exception checking in WorkerOrWorkletScriptController::initScript() very thorough and complete. Currently, they aren't. 2. Fix WorkerOrWorkletScriptController::evaluate() to handle the TerminationException. 3. Fix JSEventListener::handleEvent() to handle the TerminationException correctly. Previously, in one case, it was checking scope.exception() for the exception, but the exception has already been taken out of there. * bindings/js/JSEventListener.cpp: (WebCore::JSEventListener::handleEvent): * workers/WorkerOrWorkletScriptController.cpp: (WebCore::WorkerOrWorkletScriptController::evaluate): (WebCore::WorkerOrWorkletScriptController::initScript): Canonical link: https://commits.webkit.org/236368@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@275797 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 61a65b2 commit 342fdba

37 files changed

Lines changed: 876 additions & 235 deletions

JSTests/ChangeLog

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
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+
111
2021-04-07 Yusuke Suzuki <ysuzuki@apple.com>
212

313
[JSC] DUCET level-1 weighs are equal if characters are alphabets
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//@ runDefault("--watchdog=100", "--watchdog-exception-ok")
2+
3+
const a = [];
4+
a[2**32-2] = 0;
5+
new Uint8Array(a);

Source/JavaScriptCore/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
876876
runtime/DataView.h
877877
runtime/DateInstance.h
878878
runtime/DateInstanceCache.h
879+
runtime/DeferTermination.h
879880
runtime/DeferredWorkTimer.h
880881
runtime/DefinePropertyAttributes.h
881882
runtime/DeletePropertySlot.h

Source/JavaScriptCore/ChangeLog

Lines changed: 306 additions & 0 deletions
Large diffs are not rendered by default.

Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,6 +1992,7 @@
19921992
FE912B5125311AD100FABDDF /* AbstractSlotVisitorInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = FE912B5025311AD100FABDDF /* AbstractSlotVisitorInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
19931993
FE99B2491C24C3D300C82159 /* JITNegGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FE99B2481C24B6D300C82159 /* JITNegGenerator.h */; };
19941994
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, ); }; };
19951996
FEA08620182B7A0400F6D851 /* Breakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861E182B7A0400F6D851 /* Breakpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
19961997
FEA08621182B7A0400F6D851 /* DebuggerPrimitives.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */; settings = {ATTRIBUTES = (Private, ); }; };
19971998
FEA3BBA8212B655900E93AD1 /* CallFrameInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA3BBA7212B655800E93AD1 /* CallFrameInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -5363,6 +5364,7 @@
53635364
FE99B2481C24B6D300C82159 /* JITNegGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITNegGenerator.h; sourceTree = "<group>"; };
53645365
FE9F3FB82613C7880069E89F /* ResourceExhaustion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResourceExhaustion.h; sourceTree = "<group>"; };
53655366
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>"; };
53665368
FEA0861E182B7A0400F6D851 /* Breakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakpoint.h; sourceTree = "<group>"; };
53675369
FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerPrimitives.h; sourceTree = "<group>"; };
53685370
FEA3BBA7212B655800E93AD1 /* CallFrameInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallFrameInlines.h; sourceTree = "<group>"; };
@@ -7286,6 +7288,7 @@
72867288
14A1563010966365006FA260 /* DateInstanceCache.h */,
72877289
BCD203470E17135E002C7E82 /* DatePrototype.cpp */,
72887290
BCD203480E17135E002C7E82 /* DatePrototype.h */,
7291+
FE9F3FC626163CA90069E89F /* DeferTermination.h */,
72897292
534638761E71E06E00F12AC1 /* DeferredWorkTimer.cpp */,
72907293
534638741E70DDEC00F12AC1 /* DeferredWorkTimer.h */,
72917294
169948EDE68D4054B01EF797 /* DefinePropertyAttributes.h */,
@@ -9663,6 +9666,7 @@
96639666
0F9E32641B05AB0400801ED5 /* DFGStoreBarrierInsertionPhase.h in Headers */,
96649667
0FC20CB61852E2C600C9E954 /* DFGStrengthReductionPhase.h in Headers */,
96659668
0F63947815DCE34B006A597C /* DFGStructureAbstractValue.h in Headers */,
9669+
FE9F3FC826163CA90069E89F /* DeferTermination.h in Headers */,
96669670
0F50AF3C193E8B3900674EE8 /* DFGStructureClobberState.h in Headers */,
96679671
0F2FCCFF18A60070001A27F8 /* DFGThreadData.h in Headers */,
96689672
0FC097A2146B28CC00CF2442 /* DFGThunks.h in Headers */,

Source/JavaScriptCore/assembler/MacroAssemblerARM64.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2012-2020 Apple Inc. All rights reserved.
2+
* Copyright (C) 2012-2021 Apple Inc. All rights reserved.
33
*
44
* Redistribution and use in source and binary forms, with or without
55
* modification, are permitted provided that the following conditions
@@ -2942,6 +2942,13 @@ class MacroAssemblerARM64 : public AbstractMacroAssembler<Assembler> {
29422942
return branchTest32(cond, memoryTempRegister, mask);
29432943
}
29442944

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+
29452952
Jump branchTest64(ResultCondition cond, RegisterID reg, RegisterID mask)
29462953
{
29472954
if (reg == mask && (cond == Zero || cond == NonZero))

Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2009-2019 Apple Inc. All rights reserved.
2+
* Copyright (C) 2009-2021 Apple Inc. All rights reserved.
33
* Copyright (C) 2010 University of Szeged
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -1689,6 +1689,14 @@ class MacroAssemblerARMv7 : public AbstractMacroAssembler<Assembler> {
16891689
return branchTest32(cond, addressTempRegister, mask);
16901690
}
16911691

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+
16921700
Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
16931701
{
16941702
// use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/

Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2008-2019 Apple Inc. All rights reserved.
2+
* Copyright (C) 2008-2021 Apple Inc. All rights reserved.
33
* Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -1964,6 +1964,12 @@ class MacroAssemblerMIPS : public AbstractMacroAssembler<Assembler> {
19641964
return branchTest32(cond, dataTempRegister, mask);
19651965
}
19661966

1967+
Jump branchTest32(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1968+
{
1969+
load32(address.m_ptr, dataTempRegister);
1970+
return branchTest32(cond, dataTempRegister, mask);
1971+
}
1972+
19671973
TrustedImm32 mask8OnTest(ResultCondition cond, TrustedImm32 mask)
19681974
{
19691975
if (mask.m_value == -1 && !m_fixedWidth)

Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2008-2019 Apple Inc. All rights reserved.
2+
* Copyright (C) 2008-2021 Apple Inc. All rights reserved.
33
*
44
* Redistribution and use in source and binary forms, with or without
55
* modification, are permitted provided that the following conditions
@@ -2713,6 +2713,12 @@ class MacroAssemblerX86Common : public AbstractMacroAssembler<Assembler> {
27132713
return Jump(m_assembler.jCC(x86Condition(cond)));
27142714
}
27152715

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);
2720+
}
2721+
27162722
Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
27172723
{
27182724
TrustedImm32 mask8(static_cast<int8_t>(mask.m_value));

Source/JavaScriptCore/bindings/ScriptFunctionCall.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -108,29 +108,35 @@ Expected<JSValue, NakedPtr<Exception>> ScriptFunctionCall::call()
108108

109109
VM& vm = m_globalObject->vm();
110110
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+
};
112119

113120
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+
}
116126

117127
auto callData = getCallData(vm, function);
118128
if (callData.type == CallData::Type::None)
119129
return { };
120130

121131
JSValue result;
122-
NakedPtr<Exception> exception;
132+
NakedPtr<Exception> uncaughtException;
123133
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);
125135
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);
127137

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);
134140

135141
return result;
136142
}

0 commit comments

Comments
 (0)