diff options
Diffstat (limited to 'JavaScriptCore/jit')
-rw-r--r-- | JavaScriptCore/jit/ExecutableAllocator.cpp | 36 | ||||
-rw-r--r-- | JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp | 30 | ||||
-rw-r--r-- | JavaScriptCore/jit/ExecutableAllocatorPosix.cpp | 42 | ||||
-rw-r--r-- | JavaScriptCore/jit/ExecutableAllocatorSymbian.cpp | 2 | ||||
-rw-r--r-- | JavaScriptCore/jit/ExecutableAllocatorWin.cpp | 2 | ||||
-rw-r--r-- | JavaScriptCore/jit/JIT.h | 49 | ||||
-rw-r--r-- | JavaScriptCore/jit/JITPropertyAccess.cpp | 20 | ||||
-rw-r--r-- | JavaScriptCore/jit/JITPropertyAccess32_64.cpp | 23 | ||||
-rw-r--r-- | JavaScriptCore/jit/JITStubs.cpp | 63 | ||||
-rw-r--r-- | JavaScriptCore/jit/JITStubs.h | 5 |
10 files changed, 186 insertions, 86 deletions
diff --git a/JavaScriptCore/jit/ExecutableAllocator.cpp b/JavaScriptCore/jit/ExecutableAllocator.cpp index f6b27ec..5e10e86 100644 --- a/JavaScriptCore/jit/ExecutableAllocator.cpp +++ b/JavaScriptCore/jit/ExecutableAllocator.cpp @@ -33,6 +33,42 @@ namespace JSC { size_t ExecutableAllocator::pageSize = 0; +#if ENABLE(ASSEMBLER_WX_EXCLUSIVE) +void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSeting setting) +{ + if (!pageSize) + intializePageSize(); + + // Calculate the start of the page containing this region, + // and account for this extra memory within size. + intptr_t startPtr = reinterpret_cast<intptr_t>(start); + intptr_t pageStartPtr = startPtr & ~(pageSize - 1); + void* pageStart = reinterpret_cast<void*>(pageStartPtr); + size += (startPtr - pageStartPtr); + + // Round size up + size += (pageSize - 1); + size &= ~(pageSize - 1); + + mprotect(pageStart, size, (setting == Writable) ? PROTECTION_FLAGS_RW : PROTECTION_FLAGS_RX); +} +#endif + +#if CPU(ARM_TRADITIONAL) && OS(LINUX) && COMPILER(RVCT) +__asm void ExecutableAllocator::cacheFlush(void* code, size_t size) +{ + ARM + push {r7} + add r1, r1, r0 + mov r7, #0xf0000 + add r7, r7, #0x2 + mov r2, #0x0 + svc #0x0 + pop {r7} + bx lr +} +#endif + } #endif // HAVE(ASSEMBLER) diff --git a/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp b/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp index 4d3c847..7846a25 100644 --- a/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp +++ b/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp @@ -27,25 +27,33 @@ #include "ExecutableAllocator.h" -#if ENABLE(ASSEMBLER) && OS(DARWIN) && CPU(X86_64) +#if ENABLE(EXECUTABLE_ALLOCATOR_FIXED) #include <errno.h> #include "TCSpinLock.h" -#include <mach/mach_init.h> -#include <mach/vm_map.h> #include <sys/mman.h> #include <unistd.h> #include <wtf/AVLTree.h> #include <wtf/VMTags.h> +#if CPU(X86_64) + // These limits suitable on 64-bit platforms (particularly x86-64, where we require all jumps to have a 2Gb max range). + #define VM_POOL_SIZE (2u * 1024u * 1024u * 1024u) // 2Gb + #define COALESCE_LIMIT (16u * 1024u * 1024u) // 16Mb +#else + // These limits are hopefully sensible on embedded platforms. + #define VM_POOL_SIZE (32u * 1024u * 1024u) // 32Mb + #define COALESCE_LIMIT (4u * 1024u * 1024u) // 4Mb +#endif + +// ASLR currently only works on darwin (due to arc4random) & 64-bit (due to address space size). +#define VM_POOL_ASLR (OS(DARWIN) && CPU(X86_64)) + using namespace WTF; namespace JSC { -#define TWO_GB (2u * 1024u * 1024u * 1024u) -#define SIXTEEN_MB (16u * 1024u * 1024u) - // FreeListEntry describes a free chunk of memory, stored in the freeList. struct FreeListEntry { FreeListEntry(void* pointer, size_t size) @@ -291,9 +299,12 @@ public: // for now instead of 2^26 bits of ASLR lets stick with 25 bits of randomization plus // 2^24, which should put up somewhere in the middle of usespace (in the address range // 0x200000000000 .. 0x5fffffffffff). - intptr_t randomLocation = arc4random() & ((1 << 25) - 1); + intptr_t randomLocation = 0; +#if VM_POOL_ASLR + randomLocation = arc4random() & ((1 << 25) - 1); randomLocation += (1 << 24); randomLocation <<= 21; +#endif m_base = mmap(reinterpret_cast<void*>(randomLocation), m_totalHeapSize, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0); if (!m_base) CRASH(); @@ -387,7 +398,7 @@ public: // 16MB of allocations have been freed, sweep m_freeList // coalescing any neighboring fragments. m_countFreedSinceLastCoalesce += size; - if (m_countFreedSinceLastCoalesce >= SIXTEEN_MB) { + if (m_countFreedSinceLastCoalesce >= COALESCE_LIMIT) { m_countFreedSinceLastCoalesce = 0; coalesceFreeSpace(); } @@ -429,7 +440,7 @@ ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t size) SpinLockHolder lock_holder(&spinlock); if (!allocator) - allocator = new FixedVMPoolAllocator(JIT_ALLOCATOR_LARGE_ALLOC_SIZE, TWO_GB); + allocator = new FixedVMPoolAllocator(JIT_ALLOCATOR_LARGE_ALLOC_SIZE, VM_POOL_SIZE); ExecutablePool::Allocation alloc = {reinterpret_cast<char*>(allocator->alloc(size)), size}; return alloc; } @@ -444,4 +455,5 @@ void ExecutablePool::systemRelease(const ExecutablePool::Allocation& allocation) } + #endif // HAVE(ASSEMBLER) diff --git a/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp b/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp index eee8a7e..b04049c 100644 --- a/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp +++ b/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp @@ -27,7 +27,7 @@ #include "ExecutableAllocator.h" -#if ENABLE(ASSEMBLER) && OS(UNIX) && !OS(SYMBIAN) +#if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND) && !OS(WINDOWS) && !OS(SYMBIAN) #include <sys/mman.h> #include <unistd.h> @@ -35,8 +35,6 @@ namespace JSC { -#if !(OS(DARWIN) && CPU(X86_64)) - void ExecutableAllocator::intializePageSize() { ExecutableAllocator::pageSize = getpagesize(); @@ -57,44 +55,6 @@ void ExecutablePool::systemRelease(const ExecutablePool::Allocation& alloc) ASSERT_UNUSED(result, !result); } -#endif // !(OS(DARWIN) && CPU(X86_64)) - -#if ENABLE(ASSEMBLER_WX_EXCLUSIVE) -void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSeting setting) -{ - if (!pageSize) - intializePageSize(); - - // Calculate the start of the page containing this region, - // and account for this extra memory within size. - intptr_t startPtr = reinterpret_cast<intptr_t>(start); - intptr_t pageStartPtr = startPtr & ~(pageSize - 1); - void* pageStart = reinterpret_cast<void*>(pageStartPtr); - size += (startPtr - pageStartPtr); - - // Round size up - size += (pageSize - 1); - size &= ~(pageSize - 1); - - mprotect(pageStart, size, (setting == Writable) ? PROTECTION_FLAGS_RW : PROTECTION_FLAGS_RX); } -#endif -#if CPU(ARM_TRADITIONAL) && OS(LINUX) && COMPILER(RVCT) -__asm void ExecutableAllocator::cacheFlush(void* code, size_t size) -{ - ARM - push {r7} - add r1, r1, r0 - mov r7, #0xf0000 - add r7, r7, #0x2 - mov r2, #0x0 - svc #0x0 - pop {r7} - bx lr -} #endif - -} - -#endif // HAVE(ASSEMBLER) diff --git a/JavaScriptCore/jit/ExecutableAllocatorSymbian.cpp b/JavaScriptCore/jit/ExecutableAllocatorSymbian.cpp index e82975c..9028f50 100644 --- a/JavaScriptCore/jit/ExecutableAllocatorSymbian.cpp +++ b/JavaScriptCore/jit/ExecutableAllocatorSymbian.cpp @@ -22,7 +22,7 @@ #include "ExecutableAllocator.h" -#if ENABLE(ASSEMBLER) && OS(SYMBIAN) +#if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND) && OS(SYMBIAN) #include <e32hal.h> #include <e32std.h> diff --git a/JavaScriptCore/jit/ExecutableAllocatorWin.cpp b/JavaScriptCore/jit/ExecutableAllocatorWin.cpp index e38323c..72a1d5f 100644 --- a/JavaScriptCore/jit/ExecutableAllocatorWin.cpp +++ b/JavaScriptCore/jit/ExecutableAllocatorWin.cpp @@ -27,7 +27,7 @@ #include "ExecutableAllocator.h" -#if ENABLE(ASSEMBLER) && OS(WINDOWS) +#if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND) && OS(WINDOWS) #include "windows.h" diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h index 529a1d6..0980be2 100644 --- a/JavaScriptCore/jit/JIT.h +++ b/JavaScriptCore/jit/JIT.h @@ -211,10 +211,10 @@ namespace JSC { jit.privateCompileGetByIdChain(stubInfo, structure, chain, count, ident, slot, cachedOffset, returnAddress, callFrame); } - static void compilePutByIdTransition(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress) + static void compilePutByIdTransition(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) { JIT jit(globalData, codeBlock); - jit.privateCompilePutByIdTransition(stubInfo, oldStructure, newStructure, cachedOffset, chain, returnAddress); + jit.privateCompilePutByIdTransition(stubInfo, oldStructure, newStructure, cachedOffset, chain, returnAddress, direct); } static void compileCTIMachineTrampolines(JSGlobalData* globalData, RefPtr<ExecutablePool>* executablePool, TrampolineStructure *trampolines) @@ -230,7 +230,7 @@ namespace JSC { } static void patchGetByIdSelf(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress); - static void patchPutByIdReplace(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress); + static void patchPutByIdReplace(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct); static void patchMethodCallProto(CodeBlock* codeblock, MethodCallLinkInfo&, JSFunction*, Structure*, JSObject*, ReturnAddressPtr); static void compilePatchGetArrayLength(JSGlobalData* globalData, CodeBlock* codeBlock, ReturnAddressPtr returnAddress) @@ -266,7 +266,7 @@ namespace JSC { void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame); void privateCompileGetByIdChainList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, StructureChain* chain, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame); void privateCompileGetByIdChain(StructureStubInfo*, Structure*, StructureChain*, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame); - void privateCompilePutByIdTransition(StructureStubInfo*, Structure*, Structure*, size_t cachedOffset, StructureChain*, ReturnAddressPtr returnAddress); + void privateCompilePutByIdTransition(StructureStubInfo*, Structure*, Structure*, size_t cachedOffset, StructureChain*, ReturnAddressPtr returnAddress, bool direct); void privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* data, TrampolineStructure *trampolines); Label privateCompileCTINativeCall(JSGlobalData*, bool isConstruct = false); @@ -407,6 +407,47 @@ namespace JSC { // sequencePutById static const int sequencePutByIdInstructionSpace = 36; static const int sequencePutByIdConstantSpace = 4; +#elif CPU(ARM_THUMB2) + // These architecture specific value are used to enable patching - see comment on op_put_by_id. + static const int patchOffsetPutByIdStructure = 10; + static const int patchOffsetPutByIdExternalLoad = 26; + static const int patchLengthPutByIdExternalLoad = 12; + static const int patchOffsetPutByIdPropertyMapOffset1 = 46; + static const int patchOffsetPutByIdPropertyMapOffset2 = 58; + // These architecture specific value are used to enable patching - see comment on op_get_by_id. + static const int patchOffsetGetByIdStructure = 10; + static const int patchOffsetGetByIdBranchToSlowCase = 26; + static const int patchOffsetGetByIdExternalLoad = 26; + static const int patchLengthGetByIdExternalLoad = 12; + static const int patchOffsetGetByIdPropertyMapOffset1 = 46; + static const int patchOffsetGetByIdPropertyMapOffset2 = 58; + static const int patchOffsetGetByIdPutResult = 62; +#if ENABLE(OPCODE_SAMPLING) + #error "OPCODE_SAMPLING is not yet supported" +#else + static const int patchOffsetGetByIdSlowCaseCall = 30; +#endif + static const int patchOffsetOpCallCompareToJump = 16; + + static const int patchOffsetMethodCheckProtoObj = 24; + static const int patchOffsetMethodCheckProtoStruct = 34; + static const int patchOffsetMethodCheckPutFunction = 58; + + // sequenceOpCall + static const int sequenceOpCallInstructionSpace = 12; + static const int sequenceOpCallConstantSpace = 2; + // sequenceMethodCheck + static const int sequenceMethodCheckInstructionSpace = 40; + static const int sequenceMethodCheckConstantSpace = 6; + // sequenceGetByIdHotPath + static const int sequenceGetByIdHotPathInstructionSpace = 36; + static const int sequenceGetByIdHotPathConstantSpace = 4; + // sequenceGetByIdSlowCase + static const int sequenceGetByIdSlowCaseInstructionSpace = 40; + static const int sequenceGetByIdSlowCaseConstantSpace = 2; + // sequencePutById + static const int sequencePutByIdInstructionSpace = 36; + static const int sequencePutByIdConstantSpace = 4; #else #error "JSVALUE32_64 not supported on this platform." #endif diff --git a/JavaScriptCore/jit/JITPropertyAccess.cpp b/JavaScriptCore/jit/JITPropertyAccess.cpp index 4d36cfa..580e73f 100644 --- a/JavaScriptCore/jit/JITPropertyAccess.cpp +++ b/JavaScriptCore/jit/JITPropertyAccess.cpp @@ -307,10 +307,11 @@ void JIT::emit_op_put_by_id(Instruction* currentInstruction) unsigned baseVReg = currentInstruction[1].u.operand; Identifier* ident = &(m_codeBlock->identifier(currentInstruction[2].u.operand)); unsigned valueVReg = currentInstruction[3].u.operand; + unsigned direct = currentInstruction[8].u.operand; emitGetVirtualRegisters(baseVReg, regT0, valueVReg, regT1); - JITStubCall stubCall(this, cti_op_put_by_id_generic); + JITStubCall stubCall(this, direct ? cti_op_put_by_id_direct_generic, cti_op_put_by_id_generic); stubCall.addArgument(regT0); stubCall.addArgument(ImmPtr(ident)); stubCall.addArgument(regT1); @@ -530,13 +531,14 @@ void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCase { unsigned baseVReg = currentInstruction[1].u.operand; Identifier* ident = &(m_codeBlock->identifier(currentInstruction[2].u.operand)); + unsigned direct = currentInstruction[8].u.operand; unsigned propertyAccessInstructionIndex = m_propertyAccessInstructionIndex++; linkSlowCaseIfNotJSCell(iter, baseVReg); linkSlowCase(iter); - JITStubCall stubCall(this, cti_op_put_by_id); + JITStubCall stubCall(this, direct ? cti_op_put_by_id_direct : cti_op_put_by_id); stubCall.addArgument(regT0); stubCall.addArgument(ImmPtr(ident)); stubCall.addArgument(regT1); @@ -590,7 +592,7 @@ void JIT::testPrototype(Structure* structure, JumpList& failureCases) failureCases.append(branchPtr(NotEqual, Address(regT2), regT3)); } -void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress) +void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) { JumpList failureCases; // Check eax is an object of the right Structure. @@ -599,8 +601,10 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure testPrototype(oldStructure, failureCases); // ecx = baseObject->m_structure - for (RefPtr<Structure>* it = chain->head(); *it; ++it) - testPrototype(it->get(), failureCases); + if (!direct) { + for (RefPtr<Structure>* it = chain->head(); *it; ++it) + testPrototype(it->get(), failureCases); + } Call callTarget; @@ -641,7 +645,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure LinkBuffer patchBuffer(this, m_codeBlock->executablePool()); - patchBuffer.link(failureCall, FunctionPtr(cti_op_put_by_id_fail)); + patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail)); if (willNeedStorageRealloc) { ASSERT(m_calls.size() == 1); @@ -694,13 +698,13 @@ void JIT::patchMethodCallProto(CodeBlock* codeBlock, MethodCallLinkInfo& methodC repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id)); } -void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress) +void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct) { RepatchBuffer repatchBuffer(codeBlock); // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. // Should probably go to cti_op_put_by_id_fail, but that doesn't do anything interesting right now. - repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); int offset = sizeof(JSValue) * cachedOffset; diff --git a/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/JavaScriptCore/jit/JITPropertyAccess32_64.cpp index 16cf84a..6234842 100644 --- a/JavaScriptCore/jit/JITPropertyAccess32_64.cpp +++ b/JavaScriptCore/jit/JITPropertyAccess32_64.cpp @@ -531,11 +531,12 @@ void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCase { int base = currentInstruction[1].u.operand; int ident = currentInstruction[2].u.operand; - + int direct = currentInstruction[8].u.operand; + linkSlowCaseIfNotJSCell(iter, base); linkSlowCase(iter); - JITStubCall stubCall(this, cti_op_put_by_id); + JITStubCall stubCall(this, direct ? cti_op_put_by_id_direct : cti_op_put_by_id); stubCall.addArgument(regT1, regT0); stubCall.addArgument(ImmPtr(&(m_codeBlock->identifier(ident)))); stubCall.addArgument(regT3, regT2); @@ -592,7 +593,7 @@ void JIT::testPrototype(Structure* structure, JumpList& failureCases) failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(structure->m_prototype)->m_structure), ImmPtr(asCell(structure->m_prototype)->m_structure))); } -void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress) +void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) { // It is assumed that regT0 contains the basePayload and regT1 contains the baseTag. The value can be found on the stack. @@ -601,10 +602,12 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure failureCases.append(branchPtr(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(oldStructure))); testPrototype(oldStructure, failureCases); - // Verify that nothing in the prototype chain has a setter for this property. - for (RefPtr<Structure>* it = chain->head(); *it; ++it) - testPrototype(it->get(), failureCases); - + if (!direct) { + // Verify that nothing in the prototype chain has a setter for this property. + for (RefPtr<Structure>* it = chain->head(); *it; ++it) + testPrototype(it->get(), failureCases); + } + // Reallocate property storage if needed. Call callTarget; bool willNeedStorageRealloc = oldStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity(); @@ -643,7 +646,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure LinkBuffer patchBuffer(this, m_codeBlock->executablePool()); - patchBuffer.link(failureCall, FunctionPtr(cti_op_put_by_id_fail)); + patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail)); if (willNeedStorageRealloc) { ASSERT(m_calls.size() == 1); @@ -697,13 +700,13 @@ void JIT::patchMethodCallProto(CodeBlock* codeBlock, MethodCallLinkInfo& methodC repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id)); } -void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress) +void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct) { RepatchBuffer repatchBuffer(codeBlock); // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. // Should probably go to cti_op_put_by_id_fail, but that doesn't do anything interesting right now. - repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); int offset = sizeof(JSValue) * cachedOffset; diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp index 30a9898..85bd54f 100644 --- a/JavaScriptCore/jit/JITStubs.cpp +++ b/JavaScriptCore/jit/JITStubs.cpp @@ -247,7 +247,7 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" #define REGISTER_FILE_OFFSET 0x50 #define CALLFRAME_OFFSET 0x54 #define EXCEPTION_OFFSET 0x58 -#define ENABLE_PROFILER_REFERENCE_OFFSET 0x64 +#define ENABLE_PROFILER_REFERENCE_OFFSET 0x60 #elif COMPILER(GCC) && CPU(ARM_TRADITIONAL) @@ -844,7 +844,7 @@ JITThunks::~JITThunks() #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) -NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo) +NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo, bool direct) { // The interpreter checks for recursion here; I do not believe this can occur in CTI. @@ -853,7 +853,7 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co // Uncacheable: give up. if (!slot.isCacheable()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } @@ -861,13 +861,13 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co Structure* structure = baseCell->structure(); if (structure->isUncacheableDictionary()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } // If baseCell != base, then baseCell must be a proxy for another object. if (baseCell != slot.base()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } @@ -876,7 +876,7 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co // Structure transition, cache transition info if (slot.type() == PutPropertySlot::NewProperty) { if (structure->isDictionary()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } @@ -885,13 +885,13 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co StructureChain* prototypeChain = structure->prototypeChain(callFrame); stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain); - JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress); + JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct); return; } stubInfo->initPutByIdReplace(structure); - JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); + JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress, direct); } NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo) @@ -1344,6 +1344,15 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_generic) CHECK_FOR_EXCEPTION_AT_END(); } +DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_generic) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + PutPropertySlot slot; + stackFrame.args[0].jsValue().putDirect(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot); + CHECK_FOR_EXCEPTION_AT_END(); +} + DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_generic) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1366,17 +1375,36 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id) STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); - + PutPropertySlot slot; stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot); - + CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); if (!stubInfo->seenOnce()) stubInfo->setSeen(); else - JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo); + JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, false); + + CHECK_FOR_EXCEPTION_AT_END(); +} +DEFINE_STUB_FUNCTION(void, op_put_by_id_direct) +{ + STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; + Identifier& ident = stackFrame.args[1].identifier(); + + PutPropertySlot slot; + stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot); + + CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); + StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); + if (!stubInfo->seenOnce()) + stubInfo->setSeen(); + else + JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, true); + CHECK_FOR_EXCEPTION_AT_END(); } @@ -1393,6 +1421,19 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_fail) CHECK_FOR_EXCEPTION_AT_END(); } +DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_fail) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + CallFrame* callFrame = stackFrame.callFrame; + Identifier& ident = stackFrame.args[1].identifier(); + + PutPropertySlot slot; + stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot); + + CHECK_FOR_EXCEPTION_AT_END(); +} + DEFINE_STUB_FUNCTION(JSObject*, op_put_by_id_transition_realloc) { STUB_INIT_STACK_FRAME(stackFrame); diff --git a/JavaScriptCore/jit/JITStubs.h b/JavaScriptCore/jit/JITStubs.h index 6d627a1..a5b21e5 100644 --- a/JavaScriptCore/jit/JITStubs.h +++ b/JavaScriptCore/jit/JITStubs.h @@ -257,7 +257,7 @@ namespace JSC { ~JITThunks(); static void tryCacheGetByID(CallFrame*, CodeBlock*, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot&, StructureStubInfo* stubInfo); - static void tryCachePutByID(CallFrame*, CodeBlock*, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot&, StructureStubInfo* stubInfo); + static void tryCachePutByID(CallFrame*, CodeBlock*, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot&, StructureStubInfo* stubInfo, bool direct); MacroAssemblerCodePtr ctiStringLengthTrampoline() { return m_trampolineStructure.ctiStringLengthTrampoline; } MacroAssemblerCodePtr ctiVirtualCallLink() { return m_trampolineStructure.ctiVirtualCallLink; } @@ -378,6 +378,9 @@ extern "C" { void JIT_STUB cti_op_put_by_id(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_by_id_fail(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_by_id_generic(STUB_ARGS_DECLARATION); + void JIT_STUB cti_op_put_by_id_direct(STUB_ARGS_DECLARATION); + void JIT_STUB cti_op_put_by_id_direct_fail(STUB_ARGS_DECLARATION); + void JIT_STUB cti_op_put_by_id_direct_generic(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_by_index(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_by_val(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_by_val_byte_array(STUB_ARGS_DECLARATION); |