summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/jit
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/jit')
-rw-r--r--JavaScriptCore/jit/ExecutableAllocator.cpp36
-rw-r--r--JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp30
-rw-r--r--JavaScriptCore/jit/ExecutableAllocatorPosix.cpp42
-rw-r--r--JavaScriptCore/jit/ExecutableAllocatorSymbian.cpp2
-rw-r--r--JavaScriptCore/jit/ExecutableAllocatorWin.cpp2
-rw-r--r--JavaScriptCore/jit/JIT.h49
-rw-r--r--JavaScriptCore/jit/JITPropertyAccess.cpp20
-rw-r--r--JavaScriptCore/jit/JITPropertyAccess32_64.cpp23
-rw-r--r--JavaScriptCore/jit/JITStubs.cpp63
-rw-r--r--JavaScriptCore/jit/JITStubs.h5
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);