WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
more
blah.patch (text/plain), 64.15 KB, created by
Filip Pizlo
on 2018-03-09 12:04:42 PST
(
hide
)
Description:
more
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2018-03-09 12:04:42 PST
Size:
64.15 KB
patch
obsolete
>Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 229475) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,86 @@ >+2018-03-09 Filip Pizlo <fpizlo@apple.com> >+ >+ Split DirectArguments into JSValueOOB and JSValueStrict parts >+ https://bugs.webkit.org/show_bug.cgi?id=183458 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Our Spectre plan for JSValue objects is to allow inline JSValue stores and loads subject guarded by >+ unmitigated structure checks. This works because objects reachable from JSValues (i.e. JSValue >+ objects, like String, Symbol, and any descendant of JSObject) will only contain fields that it's OK >+ to read and write within a Spectre mitigation window. Writes are important, because within the >+ window, a write could be made speculatively and rolled out later. This means that: >+ >+ - JSValue objects cannot have lengths, masks, or anything else inline. >+ >+ - JSValue objects cannot have an inline type that is used as part of a Spectre mitigation for a type >+ check, unless that type is in the form of a poison key. >+ >+ This means that the dynamic poisoning that I previously landed for DirectArguments is wrong. It also >+ means that it's wrong for DirectArguments to have an inline length. >+ >+ This changes DirectArguments to use poisoning according to the universal formula: >+ >+ - The random accessed portions are out-of-line, pointed to by a poisoned pointer. >+ >+ - No inline length. >+ >+ Surprisingly, this is perf-neutral. It's probably perf-neutral because our compiler optimizations >+ amortize whatever cost there was. >+ >+ * bytecode/AccessCase.cpp: >+ (JSC::AccessCase::generateWithGuard): >+ * dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h: >+ (JSC::DFG::CallCreateDirectArgumentsSlowPathGenerator::CallCreateDirectArgumentsSlowPathGenerator): >+ * dfg/DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h: Added. >+ (JSC::DFG::CallCreateDirectArgumentsWithKnownLengthSlowPathGenerator::CallCreateDirectArgumentsWithKnownLengthSlowPathGenerator): >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::compileGetByValOnDirectArguments): >+ (JSC::DFG::SpeculativeJIT::compileGetArrayLength): >+ (JSC::DFG::SpeculativeJIT::compileCreateDirectArguments): >+ (JSC::DFG::SpeculativeJIT::compileGetFromArguments): >+ (JSC::DFG::SpeculativeJIT::compilePutToArguments): >+ * ftl/FTLAbstractHeapRepository.h: >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compileGetArrayLength): >+ (JSC::FTL::DFG::LowerDFGToB3::compileGetByVal): >+ (JSC::FTL::DFG::LowerDFGToB3::compileCreateDirectArguments): >+ (JSC::FTL::DFG::LowerDFGToB3::compileGetFromArguments): >+ (JSC::FTL::DFG::LowerDFGToB3::compilePutToArguments): >+ (JSC::FTL::DFG::LowerDFGToB3::compileCheckSubClass): >+ (JSC::FTL::DFG::LowerDFGToB3::allocateVariableSizedHeapCell): >+ (JSC::FTL::DFG::LowerDFGToB3::dynamicPoison): Deleted. >+ (JSC::FTL::DFG::LowerDFGToB3::dynamicPoisonOnLoadedType): Deleted. >+ (JSC::FTL::DFG::LowerDFGToB3::dynamicPoisonOnType): Deleted. >+ * heap/SecurityKind.h: >+ * jit/JITPropertyAccess.cpp: >+ (JSC::JIT::emit_op_get_from_arguments): >+ (JSC::JIT::emit_op_put_to_arguments): >+ (JSC::JIT::emitDirectArgumentsGetByVal): >+ * jit/JITPropertyAccess32_64.cpp: >+ (JSC::JIT::emit_op_get_from_arguments): >+ (JSC::JIT::emit_op_put_to_arguments): >+ * llint/LowLevelInterpreter.asm: >+ * llint/LowLevelInterpreter32_64.asm: >+ * llint/LowLevelInterpreter64.asm: >+ * runtime/DirectArguments.cpp: >+ (JSC::DirectArguments::DirectArguments): >+ (JSC::DirectArguments::createUninitialized): >+ (JSC::DirectArguments::create): >+ (JSC::DirectArguments::createByCopying): >+ (JSC::DirectArguments::estimatedSize): >+ (JSC::DirectArguments::visitChildren): >+ (JSC::DirectArguments::overrideThings): >+ (JSC::DirectArguments::copyToArguments): >+ (JSC::DirectArguments::mappedArgumentsSize): >+ * runtime/DirectArguments.h: >+ * runtime/JSCPoison.h: >+ * runtime/JSLexicalEnvironment.h: >+ * runtime/JSSymbolTableObject.h: >+ * runtime/VM.cpp: >+ (JSC::VM::VM): >+ * runtime/VM.h: >+ > 2018-03-09 Yusuke Suzuki <utatane.tea@gmail.com> > > Unreviewed, remove WebAssemblyFunctionType >Index: Source/JavaScriptCore/bytecode/AccessCase.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/AccessCase.cpp (revision 229411) >+++ Source/JavaScriptCore/bytecode/AccessCase.cpp (working copy) >@@ -383,8 +383,12 @@ void AccessCase::generateWithGuard( > jit.branchTestPtr( > CCallHelpers::NonZero, > CCallHelpers::Address(baseGPR, DirectArguments::offsetOfMappedArguments()))); >+ jit.loadPtr( >+ CCallHelpers::Address(baseGPR, DirectArguments::offsetOfStorage()), >+ valueRegs.payloadGPR()); >+ jit.xorPtr(CCallHelpers::TrustedImmPtr(DirectArgumentsPoison::key()), valueRegs.payloadGPR()); > jit.load32( >- CCallHelpers::Address(baseGPR, DirectArguments::offsetOfLength()), >+ CCallHelpers::Address(valueRegs.payloadGPR(), DirectArguments::offsetOfLengthInStorage()), > valueRegs.payloadGPR()); > jit.boxInt32(valueRegs.payloadGPR(), valueRegs); > state.succeed(); >Index: Source/JavaScriptCore/dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h (revision 229411) >+++ Source/JavaScriptCore/dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2015-2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -39,11 +39,12 @@ class CallCreateDirectArgumentsSlowPathG > public: > CallCreateDirectArgumentsSlowPathGenerator( > MacroAssembler::JumpList from, SpeculativeJIT* jit, GPRReg resultGPR, RegisteredStructure structure, >- GPRReg lengthGPR, unsigned minCapacity) >+ GPRReg lengthGPR, GPRReg storageGPR, unsigned minCapacity) > : JumpingSlowPathGenerator<MacroAssembler::JumpList>(from, jit) > , m_resultGPR(resultGPR) > , m_structure(structure) > , m_lengthGPR(lengthGPR) >+ , m_storageGPR(storageGPR) > , m_minCapacity(minCapacity) > { > jit->silentSpillAllRegistersImpl(false, m_plans, resultGPR); >@@ -61,7 +62,11 @@ protected: > jit->silentFill(m_plans[i]); > jit->m_jit.exceptionCheck(); > jit->m_jit.loadPtr( >- MacroAssembler::Address(m_resultGPR, DirectArguments::offsetOfLength()), m_lengthGPR); >+ MacroAssembler::Address(m_resultGPR, DirectArguments::offsetOfStorage()), m_storageGPR); >+ jit->m_jit.xorPtr( >+ MacroAssembler::TrustedImmPtr(DirectArgumentsPoison::key()), m_storageGPR); >+ jit->m_jit.load32( >+ MacroAssembler::Address(m_storageGPR, DirectArguments::offsetOfLengthInStorage()), m_lengthGPR); > jumpTo(jit); > } > >@@ -69,6 +74,7 @@ private: > GPRReg m_resultGPR; > RegisteredStructure m_structure; > GPRReg m_lengthGPR; >+ GPRReg m_storageGPR; > unsigned m_minCapacity; > Vector<SilentRegisterSavePlan, 2> m_plans; > }; >Index: Source/JavaScriptCore/dfg/DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h (nonexistent) >+++ Source/JavaScriptCore/dfg/DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h (working copy) >@@ -0,0 +1,82 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(DFG_JIT) >+ >+#include "DFGOperations.h" >+#include "DFGSlowPathGenerator.h" >+#include "DFGSpeculativeJIT.h" >+#include "DirectArguments.h" >+ >+namespace JSC { namespace DFG { >+ >+// This calls operationCreateDirectArguments but then restores the value of lengthGPR. >+class CallCreateDirectArgumentsWithKnownLengthSlowPathGenerator : public JumpingSlowPathGenerator<MacroAssembler::JumpList> { >+public: >+ CallCreateDirectArgumentsWithKnownLengthSlowPathGenerator( >+ MacroAssembler::JumpList from, SpeculativeJIT* jit, GPRReg resultGPR, RegisteredStructure structure, >+ unsigned knownLength, GPRReg storageGPR, unsigned minCapacity) >+ : JumpingSlowPathGenerator<MacroAssembler::JumpList>(from, jit) >+ , m_resultGPR(resultGPR) >+ , m_structure(structure) >+ , m_knownLength(knownLength) >+ , m_storageGPR(storageGPR) >+ , m_minCapacity(minCapacity) >+ { >+ jit->silentSpillAllRegistersImpl(false, m_plans, resultGPR); >+ } >+ >+protected: >+ void generateInternal(SpeculativeJIT* jit) override >+ { >+ linkFrom(jit); >+ for (unsigned i = 0; i < m_plans.size(); ++i) >+ jit->silentSpill(m_plans[i]); >+ jit->callOperation( >+ operationCreateDirectArguments, m_resultGPR, m_structure, m_knownLength, m_minCapacity); >+ for (unsigned i = m_plans.size(); i--;) >+ jit->silentFill(m_plans[i]); >+ jit->m_jit.exceptionCheck(); >+ jit->m_jit.loadPtr( >+ MacroAssembler::Address(m_resultGPR, DirectArguments::offsetOfStorage()), m_storageGPR); >+ jit->m_jit.xorPtr( >+ MacroAssembler::TrustedImmPtr(DirectArgumentsPoison::key()), m_storageGPR); >+ jumpTo(jit); >+ } >+ >+private: >+ GPRReg m_resultGPR; >+ RegisteredStructure m_structure; >+ unsigned m_knownLength; >+ GPRReg m_storageGPR; >+ unsigned m_minCapacity; >+ Vector<SilentRegisterSavePlan, 2> m_plans; >+}; >+ >+} } // namespace JSC::DFG >+ >+#endif // ENABLE(DFG_JIT) >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (revision 229411) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (working copy) >@@ -33,6 +33,7 @@ > #include "DFGArrayifySlowPathGenerator.h" > #include "DFGCallArrayAllocatorSlowPathGenerator.h" > #include "DFGCallCreateDirectArgumentsSlowPathGenerator.h" >+#include "DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h" > #include "DFGCapabilities.h" > #include "DFGMayExit.h" > #include "DFGOSRExitFuzz.h" >@@ -6423,6 +6424,7 @@ void SpeculativeJIT::compileGetByValOnDi > GPRTemporary resultTag(this); > #endif > GPRTemporary scratch(this); >+ GPRTemporary storage(this); > > GPRReg baseReg = base.gpr(); > GPRReg propertyReg = property.gpr(); >@@ -6434,6 +6436,7 @@ void SpeculativeJIT::compileGetByValOnDi > JSValueRegs resultRegs = JSValueRegs(resultReg); > #endif > GPRReg scratchReg = scratch.gpr(); >+ GPRReg storageReg = storage.gpr(); > > if (!m_compileOkay) > return; >@@ -6445,18 +6448,20 @@ void SpeculativeJIT::compileGetByValOnDi > m_jit.branchTestPtr( > MacroAssembler::NonZero, > MacroAssembler::Address(baseReg, DirectArguments::offsetOfMappedArguments()))); >- >- m_jit.load32(CCallHelpers::Address(baseReg, DirectArguments::offsetOfLength()), scratchReg); >+ >+ m_jit.loadPtr(CCallHelpers::Address(baseReg, DirectArguments::offsetOfStorage()), storageReg); >+ m_jit.xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), storageReg); >+ >+ m_jit.load32(CCallHelpers::Address(storageReg, DirectArguments::offsetOfLengthInStorage()), scratchReg); > auto isOutOfBounds = m_jit.branch32(CCallHelpers::AboveOrEqual, propertyReg, scratchReg); > if (node->arrayMode().isInBounds()) > speculationCheck(OutOfBounds, JSValueSource(), 0, isOutOfBounds); > >- m_jit.emitDynamicPoisonOnType(baseReg, resultReg, DirectArgumentsType); > m_jit.emitPreparePreciseIndexMask32(propertyReg, scratchReg, scratchReg); > > m_jit.loadValue( > MacroAssembler::BaseIndex( >- baseReg, propertyReg, MacroAssembler::TimesEight, DirectArguments::storageOffset()), >+ storageReg, propertyReg, MacroAssembler::TimesEight), > resultRegs); > > m_jit.andPtr(scratchReg, resultReg); >@@ -6641,8 +6646,12 @@ void SpeculativeJIT::compileGetArrayLeng > MacroAssembler::NonZero, > MacroAssembler::Address(baseReg, DirectArguments::offsetOfMappedArguments()))); > >+ m_jit.loadPtr( >+ MacroAssembler::Address(baseReg, DirectArguments::offsetOfStorage()), resultReg); >+ m_jit.xorPtr( >+ TrustedImmPtr(DirectArgumentsPoison::key()), resultReg); > m_jit.load32( >- MacroAssembler::Address(baseReg, DirectArguments::offsetOfLength()), resultReg); >+ MacroAssembler::Address(resultReg, DirectArguments::offsetOfLengthInStorage()), resultReg); > > int32Result(resultReg, node); > break; >@@ -6965,6 +6974,32 @@ void SpeculativeJIT::compileCreateActiva > > void SpeculativeJIT::compileCreateDirectArguments(Node* node) > { >+ VM& vm = *m_jit.vm(); >+ >+ bool lengthIsKnown = node->origin.semantic.inlineCallFrame >+ && !node->origin.semantic.inlineCallFrame->isVarargs(); >+ >+ RegisteredStructure structure = >+ m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(node->origin.semantic)->directArgumentsStructure()); >+ unsigned minCapacity = m_jit.graph().baselineCodeBlockFor(node->origin.semantic)->numParameters() - 1; >+ >+ auto loadLength = [&] (GPRReg lengthGPR) { >+ VirtualRegister argumentCountRegister = m_jit.argumentCount(node->origin.semantic); >+ m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), lengthGPR); >+ m_jit.sub32(TrustedImm32(1), lengthGPR); >+ }; >+ >+ if (isX86() && is32Bit() && !lengthIsKnown) { >+ GPRFlushedCallResult result(this); >+ GPRReg resultGPR = result.gpr(); >+ flushRegisters(); >+ GPRReg lengthGPR = GPRInfo::regT0; // Can be anything we like because registers are flushed. >+ loadLength(lengthGPR); >+ callOperation(operationCreateDirectArguments, resultGPR, structure, lengthGPR, minCapacity); >+ cellResult(resultGPR, node); >+ return; >+ } >+ > // FIXME: A more effective way of dealing with the argument count and callee is to have > // them be explicit arguments to this node. > // https://bugs.webkit.org/show_bug.cgi?id=142207 >@@ -6972,50 +7007,42 @@ void SpeculativeJIT::compileCreateDirect > GPRTemporary result(this); > GPRTemporary scratch1(this); > GPRTemporary scratch2(this); >+ GPRTemporary storage(this); > GPRTemporary length; > GPRReg resultGPR = result.gpr(); > GPRReg scratch1GPR = scratch1.gpr(); > GPRReg scratch2GPR = scratch2.gpr(); > GPRReg lengthGPR = InvalidGPRReg; >+ GPRReg storageGPR = storage.gpr(); > JSValueRegs valueRegs = JSValueRegs::withTwoAvailableRegs(scratch1GPR, scratch2GPR); > >- unsigned minCapacity = m_jit.graph().baselineCodeBlockFor(node->origin.semantic)->numParameters() - 1; >- > unsigned knownLength; >- bool lengthIsKnown; // if false, lengthGPR will have the length. >- if (node->origin.semantic.inlineCallFrame >- && !node->origin.semantic.inlineCallFrame->isVarargs()) { >+ if (lengthIsKnown) > knownLength = node->origin.semantic.inlineCallFrame->argumentCountIncludingThis - 1; >- lengthIsKnown = true; >- } else { >+ else { > knownLength = UINT_MAX; >- lengthIsKnown = false; > > GPRTemporary realLength(this); > length.adopt(realLength); > lengthGPR = length.gpr(); > >- VirtualRegister argumentCountRegister = m_jit.argumentCount(node->origin.semantic); >- m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), lengthGPR); >- m_jit.sub32(TrustedImm32(1), lengthGPR); >+ loadLength(lengthGPR); > } > >- RegisteredStructure structure = >- m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(node->origin.semantic)->directArgumentsStructure()); >- > // Use a different strategy for allocating the object depending on whether we know its > // size statically. > JITCompiler::JumpList slowPath; > if (lengthIsKnown) { >- auto butterfly = TrustedImmPtr(nullptr); >- auto mask = TrustedImm32(0); >- emitAllocateJSObjectWithKnownSize<DirectArguments>( >- resultGPR, TrustedImmPtr(structure), butterfly, mask, scratch1GPR, scratch2GPR, >- slowPath, DirectArguments::allocationSize(std::max(knownLength, minCapacity))); >- >+ JITAllocator storageAllocator = JITAllocator::constant( >+ vm.jsValueGigacageAuxiliarySpace.allocatorForNonVirtual( >+ DirectArguments::storageSize(std::max(knownLength, minCapacity)), >+ AllocatorForMode::AllocatorIfExists)); >+ >+ m_jit.emitAllocate(storageGPR, storageAllocator, scratch1GPR, scratch2GPR, slowPath); >+ m_jit.addPtr(TrustedImmPtr(DirectArguments::storageHeaderSize()), storageGPR); > m_jit.store32( > TrustedImm32(knownLength), >- JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength())); >+ JITCompiler::Address(storageGPR, DirectArguments::offsetOfLengthInStorage())); > } else { > JITCompiler::Jump tooFewArguments; > if (minCapacity) { >@@ -7023,25 +7050,32 @@ void SpeculativeJIT::compileCreateDirect > m_jit.branch32(JITCompiler::Below, lengthGPR, TrustedImm32(minCapacity)); > } > m_jit.lshift32(lengthGPR, TrustedImm32(3), scratch1GPR); >- m_jit.add32(TrustedImm32(DirectArguments::storageOffset()), scratch1GPR); >+ m_jit.add32(TrustedImm32(DirectArguments::storageHeaderSize()), scratch1GPR); > if (minCapacity) { > JITCompiler::Jump done = m_jit.jump(); > tooFewArguments.link(&m_jit); >- m_jit.move(TrustedImm32(DirectArguments::allocationSize(minCapacity)), scratch1GPR); >+ m_jit.move(TrustedImm32(DirectArguments::storageSize(minCapacity)), scratch1GPR); > done.link(&m_jit); > } > >- emitAllocateVariableSizedJSObject<DirectArguments>( >- resultGPR, TrustedImmPtr(structure), scratch1GPR, scratch1GPR, scratch2GPR, >- slowPath); >- >+ m_jit.emitAllocateVariableSized( >+ storageGPR, vm.jsValueGigacageAuxiliarySpace, scratch1GPR, scratch1GPR, scratch2GPR, slowPath); >+ m_jit.addPtr(TrustedImmPtr(DirectArguments::storageHeaderSize()), storageGPR); > m_jit.store32( >- lengthGPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength())); >+ lengthGPR, >+ JITCompiler::Address(storageGPR, DirectArguments::offsetOfLengthInStorage())); > } >- >+ > m_jit.store32( > TrustedImm32(minCapacity), >- JITCompiler::Address(resultGPR, DirectArguments::offsetOfMinCapacity())); >+ JITCompiler::Address(storageGPR, DirectArguments::offsetOfMinCapacityInStorage())); >+ >+ auto butterfly = TrustedImmPtr(nullptr); >+ auto mask = TrustedImm32(0); >+ emitAllocateJSObject<DirectArguments>(resultGPR, TrustedImmPtr(structure), butterfly, mask, scratch1GPR, scratch2GPR, slowPath); >+ m_jit.move(storageGPR, scratch1GPR); >+ m_jit.xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), scratch1GPR); >+ m_jit.storePtr(scratch1GPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfStorage())); > > m_jit.storePtr( > TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfMappedArguments())); >@@ -7049,17 +7083,16 @@ void SpeculativeJIT::compileCreateDirect > m_jit.storePtr( > TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfModifiedArgumentsDescriptor())); > >+ std::unique_ptr<SlowPathGenerator> generator; > if (lengthIsKnown) { >- addSlowPathGenerator( >- slowPathCall( >- slowPath, this, operationCreateDirectArguments, resultGPR, structure, >- knownLength, minCapacity)); >+ generator = std::make_unique<CallCreateDirectArgumentsWithKnownLengthSlowPathGenerator>( >+ slowPath, this, resultGPR, structure, knownLength, storageGPR, minCapacity); > } else { >- auto generator = std::make_unique<CallCreateDirectArgumentsSlowPathGenerator>( >- slowPath, this, resultGPR, structure, lengthGPR, minCapacity); >- addSlowPathGenerator(WTFMove(generator)); >+ generator = std::make_unique<CallCreateDirectArgumentsSlowPathGenerator>( >+ slowPath, this, resultGPR, structure, lengthGPR, storageGPR, minCapacity); > } >- >+ addSlowPathGenerator(WTFMove(generator)); >+ > if (node->origin.semantic.inlineCallFrame) { > if (node->origin.semantic.inlineCallFrame->isClosureCall) { > m_jit.loadPtr( >@@ -7085,7 +7118,7 @@ void SpeculativeJIT::compileCreateDirect > for (unsigned i = 0; i < std::max(knownLength, minCapacity); ++i) { > m_jit.loadValue(JITCompiler::addressFor(start + i), valueRegs); > m_jit.storeValue( >- valueRegs, JITCompiler::Address(resultGPR, DirectArguments::offsetOfSlot(i))); >+ valueRegs, JITCompiler::Address(storageGPR, i * sizeof(WriteBarrier<Unknown>))); > } > } else { > JITCompiler::Jump done; >@@ -7106,14 +7139,13 @@ void SpeculativeJIT::compileCreateDirect > m_jit.storeValue( > valueRegs, > JITCompiler::BaseIndex( >- resultGPR, lengthGPR, JITCompiler::TimesEight, >- DirectArguments::storageOffset())); >+ storageGPR, lengthGPR, JITCompiler::TimesEight)); > m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loop, &m_jit); > if (done.isSet()) > done.link(&m_jit); > } > >- m_jit.mutatorFence(*m_jit.vm()); >+ m_jit.mutatorFence(vm); > > cellResult(resultGPR, node); > } >@@ -7126,7 +7158,9 @@ void SpeculativeJIT::compileGetFromArgum > GPRReg argumentsGPR = arguments.gpr(); > JSValueRegs resultRegs = result.regs(); > >- m_jit.loadValue(JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset())), resultRegs); >+ m_jit.loadPtr(JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfStorage()), resultRegs.payloadGPR()); >+ m_jit.xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), resultRegs.payloadGPR()); >+ m_jit.loadValue(JITCompiler::Address(resultRegs.payloadGPR(), node->capturedArgumentsOffset().offset() * sizeof(WriteBarrier<Unknown>)), resultRegs); > jsValueResult(resultRegs, node); > } > >@@ -7134,11 +7168,15 @@ void SpeculativeJIT::compilePutToArgumen > { > SpeculateCellOperand arguments(this, node->child1()); > JSValueOperand value(this, node->child2()); >+ GPRTemporary storage(this); > > GPRReg argumentsGPR = arguments.gpr(); >+ GPRReg storageGPR = storage.gpr(); > JSValueRegs valueRegs = value.jsValueRegs(); > >- m_jit.storeValue(valueRegs, JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset()))); >+ m_jit.loadPtr(JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfStorage()), storageGPR); >+ m_jit.xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), storageGPR); >+ m_jit.storeValue(valueRegs, JITCompiler::Address(storageGPR, node->capturedArgumentsOffset().offset() * sizeof(WriteBarrier<Unknown>))); > noResult(node); > } > >Index: Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (revision 229411) >+++ Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (working copy) >@@ -51,11 +51,12 @@ namespace JSC { namespace FTL { > macro(Butterfly_vectorLength, Butterfly::offsetOfVectorLength()) \ > macro(CallFrame_callerFrame, CallFrame::callerFrameOffset()) \ > macro(ClassInfo_parentClass, ClassInfo::offsetOfParentClass()) \ >+ macro(DirectArguments_Storage_length, DirectArguments::offsetOfLengthInStorage()) \ >+ macro(DirectArguments_Storage_minCapacity, DirectArguments::offsetOfMinCapacityInStorage()) \ > macro(DirectArguments_callee, DirectArguments::offsetOfCallee()) \ >- macro(DirectArguments_length, DirectArguments::offsetOfLength()) \ >- macro(DirectArguments_minCapacity, DirectArguments::offsetOfMinCapacity()) \ > macro(DirectArguments_mappedArguments, DirectArguments::offsetOfMappedArguments()) \ > macro(DirectArguments_modifiedArgumentsDescriptor, DirectArguments::offsetOfModifiedArgumentsDescriptor()) \ >+ macro(DirectArguments_storage, DirectArguments::offsetOfStorage()) \ > macro(GetterSetter_getter, GetterSetter::offsetOfGetter()) \ > macro(GetterSetter_setter, GetterSetter::offsetOfSetter()) \ > macro(JSArrayBufferView_length, JSArrayBufferView::offsetOfLength()) \ >@@ -133,7 +134,7 @@ namespace JSC { namespace FTL { > #define FOR_EACH_INDEXED_ABSTRACT_HEAP(macro) \ > macro(ArrayStorage_vector, ArrayStorage::vectorOffset(), sizeof(WriteBarrier<Unknown>)) \ > macro(CompleteSubspace_allocatorForSizeStep, CompleteSubspace::offsetOfAllocatorForSizeStep(), sizeof(Allocator)) \ >- macro(DirectArguments_storage, DirectArguments::storageOffset(), sizeof(EncodedJSValue)) \ >+ macro(DirectArguments_Storage_storage, 0, sizeof(EncodedJSValue)) \ > macro(JSLexicalEnvironment_variables, JSLexicalEnvironment::offsetOfVariables(), sizeof(EncodedJSValue)) \ > macro(JSPropertyNameEnumerator_cachedPropertyNamesVectorContents, 0, sizeof(WriteBarrier<JSString>)) \ > macro(JSRopeString_fibers, JSRopeString::offsetOfFibers(), sizeof(WriteBarrier<JSString>)) \ >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (revision 229411) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (working copy) >@@ -3667,7 +3667,10 @@ private: > speculate( > ExoticObjectMode, noValue(), nullptr, > m_out.notNull(m_out.loadPtr(arguments, m_heaps.DirectArguments_mappedArguments))); >- setInt32(m_out.load32NonNegative(arguments, m_heaps.DirectArguments_length)); >+ LValue storage = m_out.bitXor( >+ m_out.loadPtr(lowCell(m_node->child1()), m_heaps.DirectArguments_storage), >+ m_out.constIntPtr(DirectArgumentsPoison::key())); >+ setInt32(m_out.load32NonNegative(storage, m_heaps.DirectArguments_Storage_length)); > return; > } > >@@ -3833,13 +3836,16 @@ private: > ExoticObjectMode, noValue(), nullptr, > m_out.notNull(m_out.loadPtr(base, m_heaps.DirectArguments_mappedArguments))); > >- LValue length = m_out.load32NonNegative(base, m_heaps.DirectArguments_length); >+ LValue storage = m_out.loadPtr(base, m_heaps.DirectArguments_storage); >+ storage = m_out.bitXor(storage, m_out.constIntPtr(DirectArgumentsPoison::key())); >+ >+ LValue length = m_out.load32NonNegative(storage, m_heaps.DirectArguments_Storage_length); > auto isOutOfBounds = m_out.aboveOrEqual(index, length); > if (m_node->arrayMode().isInBounds()) { > speculate(OutOfBounds, noValue(), nullptr, isOutOfBounds); > TypedPointer address = m_out.baseIndex( >- m_heaps.DirectArguments_storage, base, m_out.zeroExtPtr(index)); >- setJSValue(m_out.load64(address)); >+ m_heaps.DirectArguments_Storage_storage, storage, m_out.zeroExtPtr(index)); >+ setJSValue(preciseIndexMask32(m_out.load64(address), index, length)); > return; > } > >@@ -3851,8 +3857,7 @@ private: > > LBasicBlock lastNext = m_out.appendTo(inBounds, slowCase); > TypedPointer address = m_out.baseIndex( >- m_heaps.DirectArguments_storage, >- dynamicPoisonOnType(base, DirectArgumentsType), >+ m_heaps.DirectArguments_Storage_storage, storage, > m_out.zeroExt(index, pointerType())); > ValueFromBlock fastResult = m_out.anchor( > preciseIndexMask32(m_out.load64(address), index, length)); >@@ -5151,29 +5156,39 @@ private: > > ArgumentsLength length = getArgumentsLength(); > >+ LValue fastStorage; > LValue fastObject; > if (length.isKnown) { >- fastObject = allocateObject<DirectArguments>( >- DirectArguments::allocationSize(std::max(length.known, minCapacity)), structure, >- m_out.intPtrZero, m_out.int32Zero, slowPath); >+ LValue allocator = m_out.constInt32( >+ vm().jsValueGigacageAuxiliarySpace.allocatorForNonVirtual( >+ DirectArguments::storageSize(std::max(length.known, minCapacity)), >+ AllocatorForMode::AllocatorIfExists).offset()); >+ >+ fastStorage = allocateHeapCell(allocator, slowPath); > } else { > LValue size = m_out.add( > m_out.shl(length.value, m_out.constInt32(3)), >- m_out.constInt32(DirectArguments::storageOffset())); >+ m_out.constInt32(DirectArguments::storageHeaderSize())); > > size = m_out.select( > m_out.aboveOrEqual(length.value, m_out.constInt32(minCapacity)), >- size, m_out.constInt32(DirectArguments::allocationSize(minCapacity))); >- >- fastObject = allocateVariableSizedObject<DirectArguments>( >- m_out.zeroExtPtr(size), structure, m_out.intPtrZero, m_out.int32Zero, slowPath); >+ size, m_out.constInt32(DirectArguments::storageSize(minCapacity))); >+ >+ fastStorage = allocateVariableSizedHeapCell( >+ vm().jsValueGigacageAuxiliarySpace, m_out.zeroExtPtr(size), slowPath); > } > >- m_out.store32(length.value, fastObject, m_heaps.DirectArguments_length); >- m_out.store32(m_out.constInt32(minCapacity), fastObject, m_heaps.DirectArguments_minCapacity); >+ fastStorage = m_out.add(fastStorage, m_out.constIntPtr(DirectArguments::storageHeaderSize())); >+ m_out.store32(length.value, fastStorage, m_heaps.DirectArguments_Storage_length); >+ m_out.store32(m_out.constInt32(minCapacity), fastStorage, m_heaps.DirectArguments_Storage_minCapacity); >+ >+ fastObject = allocateObject<DirectArguments>(structure, m_out.intPtrZero, m_out.intPtrZero, slowPath); >+ >+ m_out.storePtr(m_out.bitXor(fastStorage, m_out.constIntPtr(DirectArgumentsPoison::key())), fastObject, m_heaps.DirectArguments_storage); > m_out.storePtr(m_out.intPtrZero, fastObject, m_heaps.DirectArguments_mappedArguments); > m_out.storePtr(m_out.intPtrZero, fastObject, m_heaps.DirectArguments_modifiedArgumentsDescriptor); > >+ ValueFromBlock fastStorageAnchor = m_out.anchor(fastStorage); > ValueFromBlock fastResult = m_out.anchor(fastObject); > m_out.jump(continuation); > >@@ -5187,9 +5202,14 @@ private: > CCallHelpers::TrustedImm32(minCapacity)); > }, length.value); > ValueFromBlock slowResult = m_out.anchor(callResult); >+ ValueFromBlock slowStorage = m_out.anchor( >+ m_out.bitXor( >+ m_out.loadPtr(callResult, m_heaps.DirectArguments_storage), >+ m_out.constIntPtr(DirectArgumentsPoison::key()))); > m_out.jump(continuation); > > m_out.appendTo(continuation, lastNext); >+ LValue storage = m_out.phi(pointerType(), fastStorageAnchor, slowStorage); > LValue result = m_out.phi(pointerType(), fastResult, slowResult); > > m_out.storePtr(getCurrentCallee(), result, m_heaps.DirectArguments_callee); >@@ -5199,7 +5219,7 @@ private: > for (unsigned i = 0; i < std::max(length.known, minCapacity); ++i) { > m_out.store64( > m_out.load64(addressFor(start + i)), >- result, m_heaps.DirectArguments_storage[i]); >+ storage, m_heaps.DirectArguments_Storage_storage[i]); > } > } else { > LValue stackBase = getArgumentsStart(); >@@ -5227,7 +5247,7 @@ private: > LValue index = m_out.sub(previousIndex, m_out.intPtrOne); > m_out.store64( > m_out.load64(m_out.baseIndex(m_heaps.variables, stackBase, index)), >- m_out.baseIndex(m_heaps.DirectArguments_storage, result, index)); >+ m_out.baseIndex(m_heaps.DirectArguments_Storage_storage, storage, index)); > ValueFromBlock nextIndex = m_out.anchor(index); > m_out.addIncomingToPhi(previousIndex, nextIndex); > m_out.branch(m_out.isNull(index), unsure(end), unsure(loop)); >@@ -6684,18 +6704,23 @@ private: > > void compileGetFromArguments() > { >+ LValue storage = m_out.bitXor( >+ m_out.loadPtr(lowCell(m_node->child1()), m_heaps.DirectArguments_storage), >+ m_out.constIntPtr(DirectArgumentsPoison::key())); > setJSValue( > m_out.load64( >- lowCell(m_node->child1()), >- m_heaps.DirectArguments_storage[m_node->capturedArgumentsOffset().offset()])); >+ storage, >+ m_heaps.DirectArguments_Storage_storage[m_node->capturedArgumentsOffset().offset()])); > } > > void compilePutToArguments() > { >+ LValue storage = m_out.bitXor( >+ m_out.loadPtr(lowCell(m_node->child1()), m_heaps.DirectArguments_storage), >+ m_out.constIntPtr(DirectArgumentsPoison::key())); > m_out.store64( >- lowJSValue(m_node->child2()), >- lowCell(m_node->child1()), >- m_heaps.DirectArguments_storage[m_node->capturedArgumentsOffset().offset()]); >+ lowJSValue(m_node->child2()), storage, >+ m_heaps.DirectArguments_Storage_storage[m_node->capturedArgumentsOffset().offset()]); > } > > void compileGetArgument() >@@ -11826,7 +11851,7 @@ private: > > LValue structure = loadStructure(cell); > LValue poisonedClassInfo = m_out.loadPtr(structure, m_heaps.Structure_classInfo); >- LValue classInfo = m_out.bitXor(poisonedClassInfo, m_out.constInt64(GlobalDataPoison::key())); >+ LValue classInfo = m_out.bitXor(poisonedClassInfo, m_out.constIntPtr(GlobalDataPoison::key())); > ValueFromBlock otherAtStart = m_out.anchor(classInfo); > m_out.jump(loop); > >@@ -12601,6 +12626,12 @@ private: > return allocateCell(allocator, structure, slowPath); > } > >+ LValue allocateVariableSizedHeapCell(CompleteSubspace& subspace, LValue size, LBasicBlock slowPath) >+ { >+ LValue allocator = allocatorForSize(subspace, size, slowPath); >+ return allocateHeapCell(allocator, slowPath); >+ } >+ > LValue allocateObject(RegisteredStructure structure) > { > size_t allocationSize = JSFinalObject::allocationSize(structure.get()->inlineCapacity()); >@@ -15557,32 +15588,6 @@ private: > return preciseIndexMask64(value, m_out.zeroExt(index, Int64), m_out.zeroExt(limit, Int64)); > } > >- LValue dynamicPoison(LValue value, LValue poison) >- { >- return m_out.add( >- value, >- m_out.shl( >- m_out.zeroExt(poison, pointerType()), >- m_out.constInt32(40))); >- } >- >- LValue dynamicPoisonOnLoadedType(LValue value, LValue actualType, JSType expectedType) >- { >- return dynamicPoison( >- value, >- m_out.bitXor( >- m_out.opaque(actualType), >- m_out.constInt32(expectedType))); >- } >- >- LValue dynamicPoisonOnType(LValue value, JSType expectedType) >- { >- return dynamicPoisonOnLoadedType( >- value, >- m_out.load8ZeroExt32(value, m_heaps.JSCell_typeInfoType), >- expectedType); >- } >- > template<typename... Args> > LValue vmCall(LType type, LValue function, Args&&... args) > { >Index: Source/JavaScriptCore/heap/SecurityKind.h >=================================================================== >--- Source/JavaScriptCore/heap/SecurityKind.h (revision 229411) >+++ Source/JavaScriptCore/heap/SecurityKind.h (working copy) >@@ -27,6 +27,8 @@ > > namespace JSC { > >+// NOTE: SecurityKind is for distancing. But caging implies distancing. So, things that have their own >+// cages (like typed arrays) don't need to worry about the security kind. > enum class SecurityKind : uint8_t { > // The JSValueOOB security kind is for cells that contain JValues and can be accessed out-of-bounds > // up to minimumDistanceBetweenCellsFromDifferentOrigins. >@@ -41,7 +43,11 @@ enum class SecurityKind : uint8_t { > // The JSValueStrict security kind is for cells that contain JSValues but cannot be accessed > // out-of-bounds. Currently, it's not essential to keep this separate from DangerousBits. We're > // using this to get some wiggle room for how we handle array elements. For example, we might want >- // to allow OOB reads but not OOB writes. >+ // to allow OOB reads but not OOB writes, since JSValueStrict contains only JSValues and length fields. >+ // Using Spectre to read the length fields is not useful for attackers since they can read them anyway. >+ // So, they will only want to write to length fields, in order to confuse a subsequent bounds check. >+ // They can do that within a speculation window. However, we currently use precise index masking for >+ // this. > // > // It's illegal to use this for any subclass of JSObject, JSString, or Symbol, or any other cell > // that could be referenced from a JSValue. You must use poisoned pointers to point at these cells. >Index: Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp (revision 229411) >+++ Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp (working copy) >@@ -1118,8 +1118,9 @@ void JIT::emit_op_get_from_arguments(Ins > int index = currentInstruction[3].u.operand; > > emitLoadPayload(arguments, regT0); >- load32(Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + TagOffset), regT1); >- load32(Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + PayloadOffset), regT0); >+ loadPtr(Address(regT0, DirectArguments::offsetOfStorage()), regT0); >+ load32(Address(regT0, index * sizeof(WriteBarrier<Unknown>) + TagOffset), regT1); >+ load32(Address(regT0, index * sizeof(WriteBarrier<Unknown>) + PayloadOffset), regT0); > emitValueProfilingSite(); > emitStore(dst, regT1, regT0); > } >@@ -1133,9 +1134,10 @@ void JIT::emit_op_put_to_arguments(Instr > emitWriteBarrier(arguments, value, ShouldFilterValue); > > emitLoadPayload(arguments, regT0); >+ loadPtr(Address(regT0, DirectArguments::offsetOfStorage()), regT0); > emitLoad(value, regT1, regT2); >- store32(regT1, Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + TagOffset)); >- store32(regT2, Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + PayloadOffset)); >+ store32(regT1, Address(regT0, index * sizeof(WriteBarrier<Unknown>) + TagOffset)); >+ store32(regT2, Address(regT0, index * sizeof(WriteBarrier<Unknown>) + PayloadOffset)); > } > > } // namespace JSC >Index: Source/JavaScriptCore/jit/JITPropertyAccess.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITPropertyAccess.cpp (revision 229411) >+++ Source/JavaScriptCore/jit/JITPropertyAccess.cpp (working copy) >@@ -1100,7 +1100,9 @@ void JIT::emit_op_get_from_arguments(Ins > int index = currentInstruction[3].u.operand; > > emitGetVirtualRegister(arguments, regT0); >- load64(Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>)), regT0); >+ loadPtr(Address(regT0, DirectArguments::offsetOfStorage()), regT0); >+ xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), regT0); >+ load64(Address(regT0, index * sizeof(WriteBarrier<Unknown>)), regT0); > emitValueProfilingSite(); > emitPutVirtualRegister(dst); > } >@@ -1113,7 +1115,9 @@ void JIT::emit_op_put_to_arguments(Instr > > emitGetVirtualRegister(arguments, regT0); > emitGetVirtualRegister(value, regT1); >- store64(regT1, Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>))); >+ loadPtr(Address(regT0, DirectArguments::offsetOfStorage()), regT0); >+ xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), regT0); >+ store64(regT1, Address(regT0, index * sizeof(WriteBarrier<Unknown>))); > > emitWriteBarrier(arguments, value, ShouldFilterValue); > } >@@ -1412,14 +1416,16 @@ JIT::JumpList JIT::emitDirectArgumentsGe > > load8(Address(base, JSCell::typeInfoTypeOffset()), scratch); > badType = patchableBranch32(NotEqual, scratch, TrustedImm32(DirectArgumentsType)); >- emitDynamicPoisonOnLoadedType(base, scratch, DirectArgumentsType); > >- load32(Address(base, DirectArguments::offsetOfLength()), scratch2); >+ loadPtr(Address(base, DirectArguments::offsetOfStorage()), scratch); >+ xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), scratch); >+ >+ load32(Address(scratch, DirectArguments::offsetOfLengthInStorage()), scratch2); > slowCases.append(branch32(AboveOrEqual, property, scratch2)); > slowCases.append(branchTestPtr(NonZero, Address(base, DirectArguments::offsetOfMappedArguments()))); > > emitPreparePreciseIndexMask32(property, scratch2, scratch2); >- loadValue(BaseIndex(base, property, TimesEight, DirectArguments::storageOffset()), result); >+ loadValue(BaseIndex(scratch, property, TimesEight), result); > andPtr(scratch2, result.payloadGPR()); > > return slowCases; >Index: Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm >=================================================================== >--- Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (revision 229411) >+++ Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (working copy) >@@ -2496,8 +2496,9 @@ _llint_op_get_from_arguments: > loadisFromInstruction(2, t0) > loadi PayloadOffset[cfr, t0, 8], t0 > loadi 12[PC], t1 >- loadi DirectArguments_storage + TagOffset[t0, t1, 8], t2 >- loadi DirectArguments_storage + PayloadOffset[t0, t1, 8], t3 >+ loadp DirectArguments::m_storage[t0], t0 >+ loadi TagOffset[t0, t1, 8], t2 >+ loadi PayloadOffset[t0, t1, 8], t3 > loadisFromInstruction(1, t1) > valueProfile(t2, t3, 16, t0) > storei t2, TagOffset[cfr, t1, 8] >@@ -2512,9 +2513,10 @@ _llint_op_put_to_arguments: > loadi PayloadOffset[cfr, t0, 8], t0 > loadisFromInstruction(3, t1) > loadConstantOrVariable(t1, t2, t3) >+ loadp DirectArguments::m_storage[t0], t0 > loadi 8[PC], t1 >- storei t2, DirectArguments_storage + TagOffset[t0, t1, 8] >- storei t3, DirectArguments_storage + PayloadOffset[t0, t1, 8] >+ storei t2, TagOffset[t0, t1, 8] >+ storei t3, PayloadOffset[t0, t1, 8] > dispatch(4) > > >Index: Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >=================================================================== >--- Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (revision 229411) >+++ Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (working copy) >@@ -2529,7 +2529,9 @@ _llint_op_get_from_arguments: > traceExecution() > loadVariable(2, t0) > loadi 24[PB, PC, 8], t1 >- loadq DirectArguments_storage[t0, t1, 8], t0 >+ loadp DirectArguments::m_storage[t0], t0 >+ unpoison(_g_DirectArgumentsPoison, t0, t3) >+ loadq [t0, t1, 8], t0 > valueProfile(t0, 4, t1) > loadisFromInstruction(1, t1) > storeq t0, [cfr, t1, 8] >@@ -2542,7 +2544,9 @@ _llint_op_put_to_arguments: > loadi 16[PB, PC, 8], t1 > loadisFromInstruction(3, t3) > loadConstantOrVariable(t3, t2) >- storeq t2, DirectArguments_storage[t0, t1, 8] >+ loadp DirectArguments::m_storage[t0], t0 >+ unpoison(_g_DirectArgumentsPoison, t0, t3) >+ storeq t2, [t0, t1, 8] > writeBarrierOnOperands(1, 3) > dispatch(constexpr op_put_to_arguments_length) > >Index: Source/JavaScriptCore/llint/LowLevelInterpreter.asm >=================================================================== >--- Source/JavaScriptCore/llint/LowLevelInterpreter.asm (revision 229411) >+++ Source/JavaScriptCore/llint/LowLevelInterpreter.asm (working copy) >@@ -164,7 +164,6 @@ end > const SlotSize = 8 > > const JSLexicalEnvironment_variables = (sizeof JSLexicalEnvironment + SlotSize - 1) & ~(SlotSize - 1) >-const DirectArguments_storage = (sizeof DirectArguments + SlotSize - 1) & ~(SlotSize - 1) > > const StackAlignment = 16 > const StackAlignmentSlots = 2 >Index: Source/JavaScriptCore/runtime/DirectArguments.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/DirectArguments.cpp (revision 229411) >+++ Source/JavaScriptCore/runtime/DirectArguments.cpp (working copy) >@@ -36,22 +36,27 @@ STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE( > > const ClassInfo DirectArguments::s_info = { "Arguments", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DirectArguments) }; > >-DirectArguments::DirectArguments(VM& vm, Structure* structure, unsigned length, unsigned capacity) >+DirectArguments::DirectArguments(VM& vm, Structure* structure, WriteBarrier<Unknown>* storage) > : GenericArguments(vm, structure) >- , m_length(length) >- , m_minCapacity(capacity) >+ , m_storage(vm, this, storage) > { > // When we construct the object from C++ code, we expect the capacity to be at least as large as > // length. JIT-allocated DirectArguments objects play evil tricks, though. >- ASSERT(capacity >= length); >+ ASSERT(storage->capacity >= storage->length); > } > > DirectArguments* DirectArguments::createUninitialized( > VM& vm, Structure* structure, unsigned length, unsigned capacity) > { >+ void* rawStoragePtr = vm.jsValueGigacageAuxiliarySpace.allocateNonVirtual( >+ vm, storageSize(capacity), nullptr, AllocationFailureMode::Assert); >+ WriteBarrier<Unknown>* storage = static_cast<WriteBarrier<Unknown>*>(rawStoragePtr) + 1; >+ storageHeader(storage).length = length; >+ storageHeader(storage).minCapacity = capacity; >+ > DirectArguments* result = >- new (NotNull, allocateCell<DirectArguments>(vm.heap, allocationSize(capacity))) >- DirectArguments(vm, structure, length, capacity); >+ new (NotNull, allocateCell<DirectArguments>(vm.heap)) >+ DirectArguments(vm, structure, storage); > result->finishCreation(vm); > return result; > } >@@ -59,9 +64,10 @@ DirectArguments* DirectArguments::create > DirectArguments* DirectArguments::create(VM& vm, Structure* structure, unsigned length, unsigned capacity) > { > DirectArguments* result = createUninitialized(vm, structure, length, capacity); >- >+ >+ WriteBarrier<Unknown>* storage = result->storage(); > for (unsigned i = capacity; i--;) >- result->storage()[i].clear(); >+ storage[i].clear(); > > return result; > } >@@ -75,8 +81,9 @@ DirectArguments* DirectArguments::create > DirectArguments* result = createUninitialized( > vm, exec->lexicalGlobalObject()->directArgumentsStructure(), length, capacity); > >+ WriteBarrier<Unknown>* storage = result->storage(); > for (unsigned i = capacity; i--;) >- result->storage()[i].set(vm, result, exec->getArgumentUnsafe(i)); >+ storage[i].set(vm, result, exec->getArgumentUnsafe(i)); > > result->callee().set(vm, result, jsCast<JSFunction*>(exec->jsCallee())); > >@@ -87,7 +94,7 @@ size_t DirectArguments::estimatedSize(JS > { > DirectArguments* thisObject = jsCast<DirectArguments*>(cell); > size_t mappedArgumentsSize = thisObject->m_mappedArguments ? thisObject->mappedArgumentsSize() * sizeof(bool) : 0; >- size_t modifiedArgumentsSize = thisObject->m_modifiedArgumentsDescriptor ? thisObject->m_length * sizeof(bool) : 0; >+ size_t modifiedArgumentsSize = thisObject->m_modifiedArgumentsDescriptor ? thisObject->storageHeader().length * sizeof(bool) : 0; > return Base::estimatedSize(cell) + mappedArgumentsSize + modifiedArgumentsSize; > } > >@@ -97,11 +104,14 @@ void DirectArguments::visitChildren(JSCe > ASSERT_GC_OBJECT_INHERITS(thisObject, info()); > Base::visitChildren(thisObject, visitor); > >- visitor.appendValues(thisObject->storage(), std::max(thisObject->m_length, thisObject->m_minCapacity)); >+ visitor.markAuxiliary(&thisObject->storageHeader()); >+ visitor.appendValues(thisObject->storage(), std::max(thisObject->storageHeader().length, thisObject->storageHeader().minCapacity)); >+ > visitor.append(thisObject->m_callee); > > if (thisObject->m_mappedArguments) > visitor.markAuxiliary(thisObject->m_mappedArguments.get()); >+ > GenericArguments<DirectArguments>::visitChildren(thisCell, visitor); > } > >@@ -114,14 +124,14 @@ void DirectArguments::overrideThings(VM& > { > RELEASE_ASSERT(!m_mappedArguments); > >- putDirect(vm, vm.propertyNames->length, jsNumber(m_length), static_cast<unsigned>(PropertyAttribute::DontEnum)); >+ putDirect(vm, vm.propertyNames->length, jsNumber(storageHeader().length), static_cast<unsigned>(PropertyAttribute::DontEnum)); > putDirect(vm, vm.propertyNames->callee, m_callee.get(), static_cast<unsigned>(PropertyAttribute::DontEnum)); > putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject()->arrayProtoValuesFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum)); > > void* backingStore = vm.gigacageAuxiliarySpace(m_mappedArguments.kind).allocateNonVirtual(vm, mappedArgumentsSize(), nullptr, AllocationFailureMode::Assert); > bool* overrides = static_cast<bool*>(backingStore); > m_mappedArguments.set(vm, this, overrides); >- for (unsigned i = m_length; i--;) >+ for (unsigned i = storageHeader().length; i--;) > overrides[i] = false; > } > >@@ -140,11 +150,12 @@ void DirectArguments::unmapArgument(VM& > void DirectArguments::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length) > { > if (!m_mappedArguments) { >- unsigned limit = std::min(length + offset, m_length); >+ unsigned limit = std::min(length + offset, storageHeader().length); > unsigned i; > VirtualRegister start = firstElementDest - offset; >+ WriteBarrier<Unknown>* storage = this->storage(); > for (i = offset; i < limit; ++i) >- exec->r(start + i) = storage()[i].get(); >+ exec->r(start + i) = storage[i].get(); > for (; i < length; ++i) > exec->r(start + i) = get(exec, i); > return; >@@ -158,7 +169,7 @@ unsigned DirectArguments::mappedArgument > // We always allocate something; in the relatively uncommon case of overriding an empty argument we > // still allocate so that m_mappedArguments is non-null. We use that to indicate that the other properties > // (length, etc) are overridden. >- return WTF::roundUpToMultipleOf<8>(m_length ? m_length : 1); >+ return WTF::roundUpToMultipleOf<8>(storageHeader().length ? storageHeader().length : 1); > } > > } // namespace JSC >Index: Source/JavaScriptCore/runtime/DirectArguments.h >=================================================================== >--- Source/JavaScriptCore/runtime/DirectArguments.h (revision 229411) >+++ Source/JavaScriptCore/runtime/DirectArguments.h (working copy) >@@ -32,25 +32,24 @@ > > namespace JSC { > >+class LLIntOffsetsExtractor; >+ > // This is an Arguments-class object that we create when you say "arguments" inside a function, > // and none of the arguments are captured in the function's activation. The function will copy all > // of its arguments into this object, and all subsequent accesses to the arguments will go through > // this object thereafter. Special support is in place for mischevious events like the arguments > // being deleted (something like "delete arguments[0]") or reconfigured (broadly, we say deletions > // and reconfigurations mean that the respective argument was "overridden"). >-// >-// To speed allocation, this object will hold all of the arguments in-place. The arguments as well >-// as a table of flags saying which arguments were overridden. > class DirectArguments final : public GenericArguments<DirectArguments> { > private: >- DirectArguments(VM&, Structure*, unsigned length, unsigned capacity); >+ DirectArguments(VM&, Structure*, WriteBarrier<Unknown>* storage); > > public: > template<typename CellType> >- static CompleteSubspace* subspaceFor(VM& vm) >+ static IsoSubspace* subspaceFor(VM& vm) > { > RELEASE_ASSERT(!CellType::needsDestruction); >- return &vm.jsValueGigacageCellSpace; >+ return &vm.directArgumentsSpace; > } > > // Creates an arguments object but leaves it uninitialized. This is dangerous if we GC right >@@ -69,7 +68,7 @@ public: > > uint32_t internalLength() const > { >- return m_length; >+ return storageHeader().length; > } > > uint32_t length(ExecState* exec) const >@@ -82,31 +81,33 @@ public: > scope.release(); > return value.toUInt32(exec); > } >- return m_length; >+ return storageHeader().length; > } > > bool isMappedArgument(uint32_t i) const > { >- return i < m_length && (!m_mappedArguments || !m_mappedArguments[i]); >+ return i < storageHeader().length && (!m_mappedArguments || !m_mappedArguments[i]); > } > > bool isMappedArgumentInDFG(uint32_t i) const > { >- return i < m_length && !overrodeThings(); >+ return i < storageHeader().length && !overrodeThings(); > } >- >+ > JSValue getIndexQuickly(uint32_t i) const > { > ASSERT_WITH_SECURITY_IMPLICATION(isMappedArgument(i)); >- auto* ptr = &const_cast<DirectArguments*>(this)->storage()[i]; >- return preciseIndexMaskPtr(i, m_length, dynamicPoison(type(), DirectArgumentsType, ptr))->get(); >+ WriteBarrier<Unknown>* storage = this->storage(); >+ auto* ptr = &storage[i]; >+ return preciseIndexMaskPtr(i, storageHeader(storage).length, ptr)->get(); > } > > void setIndexQuickly(VM& vm, uint32_t i, JSValue value) > { > ASSERT_WITH_SECURITY_IMPLICATION(isMappedArgument(i)); >- auto* ptr = &storage()[i]; >- preciseIndexMaskPtr(i, m_length, dynamicPoison(type(), DirectArgumentsType, ptr))->set(vm, this, value); >+ WriteBarrier<Unknown>* storage = this->storage(); >+ auto* ptr = &storage[i]; >+ preciseIndexMaskPtr(i, storageHeader(storage).length, ptr)->set(vm, this, value); > } > > WriteBarrier<JSFunction>& callee() >@@ -117,9 +118,13 @@ public: > WriteBarrier<Unknown>& argument(DirectArgumentsOffset offset) > { > ASSERT(offset); >- ASSERT_WITH_SECURITY_IMPLICATION(offset.offset() < std::max(m_length, m_minCapacity)); >- auto* ptr = &storage()[offset.offset()]; >- return *preciseIndexMaskPtr(offset.offset(), std::max(m_length, m_minCapacity), dynamicPoison(type(), DirectArgumentsType, ptr)); >+ ASSERT_WITH_SECURITY_IMPLICATION(offset.offset() < std::max(storageHeader().length, m_minCapacity)); >+ WriteBarrier<Unknown>* storage = this->storage(); >+ auto* ptr = &storage[offset.offset()]; >+ return *preciseIndexMaskPtr( >+ offset.offset(), >+ std::max(storageHeader(storage).length, storageHeader(storage).minCapacity), >+ ptr); > } > > // Methods intended for use by the GenericArguments mixin. >@@ -130,17 +135,17 @@ public: > > void initModifiedArgumentsDescriptorIfNecessary(VM& vm) > { >- GenericArguments<DirectArguments>::initModifiedArgumentsDescriptorIfNecessary(vm, m_length); >+ GenericArguments<DirectArguments>::initModifiedArgumentsDescriptorIfNecessary(vm, storageHeader().length); > } > > void setModifiedArgumentDescriptor(VM& vm, unsigned index) > { >- GenericArguments<DirectArguments>::setModifiedArgumentDescriptor(vm, index, m_length); >+ GenericArguments<DirectArguments>::setModifiedArgumentDescriptor(vm, index, storageHeader().length); > } > > bool isModifiedArgumentDescriptor(unsigned index) > { >- return GenericArguments<DirectArguments>::isModifiedArgumentDescriptor(index, m_length); >+ return GenericArguments<DirectArguments>::isModifiedArgumentDescriptor(index, storageHeader().length); > } > > void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length); >@@ -150,38 +155,55 @@ public: > static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); > > static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(DirectArguments, m_callee); } >- static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(DirectArguments, m_length); } >- static ptrdiff_t offsetOfMinCapacity() { return OBJECT_OFFSETOF(DirectArguments, m_minCapacity); } > static ptrdiff_t offsetOfMappedArguments() { return OBJECT_OFFSETOF(DirectArguments, m_mappedArguments); } > static ptrdiff_t offsetOfModifiedArgumentsDescriptor() { return OBJECT_OFFSETOF(DirectArguments, m_modifiedArgumentsDescriptor); } >+ static ptrdiff_t offsetOfStorage() { return OBJECT_OFFSETOF(DirectArguments, m_storage); } >+ >+ static ptrdiff_t offsetOfLengthInStorage() { return OBJECT_OFFSETOF(StorageHeader, length) - sizeof(WriteBarrier<Unknown>); } >+ static ptrdiff_t offsetOfMinCapacityInStorage() { return OBJECT_OFFSETOF(StorageHeader, minCapacity) - sizeof(WriteBarrier<Unknown>); } > >- static size_t storageOffset() >+ static size_t storageSize(Checked<size_t> capacity) > { >- return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(DirectArguments)); >+ return (sizeof(WriteBarrier<Unknown>*) * (capacity + static_cast<size_t>(1))).unsafeGet(); > } > >- static size_t offsetOfSlot(Checked<size_t> index) >+ static size_t storageHeaderSize() { return sizeof(WriteBarrier<Unknown>); } >+ >+ static size_t allocationSize(size_t inlineSize) > { >- return (storageOffset() + sizeof(WriteBarrier<Unknown>) * index).unsafeGet(); >+ RELEASE_ASSERT(!inlineSize); >+ return sizeof(DirectArguments); > } > >- static size_t allocationSize(Checked<size_t> capacity) >+private: >+ friend class LLIntOffsetsExtractor; >+ >+ struct StorageHeader { >+ uint32_t length; // Always the actual length of captured arguments and never what was stored into the length property. >+ uint32_t minCapacity; // The max of this and length determines the capacity of this object. It may be the actual capacity, or maybe something smaller. We arrange it this way to be kind to the JITs. >+ }; >+ >+ WriteBarrier<Unknown>* storage() const > { >- return offsetOfSlot(capacity); >+ return m_storage.get().unpoisoned(); > } > >-private: >- WriteBarrier<Unknown>* storage() >+ static StorageHeader& storageHeader(WriteBarrier<Unknown>* storage) >+ { >+ static_assert(sizeof(StorageHeader) == sizeof(WriteBarrier<Unknown>), "StorageHeader needs to be the same size as a JSValue"); >+ return *bitwise_cast<StorageHeader*>(storage - 1); >+ } >+ >+ StorageHeader& storageHeader() const > { >- return bitwise_cast<WriteBarrier<Unknown>*>(bitwise_cast<char*>(this) + storageOffset()); >+ return storageHeader(storage()); > } > > unsigned mappedArgumentsSize(); > > WriteBarrier<JSFunction> m_callee; >- uint32_t m_length; // Always the actual length of captured arguments and never what was stored into the length property. >- uint32_t m_minCapacity; // The max of this and length determines the capacity of this object. It may be the actual capacity, or maybe something smaller. We arrange it this way to be kind to the JITs. > CagedBarrierPtr<Gigacage::Primitive, bool> m_mappedArguments; // If non-null, it means that length, callee, and caller are fully materialized properties. >+ AuxiliaryBarrier<Poisoned<DirectArgumentsPoison, WriteBarrier<Unknown>*>> m_storage; > }; > > } // namespace JSC >Index: Source/JavaScriptCore/runtime/JSCPoison.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSCPoison.h (revision 229411) >+++ Source/JavaScriptCore/runtime/JSCPoison.h (working copy) >@@ -34,6 +34,7 @@ namespace JSC { > v(ArrayPrototype) \ > v(CodeBlock) \ > v(DateInstance) \ >+ v(DirectArguments) \ > v(GlobalData) \ > v(JITCode) \ > v(JSAPIWrapperObject) \ >Index: Source/JavaScriptCore/runtime/JSLexicalEnvironment.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSLexicalEnvironment.h (revision 229411) >+++ Source/JavaScriptCore/runtime/JSLexicalEnvironment.h (working copy) >@@ -36,6 +36,7 @@ namespace JSC { > > class LLIntOffsetsExtractor; > >+// This is Spectre-safe because it doesn't have its length inline. > class JSLexicalEnvironment : public JSSymbolTableObject { > friend class JIT; > friend class LLIntOffsetsExtractor; >Index: Source/JavaScriptCore/runtime/JSSymbolTableObject.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSSymbolTableObject.h (revision 229411) >+++ Source/JavaScriptCore/runtime/JSSymbolTableObject.h (working copy) >@@ -73,6 +73,7 @@ protected: > static void visitChildren(JSCell*, SlotVisitor&); > > private: >+ // FIXME: This needs to be poisoned. > WriteBarrier<SymbolTable> m_symbolTable; > }; > >Index: Source/JavaScriptCore/runtime/VM.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/VM.cpp (revision 229411) >+++ Source/JavaScriptCore/runtime/VM.cpp (working copy) >@@ -261,6 +261,7 @@ VM::VM(VMType vmType, HeapType heapType) > , asyncGeneratorFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSAsyncGeneratorFunction) > , boundFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSBoundFunction) > , customGetterSetterFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSCustomGetterSetterFunction) >+ , directArgumentsSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), DirectArguments) > , directEvalExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), DirectEvalExecutable) > , executableToCodeBlockEdgeSpace ISO_SUBSPACE_INIT(heap, cellDangerousBitsHeapCellType.get(), ExecutableToCodeBlockEdge) > , functionExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), FunctionExecutable) >Index: Source/JavaScriptCore/runtime/VM.h >=================================================================== >--- Source/JavaScriptCore/runtime/VM.h (revision 229411) >+++ Source/JavaScriptCore/runtime/VM.h (working copy) >@@ -345,6 +345,7 @@ public: > IsoSubspace asyncGeneratorFunctionSpace; > IsoSubspace boundFunctionSpace; > IsoSubspace customGetterSetterFunctionSpace; >+ IsoSubspace directArgumentsSpace; > IsoSubspace directEvalExecutableSpace; > IsoSubspace executableToCodeBlockEdgeSpace; > IsoSubspace functionExecutableSpace;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
ews-watchlist
:
commit-queue-
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 183458
:
335312
|
335332
|
335342
|
335345
|
335355
|
335362
|
335375
|
335445
|
335464
|
335481
|
335494
|
335496