summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/jit
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-08-11 14:44:44 +0100
committerBen Murdoch <benm@google.com>2010-08-12 19:15:41 +0100
commitdd8bb3de4f353a81954234999f1fea748aee2ea9 (patch)
tree729b52bf09294f0d6c67cd5ea80aee1b727b7bd8 /JavaScriptCore/jit
parentf3d41ba51d86bf719c7a65ab5297aea3c17e2d98 (diff)
downloadexternal_webkit-dd8bb3de4f353a81954234999f1fea748aee2ea9.zip
external_webkit-dd8bb3de4f353a81954234999f1fea748aee2ea9.tar.gz
external_webkit-dd8bb3de4f353a81954234999f1fea748aee2ea9.tar.bz2
Merge WebKit at r65072 : Initial merge by git.
Change-Id: Ibcf418498376b2660aacb7f8d46ea7085ef91585
Diffstat (limited to 'JavaScriptCore/jit')
-rw-r--r--JavaScriptCore/jit/ExecutableAllocator.cpp4
-rw-r--r--JavaScriptCore/jit/ExecutableAllocator.h67
-rw-r--r--JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp32
-rw-r--r--JavaScriptCore/jit/JIT.cpp10
-rw-r--r--JavaScriptCore/jit/JIT.h65
-rw-r--r--JavaScriptCore/jit/JITArithmetic32_64.cpp2
-rw-r--r--JavaScriptCore/jit/JITInlineMethods.h2
-rw-r--r--JavaScriptCore/jit/JITOpcodes.cpp54
-rw-r--r--JavaScriptCore/jit/JITOpcodes32_64.cpp51
-rw-r--r--JavaScriptCore/jit/JITPropertyAccess.cpp149
-rw-r--r--JavaScriptCore/jit/JITPropertyAccess32_64.cpp165
-rw-r--r--JavaScriptCore/jit/JITStubs.cpp410
-rw-r--r--JavaScriptCore/jit/JITStubs.h4
-rw-r--r--JavaScriptCore/jit/JSInterfaceJIT.h2
-rw-r--r--JavaScriptCore/jit/SpecializedThunkJIT.h5
15 files changed, 572 insertions, 450 deletions
diff --git a/JavaScriptCore/jit/ExecutableAllocator.cpp b/JavaScriptCore/jit/ExecutableAllocator.cpp
index 86c24fd..e3525f5 100644
--- a/JavaScriptCore/jit/ExecutableAllocator.cpp
+++ b/JavaScriptCore/jit/ExecutableAllocator.cpp
@@ -45,15 +45,13 @@ void ExecutableAllocator::intializePageSize()
// for moving memory model limitation
ExecutableAllocator::pageSize = 256 * 1024;
#else
- ExecutableAllocator::pageSize = PageAllocation::pagesize();
+ ExecutableAllocator::pageSize = PageAllocation::pageSize();
#endif
}
ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t size)
{
PageAllocation allocation = PageAllocation::allocate(size, PageAllocation::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
- if (!allocation)
- CRASH();
return allocation;
}
diff --git a/JavaScriptCore/jit/ExecutableAllocator.h b/JavaScriptCore/jit/ExecutableAllocator.h
index f8e991f..b60d591 100644
--- a/JavaScriptCore/jit/ExecutableAllocator.h
+++ b/JavaScriptCore/jit/ExecutableAllocator.h
@@ -34,7 +34,7 @@
#include <wtf/UnusedParam.h>
#include <wtf/Vector.h>
-#if OS(IPHONE_OS)
+#if OS(IOS)
#include <libkern/OSCacheControl.h>
#include <sys/mman.h>
#endif
@@ -85,15 +85,29 @@ inline size_t roundUpAllocationSize(size_t request, size_t granularity)
namespace JSC {
class ExecutablePool : public RefCounted<ExecutablePool> {
-private:
+public:
+#if ENABLE(EXECUTABLE_ALLOCATOR_DEMAND)
typedef PageAllocation Allocation;
+#else
+ class Allocation {
+ public:
+ Allocation(void* base, size_t size)
+ : m_base(base)
+ , m_size(size)
+ {
+ }
+ void* base() { return m_base; }
+ size_t size() { return m_size; }
+ bool operator!() const { return !m_base; }
+
+ private:
+ void* m_base;
+ size_t m_size;
+ };
+#endif
typedef Vector<Allocation, 2> AllocationList;
-public:
- static PassRefPtr<ExecutablePool> create(size_t n)
- {
- return adoptRef(new ExecutablePool(n));
- }
+ static PassRefPtr<ExecutablePool> create(size_t n);
void* alloc(size_t n)
{
@@ -114,6 +128,11 @@ public:
return poolAllocate(n);
}
+ void returnLastBytes(size_t count)
+ {
+ m_freePtr -= count;
+ }
+
~ExecutablePool()
{
AllocationList::iterator end = m_pools.end();
@@ -127,7 +146,7 @@ private:
static Allocation systemAlloc(size_t n);
static void systemRelease(Allocation& alloc);
- ExecutablePool(size_t n);
+ ExecutablePool(Allocation&);
void* poolAllocate(size_t n);
@@ -145,8 +164,11 @@ public:
{
if (!pageSize)
intializePageSize();
- if (isValid())
+ if (isValid()) {
m_smallAllocationPool = ExecutablePool::create(JIT_ALLOCATOR_LARGE_ALLOC_SIZE);
+ if (!m_smallAllocationPool)
+ CRASH();
+ }
#if !ENABLE(INTERPRETER)
else
CRASH();
@@ -163,7 +185,7 @@ public:
return m_smallAllocationPool;
// If the request is large, we just provide a unshared allocator
- if (n > JIT_ALLOCATOR_LARGE_ALLOC_SIZE)
+ if (n > JIT_ALLOCATOR_LARGE_ALLOC_SIZE)
return ExecutablePool::create(n);
// Create a new allocator
@@ -200,7 +222,7 @@ public:
static void cacheFlush(void* code, size_t size)
{
#if COMPILER(GCC) && GCC_VERSION_AT_LEAST(4,3,0)
-#if WTF_MIPS_ISA_REV(2) && GCC_VERSION_AT_LEAST(4,4,3)
+#if WTF_MIPS_ISA_REV(2) && !GCC_VERSION_AT_LEAST(4,4,3)
int lineSize;
asm("rdhwr %0, $1" : "=r" (lineSize));
//
@@ -222,7 +244,7 @@ public:
_flush_cache(reinterpret_cast<char*>(code), size, BCACHE);
#endif
}
-#elif CPU(ARM_THUMB2) && OS(IPHONE_OS)
+#elif CPU(ARM_THUMB2) && OS(IOS)
static void cacheFlush(void* code, size_t size)
{
sys_dcache_flush(code, size);
@@ -286,15 +308,20 @@ private:
static void intializePageSize();
};
-inline ExecutablePool::ExecutablePool(size_t n)
+inline PassRefPtr<ExecutablePool> ExecutablePool::create(size_t n)
+ {
+ Allocation mem = systemAlloc(roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE));
+ if (!mem)
+ return 0;
+ return adoptRef(new ExecutablePool(mem));
+ }
+
+inline ExecutablePool::ExecutablePool(Allocation& mem)
{
- size_t allocSize = roundUpAllocationSize(n, JIT_ALLOCATOR_PAGE_SIZE);
- Allocation mem = systemAlloc(allocSize);
+ ASSERT(!!mem);
m_pools.append(mem);
m_freePtr = static_cast<char*>(mem.base());
- if (!m_freePtr)
- CRASH(); // Failed to allocate
- m_end = m_freePtr + allocSize;
+ m_end = m_freePtr + mem.size();
}
inline void* ExecutablePool::poolAllocate(size_t n)
@@ -303,8 +330,8 @@ inline void* ExecutablePool::poolAllocate(size_t n)
Allocation result = systemAlloc(allocSize);
if (!result.base())
- CRASH(); // Failed to allocate
-
+ return 0; // Failed to allocate
+
ASSERT(m_end >= m_freePtr);
if ((allocSize - n) > static_cast<size_t>(m_end - m_freePtr)) {
// Replace allocation pool
diff --git a/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp b/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp
index 421c34b..f05e919 100644
--- a/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp
+++ b/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp
@@ -35,6 +35,7 @@
#include <sys/mman.h>
#include <unistd.h>
#include <wtf/AVLTree.h>
+#include <wtf/PageReservation.h>
#include <wtf/VMTags.h>
#if CPU(X86_64)
@@ -131,12 +132,12 @@ class FixedVMPoolAllocator
void reuse(void* position, size_t size)
{
- bool okay = m_allocation.commit(position, size, EXECUTABLE_POOL_WRITABLE, true);
+ bool okay = m_allocation.commit(position, size);
ASSERT_UNUSED(okay, okay);
}
// All addition to the free list should go through this method, rather than
- // calling insert directly, to avoid multiple entries beging added with the
+ // calling insert directly, to avoid multiple entries being added with the
// same key. All nodes being added should be singletons, they should not
// already be a part of a chain.
void addToFreeList(FreeListEntry* entry)
@@ -155,7 +156,7 @@ class FixedVMPoolAllocator
}
// We do not attempt to coalesce addition, which may lead to fragmentation;
- // instead we periodically perform a sweep to try to coalesce neigboring
+ // instead we periodically perform a sweep to try to coalesce neighboring
// entries in m_freeList. Presently this is triggered at the point 16MB
// of memory has been released.
void coalesceFreeSpace()
@@ -168,7 +169,7 @@ class FixedVMPoolAllocator
for (FreeListEntry* entry; (entry = *iter); ++iter) {
// Each entry in m_freeList might correspond to multiple
// free chunks of memory (of the same size). Walk the chain
- // (this is likely of couse only be one entry long!) adding
+ // (this is likely of course only be one entry long!) adding
// each entry to the Vector (at reseting the next in chain
// pointer to separate each node out).
FreeListEntry* next;
@@ -283,16 +284,16 @@ public:
//
// But! - as a temporary workaround for some plugin problems (rdar://problem/6812854),
// 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
+ // 2^24, which should put up somewhere in the middle of userspace (in the address range
// 0x200000000000 .. 0x5fffffffffff).
#if VM_POOL_ASLR
intptr_t randomLocation = 0;
randomLocation = arc4random() & ((1 << 25) - 1);
randomLocation += (1 << 24);
randomLocation <<= 21;
- m_allocation = PageAllocation::reserveAt(reinterpret_cast<void*>(randomLocation), false, totalHeapSize, PageAllocation::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
+ m_allocation = PageReservation::reserveAt(reinterpret_cast<void*>(randomLocation), false, totalHeapSize, PageAllocation::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
#else
- m_allocation = PageAllocation::reserve(totalHeapSize, PageAllocation::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
+ m_allocation = PageReservation::reserve(totalHeapSize, PageAllocation::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
#endif
if (!!m_allocation)
@@ -303,12 +304,12 @@ public:
#endif
}
- PageAllocation alloc(size_t size)
+ ExecutablePool::Allocation alloc(size_t size)
{
- return PageAllocation(allocInternal(size), size, m_allocation);
+ return ExecutablePool::Allocation(allocInternal(size), size);
}
- void free(PageAllocation allocation)
+ void free(ExecutablePool::Allocation allocation)
{
void* pointer = allocation.base();
size_t size = allocation.size();
@@ -356,18 +357,17 @@ private:
result = m_commonSizedAllocations.last();
m_commonSizedAllocations.removeLast();
} else {
- // Serach m_freeList for a suitable sized chunk to allocate memory from.
+ // Search m_freeList for a suitable sized chunk to allocate memory from.
FreeListEntry* entry = m_freeList.search(size, m_freeList.GREATER_EQUAL);
- // This would be bad news.
+ // This is bad news.
if (!entry) {
- // Errk! Lets take a last-ditch desparation attempt at defragmentation...
+ // Errk! Lets take a last-ditch desperation attempt at defragmentation...
coalesceFreeSpace();
// Did that free up a large enough chunk?
entry = m_freeList.search(size, m_freeList.GREATER_EQUAL);
- // No?... *BOOM!*
if (!entry)
- CRASH();
+ return 0;
}
ASSERT(entry->size != m_commonSize);
@@ -424,7 +424,7 @@ private:
// This is used for housekeeping, to trigger defragmentation of the freed lists.
size_t m_countFreedSinceLastCoalesce;
- PageAllocation m_allocation;
+ PageReservation m_allocation;
};
void ExecutableAllocator::intializePageSize()
diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp
index f5df5f7..cd5944a 100644
--- a/JavaScriptCore/jit/JIT.cpp
+++ b/JavaScriptCore/jit/JIT.cpp
@@ -71,7 +71,7 @@ void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAd
repatchBuffer.relinkCallerToFunction(returnAddress, newCalleeFunction);
}
-JIT::JIT(JSGlobalData* globalData, CodeBlock* codeBlock)
+JIT::JIT(JSGlobalData* globalData, CodeBlock* codeBlock, void* linkerOffset)
: m_interpreter(globalData->interpreter)
, m_globalData(globalData)
, m_codeBlock(codeBlock)
@@ -89,6 +89,7 @@ JIT::JIT(JSGlobalData* globalData, CodeBlock* codeBlock)
, m_lastResultBytecodeRegister(std::numeric_limits<int>::max())
, m_jumpTargetsPosition(0)
#endif
+ , m_linkerOffset(linkerOffset)
{
}
@@ -508,7 +509,12 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck)
ASSERT(m_jmpTable.isEmpty());
- LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()));
+ RefPtr<ExecutablePool> executablePool = m_globalData->executableAllocator.poolForSize(m_assembler.size());
+ if (!executablePool)
+ return JITCode();
+ LinkBuffer patchBuffer(this, executablePool.release(), m_linkerOffset);
+ if (!patchBuffer.allocationSuccessful())
+ return JITCode();
// Translate vPC offsets into addresses in JIT generated code, for switch tables.
for (unsigned i = 0; i < m_switches.size(); ++i) {
diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h
index d398d51..393c771 100644
--- a/JavaScriptCore/jit/JIT.h
+++ b/JavaScriptCore/jit/JIT.h
@@ -178,50 +178,50 @@ namespace JSC {
static const int patchGetByIdDefaultOffset = 256;
public:
- static JITCode compile(JSGlobalData* globalData, CodeBlock* codeBlock, CodePtr* functionEntryArityCheck = 0)
+ static JITCode compile(JSGlobalData* globalData, CodeBlock* codeBlock, CodePtr* functionEntryArityCheck = 0, void* offsetBase = 0)
{
- return JIT(globalData, codeBlock).privateCompile(functionEntryArityCheck);
+ return JIT(globalData, codeBlock, offsetBase).privateCompile(functionEntryArityCheck);
}
- static void compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress)
+ static bool compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress)
{
JIT jit(globalData, codeBlock);
- jit.privateCompileGetByIdProto(stubInfo, structure, prototypeStructure, ident, slot, cachedOffset, returnAddress, callFrame);
+ return jit.privateCompileGetByIdProto(stubInfo, structure, prototypeStructure, ident, slot, cachedOffset, returnAddress, callFrame);
}
- static void compileGetByIdSelfList(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
+ static bool compileGetByIdSelfList(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
{
JIT jit(globalData, codeBlock);
- jit.privateCompileGetByIdSelfList(stubInfo, polymorphicStructures, currentIndex, structure, ident, slot, cachedOffset);
+ return jit.privateCompileGetByIdSelfList(stubInfo, structure, ident, slot, cachedOffset);
}
- static void compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
+ static bool compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
{
JIT jit(globalData, codeBlock);
- jit.privateCompileGetByIdProtoList(stubInfo, prototypeStructureList, currentIndex, structure, prototypeStructure, ident, slot, cachedOffset, callFrame);
+ return jit.privateCompileGetByIdProtoList(stubInfo, structure, prototypeStructure, ident, slot, cachedOffset, callFrame);
}
- static void compileGetByIdChainList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
+ static bool compileGetByIdChainList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
{
JIT jit(globalData, codeBlock);
- jit.privateCompileGetByIdChainList(stubInfo, prototypeStructureList, currentIndex, structure, chain, count, ident, slot, cachedOffset, callFrame);
+ return jit.privateCompileGetByIdChainList(stubInfo, structure, chain, count, ident, slot, cachedOffset, callFrame);
}
- static void compileGetByIdChain(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress)
+ static bool compileGetByIdChain(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress)
{
JIT jit(globalData, codeBlock);
- jit.privateCompileGetByIdChain(stubInfo, structure, chain, count, ident, slot, cachedOffset, returnAddress, callFrame);
+ return 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, bool direct)
+ static bool 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, direct);
+ return jit.privateCompilePutByIdTransition(stubInfo, oldStructure, newStructure, cachedOffset, chain, returnAddress, direct);
}
static void compileCTIMachineTrampolines(JSGlobalData* globalData, RefPtr<ExecutablePool>* executablePool, TrampolineStructure *trampolines)
{
if (!globalData->canUseJIT())
return;
- JIT jit(globalData);
+ JIT jit(globalData, 0, 0);
jit.privateCompileCTIMachineTrampolines(executablePool, globalData, trampolines);
}
@@ -229,7 +229,7 @@ namespace JSC {
{
if (!globalData->canUseJIT())
return CodePtr();
- JIT jit(globalData);
+ JIT jit(globalData, 0, 0);
return jit.privateCompileCTINativeCall(executablePool, globalData, func);
}
@@ -237,10 +237,10 @@ namespace JSC {
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)
+ static bool compilePatchGetArrayLength(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, ReturnAddressPtr returnAddress)
{
JIT jit(globalData, codeBlock);
- return jit.privateCompilePatchGetArrayLength(returnAddress);
+ return jit.privateCompilePatchGetArrayLength(stubInfo, returnAddress);
}
static void linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, CodePtr, CallLinkInfo*, int callerArgCount, JSGlobalData*);
@@ -259,23 +259,23 @@ namespace JSC {
}
};
- JIT(JSGlobalData*, CodeBlock* = 0);
+ JIT(JSGlobalData*, CodeBlock* = 0, void* = 0);
void privateCompileMainPass();
void privateCompileLinkPass();
void privateCompileSlowCases();
JITCode privateCompile(CodePtr* functionEntryArityCheck);
- void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
- void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, const Identifier&, const PropertySlot&, size_t cachedOffset);
- 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, bool direct);
+ bool privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
+ bool privateCompileGetByIdSelfList(StructureStubInfo*, Structure*, const Identifier&, const PropertySlot&, size_t cachedOffset);
+ bool privateCompileGetByIdProtoList(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame);
+ bool privateCompileGetByIdChainList(StructureStubInfo*, Structure*, StructureChain* chain, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame);
+ bool privateCompileGetByIdChain(StructureStubInfo*, Structure*, StructureChain*, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
+ bool privateCompilePutByIdTransition(StructureStubInfo* stubInfo, 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);
CodePtr privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executablePool, JSGlobalData* data, NativeFunction func);
- void privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress);
+ bool privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnAddressPtr returnAddress);
void addSlowCase(Jump);
void addSlowCase(JumpList);
@@ -295,7 +295,7 @@ namespace JSC {
void emitLoadDouble(unsigned index, FPRegisterID value);
void emitLoadInt32ToDouble(unsigned index, FPRegisterID value);
- void testPrototype(Structure*, JumpList& failureCases);
+ void testPrototype(JSValue, JumpList& failureCases);
#if USE(JSVALUE32_64)
bool getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant);
@@ -666,16 +666,16 @@ namespace JSC {
#endif
#endif // USE(JSVALUE32_64)
-#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL
-#define BEGIN_UNINTERRUPTED_SEQUENCE(name) beginUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace)
-#define END_UNINTERRUPTED_SEQUENCE(name) endUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace)
+#if (defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL)
+#define BEGIN_UNINTERRUPTED_SEQUENCE(name) do { beginUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace); } while (false)
+#define END_UNINTERRUPTED_SEQUENCE(name) do { endUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace); } while (false)
void beginUninterruptedSequence(int, int);
void endUninterruptedSequence(int, int);
#else
-#define BEGIN_UNINTERRUPTED_SEQUENCE(name)
-#define END_UNINTERRUPTED_SEQUENCE(name)
+#define BEGIN_UNINTERRUPTED_SEQUENCE(name) do { beginUninterruptedSequence(); } while (false)
+#define END_UNINTERRUPTED_SEQUENCE(name) do { endUninterruptedSequence(); } while (false)
#endif
void emit_op_add(Instruction*);
@@ -940,6 +940,7 @@ namespace JSC {
int m_uninterruptedConstantSequenceBegin;
#endif
#endif
+ void* m_linkerOffset;
static CodePtr stringGetByValStubGenerator(JSGlobalData* globalData, ExecutablePool* pool);
} JIT_CLASS_ALIGNMENT;
diff --git a/JavaScriptCore/jit/JITArithmetic32_64.cpp b/JavaScriptCore/jit/JITArithmetic32_64.cpp
index 5a69d5a..e53af77 100644
--- a/JavaScriptCore/jit/JITArithmetic32_64.cpp
+++ b/JavaScriptCore/jit/JITArithmetic32_64.cpp
@@ -1383,6 +1383,8 @@ void JIT::emit_op_mod(Instruction* currentInstruction)
void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
+ UNUSED_PARAM(currentInstruction);
+ UNUSED_PARAM(iter);
#if ENABLE(JIT_USE_SOFT_MODULO)
unsigned result = currentInstruction[1].u.operand;
unsigned op1 = currentInstruction[2].u.operand;
diff --git a/JavaScriptCore/jit/JITInlineMethods.h b/JavaScriptCore/jit/JITInlineMethods.h
index 3b28f34..e2e77db 100644
--- a/JavaScriptCore/jit/JITInlineMethods.h
+++ b/JavaScriptCore/jit/JITInlineMethods.h
@@ -99,6 +99,7 @@ ALWAYS_INLINE JIT::Call JIT::emitNakedCall(CodePtr function)
ALWAYS_INLINE void JIT::beginUninterruptedSequence(int insnSpace, int constSpace)
{
+ JSInterfaceJIT::beginUninterruptedSequence();
#if CPU(ARM_TRADITIONAL)
#ifndef NDEBUG
// Ensure the label after the sequence can also fit
@@ -124,6 +125,7 @@ ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace)
ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) == insnSpace);
ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin == constSpace);
#endif
+ JSInterfaceJIT::endUninterruptedSequence();
}
#endif
diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp
index 852de4e..28ef4ca 100644
--- a/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/JavaScriptCore/jit/JITOpcodes.cpp
@@ -161,7 +161,14 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
#endif
// All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
- LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()));
+ *executablePool = m_globalData->executableAllocator.poolForSize(m_assembler.size());
+ // We can't run without the JIT trampolines!
+ if (!*executablePool)
+ CRASH();
+ LinkBuffer patchBuffer(this, *executablePool, 0);
+ // We can't run without the JIT trampolines!
+ if (!patchBuffer.allocationSuccessful())
+ CRASH();
#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail));
@@ -176,19 +183,18 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
patchBuffer.link(callCompileConstruct, FunctionPtr(cti_op_construct_jitCompile));
CodeRef finalCode = patchBuffer.finalizeCode();
- *executablePool = finalCode.m_executablePool;
-
- trampolines->ctiVirtualCallLink = trampolineAt(finalCode, virtualCallLinkBegin);
- trampolines->ctiVirtualConstructLink = trampolineAt(finalCode, virtualConstructLinkBegin);
- trampolines->ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin);
- trampolines->ctiVirtualConstruct = trampolineAt(finalCode, virtualConstructBegin);
- trampolines->ctiNativeCall = trampolineAt(finalCode, nativeCallThunk);
- trampolines->ctiNativeConstruct = trampolineAt(finalCode, nativeConstructThunk);
+
+ trampolines->ctiVirtualCallLink = patchBuffer.trampolineAt(virtualCallLinkBegin);
+ trampolines->ctiVirtualConstructLink = patchBuffer.trampolineAt(virtualConstructLinkBegin);
+ trampolines->ctiVirtualCall = patchBuffer.trampolineAt(virtualCallBegin);
+ trampolines->ctiVirtualConstruct = patchBuffer.trampolineAt(virtualConstructBegin);
+ trampolines->ctiNativeCall = patchBuffer.trampolineAt(nativeCallThunk);
+ trampolines->ctiNativeConstruct = patchBuffer.trampolineAt(nativeConstructThunk);
#if ENABLE(JIT_USE_SOFT_MODULO)
- trampolines->ctiSoftModulo = trampolineAt(finalCode, softModBegin);
+ trampolines->ctiSoftModulo = patchBuffer.trampolineAt(softModBegin);
#endif
#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
- trampolines->ctiStringLengthTrampoline = trampolineAt(finalCode, stringLengthBegin);
+ trampolines->ctiStringLengthTrampoline = patchBuffer.trampolineAt(stringLengthBegin);
#endif
}
@@ -462,18 +468,18 @@ void JIT::emit_op_construct(Instruction* currentInstruction)
void JIT::emit_op_get_global_var(Instruction* currentInstruction)
{
- JSVariableObject* globalObject = static_cast<JSVariableObject*>(currentInstruction[2].u.jsCell);
+ JSVariableObject* globalObject = m_codeBlock->globalObject();
move(ImmPtr(globalObject), regT0);
- emitGetVariableObjectRegister(regT0, currentInstruction[3].u.operand, regT0);
+ emitGetVariableObjectRegister(regT0, currentInstruction[2].u.operand, regT0);
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
void JIT::emit_op_put_global_var(Instruction* currentInstruction)
{
- emitGetVirtualRegister(currentInstruction[3].u.operand, regT1);
- JSVariableObject* globalObject = static_cast<JSVariableObject*>(currentInstruction[1].u.jsCell);
+ emitGetVirtualRegister(currentInstruction[2].u.operand, regT1);
+ JSVariableObject* globalObject = m_codeBlock->globalObject();
move(ImmPtr(globalObject), regT0);
- emitPutVariableObjectRegister(regT1, regT0, currentInstruction[2].u.operand);
+ emitPutVariableObjectRegister(regT1, regT0, currentInstruction[1].u.operand);
}
void JIT::emit_op_get_scoped_var(Instruction* currentInstruction)
@@ -644,7 +650,7 @@ void JIT::emit_op_resolve_skip(Instruction* currentInstruction)
void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool)
{
// Fast case
- void* globalObject = currentInstruction[2].u.jsCell;
+ void* globalObject = m_codeBlock->globalObject();
unsigned currentIndex = m_globalResolveInfoIndex++;
void* structureAddress = &(m_codeBlock->globalResolveInfo(currentIndex).structure);
void* offsetAddr = &(m_codeBlock->globalResolveInfo(currentIndex).offset);
@@ -665,16 +671,15 @@ void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool)
void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
unsigned dst = currentInstruction[1].u.operand;
- void* globalObject = currentInstruction[2].u.jsCell;
- Identifier* ident = &m_codeBlock->identifier(currentInstruction[3].u.operand);
+ Identifier* ident = &m_codeBlock->identifier(currentInstruction[2].u.operand);
unsigned currentIndex = m_globalResolveInfoIndex++;
linkSlowCase(iter);
JITStubCall stubCall(this, cti_op_resolve_global);
- stubCall.addArgument(ImmPtr(globalObject));
stubCall.addArgument(ImmPtr(ident));
stubCall.addArgument(Imm32(currentIndex));
+ stubCall.addArgument(regT0);
stubCall.call(dst);
}
@@ -1489,7 +1494,7 @@ void JIT::emitSlow_op_to_jsnumber(Instruction* currentInstruction, Vector<SlowCa
void JIT::emit_op_resolve_global_dynamic(Instruction* currentInstruction)
{
- int skip = currentInstruction[6].u.operand;
+ int skip = currentInstruction[5].u.operand;
emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT0);
while (skip--) {
@@ -1503,9 +1508,8 @@ void JIT::emit_op_resolve_global_dynamic(Instruction* currentInstruction)
void JIT::emitSlow_op_resolve_global_dynamic(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
unsigned dst = currentInstruction[1].u.operand;
- void* globalObject = currentInstruction[2].u.jsCell;
- Identifier* ident = &m_codeBlock->identifier(currentInstruction[3].u.operand);
- int skip = currentInstruction[6].u.operand;
+ Identifier* ident = &m_codeBlock->identifier(currentInstruction[2].u.operand);
+ int skip = currentInstruction[5].u.operand;
while (skip--)
linkSlowCase(iter);
JITStubCall resolveStubCall(this, cti_op_resolve);
@@ -1517,9 +1521,9 @@ void JIT::emitSlow_op_resolve_global_dynamic(Instruction* currentInstruction, Ve
linkSlowCase(iter); // We managed to skip all the nodes in the scope chain, but the cache missed.
JITStubCall stubCall(this, cti_op_resolve_global);
- stubCall.addArgument(ImmPtr(globalObject));
stubCall.addArgument(ImmPtr(ident));
stubCall.addArgument(Imm32(currentIndex));
+ stubCall.addArgument(regT0);
stubCall.call(dst);
}
diff --git a/JavaScriptCore/jit/JITOpcodes32_64.cpp b/JavaScriptCore/jit/JITOpcodes32_64.cpp
index 5622e9c..939aa8c 100644
--- a/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -159,7 +159,14 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
#endif
// All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
- LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()));
+ *executablePool = m_globalData->executableAllocator.poolForSize(m_assembler.size());
+ // We can't run without the JIT trampolines!
+ if (!*executablePool)
+ CRASH();
+ LinkBuffer patchBuffer(this, *executablePool, 0);
+ // We can't run without the JIT trampolines!
+ if (!patchBuffer.allocationSuccessful())
+ CRASH();
#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail));
@@ -174,21 +181,20 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable
patchBuffer.link(callCompileCconstruct, FunctionPtr(cti_op_construct_jitCompile));
CodeRef finalCode = patchBuffer.finalizeCode();
- *executablePool = finalCode.m_executablePool;
- trampolines->ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin);
- trampolines->ctiVirtualConstruct = trampolineAt(finalCode, virtualConstructBegin);
- trampolines->ctiNativeCall = trampolineAt(finalCode, nativeCallThunk);
- trampolines->ctiNativeConstruct = trampolineAt(finalCode, nativeConstructThunk);
+ trampolines->ctiVirtualCall = patchBuffer.trampolineAt(virtualCallBegin);
+ trampolines->ctiVirtualConstruct = patchBuffer.trampolineAt(virtualConstructBegin);
+ trampolines->ctiNativeCall = patchBuffer.trampolineAt(nativeCallThunk);
+ trampolines->ctiNativeConstruct = patchBuffer.trampolineAt(nativeConstructThunk);
#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
- trampolines->ctiStringLengthTrampoline = trampolineAt(finalCode, stringLengthBegin);
+ trampolines->ctiStringLengthTrampoline = patchBuffer.trampolineAt(stringLengthBegin);
#endif
#if ENABLE(JIT_OPTIMIZE_CALL)
- trampolines->ctiVirtualCallLink = trampolineAt(finalCode, virtualCallLinkBegin);
- trampolines->ctiVirtualConstructLink = trampolineAt(finalCode, virtualConstructLinkBegin);
+ trampolines->ctiVirtualCallLink = patchBuffer.trampolineAt(virtualCallLinkBegin);
+ trampolines->ctiVirtualConstructLink = patchBuffer.trampolineAt(virtualConstructLinkBegin);
#endif
#if ENABLE(JIT_USE_SOFT_MODULO)
- trampolines->ctiSoftModulo = trampolineAt(finalCode, softModBegin);
+ trampolines->ctiSoftModulo = patchBuffer.trampolineAt(softModBegin);
#endif
}
@@ -356,12 +362,15 @@ JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executa
ret();
// All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
- LinkBuffer patchBuffer(this, executablePool);
+ LinkBuffer patchBuffer(this, executablePool, 0);
+ // We can't continue if we can't call a function!
+ if (!patchBuffer.allocationSuccessful())
+ CRASH();
patchBuffer.link(nativeCall, FunctionPtr(func));
+ patchBuffer.finalizeCode();
- CodeRef finalCode = patchBuffer.finalizeCode();
- return trampolineAt(finalCode, nativeCallThunk);
+ return patchBuffer.trampolineAt(nativeCallThunk);
}
void JIT::emit_op_mov(Instruction* currentInstruction)
@@ -516,9 +525,9 @@ void JIT::emit_op_new_func(Instruction* currentInstruction)
void JIT::emit_op_get_global_var(Instruction* currentInstruction)
{
int dst = currentInstruction[1].u.operand;
- JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(currentInstruction[2].u.jsCell);
+ JSGlobalObject* globalObject = m_codeBlock->globalObject();
ASSERT(globalObject->isGlobalObject());
- int index = currentInstruction[3].u.operand;
+ int index = currentInstruction[2].u.operand;
loadPtr(&globalObject->d()->registers, regT2);
@@ -529,10 +538,10 @@ void JIT::emit_op_get_global_var(Instruction* currentInstruction)
void JIT::emit_op_put_global_var(Instruction* currentInstruction)
{
- JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(currentInstruction[1].u.jsCell);
+ JSGlobalObject* globalObject = m_codeBlock->globalObject();
ASSERT(globalObject->isGlobalObject());
- int index = currentInstruction[2].u.operand;
- int value = currentInstruction[3].u.operand;
+ int index = currentInstruction[1].u.operand;
+ int value = currentInstruction[2].u.operand;
emitLoad(value, regT1, regT0);
@@ -669,7 +678,7 @@ void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool dynamic)
// FIXME: Optimize to use patching instead of so many memory accesses.
unsigned dst = currentInstruction[1].u.operand;
- void* globalObject = currentInstruction[2].u.jsCell;
+ void* globalObject = m_codeBlock->globalObject();
unsigned currentIndex = m_globalResolveInfoIndex++;
void* structureAddress = &(m_codeBlock->globalResolveInfo(currentIndex).structure);
@@ -692,14 +701,12 @@ void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool dynamic)
void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
unsigned dst = currentInstruction[1].u.operand;
- void* globalObject = currentInstruction[2].u.jsCell;
- Identifier* ident = &m_codeBlock->identifier(currentInstruction[3].u.operand);
+ Identifier* ident = &m_codeBlock->identifier(currentInstruction[2].u.operand);
unsigned currentIndex = m_globalResolveInfoIndex++;
linkSlowCase(iter);
JITStubCall stubCall(this, cti_op_resolve_global);
- stubCall.addArgument(ImmPtr(globalObject));
stubCall.addArgument(ImmPtr(ident));
stubCall.addArgument(Imm32(currentIndex));
stubCall.call(dst);
diff --git a/JavaScriptCore/jit/JITPropertyAccess.cpp b/JavaScriptCore/jit/JITPropertyAccess.cpp
index 10dcd3f..6b2a2fe 100644
--- a/JavaScriptCore/jit/JITPropertyAccess.cpp
+++ b/JavaScriptCore/jit/JITPropertyAccess.cpp
@@ -77,7 +77,10 @@ JIT::CodePtr JIT::stringGetByValStubGenerator(JSGlobalData* globalData, Executab
jit.move(Imm32(0), regT0);
jit.ret();
- LinkBuffer patchBuffer(&jit, pool);
+ LinkBuffer patchBuffer(&jit, pool, 0);
+ // We can't run without the JIT trampolines!
+ if (!patchBuffer.allocationSuccessful())
+ CRASH();
return patchBuffer.finalizeCode().m_code;
}
@@ -103,10 +106,10 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
emitJumpSlowCaseIfNotJSCell(regT0, base);
addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT2);
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2);
addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
- loadPtr(BaseIndex(regT2, regT1, ScalePtr), regT0);
+ loadPtr(BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0);
addSlowCase(branchTestPtr(Zero, regT0));
emitPutVirtualRegister(dst);
@@ -214,21 +217,21 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT2);
- Jump empty = branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr));
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2);
+ Jump empty = branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
Label storeResult(this);
emitGetVirtualRegister(value, regT0);
- storePtr(regT0, BaseIndex(regT2, regT1, ScalePtr));
+ storePtr(regT0, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
Jump end = jump();
empty.link(this);
- add32(Imm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)-OBJECT_OFFSETOF(ArrayStorage, m_vector)));
- branch32(Below, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector))).linkTo(storeResult, this);
+ add32(Imm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
+ branch32(Below, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this);
move(regT1, regT0);
add32(Imm32(1), regT0);
- store32(regT0, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector)));
+ store32(regT0, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)));
jump().linkTo(storeResult, this);
end.link(this);
@@ -581,28 +584,35 @@ void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID res
}
}
-void JIT::testPrototype(Structure* structure, JumpList& failureCases)
+void JIT::testPrototype(JSValue prototype, JumpList& failureCases)
{
- if (structure->m_prototype.isNull())
+ if (prototype.isNull())
return;
- move(ImmPtr(&asCell(structure->m_prototype)->m_structure), regT2);
- move(ImmPtr(asCell(structure->m_prototype)->m_structure), regT3);
- failureCases.append(branchPtr(NotEqual, Address(regT2), regT3));
+ // We have a special case for X86_64 here because X86 instructions that take immediate values
+ // only take 32 bit immediate values, wheras the pointer constants we are using here are 64 bit
+ // values. In the non X86_64 case, the generated code is slightly more efficient because it uses
+ // two less instructions and doesn't require any scratch registers.
+#if CPU(X86_64)
+ move(ImmPtr(asCell(prototype)->structure()), regT3);
+ failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(prototype)->m_structure), regT3));
+#else
+ failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(prototype)->m_structure), ImmPtr(asCell(prototype)->structure())));
+#endif
}
-void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
+bool 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.
failureCases.append(emitJumpIfNotJSCell(regT0));
failureCases.append(branchPtr(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(oldStructure)));
- testPrototype(oldStructure, failureCases);
+ testPrototype(oldStructure->storedPrototype(), failureCases);
// ecx = baseObject->m_structure
if (!direct) {
for (RefPtr<Structure>* it = chain->head(); *it; ++it)
- testPrototype(it->get(), failureCases);
+ testPrototype((*it)->storedPrototype(), failureCases);
}
Call callTarget;
@@ -642,7 +652,9 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
restoreArgumentReferenceForTrampoline();
Call failureCall = tailRecursiveCall();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail));
@@ -652,9 +664,10 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
}
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
- stubInfo->stubRoutine = entryLabel;
RepatchBuffer repatchBuffer(m_codeBlock);
repatchBuffer.relinkCallerToTrampoline(returnAddress, entryLabel);
+ stubInfo->initPutByIdTransition(oldStructure, newStructure, chain, entryLabel);
+ return true;
}
void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress)
@@ -717,22 +730,22 @@ void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo,
repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset), offset);
}
-void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
+bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnAddressPtr returnAddress)
{
- StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress);
-
// Check eax is an array
Jump failureCases1 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr));
// Checks out okay! - get the length from the storage
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT3);
- load32(Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector)), regT2);
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3);
+ load32(Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2);
Jump failureCases2 = branch32(Above, regT2, Imm32(JSImmediate::maxImmediateInt));
emitFastArithIntToImmNoCheck(regT2, regT0);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall);
@@ -744,7 +757,6 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
// Track the stub we have created so that it will be deleted later.
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
- stubInfo->stubRoutine = entryLabel;
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
@@ -753,9 +765,11 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
// We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_array_fail));
+ stubInfo->stubRoutine = entryLabel;
+ return true;
}
-void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
{
// The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
// referencing the prototype object - let's speculatively load it's table nice and early!)
@@ -795,7 +809,9 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
} else
compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall);
@@ -813,7 +829,6 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
}
// Track the stub we have created so that it will be deleted later.
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
- stubInfo->stubRoutine = entryLabel;
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
@@ -822,10 +837,15 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
// We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
+ stubInfo->initGetByIdProto(structure, prototypeStructure, entryLabel);
+ return true;
}
-void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
+bool JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
{
+ PolymorphicAccessStructureList* polymorphicStructures = stubInfo->u.getByIdSelfList.structureList;
+ int currentIndex = stubInfo->u.getByIdSelfList.listSize;
+
Jump failureCase = checkStructure(regT0, structure);
bool needsStubLink = false;
if (slot.cachedPropertyType() == PropertySlot::Getter) {
@@ -852,7 +872,9 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
compileGetDirectOffset(regT0, regT0, structure, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
@@ -880,10 +902,15 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
RepatchBuffer repatchBuffer(m_codeBlock);
repatchBuffer.relink(jumpLocation, entryLabel);
+ stubInfo->u.getByIdSelfList.listSize++;
+ return true;
}
-void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
+bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
{
+ PolymorphicAccessStructureList* prototypeStructures = stubInfo->u.getByIdProtoList.structureList;
+ int currentIndex = stubInfo->u.getByIdProtoList.listSize;
+
// The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
// referencing the prototype object - let's speculatively load it's table nice and early!)
JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
@@ -923,7 +950,9 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
@@ -950,10 +979,15 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
RepatchBuffer repatchBuffer(m_codeBlock);
repatchBuffer.relink(jumpLocation, entryLabel);
+ stubInfo->u.getByIdProtoList.listSize++;
+ return true;
}
-void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
+bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
{
+ PolymorphicAccessStructureList* prototypeStructures = stubInfo->u.getByIdProtoList.structureList;
+ int currentIndex = stubInfo->u.getByIdProtoList.listSize;
+
ASSERT(count);
JumpList bucketsOfFail;
@@ -962,20 +996,12 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
bucketsOfFail.append(baseObjectCheck);
Structure* currStructure = structure;
- RefPtr<Structure>* chainEntries = chain->head();
+ RefPtr<Structure>* it = chain->head();
JSObject* protoObject = 0;
- for (unsigned i = 0; i < count; ++i) {
+ for (unsigned i = 0; i < count; ++i, ++it) {
protoObject = asObject(currStructure->prototypeForLookup(callFrame));
- currStructure = chainEntries[i].get();
-
- // Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(currStructure), regT3);
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3));
-#else
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
-#endif
+ currStructure = it->get();
+ testPrototype(protoObject, bucketsOfFail);
}
ASSERT(protoObject);
@@ -1000,7 +1026,9 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
@@ -1028,9 +1056,11 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
RepatchBuffer repatchBuffer(m_codeBlock);
repatchBuffer.relink(jumpLocation, entryLabel);
+ stubInfo->u.getByIdProtoList.listSize++;
+ return true;
}
-void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
{
ASSERT(count);
@@ -1040,20 +1070,12 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
bucketsOfFail.append(checkStructure(regT0, structure));
Structure* currStructure = structure;
- RefPtr<Structure>* chainEntries = chain->head();
+ RefPtr<Structure>* it = chain->head();
JSObject* protoObject = 0;
- for (unsigned i = 0; i < count; ++i) {
+ for (unsigned i = 0; i < count; ++i, ++it) {
protoObject = asObject(currStructure->prototypeForLookup(callFrame));
- currStructure = chainEntries[i].get();
-
- // Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(currStructure), regT3);
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3));
-#else
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
-#endif
+ currStructure = it->get();
+ testPrototype(protoObject, bucketsOfFail);
}
ASSERT(protoObject);
@@ -1078,7 +1100,9 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
@@ -1095,7 +1119,6 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
// Track the stub we have created so that it will be deleted later.
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
- stubInfo->stubRoutine = entryLabel;
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
@@ -1104,6 +1127,8 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
// We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
+ stubInfo->initGetByIdChain(structure, chain, entryLabel);
+ return true;
}
/* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) ------------------------------ */
diff --git a/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
index 375d3e8..9239641 100644
--- a/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
+++ b/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
@@ -295,7 +295,10 @@ JIT::CodePtr JIT::stringGetByValStubGenerator(JSGlobalData* globalData, Executab
jit.move(Imm32(0), regT0);
jit.ret();
- LinkBuffer patchBuffer(&jit, pool);
+ LinkBuffer patchBuffer(&jit, pool, 0);
+ // We can't run without the JIT trampolines!
+ if (!patchBuffer.allocationSuccessful())
+ CRASH();
return patchBuffer.finalizeCode().m_code;
}
@@ -311,11 +314,11 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction)
emitJumpSlowCaseIfNotJSCell(base, regT1);
addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT3);
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3);
addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
- load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag
- load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload
+ load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag
+ load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload
addSlowCase(branch32(Equal, regT1, Imm32(JSValue::EmptyValueTag)));
emitStore(dst, regT1, regT0);
@@ -364,22 +367,22 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction)
addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength))));
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT3);
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3);
- Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::EmptyValueTag));
+ Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::EmptyValueTag));
Label storeResult(this);
emitLoad(value, regT1, regT0);
- store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); // payload
- store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); // tag
+ store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); // payload
+ store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); // tag
Jump end = jump();
empty.link(this);
- add32(Imm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)-OBJECT_OFFSETOF(ArrayStorage, m_vector)));
- branch32(Below, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector))).linkTo(storeResult, this);
+ add32(Imm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
+ branch32(Below, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this);
add32(Imm32(1), regT2, regT0);
- store32(regT0, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector)));
+ store32(regT0, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)));
jump().linkTo(storeResult, this);
end.link(this);
@@ -585,27 +588,36 @@ void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID res
load32(Address(temp, offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
}
-void JIT::testPrototype(Structure* structure, JumpList& failureCases)
+void JIT::testPrototype(JSValue prototype, JumpList& failureCases)
{
- if (structure->m_prototype.isNull())
+ if (prototype.isNull())
return;
- failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(structure->m_prototype)->m_structure), ImmPtr(asCell(structure->m_prototype)->m_structure)));
+ // We have a special case for X86_64 here because X86 instructions that take immediate values
+ // only take 32 bit immediate values, wheras the pointer constants we are using here are 64 bit
+ // values. In the non X86_64 case, the generated code is slightly more efficient because it uses
+ // two less instructions and doesn't require any scratch registers.
+#if CPU(X86_64)
+ move(ImmPtr(asCell(prototype)->structure()), regT3);
+ failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(prototype)->m_structure), regT3));
+#else
+ failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(prototype)->m_structure), ImmPtr(asCell(prototype)->structure())));
+#endif
}
-void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
+bool 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.
JumpList failureCases;
failureCases.append(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
failureCases.append(branchPtr(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(oldStructure)));
- testPrototype(oldStructure, failureCases);
+ testPrototype(oldStructure->storedPrototype(), 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);
+ testPrototype((*it)->storedPrototype(), failureCases);
}
// Reallocate property storage if needed.
@@ -644,8 +656,10 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
restoreArgumentReferenceForTrampoline();
Call failureCall = tailRecursiveCall();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
-
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
+
patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail));
if (willNeedStorageRealloc) {
@@ -654,9 +668,10 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
}
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
- stubInfo->stubRoutine = entryLabel;
RepatchBuffer repatchBuffer(m_codeBlock);
repatchBuffer.relinkCallerToTrampoline(returnAddress, entryLabel);
+ stubInfo->initPutByIdTransition(oldStructure, newStructure, chain, entryLabel);
+ return true;
}
void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress)
@@ -721,26 +736,26 @@ void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo,
repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset2), offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag
}
-void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
+bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnAddressPtr returnAddress)
{
- StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress);
-
// regT0 holds a JSCell*
// Check for array
Jump failureCases1 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr));
// Checks out okay! - get the length from the storage
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT2);
- load32(Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector)), regT2);
+ loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2);
+ load32(Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2);
Jump failureCases2 = branch32(Above, regT2, Imm32(INT_MAX));
move(regT2, regT0);
move(Imm32(JSValue::Int32Tag), regT1);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
-
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
+
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall);
patchBuffer.link(failureCases1, slowCaseBegin);
@@ -751,8 +766,7 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
// Track the stub we have created so that it will be deleted later.
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
- stubInfo->stubRoutine = entryLabel;
-
+
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
RepatchBuffer repatchBuffer(m_codeBlock);
@@ -760,9 +774,11 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
// We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_array_fail));
+ stubInfo->stubRoutine = entryLabel;
+ return true;
}
-void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
{
// regT0 holds a JSCell*
@@ -803,8 +819,10 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
-
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
+
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall);
patchBuffer.link(failureCases1, slowCaseBegin);
@@ -822,7 +840,6 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
// Track the stub we have created so that it will be deleted later.
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
- stubInfo->stubRoutine = entryLabel;
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
@@ -831,11 +848,16 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
// We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
+ stubInfo->initGetByIdProto(structure, prototypeStructure, entryLabel);
+ return true;
}
-void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
+bool JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
{
+ PolymorphicAccessStructureList* polymorphicStructures = stubInfo->u.getByIdSelfList.structureList;
+ int currentIndex = stubInfo->u.getByIdSelfList.listSize;
+
// regT0 holds a JSCell*
Jump failureCase = checkStructure(regT0, structure);
bool needsStubLink = false;
@@ -864,7 +886,10 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
+
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
if (iter->to)
@@ -890,10 +915,15 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
RepatchBuffer repatchBuffer(m_codeBlock);
repatchBuffer.relink(jumpLocation, entryLabel);
+ stubInfo->u.getByIdSelfList.listSize++;
+ return true;
}
-void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
+bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
{
+ PolymorphicAccessStructureList* prototypeStructures = stubInfo->u.getByIdProtoList.structureList;
+ int currentIndex = stubInfo->u.getByIdProtoList.listSize;
+
// regT0 holds a JSCell*
// The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
@@ -934,7 +964,10 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
+
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
if (iter->to)
@@ -959,10 +992,15 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
RepatchBuffer repatchBuffer(m_codeBlock);
repatchBuffer.relink(jumpLocation, entryLabel);
+ stubInfo->u.getByIdProtoList.listSize++;
+ return true;
}
-void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
+bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
{
+ PolymorphicAccessStructureList* prototypeStructures = stubInfo->u.getByIdProtoList.structureList;
+ int currentIndex = stubInfo->u.getByIdProtoList.listSize;
+
// regT0 holds a JSCell*
ASSERT(count);
@@ -972,20 +1010,12 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
bucketsOfFail.append(checkStructure(regT0, structure));
Structure* currStructure = structure;
- RefPtr<Structure>* chainEntries = chain->head();
+ RefPtr<Structure>* it = chain->head();
JSObject* protoObject = 0;
- for (unsigned i = 0; i < count; ++i) {
+ for (unsigned i = 0; i < count; ++i, ++it) {
protoObject = asObject(currStructure->prototypeForLookup(callFrame));
- currStructure = chainEntries[i].get();
-
- // Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(currStructure), regT3);
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3));
-#else
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
-#endif
+ currStructure = it->get();
+ testPrototype(protoObject, bucketsOfFail);
}
ASSERT(protoObject);
@@ -1011,7 +1041,10 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
+
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
if (iter->to)
@@ -1037,9 +1070,11 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
RepatchBuffer repatchBuffer(m_codeBlock);
repatchBuffer.relink(jumpLocation, entryLabel);
+ stubInfo->u.getByIdProtoList.listSize++;
+ return true;
}
-void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
{
// regT0 holds a JSCell*
ASSERT(count);
@@ -1050,20 +1085,12 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
bucketsOfFail.append(checkStructure(regT0, structure));
Structure* currStructure = structure;
- RefPtr<Structure>* chainEntries = chain->head();
+ RefPtr<Structure>* it = chain->head();
JSObject* protoObject = 0;
- for (unsigned i = 0; i < count; ++i) {
+ for (unsigned i = 0; i < count; ++i, ++it) {
protoObject = asObject(currStructure->prototypeForLookup(callFrame));
- currStructure = chainEntries[i].get();
-
- // Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if CPU(X86_64)
- move(ImmPtr(currStructure), regT3);
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3));
-#else
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
-#endif
+ currStructure = it->get();
+ testPrototype(protoObject, bucketsOfFail);
}
ASSERT(protoObject);
@@ -1088,7 +1115,10 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
compileGetDirectOffset(protoObject, regT2, regT1, regT0, cachedOffset);
Jump success = jump();
- LinkBuffer patchBuffer(this, m_codeBlock->executablePool());
+ LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0);
+ if (!patchBuffer.allocationSuccessful())
+ return false;
+
if (needsStubLink) {
for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
if (iter->to)
@@ -1103,8 +1133,7 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
// Track the stub we have created so that it will be deleted later.
CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
- stubInfo->stubRoutine = entryLabel;
-
+
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
RepatchBuffer repatchBuffer(m_codeBlock);
@@ -1112,6 +1141,8 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
// We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
+ stubInfo->initGetByIdChain(structure, chain, entryLabel);
+ return true;
}
/* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) ------------------------------ */
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp
index f088b6e..c4ff0ca 100644
--- a/JavaScriptCore/jit/JITStubs.cpp
+++ b/JavaScriptCore/jit/JITStubs.cpp
@@ -71,7 +71,7 @@ namespace JSC {
#define SYMBOL_STRING(name) #name
#endif
-#if OS(IPHONE_OS)
+#if OS(IOS)
#define THUMB_FUNC_PARAM(name) SYMBOL_STRING(name)
#else
#define THUMB_FUNC_PARAM(name)
@@ -239,7 +239,7 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
#define EXCEPTION_OFFSET 0x58
#define ENABLE_PROFILER_REFERENCE_OFFSET 0x60
-#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
+#elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL)
#define THUNK_RETURN_ADDRESS_OFFSET 64
#define PRESERVEDR4_OFFSET 68
@@ -304,6 +304,12 @@ extern "C" {
}
}
+#elif COMPILER(MSVC) && CPU(ARM_TRADITIONAL)
+
+#define THUNK_RETURN_ADDRESS_OFFSET 64
+#define PRESERVEDR4_OFFSET 68
+// See DEFINE_STUB_FUNCTION for more information.
+
#else
#error "JIT not supported on this platform."
#endif
@@ -451,7 +457,7 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
#define EXCEPTION_OFFSET 0x38
#define ENABLE_PROFILER_REFERENCE_OFFSET 0x40
-#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
+#elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL)
#define THUNK_RETURN_ADDRESS_OFFSET 32
#define PRESERVEDR4_OFFSET 36
@@ -548,48 +554,6 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
".end " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
);
-#elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL)
-
-#define THUNK_RETURN_ADDRESS_OFFSET 32
-#define PRESERVEDR4_OFFSET 36
-
-__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*)
-{
- ARM
- stmdb sp!, {r1-r3}
- stmdb sp!, {r4-r8, lr}
- sub sp, sp, #36
- mov r4, r2
- mov r5, #512
- mov lr, pc
- bx r0
- add sp, sp, #36
- ldmia sp!, {r4-r8, lr}
- add sp, sp, #12
- bx lr
-}
-
-__asm void ctiVMThrowTrampoline()
-{
- ARM
- PRESERVE8
- mov r0, sp
- bl cti_vm_throw
- add sp, sp, #36
- ldmia sp!, {r4-r8, lr}
- add sp, sp, #12
- bx lr
-}
-
-__asm void ctiOpThrowNotCaught()
-{
- ARM
- add sp, sp, #36
- ldmia sp!, {r4-r8, lr}
- add sp, sp, #12
- bx lr
-}
-
#elif COMPILER(MSVC) && CPU(X86)
// These ASSERTs remind you that, if you change the layout of JITStackFrame, you
@@ -649,6 +613,12 @@ extern "C" {
}
}
+#elif COMPILER(MSVC) && CPU(ARM_TRADITIONAL)
+
+#define THUNK_RETURN_ADDRESS_OFFSET 32
+#define PRESERVEDR4_OFFSET 36
+// See DEFINE_STUB_FUNCTION for more information.
+
#else
#error "JIT not supported on this platform."
#endif
@@ -755,6 +725,44 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
"mov pc, lr" "\n"
);
+#elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL)
+
+__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*)
+{
+ ARM
+ stmdb sp!, {r1-r3}
+ stmdb sp!, {r4-r8, lr}
+ sub sp, sp, # PRESERVEDR4_OFFSET
+ mov r4, r2
+ mov r5, #512
+ mov lr, pc
+ bx r0
+ add sp, sp, # PRESERVEDR4_OFFSET
+ ldmia sp!, {r4-r8, lr}
+ add sp, sp, #12
+ bx lr
+}
+
+__asm void ctiVMThrowTrampoline()
+{
+ ARM
+ PRESERVE8
+ mov r0, sp
+ bl cti_vm_throw
+ add sp, sp, # PRESERVEDR4_OFFSET
+ ldmia sp!, {r4-r8, lr}
+ add sp, sp, #12
+ bx lr
+}
+
+__asm void ctiOpThrowNotCaught()
+{
+ ARM
+ add sp, sp, # PRESERVEDR4_OFFSET
+ ldmia sp!, {r4-r8, lr}
+ add sp, sp, #12
+ bx lr
+}
#endif
#if ENABLE(OPCODE_SAMPLING)
@@ -815,111 +823,89 @@ 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, bool direct)
+NEVER_INLINE bool 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.
if (!baseValue.isCell())
- return;
+ return false;
// Uncacheable: give up.
- if (!slot.isCacheable()) {
- ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
- return;
- }
+ if (!slot.isCacheable())
+ return false;
JSCell* baseCell = asCell(baseValue);
Structure* structure = baseCell->structure();
- if (structure->isUncacheableDictionary()) {
- ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
- return;
- }
+ if (structure->isUncacheableDictionary())
+ return false;
// If baseCell != base, then baseCell must be a proxy for another object.
- if (baseCell != slot.base()) {
- ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
- return;
- }
+ if (baseCell != slot.base())
+ return false;
// Cache hit: Specialize instruction and ref Structures.
// Structure transition, cache transition info
if (slot.type() == PutPropertySlot::NewProperty) {
- if (structure->isDictionary()) {
- ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
- return;
- }
+ if (structure->isDictionary())
+ return false;
// put_by_id_transition checks the prototype chain for setters.
normalizePrototypeChain(callFrame, baseCell);
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, direct);
- return;
+ return JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct);
}
-
- stubInfo->initPutByIdReplace(structure);
JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress, direct);
+ stubInfo->initPutByIdReplace(structure);
+ return true;
}
-NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo)
+NEVER_INLINE bool JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo)
{
// FIXME: Write a test that proves we need to check for recursion here just
// like the interpreter does, then add a check for recursion.
// FIXME: Cache property access for immediates.
- if (!baseValue.isCell()) {
- ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
- return;
- }
+ if (!baseValue.isCell())
+ return false;
JSGlobalData* globalData = &callFrame->globalData();
- if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
- JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, returnAddress);
- return;
- }
+ if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length)
+ return JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, stubInfo, returnAddress);
if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
// The tradeoff of compiling an patched inline string length access routine does not seem
// to pay off, so we currently only do this for arrays.
ctiPatchCallByReturnAddress(codeBlock, returnAddress, globalData->jitStubs->ctiStringLengthTrampoline());
- return;
+ return true;
}
// Uncacheable: give up.
- if (!slot.isCacheable()) {
- ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
- return;
- }
+ if (!slot.isCacheable())
+ return false;
JSCell* baseCell = asCell(baseValue);
Structure* structure = baseCell->structure();
- if (structure->isUncacheableDictionary()) {
- ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
- return;
- }
+ if (structure->isUncacheableDictionary())
+ return false;
// Cache hit: Specialize instruction and ref Structures.
if (slot.slotBase() == baseValue) {
- // set this up, so derefStructures can do it's job.
- stubInfo->initGetByIdSelf(structure);
if (slot.cachedPropertyType() != PropertySlot::Value)
- ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail));
- else
- JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress);
- return;
+ return false;
+ JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress);
+ stubInfo->initGetByIdSelf(structure);
+ return true;
}
- if (structure->isDictionary()) {
- ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
- return;
- }
+ if (structure->isDictionary())
+ return false;
if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
ASSERT(slot.slotBase().isObject());
@@ -933,25 +919,20 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co
slotBaseObject->flattenDictionaryObject();
offset = slotBaseObject->structure()->get(propertyName);
}
-
- stubInfo->initGetByIdProto(structure, slotBaseObject->structure());
-
ASSERT(!structure->isDictionary());
ASSERT(!slotBaseObject->structure()->isDictionary());
- JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset, returnAddress);
- return;
+ return JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset, returnAddress);
}
size_t offset = slot.cachedOffset();
size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset);
if (!count) {
stubInfo->accessType = access_get_by_id_generic;
- return;
+ return true;
}
StructureChain* prototypeChain = structure->prototypeChain(callFrame);
- stubInfo->initGetByIdChain(structure, prototypeChain);
- JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress);
+ return JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress);
}
#endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
@@ -1152,9 +1133,9 @@ RVCT(__asm #rtype# cti_#op#(STUB_ARGS_DECLARATION))
RVCT({)
RVCT( ARM)
RVCT( IMPORT JITStubThunked_#op#)
-RVCT( str lr, [sp, ##offset#])
+RVCT( str lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET])
RVCT( bl JITStubThunked_#op#)
-RVCT( ldr lr, [sp, ##offset#])
+RVCT( ldr lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET])
RVCT( bx lr)
RVCT(})
RVCT()
@@ -1163,6 +1144,62 @@ RVCT()
/* Include the generated file */
#include "GeneratedJITStubs_RVCT.h"
+#elif CPU(ARM_TRADITIONAL) && COMPILER(MSVC)
+
+#define DEFINE_STUB_FUNCTION(rtype, op) extern "C" rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
+
+/* The following is a workaround for MSVC toolchain; inline assembler is not supported */
+
+/* The following section is a template to generate code for GeneratedJITStubs_MSVC.asm */
+/* The pattern "#xxx#" will be replaced with "xxx" */
+
+/*
+MSVC_BEGIN( AREA Trampoline, CODE)
+MSVC_BEGIN()
+MSVC_BEGIN( EXPORT ctiTrampoline)
+MSVC_BEGIN( EXPORT ctiVMThrowTrampoline)
+MSVC_BEGIN( EXPORT ctiOpThrowNotCaught)
+MSVC_BEGIN()
+MSVC_BEGIN(ctiTrampoline PROC)
+MSVC_BEGIN( stmdb sp!, {r1-r3})
+MSVC_BEGIN( stmdb sp!, {r4-r8, lr})
+MSVC_BEGIN( sub sp, sp, ##offset#+4)
+MSVC_BEGIN( mov r4, r2)
+MSVC_BEGIN( mov r5, #512)
+MSVC_BEGIN( ; r0 contains the code)
+MSVC_BEGIN( mov lr, pc)
+MSVC_BEGIN( bx r0)
+MSVC_BEGIN( add sp, sp, ##offset#+4)
+MSVC_BEGIN( ldmia sp!, {r4-r8, lr})
+MSVC_BEGIN( add sp, sp, #12)
+MSVC_BEGIN( bx lr)
+MSVC_BEGIN(ctiTrampoline ENDP)
+MSVC_BEGIN()
+MSVC_BEGIN(ctiVMThrowTrampoline PROC)
+MSVC_BEGIN( mov r0, sp)
+MSVC_BEGIN( mov lr, pc)
+MSVC_BEGIN( bl cti_vm_throw)
+MSVC_BEGIN(ctiOpThrowNotCaught)
+MSVC_BEGIN( add sp, sp, ##offset#+4)
+MSVC_BEGIN( ldmia sp!, {r4-r8, lr})
+MSVC_BEGIN( add sp, sp, #12)
+MSVC_BEGIN( bx lr)
+MSVC_BEGIN(ctiVMThrowTrampoline ENDP)
+MSVC_BEGIN()
+
+MSVC( EXPORT cti_#op#)
+MSVC( IMPORT JITStubThunked_#op#)
+MSVC(cti_#op# PROC)
+MSVC( str lr, [sp, ##offset#])
+MSVC( bl JITStubThunked_#op#)
+MSVC( ldr lr, [sp, ##offset#])
+MSVC( bx lr)
+MSVC(cti_#op# ENDP)
+MSVC()
+
+MSVC_END( END)
+*/
+
#else
#define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION)
#endif
@@ -1348,9 +1385,13 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id)
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, false);
-
+ else {
+ JSValue baseValue = stackFrame.args[0].jsValue();
+ bool cached = JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, slot, stubInfo, false);
+ if (!cached && baseValue.isCell())
+ ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_id_generic));
+ }
+
CHECK_FOR_EXCEPTION_AT_END();
}
@@ -1367,9 +1408,13 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_direct)
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);
-
+ else {
+ JSValue baseValue = stackFrame.args[0].jsValue();
+ bool cached = JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, slot, stubInfo, true);
+ if (!cached && baseValue.isCell())
+ ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_id_direct_generic));
+ }
+
CHECK_FOR_EXCEPTION_AT_END();
}
@@ -1501,8 +1546,11 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id)
StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
if (!stubInfo->seenOnce())
stubInfo->setSeen();
- else
- JITThunks::tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo);
+ else {
+ bool cached = JITThunks::tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo);
+ if (!cached)
+ ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
+ }
CHECK_FOR_EXCEPTION_AT_END();
return JSValue::encode(result);
@@ -1531,57 +1579,28 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail)
ASSERT(slot.slotBase().isObject());
- PolymorphicAccessStructureList* polymorphicStructureList;
- int listIndex = 1;
-
- if (stubInfo->accessType == access_get_by_id_self) {
- ASSERT(!stubInfo->stubRoutine);
- polymorphicStructureList = new PolymorphicAccessStructureList(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure);
- stubInfo->initGetByIdSelfList(polymorphicStructureList, 1);
- } else {
- polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList;
- listIndex = stubInfo->u.getByIdSelfList.listSize;
- }
- if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
- stubInfo->u.getByIdSelfList.listSize++;
- JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), ident, slot, slot.cachedOffset());
+ // If this is a regular self access (not yet upgraded to list), then switch the stubInfo over.
+ if (stubInfo->accessType == access_get_by_id_self)
+ stubInfo->initGetByIdSelfList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdSelf.baseObjectStructure));
- if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
- ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
+ // If there is room in the list, try to add a cached entry.
+ if (stubInfo->u.getByIdSelfList.listSize < POLYMORPHIC_LIST_CACHE_SIZE) {
+ bool cached = JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, asCell(baseValue)->structure(), ident, slot, slot.cachedOffset());
+ if (cached)
+ return JSValue::encode(result);
}
- } else
- ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
+ }
+ ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
return JSValue::encode(result);
}
-static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(StructureStubInfo* stubInfo, int& listIndex)
-{
- PolymorphicAccessStructureList* prototypeStructureList = 0;
- listIndex = 1;
-
- switch (stubInfo->accessType) {
- case access_get_by_id_proto:
- prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure);
- stubInfo->stubRoutine = CodeLocationLabel();
- stubInfo->initGetByIdProtoList(prototypeStructureList, 2);
- break;
- case access_get_by_id_chain:
- prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain);
- stubInfo->stubRoutine = CodeLocationLabel();
- stubInfo->initGetByIdProtoList(prototypeStructureList, 2);
- break;
- case access_get_by_id_proto_list:
- prototypeStructureList = stubInfo->u.getByIdProtoList.structureList;
- listIndex = stubInfo->u.getByIdProtoList.listSize;
- if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE)
- stubInfo->u.getByIdProtoList.listSize++;
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-
- ASSERT(listIndex <= POLYMORPHIC_LIST_CACHE_SIZE);
- return prototypeStructureList;
+static void setupPolymorphicProtoList(StructureStubInfo* stubInfo)
+{
+ if (stubInfo->accessType == access_get_by_id_proto)
+ stubInfo->initGetByIdProtoList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure));
+ else if (stubInfo->accessType == access_get_by_id_chain)
+ stubInfo->initGetByIdProtoList(new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain));
+ ASSERT(stubInfo->accessType == access_get_by_id_proto_list);
}
DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_getter_stub)
@@ -1642,40 +1661,36 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list)
size_t offset = slot.cachedOffset();
- if (slot.slotBase() == baseValue)
- ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
- else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) {
- ASSERT(!asCell(baseValue)->structure()->isDictionary());
- // Since we're accessing a prototype in a loop, it's a good bet that it
- // should not be treated as a dictionary.
- if (slotBaseObject->structure()->isDictionary()) {
- slotBaseObject->flattenDictionaryObject();
- offset = slotBaseObject->structure()->get(propertyName);
- }
-
- int listIndex;
- PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
- if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
- JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), propertyName, slot, offset);
-
- if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
- ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
- }
- } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) {
- ASSERT(!asCell(baseValue)->structure()->isDictionary());
- int listIndex;
- PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
-
- if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
- StructureChain* protoChain = structure->prototypeChain(callFrame);
- JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, propertyName, slot, offset);
+ // Don't mix self & proto/chain accesses in the same list
+ if (slot.slotBase() != baseValue) {
+ if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) {
+ ASSERT(!asCell(baseValue)->structure()->isDictionary());
+ // Since we're accessing a prototype in a loop, it's a good bet that it
+ // should not be treated as a dictionary.
+ if (slotBaseObject->structure()->isDictionary()) {
+ slotBaseObject->flattenDictionaryObject();
+ offset = slotBaseObject->structure()->get(propertyName);
+ }
- if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
- ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
+ setupPolymorphicProtoList(stubInfo);
+ if (stubInfo->u.getByIdProtoList.listSize < POLYMORPHIC_LIST_CACHE_SIZE) {
+ bool cached = JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset);
+ if (cached)
+ return JSValue::encode(result);
+ }
+ } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) {
+ ASSERT(!asCell(baseValue)->structure()->isDictionary());
+
+ setupPolymorphicProtoList(stubInfo);
+ if (stubInfo->u.getByIdProtoList.listSize < POLYMORPHIC_LIST_CACHE_SIZE) {
+ bool cached = JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, structure->prototypeChain(callFrame), count, propertyName, slot, offset);
+ if (cached)
+ return JSValue::encode(result);
+ }
}
- } else
- ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
+ }
+ ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
return JSValue::encode(result);
}
@@ -2611,16 +2626,17 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global)
STUB_INIT_STACK_FRAME(stackFrame);
CallFrame* callFrame = stackFrame.callFrame;
- JSGlobalObject* globalObject = stackFrame.args[0].globalObject();
- Identifier& ident = stackFrame.args[1].identifier();
- unsigned globalResolveInfoIndex = stackFrame.args[2].int32();
+ CodeBlock* codeBlock = callFrame->codeBlock();
+ JSGlobalObject* globalObject = codeBlock->globalObject();
+ Identifier& ident = stackFrame.args[0].identifier();
+ unsigned globalResolveInfoIndex = stackFrame.args[1].int32();
ASSERT(globalObject->isGlobalObject());
PropertySlot slot(globalObject);
if (globalObject->getPropertySlot(callFrame, ident, slot)) {
JSValue result = slot.getValue(callFrame, ident);
if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
- GlobalResolveInfo& globalResolveInfo = callFrame->codeBlock()->globalResolveInfo(globalResolveInfoIndex);
+ GlobalResolveInfo& globalResolveInfo = codeBlock->globalResolveInfo(globalResolveInfoIndex);
if (globalResolveInfo.structure)
globalResolveInfo.structure->deref();
globalObject->structure()->ref();
@@ -2633,8 +2649,8 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global)
return JSValue::encode(result);
}
- unsigned vPCIndex = callFrame->codeBlock()->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS);
- stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, callFrame->codeBlock());
+ unsigned vPCIndex = codeBlock->bytecodeOffset(callFrame, STUB_RETURN_ADDRESS);
+ stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock);
VM_THROW_EXCEPTION();
}
diff --git a/JavaScriptCore/jit/JITStubs.h b/JavaScriptCore/jit/JITStubs.h
index 306e475..94e319f 100644
--- a/JavaScriptCore/jit/JITStubs.h
+++ b/JavaScriptCore/jit/JITStubs.h
@@ -252,8 +252,8 @@ namespace JSC {
JITThunks(JSGlobalData*);
~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, bool direct);
+ static bool tryCacheGetByID(CallFrame*, CodeBlock*, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot&, StructureStubInfo* stubInfo);
+ static bool 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; }
diff --git a/JavaScriptCore/jit/JSInterfaceJIT.h b/JavaScriptCore/jit/JSInterfaceJIT.h
index c85b94d..031bfa8 100644
--- a/JavaScriptCore/jit/JSInterfaceJIT.h
+++ b/JavaScriptCore/jit/JSInterfaceJIT.h
@@ -177,7 +177,7 @@ namespace JSC {
};
struct ThunkHelpers {
- static unsigned stringImplDataOffset() { return WebCore::StringImpl::dataOffset(); }
+ static unsigned stringImplDataOffset() { return StringImpl::dataOffset(); }
static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString, m_length); }
static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString, m_value); }
};
diff --git a/JavaScriptCore/jit/SpecializedThunkJIT.h b/JavaScriptCore/jit/SpecializedThunkJIT.h
index 00f7aef..ba95498 100644
--- a/JavaScriptCore/jit/SpecializedThunkJIT.h
+++ b/JavaScriptCore/jit/SpecializedThunkJIT.h
@@ -129,7 +129,10 @@ namespace JSC {
MacroAssemblerCodePtr finalize(MacroAssemblerCodePtr fallback)
{
- LinkBuffer patchBuffer(this, m_pool.get());
+ LinkBuffer patchBuffer(this, m_pool.get(), 0);
+ // We can't continue if we can't call a function!
+ if (!patchBuffer.allocationSuccessful())
+ CRASH();
patchBuffer.link(m_failures, CodeLocationLabel(fallback));
return patchBuffer.finalizeCode().m_code;
}