Changeset 229518 in webkit
- Timestamp:
- Mar 11, 2018 2:09:20 PM (6 years ago)
- Location:
- trunk/Source
- Files:
-
- 1 added
- 22 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r229517 r229518 1 2018-03-09 Filip Pizlo <fpizlo@apple.com> 2 3 Split DirectArguments into JSValueOOB and JSValueStrict parts 4 https://bugs.webkit.org/show_bug.cgi?id=183458 5 6 Reviewed by Yusuke Suzuki. 7 8 Our Spectre plan for JSValue objects is to allow inline JSValue stores and loads guarded by 9 unmitigated structure checks. This works because objects reachable from JSValues (i.e. JSValue 10 objects, like String, Symbol, and any descendant of JSObject) will only contain fields that it's OK 11 to read and write within a Spectre mitigation window. Writes are important, because within the 12 window, a write could appear to be made speculatively and rolled out later. This means that: 13 14 - JSValue objects cannot have lengths, masks, or anything else inline. 15 16 - JSValue objects cannot have an inline type that is used as part of a Spectre mitigation for a type 17 check, unless that type is in the form of a poison key. 18 19 This means that the dynamic poisoning that I previously landed for DirectArguments is wrong. It also 20 means that it's wrong for DirectArguments to have an inline length. 21 22 This changes DirectArguments to use poisoning according to the universal formula: 23 24 - The random accessed portions are out-of-line, pointed to by a poisoned pointer. 25 26 - No inline length. 27 28 Surprisingly, this is perf-neutral. It's probably perf-neutral because our compiler optimizations 29 amortize whatever cost there was. 30 31 * bytecode/AccessCase.cpp: 32 (JSC::AccessCase::generateWithGuard): 33 * dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h: 34 (JSC::DFG::CallCreateDirectArgumentsSlowPathGenerator::CallCreateDirectArgumentsSlowPathGenerator): 35 * dfg/DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h: Added. 36 (JSC::DFG::CallCreateDirectArgumentsWithKnownLengthSlowPathGenerator::CallCreateDirectArgumentsWithKnownLengthSlowPathGenerator): 37 * dfg/DFGSpeculativeJIT.cpp: 38 (JSC::DFG::SpeculativeJIT::compileGetByValOnDirectArguments): 39 (JSC::DFG::SpeculativeJIT::compileGetArrayLength): 40 (JSC::DFG::SpeculativeJIT::compileCreateDirectArguments): 41 (JSC::DFG::SpeculativeJIT::compileGetFromArguments): 42 (JSC::DFG::SpeculativeJIT::compilePutToArguments): 43 * ftl/FTLAbstractHeapRepository.h: 44 * ftl/FTLLowerDFGToB3.cpp: 45 (JSC::FTL::DFG::LowerDFGToB3::compileGetArrayLength): 46 (JSC::FTL::DFG::LowerDFGToB3::compileGetByVal): 47 (JSC::FTL::DFG::LowerDFGToB3::compileCreateDirectArguments): 48 (JSC::FTL::DFG::LowerDFGToB3::compileGetFromArguments): 49 (JSC::FTL::DFG::LowerDFGToB3::compilePutToArguments): 50 (JSC::FTL::DFG::LowerDFGToB3::compileCheckSubClass): 51 (JSC::FTL::DFG::LowerDFGToB3::allocateVariableSizedHeapCell): 52 (JSC::FTL::DFG::LowerDFGToB3::dynamicPoison): Deleted. 53 (JSC::FTL::DFG::LowerDFGToB3::dynamicPoisonOnLoadedType): Deleted. 54 (JSC::FTL::DFG::LowerDFGToB3::dynamicPoisonOnType): Deleted. 55 * heap/SecurityKind.h: 56 * jit/JITPropertyAccess.cpp: 57 (JSC::JIT::emit_op_get_from_arguments): 58 (JSC::JIT::emit_op_put_to_arguments): 59 (JSC::JIT::emitDirectArgumentsGetByVal): 60 * jit/JITPropertyAccess32_64.cpp: 61 (JSC::JIT::emit_op_get_from_arguments): 62 (JSC::JIT::emit_op_put_to_arguments): 63 * llint/LowLevelInterpreter.asm: 64 * llint/LowLevelInterpreter32_64.asm: 65 * llint/LowLevelInterpreter64.asm: 66 * runtime/DirectArguments.cpp: 67 (JSC::DirectArguments::DirectArguments): 68 (JSC::DirectArguments::createUninitialized): 69 (JSC::DirectArguments::create): 70 (JSC::DirectArguments::createByCopying): 71 (JSC::DirectArguments::estimatedSize): 72 (JSC::DirectArguments::visitChildren): 73 (JSC::DirectArguments::overrideThings): 74 (JSC::DirectArguments::copyToArguments): 75 (JSC::DirectArguments::mappedArgumentsSize): 76 * runtime/DirectArguments.h: 77 * runtime/JSCPoison.h: 78 * runtime/JSLexicalEnvironment.h: 79 * runtime/JSSymbolTableObject.h: 80 * runtime/VM.cpp: 81 (JSC::VM::VM): 82 * runtime/VM.h: 83 1 84 2018-03-11 Yusuke Suzuki <utatane.tea@gmail.com> 2 85 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r229481 r229518 162 162 0F25F1B2181635F300522F39 /* FTLSlowPathCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F25F1AB181635F300522F39 /* FTLSlowPathCall.h */; settings = {ATTRIBUTES = (Private, ); }; }; 163 163 0F25F1B4181635F300522F39 /* FTLSlowPathCallKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F25F1AD181635F300522F39 /* FTLSlowPathCallKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; 164 0F26A7A32053895C0090A141 /* DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F26A7A2205389580090A141 /* DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h */; }; 164 165 0F2AC5671E8A0B790001EE3F /* AirFixSpillsAfterTerminals.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2AC5651E8A0B760001EE3F /* AirFixSpillsAfterTerminals.h */; }; 165 166 0F2AC56B1E8A0BD50001EE3F /* AirAllocateRegistersAndStackByLinearScan.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2AC5691E8A0BD10001EE3F /* AirAllocateRegistersAndStackByLinearScan.h */; }; … … 2060 2061 0F25F1AC181635F300522F39 /* FTLSlowPathCallKey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLSlowPathCallKey.cpp; path = ftl/FTLSlowPathCallKey.cpp; sourceTree = "<group>"; }; 2061 2062 0F25F1AD181635F300522F39 /* FTLSlowPathCallKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLSlowPathCallKey.h; path = ftl/FTLSlowPathCallKey.h; sourceTree = "<group>"; }; 2063 0F26A7A2205389580090A141 /* DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h; path = dfg/DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h; sourceTree = "<group>"; }; 2062 2064 0F275F2C1ECE079600620D47 /* Intrinsic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Intrinsic.cpp; sourceTree = "<group>"; }; 2063 2065 0F2AC5641E8A0B760001EE3F /* AirFixSpillsAfterTerminals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirFixSpillsAfterTerminals.cpp; path = b3/air/AirFixSpillsAfterTerminals.cpp; sourceTree = "<group>"; }; … … 7134 7136 0F256C341627B0AA007F2783 /* DFGCallArrayAllocatorSlowPathGenerator.h */, 7135 7137 0FBDB9AC1AB0FBC6000B57E5 /* DFGCallCreateDirectArgumentsSlowPathGenerator.h */, 7138 0F26A7A2205389580090A141 /* DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h */, 7136 7139 0FD82E1E14172C2F00179C94 /* DFGCapabilities.cpp */, 7137 7140 0FD82E1F14172C2F00179C94 /* DFGCapabilities.h */, … … 8747 8750 52B310FB1974AE610080857C /* FunctionHasExecutedCache.h in Headers */, 8748 8751 FE4BFF2C1AD476E700088F87 /* FunctionOverrides.h in Headers */, 8752 0F26A7A32053895C0090A141 /* DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h in Headers */, 8749 8753 BC18C4050E16F5CD00B34460 /* FunctionPrototype.h in Headers */, 8750 8754 62D2D3901ADF103F000206C1 /* FunctionRareData.h in Headers */, -
trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp
r229391 r229518 384 384 CCallHelpers::NonZero, 385 385 CCallHelpers::Address(baseGPR, DirectArguments::offsetOfMappedArguments()))); 386 jit.loadPtr( 387 CCallHelpers::Address(baseGPR, DirectArguments::offsetOfStorage()), 388 valueRegs.payloadGPR()); 389 jit.xorPtr(CCallHelpers::TrustedImmPtr(DirectArgumentsPoison::key()), valueRegs.payloadGPR()); 386 390 jit.load32( 387 CCallHelpers::Address( baseGPR, DirectArguments::offsetOfLength()),391 CCallHelpers::Address(valueRegs.payloadGPR(), DirectArguments::offsetOfLengthInStorage()), 388 392 valueRegs.payloadGPR()); 389 393 jit.boxInt32(valueRegs.payloadGPR(), valueRegs); -
trunk/Source/JavaScriptCore/dfg/DFGCallCreateDirectArgumentsSlowPathGenerator.h
r218794 r229518 1 1 /* 2 * Copyright (C) 2015-201 7Apple Inc. All rights reserved.2 * Copyright (C) 2015-2018 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 35 35 namespace JSC { namespace DFG { 36 36 37 // This calls operationCreateDirectArguments but then restores the value of lengthGPR .37 // This calls operationCreateDirectArguments but then restores the value of lengthGPR and storageGPR. 38 38 class CallCreateDirectArgumentsSlowPathGenerator : public JumpingSlowPathGenerator<MacroAssembler::JumpList> { 39 39 public: 40 40 CallCreateDirectArgumentsSlowPathGenerator( 41 41 MacroAssembler::JumpList from, SpeculativeJIT* jit, GPRReg resultGPR, RegisteredStructure structure, 42 GPRReg lengthGPR, unsigned minCapacity)42 GPRReg lengthGPR, GPRReg storageGPR, unsigned minCapacity) 43 43 : JumpingSlowPathGenerator<MacroAssembler::JumpList>(from, jit) 44 44 , m_resultGPR(resultGPR) 45 45 , m_structure(structure) 46 46 , m_lengthGPR(lengthGPR) 47 , m_storageGPR(storageGPR) 47 48 , m_minCapacity(minCapacity) 48 49 { … … 62 63 jit->m_jit.exceptionCheck(); 63 64 jit->m_jit.loadPtr( 64 MacroAssembler::Address(m_resultGPR, DirectArguments::offsetOfLength()), m_lengthGPR); 65 MacroAssembler::Address(m_resultGPR, DirectArguments::offsetOfStorage()), m_storageGPR); 66 jit->m_jit.xorPtr( 67 MacroAssembler::TrustedImmPtr(DirectArgumentsPoison::key()), m_storageGPR); 68 jit->m_jit.load32( 69 MacroAssembler::Address(m_storageGPR, DirectArguments::offsetOfLengthInStorage()), m_lengthGPR); 65 70 jumpTo(jit); 66 71 } … … 70 75 RegisteredStructure m_structure; 71 76 GPRReg m_lengthGPR; 77 GPRReg m_storageGPR; 72 78 unsigned m_minCapacity; 73 79 Vector<SilentRegisterSavePlan, 2> m_plans; -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r229514 r229518 34 34 #include "DFGCallArrayAllocatorSlowPathGenerator.h" 35 35 #include "DFGCallCreateDirectArgumentsSlowPathGenerator.h" 36 #include "DFGCallCreateDirectArgumentsWithKnownLengthSlowPathGenerator.h" 36 37 #include "DFGCapabilities.h" 37 38 #include "DFGMayExit.h" … … 6426 6427 #endif 6427 6428 GPRTemporary scratch(this); 6429 GPRTemporary storage(this); 6428 6430 6429 6431 GPRReg baseReg = base.gpr(); … … 6437 6439 #endif 6438 6440 GPRReg scratchReg = scratch.gpr(); 6441 GPRReg storageReg = storage.gpr(); 6439 6442 6440 6443 if (!m_compileOkay) … … 6448 6451 MacroAssembler::NonZero, 6449 6452 MacroAssembler::Address(baseReg, DirectArguments::offsetOfMappedArguments()))); 6450 6451 m_jit.load32(CCallHelpers::Address(baseReg, DirectArguments::offsetOfLength()), scratchReg); 6453 6454 m_jit.loadPtr(CCallHelpers::Address(baseReg, DirectArguments::offsetOfStorage()), storageReg); 6455 m_jit.xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), storageReg); 6456 6457 m_jit.load32(CCallHelpers::Address(storageReg, DirectArguments::offsetOfLengthInStorage()), scratchReg); 6452 6458 auto isOutOfBounds = m_jit.branch32(CCallHelpers::AboveOrEqual, propertyReg, scratchReg); 6453 6459 if (node->arrayMode().isInBounds()) 6454 6460 speculationCheck(OutOfBounds, JSValueSource(), 0, isOutOfBounds); 6455 6461 6456 m_jit.emitDynamicPoisonOnType(baseReg, resultReg, DirectArgumentsType);6457 6462 m_jit.emitPreparePreciseIndexMask32(propertyReg, scratchReg, scratchReg); 6458 6463 6459 6464 m_jit.loadValue( 6460 6465 MacroAssembler::BaseIndex( 6461 baseReg, propertyReg, MacroAssembler::TimesEight, DirectArguments::storageOffset()),6466 storageReg, propertyReg, MacroAssembler::TimesEight), 6462 6467 resultRegs); 6463 6468 … … 6644 6649 MacroAssembler::Address(baseReg, DirectArguments::offsetOfMappedArguments()))); 6645 6650 6651 m_jit.loadPtr( 6652 MacroAssembler::Address(baseReg, DirectArguments::offsetOfStorage()), resultReg); 6653 m_jit.xorPtr( 6654 TrustedImmPtr(DirectArgumentsPoison::key()), resultReg); 6646 6655 m_jit.load32( 6647 MacroAssembler::Address( baseReg, DirectArguments::offsetOfLength()), resultReg);6656 MacroAssembler::Address(resultReg, DirectArguments::offsetOfLengthInStorage()), resultReg); 6648 6657 6649 6658 int32Result(resultReg, node); … … 6968 6977 void SpeculativeJIT::compileCreateDirectArguments(Node* node) 6969 6978 { 6970 // FIXME: A more effective way of dealing with the argument count and callee is to have 6971 // them be explicit arguments to this node. 6972 // https://bugs.webkit.org/show_bug.cgi?id=142207 6973 6974 GPRTemporary result(this); 6975 GPRTemporary scratch1(this); 6976 GPRTemporary scratch2(this); 6977 GPRTemporary length; 6978 GPRReg resultGPR = result.gpr(); 6979 GPRReg scratch1GPR = scratch1.gpr(); 6980 GPRReg scratch2GPR = scratch2.gpr(); 6981 GPRReg lengthGPR = InvalidGPRReg; 6982 JSValueRegs valueRegs = JSValueRegs::withTwoAvailableRegs(scratch1GPR, scratch2GPR); 6983 6979 VM& vm = *m_jit.vm(); 6980 6981 bool lengthIsKnown = node->origin.semantic.inlineCallFrame 6982 && !node->origin.semantic.inlineCallFrame->isVarargs(); 6983 unsigned knownLength = UINT_MAX; 6984 6985 RegisteredStructure structure = 6986 m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(node->origin.semantic)->directArgumentsStructure()); 6984 6987 unsigned minCapacity = m_jit.graph().baselineCodeBlockFor(node->origin.semantic)->numParameters() - 1; 6985 6986 unsigned knownLength; 6987 bool lengthIsKnown; // if false, lengthGPR will have the length. 6988 if (node->origin.semantic.inlineCallFrame 6989 && !node->origin.semantic.inlineCallFrame->isVarargs()) { 6990 knownLength = node->origin.semantic.inlineCallFrame->argumentCountIncludingThis - 1; 6991 lengthIsKnown = true; 6992 } else { 6993 knownLength = UINT_MAX; 6994 lengthIsKnown = false; 6995 6996 GPRTemporary realLength(this); 6997 length.adopt(realLength); 6998 lengthGPR = length.gpr(); 6999 6988 6989 GPRReg resultGPR; 6990 GPRReg lengthGPR; 6991 GPRReg scratch1GPR; 6992 GPRReg scratch2GPR; 6993 GPRReg storageGPR; 6994 JSValueRegs valueRegs; 6995 6996 auto loadLength = [&] () { 7000 6997 VirtualRegister argumentCountRegister = m_jit.argumentCount(node->origin.semantic); 7001 6998 m_jit.load32(JITCompiler::payloadFor(argumentCountRegister), lengthGPR); 7002 6999 m_jit.sub32(TrustedImm32(1), lengthGPR); 7003 } 7004 7005 RegisteredStructure structure = 7006 m_jit.graph().registerStructure(m_jit.graph().globalObjectFor(node->origin.semantic)->directArgumentsStructure()); 7007 7008 // Use a different strategy for allocating the object depending on whether we know its 7009 // size statically. 7010 JITCompiler::JumpList slowPath; 7011 if (lengthIsKnown) { 7000 }; 7001 7002 GPRTemporary result; 7003 GPRTemporary scratch1; 7004 GPRTemporary scratch2; 7005 GPRTemporary storage; 7006 GPRTemporary length; 7007 7008 if (isX86() && is32Bit() && !lengthIsKnown) { 7009 GPRFlushedCallResult result(this); 7010 resultGPR = result.gpr(); 7011 RELEASE_ASSERT(resultGPR == GPRInfo::regT0); 7012 flushRegisters(); 7013 lengthGPR = GPRInfo::regT1; // Can be anything we like because registers are flushed. 7014 scratch1GPR = GPRInfo::regT2; 7015 scratch2GPR = GPRInfo::regT3; 7016 storageGPR = GPRInfo::regT4; 7017 valueRegs = JSValueRegs::withTwoAvailableRegs(scratch1GPR, scratch2GPR); 7018 loadLength(); 7019 callOperation(operationCreateDirectArguments, resultGPR, structure, lengthGPR, minCapacity); 7020 m_jit.exceptionCheck(); 7021 m_jit.loadPtr(MacroAssembler::Address(resultGPR, DirectArguments::offsetOfStorage()), storageGPR); 7022 m_jit.xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), storageGPR); 7023 m_jit.load32(MacroAssembler::Address(storageGPR, DirectArguments::offsetOfLengthInStorage()), lengthGPR); 7024 } else { 7025 // FIXME: A more effective way of dealing with the argument count and callee is to have 7026 // them be explicit arguments to this node. 7027 // https://bugs.webkit.org/show_bug.cgi?id=142207 7028 7029 GPRTemporary realResult(this); 7030 result.adopt(realResult); 7031 GPRTemporary realScratch1(this); 7032 scratch1.adopt(realScratch1); 7033 GPRTemporary realScratch2(this); 7034 scratch2.adopt(realScratch2); 7035 GPRTemporary realStorage(this); 7036 storage.adopt(realStorage); 7037 resultGPR = result.gpr(); 7038 scratch1GPR = scratch1.gpr(); 7039 scratch2GPR = scratch2.gpr(); 7040 lengthGPR = InvalidGPRReg; 7041 storageGPR = storage.gpr(); 7042 valueRegs = JSValueRegs::withTwoAvailableRegs(scratch1GPR, scratch2GPR); 7043 7044 if (lengthIsKnown) 7045 knownLength = node->origin.semantic.inlineCallFrame->argumentCountIncludingThis - 1; 7046 else { 7047 GPRTemporary realLength(this); 7048 length.adopt(realLength); 7049 lengthGPR = length.gpr(); 7050 7051 loadLength(); 7052 } 7053 7054 // Use a different strategy for allocating the object depending on whether we know its 7055 // size statically. 7056 JITCompiler::JumpList slowPath; 7057 if (lengthIsKnown) { 7058 JITAllocator storageAllocator = JITAllocator::constant( 7059 vm.jsValueGigacageAuxiliarySpace.allocatorForNonVirtual( 7060 DirectArguments::storageSize(std::max(knownLength, minCapacity)), 7061 AllocatorForMode::AllocatorIfExists)); 7062 7063 m_jit.emitAllocate(storageGPR, storageAllocator, scratch1GPR, scratch2GPR, slowPath); 7064 m_jit.addPtr(TrustedImmPtr(DirectArguments::storageHeaderSize()), storageGPR); 7065 m_jit.store32( 7066 TrustedImm32(knownLength), 7067 JITCompiler::Address(storageGPR, DirectArguments::offsetOfLengthInStorage())); 7068 } else { 7069 JITCompiler::Jump tooFewArguments; 7070 if (minCapacity) { 7071 tooFewArguments = 7072 m_jit.branch32(JITCompiler::Below, lengthGPR, TrustedImm32(minCapacity)); 7073 } 7074 m_jit.lshift32(lengthGPR, TrustedImm32(3), scratch1GPR); 7075 m_jit.add32(TrustedImm32(DirectArguments::storageHeaderSize()), scratch1GPR); 7076 if (minCapacity) { 7077 JITCompiler::Jump done = m_jit.jump(); 7078 tooFewArguments.link(&m_jit); 7079 m_jit.move(TrustedImm32(DirectArguments::storageSize(minCapacity)), scratch1GPR); 7080 done.link(&m_jit); 7081 } 7082 7083 m_jit.emitAllocateVariableSized( 7084 storageGPR, vm.jsValueGigacageAuxiliarySpace, scratch1GPR, scratch1GPR, scratch2GPR, slowPath); 7085 m_jit.addPtr(TrustedImmPtr(DirectArguments::storageHeaderSize()), storageGPR); 7086 m_jit.store32( 7087 lengthGPR, 7088 JITCompiler::Address(storageGPR, DirectArguments::offsetOfLengthInStorage())); 7089 } 7090 7091 m_jit.store32( 7092 TrustedImm32(minCapacity), 7093 JITCompiler::Address(storageGPR, DirectArguments::offsetOfMinCapacityInStorage())); 7094 7012 7095 auto butterfly = TrustedImmPtr(nullptr); 7013 7096 auto mask = TrustedImm32(0); 7014 emitAllocateJSObjectWithKnownSize<DirectArguments>( 7015 resultGPR, TrustedImmPtr(structure), butterfly, mask, scratch1GPR, scratch2GPR, 7016 slowPath, DirectArguments::allocationSize(std::max(knownLength, minCapacity))); 7017 7018 m_jit.store32( 7019 TrustedImm32(knownLength), 7020 JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength())); 7021 } else { 7022 JITCompiler::Jump tooFewArguments; 7023 if (minCapacity) { 7024 tooFewArguments = 7025 m_jit.branch32(JITCompiler::Below, lengthGPR, TrustedImm32(minCapacity)); 7026 } 7027 m_jit.lshift32(lengthGPR, TrustedImm32(3), scratch1GPR); 7028 m_jit.add32(TrustedImm32(DirectArguments::storageOffset()), scratch1GPR); 7029 if (minCapacity) { 7030 JITCompiler::Jump done = m_jit.jump(); 7031 tooFewArguments.link(&m_jit); 7032 m_jit.move(TrustedImm32(DirectArguments::allocationSize(minCapacity)), scratch1GPR); 7033 done.link(&m_jit); 7034 } 7035 7036 emitAllocateVariableSizedJSObject<DirectArguments>( 7037 resultGPR, TrustedImmPtr(structure), scratch1GPR, scratch1GPR, scratch2GPR, 7038 slowPath); 7039 7040 m_jit.store32( 7041 lengthGPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfLength())); 7042 } 7043 7044 m_jit.store32( 7045 TrustedImm32(minCapacity), 7046 JITCompiler::Address(resultGPR, DirectArguments::offsetOfMinCapacity())); 7047 7048 m_jit.storePtr( 7049 TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfMappedArguments())); 7050 7051 m_jit.storePtr( 7052 TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfModifiedArgumentsDescriptor())); 7053 7054 if (lengthIsKnown) { 7055 addSlowPathGenerator( 7056 slowPathCall( 7057 slowPath, this, operationCreateDirectArguments, resultGPR, structure, 7058 knownLength, minCapacity)); 7059 } else { 7060 auto generator = std::make_unique<CallCreateDirectArgumentsSlowPathGenerator>( 7061 slowPath, this, resultGPR, structure, lengthGPR, minCapacity); 7097 emitAllocateJSObject<DirectArguments>(resultGPR, TrustedImmPtr(structure), butterfly, mask, scratch1GPR, scratch2GPR, slowPath); 7098 m_jit.move(storageGPR, scratch1GPR); 7099 m_jit.xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), scratch1GPR); 7100 m_jit.storePtr(scratch1GPR, JITCompiler::Address(resultGPR, DirectArguments::offsetOfStorage())); 7101 7102 m_jit.storePtr( 7103 TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfMappedArguments())); 7104 7105 m_jit.storePtr( 7106 TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, DirectArguments::offsetOfModifiedArgumentsDescriptor())); 7107 7108 std::unique_ptr<SlowPathGenerator> generator; 7109 if (lengthIsKnown) { 7110 generator = std::make_unique<CallCreateDirectArgumentsWithKnownLengthSlowPathGenerator>( 7111 slowPath, this, resultGPR, structure, knownLength, storageGPR, minCapacity); 7112 } else { 7113 generator = std::make_unique<CallCreateDirectArgumentsSlowPathGenerator>( 7114 slowPath, this, resultGPR, structure, lengthGPR, storageGPR, minCapacity); 7115 } 7062 7116 addSlowPathGenerator(WTFMove(generator)); 7063 7117 } 7064 7118 7065 7119 if (node->origin.semantic.inlineCallFrame) { 7066 7120 if (node->origin.semantic.inlineCallFrame->isClosureCall) { … … 7088 7142 m_jit.loadValue(JITCompiler::addressFor(start + i), valueRegs); 7089 7143 m_jit.storeValue( 7090 valueRegs, JITCompiler::Address( resultGPR, DirectArguments::offsetOfSlot(i)));7144 valueRegs, JITCompiler::Address(storageGPR, i * sizeof(WriteBarrier<Unknown>))); 7091 7145 } 7092 7146 } else { … … 7109 7163 valueRegs, 7110 7164 JITCompiler::BaseIndex( 7111 resultGPR, lengthGPR, JITCompiler::TimesEight, 7112 DirectArguments::storageOffset())); 7165 storageGPR, lengthGPR, JITCompiler::TimesEight)); 7113 7166 m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loop, &m_jit); 7114 7167 if (done.isSet()) 7115 7168 done.link(&m_jit); 7116 7169 } 7117 7118 m_jit.mutatorFence( *m_jit.vm());7170 7171 m_jit.mutatorFence(vm); 7119 7172 7120 7173 cellResult(resultGPR, node); … … 7129 7182 JSValueRegs resultRegs = result.regs(); 7130 7183 7131 m_jit.loadValue(JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset())), resultRegs); 7184 m_jit.loadPtr(JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfStorage()), resultRegs.payloadGPR()); 7185 m_jit.xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), resultRegs.payloadGPR()); 7186 m_jit.loadValue(JITCompiler::Address(resultRegs.payloadGPR(), node->capturedArgumentsOffset().offset() * sizeof(WriteBarrier<Unknown>)), resultRegs); 7132 7187 jsValueResult(resultRegs, node); 7133 7188 } … … 7137 7192 SpeculateCellOperand arguments(this, node->child1()); 7138 7193 JSValueOperand value(this, node->child2()); 7194 GPRTemporary storage(this); 7139 7195 7140 7196 GPRReg argumentsGPR = arguments.gpr(); 7197 GPRReg storageGPR = storage.gpr(); 7141 7198 JSValueRegs valueRegs = value.jsValueRegs(); 7142 7199 7143 m_jit.storeValue(valueRegs, JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfSlot(node->capturedArgumentsOffset().offset()))); 7200 m_jit.loadPtr(JITCompiler::Address(argumentsGPR, DirectArguments::offsetOfStorage()), storageGPR); 7201 m_jit.xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), storageGPR); 7202 m_jit.storeValue(valueRegs, JITCompiler::Address(storageGPR, node->capturedArgumentsOffset().offset() * sizeof(WriteBarrier<Unknown>))); 7144 7203 noResult(node); 7145 7204 } -
trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
r229053 r229518 52 52 macro(CallFrame_callerFrame, CallFrame::callerFrameOffset()) \ 53 53 macro(ClassInfo_parentClass, ClassInfo::offsetOfParentClass()) \ 54 macro(DirectArguments_Storage_length, DirectArguments::offsetOfLengthInStorage()) \ 55 macro(DirectArguments_Storage_minCapacity, DirectArguments::offsetOfMinCapacityInStorage()) \ 54 56 macro(DirectArguments_callee, DirectArguments::offsetOfCallee()) \ 55 macro(DirectArguments_length, DirectArguments::offsetOfLength()) \56 macro(DirectArguments_minCapacity, DirectArguments::offsetOfMinCapacity()) \57 57 macro(DirectArguments_mappedArguments, DirectArguments::offsetOfMappedArguments()) \ 58 58 macro(DirectArguments_modifiedArgumentsDescriptor, DirectArguments::offsetOfModifiedArgumentsDescriptor()) \ 59 macro(DirectArguments_storage, DirectArguments::offsetOfStorage()) \ 59 60 macro(GetterSetter_getter, GetterSetter::offsetOfGetter()) \ 60 61 macro(GetterSetter_setter, GetterSetter::offsetOfSetter()) \ … … 134 135 macro(ArrayStorage_vector, ArrayStorage::vectorOffset(), sizeof(WriteBarrier<Unknown>)) \ 135 136 macro(CompleteSubspace_allocatorForSizeStep, CompleteSubspace::offsetOfAllocatorForSizeStep(), sizeof(Allocator)) \ 136 macro(DirectArguments_ storage, DirectArguments::storageOffset(), sizeof(EncodedJSValue)) \137 macro(DirectArguments_Storage_storage, 0, sizeof(EncodedJSValue)) \ 137 138 macro(JSLexicalEnvironment_variables, JSLexicalEnvironment::offsetOfVariables(), sizeof(EncodedJSValue)) \ 138 139 macro(JSPropertyNameEnumerator_cachedPropertyNamesVectorContents, 0, sizeof(WriteBarrier<JSString>)) \ -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r229514 r229518 3674 3674 ExoticObjectMode, noValue(), nullptr, 3675 3675 m_out.notNull(m_out.loadPtr(arguments, m_heaps.DirectArguments_mappedArguments))); 3676 setInt32(m_out.load32NonNegative(arguments, m_heaps.DirectArguments_length)); 3676 LValue storage = m_out.bitXor( 3677 m_out.loadPtr(lowCell(m_node->child1()), m_heaps.DirectArguments_storage), 3678 m_out.constIntPtr(DirectArgumentsPoison::key())); 3679 setInt32(m_out.load32NonNegative(storage, m_heaps.DirectArguments_Storage_length)); 3677 3680 return; 3678 3681 } … … 3840 3843 m_out.notNull(m_out.loadPtr(base, m_heaps.DirectArguments_mappedArguments))); 3841 3844 3842 LValue length = m_out.load32NonNegative(base, m_heaps.DirectArguments_length); 3845 LValue storage = m_out.loadPtr(base, m_heaps.DirectArguments_storage); 3846 storage = m_out.bitXor(storage, m_out.constIntPtr(DirectArgumentsPoison::key())); 3847 3848 LValue length = m_out.load32NonNegative(storage, m_heaps.DirectArguments_Storage_length); 3843 3849 auto isOutOfBounds = m_out.aboveOrEqual(index, length); 3844 3850 if (m_node->arrayMode().isInBounds()) { 3845 3851 speculate(OutOfBounds, noValue(), nullptr, isOutOfBounds); 3846 3852 TypedPointer address = m_out.baseIndex( 3847 m_heaps.DirectArguments_ storage, base, m_out.zeroExtPtr(index));3848 setJSValue( m_out.load64(address));3853 m_heaps.DirectArguments_Storage_storage, storage, m_out.zeroExtPtr(index)); 3854 setJSValue(preciseIndexMask32(m_out.load64(address), index, length)); 3849 3855 return; 3850 3856 } … … 3858 3864 LBasicBlock lastNext = m_out.appendTo(inBounds, slowCase); 3859 3865 TypedPointer address = m_out.baseIndex( 3860 m_heaps.DirectArguments_storage, 3861 dynamicPoisonOnType(base, DirectArgumentsType), 3866 m_heaps.DirectArguments_Storage_storage, storage, 3862 3867 m_out.zeroExt(index, pointerType())); 3863 3868 ValueFromBlock fastResult = m_out.anchor( … … 5158 5163 ArgumentsLength length = getArgumentsLength(); 5159 5164 5165 LValue fastStorage; 5160 5166 LValue fastObject; 5161 5167 if (length.isKnown) { 5162 fastObject = allocateObject<DirectArguments>( 5163 DirectArguments::allocationSize(std::max(length.known, minCapacity)), structure, 5164 m_out.intPtrZero, m_out.int32Zero, slowPath); 5168 LValue allocator = m_out.constInt32( 5169 vm().jsValueGigacageAuxiliarySpace.allocatorForNonVirtual( 5170 DirectArguments::storageSize(std::max(length.known, minCapacity)), 5171 AllocatorForMode::AllocatorIfExists).offset()); 5172 5173 fastStorage = allocateHeapCell(allocator, slowPath); 5165 5174 } else { 5166 5175 LValue size = m_out.add( 5167 5176 m_out.shl(length.value, m_out.constInt32(3)), 5168 m_out.constInt32(DirectArguments::storage Offset()));5177 m_out.constInt32(DirectArguments::storageHeaderSize())); 5169 5178 5170 5179 size = m_out.select( 5171 5180 m_out.aboveOrEqual(length.value, m_out.constInt32(minCapacity)), 5172 size, m_out.constInt32(DirectArguments::allocationSize(minCapacity))); 5173 5174 fastObject = allocateVariableSizedObject<DirectArguments>( 5175 m_out.zeroExtPtr(size), structure, m_out.intPtrZero, m_out.int32Zero, slowPath); 5176 } 5177 5178 m_out.store32(length.value, fastObject, m_heaps.DirectArguments_length); 5179 m_out.store32(m_out.constInt32(minCapacity), fastObject, m_heaps.DirectArguments_minCapacity); 5181 size, m_out.constInt32(DirectArguments::storageSize(minCapacity))); 5182 5183 fastStorage = allocateVariableSizedHeapCell( 5184 vm().jsValueGigacageAuxiliarySpace, m_out.zeroExtPtr(size), slowPath); 5185 } 5186 5187 fastStorage = m_out.add(fastStorage, m_out.constIntPtr(DirectArguments::storageHeaderSize())); 5188 m_out.store32(length.value, fastStorage, m_heaps.DirectArguments_Storage_length); 5189 m_out.store32(m_out.constInt32(minCapacity), fastStorage, m_heaps.DirectArguments_Storage_minCapacity); 5190 5191 fastObject = allocateObject<DirectArguments>(structure, m_out.intPtrZero, m_out.intPtrZero, slowPath); 5192 5193 m_out.storePtr(m_out.bitXor(fastStorage, m_out.constIntPtr(DirectArgumentsPoison::key())), fastObject, m_heaps.DirectArguments_storage); 5180 5194 m_out.storePtr(m_out.intPtrZero, fastObject, m_heaps.DirectArguments_mappedArguments); 5181 5195 m_out.storePtr(m_out.intPtrZero, fastObject, m_heaps.DirectArguments_modifiedArgumentsDescriptor); 5182 5196 5197 ValueFromBlock fastStorageAnchor = m_out.anchor(fastStorage); 5183 5198 ValueFromBlock fastResult = m_out.anchor(fastObject); 5184 5199 m_out.jump(continuation); … … 5194 5209 }, length.value); 5195 5210 ValueFromBlock slowResult = m_out.anchor(callResult); 5211 ValueFromBlock slowStorage = m_out.anchor( 5212 m_out.bitXor( 5213 m_out.loadPtr(callResult, m_heaps.DirectArguments_storage), 5214 m_out.constIntPtr(DirectArgumentsPoison::key()))); 5196 5215 m_out.jump(continuation); 5197 5216 5198 5217 m_out.appendTo(continuation, lastNext); 5218 LValue storage = m_out.phi(pointerType(), fastStorageAnchor, slowStorage); 5199 5219 LValue result = m_out.phi(pointerType(), fastResult, slowResult); 5200 5220 … … 5206 5226 m_out.store64( 5207 5227 m_out.load64(addressFor(start + i)), 5208 result, m_heaps.DirectArguments_storage[i]);5228 storage, m_heaps.DirectArguments_Storage_storage[i]); 5209 5229 } 5210 5230 } else { … … 5234 5254 m_out.store64( 5235 5255 m_out.load64(m_out.baseIndex(m_heaps.variables, stackBase, index)), 5236 m_out.baseIndex(m_heaps.DirectArguments_ storage, result, index));5256 m_out.baseIndex(m_heaps.DirectArguments_Storage_storage, storage, index)); 5237 5257 ValueFromBlock nextIndex = m_out.anchor(index); 5238 5258 m_out.addIncomingToPhi(previousIndex, nextIndex); … … 6691 6711 void compileGetFromArguments() 6692 6712 { 6713 LValue storage = m_out.bitXor( 6714 m_out.loadPtr(lowCell(m_node->child1()), m_heaps.DirectArguments_storage), 6715 m_out.constIntPtr(DirectArgumentsPoison::key())); 6693 6716 setJSValue( 6694 6717 m_out.load64( 6695 lowCell(m_node->child1()),6696 m_heaps.DirectArguments_ storage[m_node->capturedArgumentsOffset().offset()]));6718 storage, 6719 m_heaps.DirectArguments_Storage_storage[m_node->capturedArgumentsOffset().offset()])); 6697 6720 } 6698 6721 6699 6722 void compilePutToArguments() 6700 6723 { 6724 LValue storage = m_out.bitXor( 6725 m_out.loadPtr(lowCell(m_node->child1()), m_heaps.DirectArguments_storage), 6726 m_out.constIntPtr(DirectArgumentsPoison::key())); 6701 6727 m_out.store64( 6702 lowJSValue(m_node->child2()), 6703 lowCell(m_node->child1()), 6704 m_heaps.DirectArguments_storage[m_node->capturedArgumentsOffset().offset()]); 6728 lowJSValue(m_node->child2()), storage, 6729 m_heaps.DirectArguments_Storage_storage[m_node->capturedArgumentsOffset().offset()]); 6705 6730 } 6706 6731 … … 11842 11867 LValue structure = loadStructure(cell); 11843 11868 LValue poisonedClassInfo = m_out.loadPtr(structure, m_heaps.Structure_classInfo); 11844 LValue classInfo = m_out.bitXor(poisonedClassInfo, m_out.constInt 64(GlobalDataPoison::key()));11869 LValue classInfo = m_out.bitXor(poisonedClassInfo, m_out.constIntPtr(GlobalDataPoison::key())); 11845 11870 ValueFromBlock otherAtStart = m_out.anchor(classInfo); 11846 11871 m_out.jump(loop); … … 12615 12640 LValue allocator = allocatorForSize(*subspaceFor<ClassType>(vm()), size, slowPath); 12616 12641 return allocateCell(allocator, structure, slowPath); 12642 } 12643 12644 LValue allocateVariableSizedHeapCell(CompleteSubspace& subspace, LValue size, LBasicBlock slowPath) 12645 { 12646 LValue allocator = allocatorForSize(subspace, size, slowPath); 12647 return allocateHeapCell(allocator, slowPath); 12617 12648 } 12618 12649 … … 15573 15604 } 15574 15605 15575 LValue dynamicPoison(LValue value, LValue poison)15576 {15577 return m_out.add(15578 value,15579 m_out.shl(15580 m_out.zeroExt(poison, pointerType()),15581 m_out.constInt32(40)));15582 }15583 15584 LValue dynamicPoisonOnLoadedType(LValue value, LValue actualType, JSType expectedType)15585 {15586 return dynamicPoison(15587 value,15588 m_out.bitXor(15589 m_out.opaque(actualType),15590 m_out.constInt32(expectedType)));15591 }15592 15593 LValue dynamicPoisonOnType(LValue value, JSType expectedType)15594 {15595 return dynamicPoisonOnLoadedType(15596 value,15597 m_out.load8ZeroExt32(value, m_heaps.JSCell_typeInfoType),15598 expectedType);15599 }15600 15601 15606 template<typename... Args> 15602 15607 LValue vmCall(LType type, LValue function, Args&&... args) -
trunk/Source/JavaScriptCore/heap/SecurityKind.h
r228552 r229518 28 28 namespace JSC { 29 29 30 // NOTE: SecurityKind is for distancing. But caging implies distancing. So, things that have their own 31 // cages (like typed arrays) don't need to worry about the security kind. 30 32 enum class SecurityKind : uint8_t { 31 33 // The JSValueOOB security kind is for cells that contain JValues and can be accessed out-of-bounds … … 42 44 // out-of-bounds. Currently, it's not essential to keep this separate from DangerousBits. We're 43 45 // using this to get some wiggle room for how we handle array elements. For example, we might want 44 // to allow OOB reads but not OOB writes. 46 // to allow OOB reads but not OOB writes, since JSValueStrict contains only JSValues and length fields. 47 // Using Spectre to read the length fields is not useful for attackers since they can read them anyway. 48 // So, they will only want to write to length fields, in order to confuse a subsequent bounds check. 49 // They can do that within a speculation window. However, we currently use precise index masking for 50 // this. 45 51 // 46 52 // It's illegal to use this for any subclass of JSObject, JSString, or Symbol, or any other cell -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
r229391 r229518 1101 1101 1102 1102 emitGetVirtualRegister(arguments, regT0); 1103 load64(Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>)), regT0); 1103 loadPtr(Address(regT0, DirectArguments::offsetOfStorage()), regT0); 1104 xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), regT0); 1105 load64(Address(regT0, index * sizeof(WriteBarrier<Unknown>)), regT0); 1104 1106 emitValueProfilingSite(); 1105 1107 emitPutVirtualRegister(dst); … … 1114 1116 emitGetVirtualRegister(arguments, regT0); 1115 1117 emitGetVirtualRegister(value, regT1); 1116 store64(regT1, Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>))); 1118 loadPtr(Address(regT0, DirectArguments::offsetOfStorage()), regT0); 1119 xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), regT0); 1120 store64(regT1, Address(regT0, index * sizeof(WriteBarrier<Unknown>))); 1117 1121 1118 1122 emitWriteBarrier(arguments, value, ShouldFilterValue); … … 1413 1417 load8(Address(base, JSCell::typeInfoTypeOffset()), scratch); 1414 1418 badType = patchableBranch32(NotEqual, scratch, TrustedImm32(DirectArgumentsType)); 1415 emitDynamicPoisonOnLoadedType(base, scratch, DirectArgumentsType); 1416 1417 load32(Address(base, DirectArguments::offsetOfLength()), scratch2); 1419 1420 loadPtr(Address(base, DirectArguments::offsetOfStorage()), scratch); 1421 xorPtr(TrustedImmPtr(DirectArgumentsPoison::key()), scratch); 1422 1423 load32(Address(scratch, DirectArguments::offsetOfLengthInStorage()), scratch2); 1418 1424 slowCases.append(branch32(AboveOrEqual, property, scratch2)); 1419 1425 slowCases.append(branchTestPtr(NonZero, Address(base, DirectArguments::offsetOfMappedArguments()))); 1420 1426 1421 1427 emitPreparePreciseIndexMask32(property, scratch2, scratch2); 1422 loadValue(BaseIndex( base, property, TimesEight, DirectArguments::storageOffset()), result);1428 loadValue(BaseIndex(scratch, property, TimesEight), result); 1423 1429 andPtr(scratch2, result.payloadGPR()); 1424 1430 -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
r229391 r229518 1119 1119 1120 1120 emitLoadPayload(arguments, regT0); 1121 load32(Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + TagOffset), regT1); 1122 load32(Address(regT0, DirectArguments::storageOffset() + index * sizeof(WriteBarrier<Unknown>) + PayloadOffset), regT0); 1121 loadPtr(Address(regT0, DirectArguments::offsetOfStorage()), regT0); 1122 load32(Address(regT0, index * sizeof(WriteBarrier<Unknown>) + TagOffset), regT1); 1123 load32(Address(regT0, index * sizeof(WriteBarrier<Unknown>) + PayloadOffset), regT0); 1123 1124 emitValueProfilingSite(); 1124 1125 emitStore(dst, regT1, regT0); … … 1134 1135 1135 1136 emitLoadPayload(arguments, regT0); 1137 loadPtr(Address(regT0, DirectArguments::offsetOfStorage()), regT0); 1136 1138 emitLoad(value, regT1, regT2); 1137 store32(regT1, Address(regT0, DirectArguments::storageOffset() +index * sizeof(WriteBarrier<Unknown>) + TagOffset));1138 store32(regT2, Address(regT0, DirectArguments::storageOffset() +index * sizeof(WriteBarrier<Unknown>) + PayloadOffset));1139 store32(regT1, Address(regT0, index * sizeof(WriteBarrier<Unknown>) + TagOffset)); 1140 store32(regT2, Address(regT0, index * sizeof(WriteBarrier<Unknown>) + PayloadOffset)); 1139 1141 } 1140 1142 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
r229482 r229518 165 165 166 166 const JSLexicalEnvironment_variables = (sizeof JSLexicalEnvironment + SlotSize - 1) & ~(SlotSize - 1) 167 const DirectArguments_storage = (sizeof DirectArguments + SlotSize - 1) & ~(SlotSize - 1)168 167 169 168 const StackAlignment = 16 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
r229481 r229518 2497 2497 loadi PayloadOffset[cfr, t0, 8], t0 2498 2498 loadi 12[PC], t1 2499 loadi DirectArguments_storage + TagOffset[t0, t1, 8], t2 2500 loadi DirectArguments_storage + PayloadOffset[t0, t1, 8], t3 2499 loadp DirectArguments::m_storage[t0], t0 2500 loadi TagOffset[t0, t1, 8], t2 2501 loadi PayloadOffset[t0, t1, 8], t3 2501 2502 loadisFromInstruction(1, t1) 2502 2503 valueProfile(t2, t3, 16, t0) … … 2513 2514 loadisFromInstruction(3, t1) 2514 2515 loadConstantOrVariable(t1, t2, t3) 2516 loadp DirectArguments::m_storage[t0], t0 2515 2517 loadi 8[PC], t1 2516 storei t2, DirectArguments_storage +TagOffset[t0, t1, 8]2517 storei t3, DirectArguments_storage +PayloadOffset[t0, t1, 8]2518 storei t2, TagOffset[t0, t1, 8] 2519 storei t3, PayloadOffset[t0, t1, 8] 2518 2520 dispatch(4) 2519 2521 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
r229482 r229518 2530 2530 loadVariable(2, t0) 2531 2531 loadi 24[PB, PC, 8], t1 2532 loadq DirectArguments_storage[t0, t1, 8], t0 2532 loadp DirectArguments::m_storage[t0], t0 2533 unpoison(_g_DirectArgumentsPoison, t0, t3) 2534 loadq [t0, t1, 8], t0 2533 2535 valueProfile(t0, 4, t1) 2534 2536 loadisFromInstruction(1, t1) … … 2543 2545 loadisFromInstruction(3, t3) 2544 2546 loadConstantOrVariable(t3, t2) 2545 storeq t2, DirectArguments_storage[t0, t1, 8] 2547 loadp DirectArguments::m_storage[t0], t0 2548 unpoison(_g_DirectArgumentsPoison, t0, t3) 2549 storeq t2, [t0, t1, 8] 2546 2550 writeBarrierOnOperands(1, 3) 2547 2551 dispatch(constexpr op_put_to_arguments_length) -
trunk/Source/JavaScriptCore/runtime/DirectArguments.cpp
r227617 r229518 37 37 const ClassInfo DirectArguments::s_info = { "Arguments", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DirectArguments) }; 38 38 39 DirectArguments::DirectArguments(VM& vm, Structure* structure, unsigned length, unsigned capacity)39 DirectArguments::DirectArguments(VM& vm, Structure* structure, WriteBarrier<Unknown>* storage) 40 40 : GenericArguments(vm, structure) 41 , m_length(length) 42 , m_minCapacity(capacity) 41 , m_storage(vm, this, storage) 43 42 { 44 43 // When we construct the object from C++ code, we expect the capacity to be at least as large as 45 44 // length. JIT-allocated DirectArguments objects play evil tricks, though. 46 ASSERT( capacity >=length);45 ASSERT(storageHeader(storage).minCapacity >= storageHeader(storage).length); 47 46 } 48 47 … … 50 49 VM& vm, Structure* structure, unsigned length, unsigned capacity) 51 50 { 51 void* rawStoragePtr = vm.jsValueGigacageAuxiliarySpace.allocateNonVirtual( 52 vm, storageSize(capacity), nullptr, AllocationFailureMode::Assert); 53 WriteBarrier<Unknown>* storage = static_cast<WriteBarrier<Unknown>*>(rawStoragePtr) + 1; 54 storageHeader(storage).length = length; 55 storageHeader(storage).minCapacity = capacity; 56 52 57 DirectArguments* result = 53 new (NotNull, allocateCell<DirectArguments>(vm.heap , allocationSize(capacity)))54 DirectArguments(vm, structure, length, capacity);58 new (NotNull, allocateCell<DirectArguments>(vm.heap)) 59 DirectArguments(vm, structure, storage); 55 60 result->finishCreation(vm); 56 61 return result; … … 60 65 { 61 66 DirectArguments* result = createUninitialized(vm, structure, length, capacity); 62 67 68 WriteBarrier<Unknown>* storage = result->storage(); 63 69 for (unsigned i = capacity; i--;) 64 result->storage()[i].clear();70 storage[i].clear(); 65 71 66 72 return result; … … 76 82 vm, exec->lexicalGlobalObject()->directArgumentsStructure(), length, capacity); 77 83 84 WriteBarrier<Unknown>* storage = result->storage(); 78 85 for (unsigned i = capacity; i--;) 79 result->storage()[i].set(vm, result, exec->getArgumentUnsafe(i));86 storage[i].set(vm, result, exec->getArgumentUnsafe(i)); 80 87 81 88 result->callee().set(vm, result, jsCast<JSFunction*>(exec->jsCallee())); … … 88 95 DirectArguments* thisObject = jsCast<DirectArguments*>(cell); 89 96 size_t mappedArgumentsSize = thisObject->m_mappedArguments ? thisObject->mappedArgumentsSize() * sizeof(bool) : 0; 90 size_t modifiedArgumentsSize = thisObject->m_modifiedArgumentsDescriptor ? thisObject-> m_length * sizeof(bool) : 0;97 size_t modifiedArgumentsSize = thisObject->m_modifiedArgumentsDescriptor ? thisObject->storageHeader().length * sizeof(bool) : 0; 91 98 return Base::estimatedSize(cell) + mappedArgumentsSize + modifiedArgumentsSize; 92 99 } … … 98 105 Base::visitChildren(thisObject, visitor); 99 106 100 visitor.appendValues(thisObject->storage(), std::max(thisObject->m_length, thisObject->m_minCapacity)); 107 visitor.markAuxiliary(&thisObject->storageHeader()); 108 visitor.appendValues(thisObject->storage(), std::max(thisObject->storageHeader().length, thisObject->storageHeader().minCapacity)); 109 101 110 visitor.append(thisObject->m_callee); 102 111 103 112 if (thisObject->m_mappedArguments) 104 113 visitor.markAuxiliary(thisObject->m_mappedArguments.get()); 114 105 115 GenericArguments<DirectArguments>::visitChildren(thisCell, visitor); 106 116 } … … 115 125 RELEASE_ASSERT(!m_mappedArguments); 116 126 117 putDirect(vm, vm.propertyNames->length, jsNumber( m_length), static_cast<unsigned>(PropertyAttribute::DontEnum));127 putDirect(vm, vm.propertyNames->length, jsNumber(storageHeader().length), static_cast<unsigned>(PropertyAttribute::DontEnum)); 118 128 putDirect(vm, vm.propertyNames->callee, m_callee.get(), static_cast<unsigned>(PropertyAttribute::DontEnum)); 119 129 putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject()->arrayProtoValuesFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum)); … … 122 132 bool* overrides = static_cast<bool*>(backingStore); 123 133 m_mappedArguments.set(vm, this, overrides); 124 for (unsigned i = m_length; i--;)134 for (unsigned i = storageHeader().length; i--;) 125 135 overrides[i] = false; 126 136 } … … 141 151 { 142 152 if (!m_mappedArguments) { 143 unsigned limit = std::min(length + offset, m_length);153 unsigned limit = std::min(length + offset, storageHeader().length); 144 154 unsigned i; 145 155 VirtualRegister start = firstElementDest - offset; 156 WriteBarrier<Unknown>* storage = this->storage(); 146 157 for (i = offset; i < limit; ++i) 147 exec->r(start + i) = storage ()[i].get();158 exec->r(start + i) = storage[i].get(); 148 159 for (; i < length; ++i) 149 160 exec->r(start + i) = get(exec, i); … … 159 170 // still allocate so that m_mappedArguments is non-null. We use that to indicate that the other properties 160 171 // (length, etc) are overridden. 161 return WTF::roundUpToMultipleOf<8>( m_length ? m_length : 1);172 return WTF::roundUpToMultipleOf<8>(storageHeader().length ? storageHeader().length : 1); 162 173 } 163 174 -
trunk/Source/JavaScriptCore/runtime/DirectArguments.h
r229362 r229518 33 33 namespace JSC { 34 34 35 class LLIntOffsetsExtractor; 36 35 37 // This is an Arguments-class object that we create when you say "arguments" inside a function, 36 38 // and none of the arguments are captured in the function's activation. The function will copy all … … 39 41 // being deleted (something like "delete arguments[0]") or reconfigured (broadly, we say deletions 40 42 // and reconfigurations mean that the respective argument was "overridden"). 41 //42 // To speed allocation, this object will hold all of the arguments in-place. The arguments as well43 // as a table of flags saying which arguments were overridden.44 43 class DirectArguments final : public GenericArguments<DirectArguments> { 45 44 private: 46 DirectArguments(VM&, Structure*, unsigned length, unsigned capacity);45 DirectArguments(VM&, Structure*, WriteBarrier<Unknown>* storage); 47 46 48 47 public: 49 48 template<typename CellType> 50 static CompleteSubspace* subspaceFor(VM& vm)49 static IsoSubspace* subspaceFor(VM& vm) 51 50 { 52 51 RELEASE_ASSERT(!CellType::needsDestruction); 53 return &vm. jsValueGigacageCellSpace;52 return &vm.directArgumentsSpace; 54 53 } 55 54 … … 70 69 uint32_t internalLength() const 71 70 { 72 return m_length;71 return storageHeader().length; 73 72 } 74 73 … … 83 82 return value.toUInt32(exec); 84 83 } 85 return m_length;84 return storageHeader().length; 86 85 } 87 86 88 87 bool isMappedArgument(uint32_t i) const 89 88 { 90 return i < m_length && (!m_mappedArguments || !m_mappedArguments[i]);89 return i < storageHeader().length && (!m_mappedArguments || !m_mappedArguments[i]); 91 90 } 92 91 93 92 bool isMappedArgumentInDFG(uint32_t i) const 94 93 { 95 return i < m_length && !overrodeThings();96 } 97 94 return i < storageHeader().length && !overrodeThings(); 95 } 96 98 97 JSValue getIndexQuickly(uint32_t i) const 99 98 { 100 99 ASSERT_WITH_SECURITY_IMPLICATION(isMappedArgument(i)); 101 auto* ptr = &const_cast<DirectArguments*>(this)->storage()[i]; 102 return preciseIndexMaskPtr(i, m_length, dynamicPoison(type(), DirectArgumentsType, ptr))->get(); 100 WriteBarrier<Unknown>* storage = this->storage(); 101 auto* ptr = &storage[i]; 102 return preciseIndexMaskPtr(i, storageHeader(storage).length, ptr)->get(); 103 103 } 104 104 … … 106 106 { 107 107 ASSERT_WITH_SECURITY_IMPLICATION(isMappedArgument(i)); 108 auto* ptr = &storage()[i]; 109 preciseIndexMaskPtr(i, m_length, dynamicPoison(type(), DirectArgumentsType, ptr))->set(vm, this, value); 108 WriteBarrier<Unknown>* storage = this->storage(); 109 auto* ptr = &storage[i]; 110 preciseIndexMaskPtr(i, storageHeader(storage).length, ptr)->set(vm, this, value); 110 111 } 111 112 … … 118 119 { 119 120 ASSERT(offset); 120 ASSERT_WITH_SECURITY_IMPLICATION(offset.offset() < std::max(m_length, m_minCapacity)); 121 auto* ptr = &storage()[offset.offset()]; 122 return *preciseIndexMaskPtr(offset.offset(), std::max(m_length, m_minCapacity), dynamicPoison(type(), DirectArgumentsType, ptr)); 121 ASSERT_WITH_SECURITY_IMPLICATION(offset.offset() < std::max(storageHeader().length, storageHeader().minCapacity)); 122 WriteBarrier<Unknown>* storage = this->storage(); 123 auto* ptr = &storage[offset.offset()]; 124 return *preciseIndexMaskPtr( 125 offset.offset(), 126 std::max(storageHeader(storage).length, storageHeader(storage).minCapacity), 127 ptr); 123 128 } 124 129 … … 131 136 void initModifiedArgumentsDescriptorIfNecessary(VM& vm) 132 137 { 133 GenericArguments<DirectArguments>::initModifiedArgumentsDescriptorIfNecessary(vm, m_length);138 GenericArguments<DirectArguments>::initModifiedArgumentsDescriptorIfNecessary(vm, storageHeader().length); 134 139 } 135 140 136 141 void setModifiedArgumentDescriptor(VM& vm, unsigned index) 137 142 { 138 GenericArguments<DirectArguments>::setModifiedArgumentDescriptor(vm, index, m_length);143 GenericArguments<DirectArguments>::setModifiedArgumentDescriptor(vm, index, storageHeader().length); 139 144 } 140 145 141 146 bool isModifiedArgumentDescriptor(unsigned index) 142 147 { 143 return GenericArguments<DirectArguments>::isModifiedArgumentDescriptor(index, m_length);148 return GenericArguments<DirectArguments>::isModifiedArgumentDescriptor(index, storageHeader().length); 144 149 } 145 150 … … 151 156 152 157 static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(DirectArguments, m_callee); } 153 static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(DirectArguments, m_length); }154 static ptrdiff_t offsetOfMinCapacity() { return OBJECT_OFFSETOF(DirectArguments, m_minCapacity); }155 158 static ptrdiff_t offsetOfMappedArguments() { return OBJECT_OFFSETOF(DirectArguments, m_mappedArguments); } 156 159 static ptrdiff_t offsetOfModifiedArgumentsDescriptor() { return OBJECT_OFFSETOF(DirectArguments, m_modifiedArgumentsDescriptor); } 157 158 static size_t storageOffset() 159 { 160 return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(DirectArguments)); 161 } 162 163 static size_t offsetOfSlot(Checked<size_t> index) 164 { 165 return (storageOffset() + sizeof(WriteBarrier<Unknown>) * index).unsafeGet(); 166 } 167 168 static size_t allocationSize(Checked<size_t> capacity) 169 { 170 return offsetOfSlot(capacity); 160 static ptrdiff_t offsetOfStorage() { return OBJECT_OFFSETOF(DirectArguments, m_storage); } 161 162 static ptrdiff_t offsetOfLengthInStorage() { return OBJECT_OFFSETOF(StorageHeader, length) - sizeof(WriteBarrier<Unknown>); } 163 static ptrdiff_t offsetOfMinCapacityInStorage() { return OBJECT_OFFSETOF(StorageHeader, minCapacity) - sizeof(WriteBarrier<Unknown>); } 164 165 static size_t storageSize(Checked<size_t> capacity) 166 { 167 return (sizeof(WriteBarrier<Unknown>) * (capacity + static_cast<size_t>(1))).unsafeGet(); 168 } 169 170 static size_t storageHeaderSize() { return sizeof(WriteBarrier<Unknown>); } 171 172 static size_t allocationSize(size_t inlineSize) 173 { 174 RELEASE_ASSERT(!inlineSize); 175 return sizeof(DirectArguments); 171 176 } 172 177 173 178 private: 174 WriteBarrier<Unknown>* storage() 175 { 176 return bitwise_cast<WriteBarrier<Unknown>*>(bitwise_cast<char*>(this) + storageOffset()); 179 friend class LLIntOffsetsExtractor; 180 181 struct StorageHeader { 182 uint32_t length; // Always the actual length of captured arguments and never what was stored into the length property. 183 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. 184 }; 185 186 WriteBarrier<Unknown>* storage() const 187 { 188 return m_storage.get().unpoisoned(); 189 } 190 191 static StorageHeader& storageHeader(WriteBarrier<Unknown>* storage) 192 { 193 static_assert(sizeof(StorageHeader) == sizeof(WriteBarrier<Unknown>), "StorageHeader needs to be the same size as a JSValue"); 194 return *bitwise_cast<StorageHeader*>(storage - 1); 195 } 196 197 StorageHeader& storageHeader() const 198 { 199 return storageHeader(storage()); 177 200 } 178 201 … … 180 203 181 204 WriteBarrier<JSFunction> m_callee; 182 uint32_t m_length; // Always the actual length of captured arguments and never what was stored into the length property.183 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.184 205 CagedBarrierPtr<Gigacage::Primitive, bool> m_mappedArguments; // If non-null, it means that length, callee, and caller are fully materialized properties. 206 AuxiliaryBarrier<Poisoned<DirectArgumentsPoison, WriteBarrier<Unknown>*>> m_storage; 185 207 }; 186 208 -
trunk/Source/JavaScriptCore/runtime/JSCPoison.h
r228420 r229518 35 35 v(CodeBlock) \ 36 36 v(DateInstance) \ 37 v(DirectArguments) \ 37 38 v(GlobalData) \ 38 39 v(JITCode) \ -
trunk/Source/JavaScriptCore/runtime/JSLexicalEnvironment.h
r229410 r229518 37 37 class LLIntOffsetsExtractor; 38 38 39 // This is Spectre-safe because it doesn't have its length inline. 39 40 class JSLexicalEnvironment : public JSSymbolTableObject { 40 41 friend class JIT; -
trunk/Source/JavaScriptCore/runtime/JSSymbolTableObject.h
r222473 r229518 74 74 75 75 private: 76 // FIXME: This needs to be poisoned. 76 77 WriteBarrier<SymbolTable> m_symbolTable; 77 78 }; -
trunk/Source/JavaScriptCore/runtime/VM.cpp
r229309 r229518 262 262 , boundFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSBoundFunction) 263 263 , customGetterSetterFunctionSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), JSCustomGetterSetterFunction) 264 , directArgumentsSpace ISO_SUBSPACE_INIT(heap, cellJSValueOOBHeapCellType.get(), DirectArguments) 264 265 , directEvalExecutableSpace ISO_SUBSPACE_INIT(heap, destructibleCellHeapCellType.get(), DirectEvalExecutable) 265 266 , executableToCodeBlockEdgeSpace ISO_SUBSPACE_INIT(heap, cellDangerousBitsHeapCellType.get(), ExecutableToCodeBlockEdge) -
trunk/Source/JavaScriptCore/runtime/VM.h
r229309 r229518 346 346 IsoSubspace boundFunctionSpace; 347 347 IsoSubspace customGetterSetterFunctionSpace; 348 IsoSubspace directArgumentsSpace; 348 349 IsoSubspace directEvalExecutableSpace; 349 350 IsoSubspace executableToCodeBlockEdgeSpace; -
trunk/Source/WTF/ChangeLog
r229515 r229518 1 2018-03-11 Filip Pizlo <fpizlo@apple.com> 2 3 Split DirectArguments into JSValueOOB and JSValueStrict parts 4 https://bugs.webkit.org/show_bug.cgi?id=183458 5 6 Reviewed by Yusuke Suzuki. 7 8 * wtf/MathExtras.h: 9 (WTF::dynamicPoison): Deleted. 10 1 11 2018-03-11 Yusuke Suzuki <utatane.tea@gmail.com> 2 12 -
trunk/Source/WTF/wtf/MathExtras.h
r229412 r229518 501 501 } 502 502 503 // This masks the given pointer with 0xffffffffffffffff (ptrwidth) if `index < 504 // length`. Otherwise, it masks the pointer with 0. Similar to Linux kernel's array_ptr. 503 505 template<typename T> 504 506 inline T* preciseIndexMaskPtr(uintptr_t index, uintptr_t length, T* value) … … 510 512 } 511 513 512 constexpr unsigned bytePoisonShift = 40;513 514 template<typename T, typename U>515 inline T* dynamicPoison(U actual, U expected, T* pointer)516 {517 static_assert(sizeof(U) == 1, "Poisoning only works for bytes at the moment");518 #if CPU(X86_64) || (CPU(ARM64) && !defined(__ILP32__))519 return bitwise_cast<T*>(520 bitwise_cast<char*>(pointer) +521 (static_cast<uintptr_t>(opaque(actual) ^ expected) << bytePoisonShift));522 #else523 UNUSED_PARAM(actual);524 UNUSED_PARAM(expected);525 return pointer;526 #endif527 }528 529 514 template<typename VectorType, typename RandomFunc> 530 515 void shuffleVector(VectorType& vector, size_t size, const RandomFunc& randomFunc) … … 542 527 } // namespace WTF 543 528 544 using WTF::dynamicPoison;545 529 using WTF::opaque; 546 530 using WTF::preciseIndexMaskPtr;
Note: See TracChangeset
for help on using the changeset viewer.