diff options
Diffstat (limited to 'JavaScriptCore/jit/JITStubs.cpp')
-rw-r--r-- | JavaScriptCore/jit/JITStubs.cpp | 959 |
1 files changed, 642 insertions, 317 deletions
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp index a40d1ba..d563f58 100644 --- a/JavaScriptCore/jit/JITStubs.cpp +++ b/JavaScriptCore/jit/JITStubs.cpp @@ -56,28 +56,31 @@ #include "RegExpPrototype.h" #include "Register.h" #include "SamplingTool.h" +#include <stdarg.h> #include <stdio.h> using namespace std; namespace JSC { - #if PLATFORM(DARWIN) || PLATFORM(WIN_OS) #define SYMBOL_STRING(name) "_" #name #else #define SYMBOL_STRING(name) #name #endif +#if USE(JSVALUE32_64) + #if COMPILER(GCC) && PLATFORM(X86) // These ASSERTs remind you that, if you change the layout of JITStackFrame, you // need to change the assembly trampolines below to match. -COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_callFrame_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment); +COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x3c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline); -asm( +asm volatile ( ".globl " SYMBOL_STRING(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushl %ebp" "\n" @@ -85,11 +88,11 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushl %esi" "\n" "pushl %edi" "\n" "pushl %ebx" "\n" - "subl $0x1c, %esp" "\n" + "subl $0x3c, %esp" "\n" "movl $512, %esi" "\n" - "movl 0x38(%esp), %edi" "\n" - "call *0x30(%esp)" "\n" - "addl $0x1c, %esp" "\n" + "movl 0x58(%esp), %edi" "\n" + "call *0x50(%esp)" "\n" + "addl $0x3c, %esp" "\n" "popl %ebx" "\n" "popl %edi" "\n" "popl %esi" "\n" @@ -97,16 +100,25 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "ret" "\n" ); -asm( +asm volatile ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" #if !USE(JIT_STUB_ARGUMENT_VA_LIST) "movl %esp, %ecx" "\n" #endif "call " SYMBOL_STRING(cti_vm_throw) "\n" + "addl $0x3c, %esp" "\n" + "popl %ebx" "\n" + "popl %edi" "\n" + "popl %esi" "\n" + "popl %ebp" "\n" + "ret" "\n" +); + +asm volatile ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" - "addl $0x1c, %esp" "\n" + "addl $0x3c, %esp" "\n" "popl %ebx" "\n" "popl %edi" "\n" "popl %esi" "\n" @@ -122,11 +134,12 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" // These ASSERTs remind you that, if you change the layout of JITStackFrame, you // need to change the assembly trampolines below to match. +COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 32 == 0x0, JITStackFrame_maintains_32byte_stack_alignment); +COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x48, JITStackFrame_stub_argument_space_matches_ctiTrampoline); COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x90, JITStackFrame_callFrame_offset_matches_ctiTrampoline); COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x80, JITStackFrame_code_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x48, JITStackFrame_stub_argument_space_matches_ctiTrampoline); -asm( +asm volatile ( ".globl " SYMBOL_STRING(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushq %rbp" "\n" @@ -152,11 +165,22 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "ret" "\n" ); -asm( +asm volatile ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movq %rsp, %rdi" "\n" "call " SYMBOL_STRING(cti_vm_throw) "\n" + "addq $0x48, %rsp" "\n" + "popq %rbx" "\n" + "popq %r15" "\n" + "popq %r14" "\n" + "popq %r13" "\n" + "popq %r12" "\n" + "popq %rbp" "\n" + "ret" "\n" +); + +asm volatile ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "addq $0x48, %rsp" "\n" @@ -169,24 +193,13 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "ret" "\n" ); -#elif COMPILER(GCC) && PLATFORM(ARM_V7) +#elif COMPILER(GCC) && PLATFORM_ARM_ARCH(7) #if USE(JIT_STUB_ARGUMENT_VA_LIST) #error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7." #endif -COMPILE_ASSERT(offsetof(struct JITStackFrame, preservedReturnAddress) == 0x20, JITStackFrame_outerReturnAddress_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, preservedR4) == 0x24, JITStackFrame_outerReturnAddress_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, preservedR5) == 0x28, JITStackFrame_outerReturnAddress_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, preservedR6) == 0x2c, JITStackFrame_outerReturnAddress_offset_matches_ctiTrampoline); - -COMPILE_ASSERT(offsetof(struct JITStackFrame, registerFile) == 0x30, JITStackFrame_registerFile_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x34, JITStackFrame_callFrame_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, exception) == 0x38, JITStackFrame_exception_offset_matches_ctiTrampoline); -// The fifth argument is the first item already on the stack. -COMPILE_ASSERT(offsetof(struct JITStackFrame, enabledProfilerReference) == 0x3c, JITStackFrame_enabledProfilerReference_offset_matches_ctiTrampoline); - -asm volatile ( +asm volatile ( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" @@ -252,9 +265,10 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" // These ASSERTs remind you that, if you change the layout of JITStackFrame, you // need to change the assembly trampolines below to match. -COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_callFrame_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment); +COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x3c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline); extern "C" { @@ -266,12 +280,12 @@ extern "C" { push esi; push edi; push ebx; - sub esp, 0x1c; + sub esp, 0x3c; mov esi, 512; mov ecx, esp; - mov edi, [esp + 0x38]; - call [esp + 0x30]; - add esp, 0x1c; + mov edi, [esp + 0x58]; + call [esp + 0x50]; + add esp, 0x3c; pop ebx; pop edi; pop esi; @@ -284,8 +298,8 @@ extern "C" { { __asm { mov ecx, esp; - call JITStubs::cti_vm_throw; - add esp, 0x1c; + call cti_vm_throw; + add esp, 0x3c; pop ebx; pop edi; pop esi; @@ -297,7 +311,7 @@ extern "C" { __declspec(naked) void ctiOpThrowNotCaught() { __asm { - add esp, 0x1c; + add esp, 0x3c; pop ebx; pop edi; pop esi; @@ -307,8 +321,311 @@ extern "C" { } } +#endif // COMPILER(GCC) && PLATFORM(X86) + +#else // USE(JSVALUE32_64) + +#if COMPILER(GCC) && PLATFORM(X86) + +// These ASSERTs remind you that, if you change the layout of JITStackFrame, you +// need to change the assembly trampolines below to match. +COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_callFrame_offset_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_offset_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); + +asm volatile ( +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +SYMBOL_STRING(ctiTrampoline) ":" "\n" + "pushl %ebp" "\n" + "movl %esp, %ebp" "\n" + "pushl %esi" "\n" + "pushl %edi" "\n" + "pushl %ebx" "\n" + "subl $0x1c, %esp" "\n" + "movl $512, %esi" "\n" + "movl 0x38(%esp), %edi" "\n" + "call *0x30(%esp)" "\n" + "addl $0x1c, %esp" "\n" + "popl %ebx" "\n" + "popl %edi" "\n" + "popl %esi" "\n" + "popl %ebp" "\n" + "ret" "\n" +); + +asm volatile ( +".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" +#if !USE(JIT_STUB_ARGUMENT_VA_LIST) + "movl %esp, %ecx" "\n" +#endif + "call " SYMBOL_STRING(cti_vm_throw) "\n" + "addl $0x1c, %esp" "\n" + "popl %ebx" "\n" + "popl %edi" "\n" + "popl %esi" "\n" + "popl %ebp" "\n" + "ret" "\n" +); + +asm volatile ( +".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" + "addl $0x1c, %esp" "\n" + "popl %ebx" "\n" + "popl %edi" "\n" + "popl %esi" "\n" + "popl %ebp" "\n" + "ret" "\n" +); + +#elif COMPILER(GCC) && PLATFORM(X86_64) + +#if USE(JIT_STUB_ARGUMENT_VA_LIST) +#error "JIT_STUB_ARGUMENT_VA_LIST not supported on x86-64." #endif +// These ASSERTs remind you that, if you change the layout of JITStackFrame, you +// need to change the assembly trampolines below to match. +COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x48, JITStackFrame_code_offset_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x78, JITStackFrame_stub_argument_space_matches_ctiTrampoline); + +asm volatile ( +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +SYMBOL_STRING(ctiTrampoline) ":" "\n" + "pushq %rbp" "\n" + "movq %rsp, %rbp" "\n" + "pushq %r12" "\n" + "pushq %r13" "\n" + "pushq %r14" "\n" + "pushq %r15" "\n" + "pushq %rbx" "\n" + // Form the JIT stubs area + "pushq %r9" "\n" + "pushq %r8" "\n" + "pushq %rcx" "\n" + "pushq %rdx" "\n" + "pushq %rsi" "\n" + "pushq %rdi" "\n" + "subq $0x48, %rsp" "\n" + "movq $512, %r12" "\n" + "movq $0xFFFF000000000000, %r14" "\n" + "movq $0xFFFF000000000002, %r15" "\n" + "movq %rdx, %r13" "\n" + "call *%rdi" "\n" + "addq $0x78, %rsp" "\n" + "popq %rbx" "\n" + "popq %r15" "\n" + "popq %r14" "\n" + "popq %r13" "\n" + "popq %r12" "\n" + "popq %rbp" "\n" + "ret" "\n" +); + +asm volatile ( +".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" + "movq %rsp, %rdi" "\n" + "call " SYMBOL_STRING(cti_vm_throw) "\n" + "addq $0x78, %rsp" "\n" + "popq %rbx" "\n" + "popq %r15" "\n" + "popq %r14" "\n" + "popq %r13" "\n" + "popq %r12" "\n" + "popq %rbp" "\n" + "ret" "\n" +); + +asm volatile ( +".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" + "addq $0x78, %rsp" "\n" + "popq %rbx" "\n" + "popq %r15" "\n" + "popq %r14" "\n" + "popq %r13" "\n" + "popq %r12" "\n" + "popq %rbp" "\n" + "ret" "\n" +); + +#elif COMPILER(GCC) && PLATFORM_ARM_ARCH(7) + +#if USE(JIT_STUB_ARGUMENT_VA_LIST) +#error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7." +#endif + +asm volatile ( +".text" "\n" +".align 2" "\n" +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +".thumb" "\n" +".thumb_func " SYMBOL_STRING(ctiTrampoline) "\n" +SYMBOL_STRING(ctiTrampoline) ":" "\n" + "sub sp, sp, #0x3c" "\n" + "str lr, [sp, #0x20]" "\n" + "str r4, [sp, #0x24]" "\n" + "str r5, [sp, #0x28]" "\n" + "str r6, [sp, #0x2c]" "\n" + "str r1, [sp, #0x30]" "\n" + "str r2, [sp, #0x34]" "\n" + "str r3, [sp, #0x38]" "\n" + "cpy r5, r2" "\n" + "mov r6, #512" "\n" + "blx r0" "\n" + "ldr r6, [sp, #0x2c]" "\n" + "ldr r5, [sp, #0x28]" "\n" + "ldr r4, [sp, #0x24]" "\n" + "ldr lr, [sp, #0x20]" "\n" + "add sp, sp, #0x3c" "\n" + "bx lr" "\n" +); + +asm volatile ( +".text" "\n" +".align 2" "\n" +".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +".thumb" "\n" +".thumb_func " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" + "cpy r0, sp" "\n" + "bl " SYMBOL_STRING(cti_vm_throw) "\n" + "ldr r6, [sp, #0x2c]" "\n" + "ldr r5, [sp, #0x28]" "\n" + "ldr r4, [sp, #0x24]" "\n" + "ldr lr, [sp, #0x20]" "\n" + "add sp, sp, #0x3c" "\n" + "bx lr" "\n" +); + +asm volatile ( +".text" "\n" +".align 2" "\n" +".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +".thumb" "\n" +".thumb_func " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" + "ldr r6, [sp, #0x2c]" "\n" + "ldr r5, [sp, #0x28]" "\n" + "ldr r4, [sp, #0x24]" "\n" + "ldr lr, [sp, #0x20]" "\n" + "add sp, sp, #0x3c" "\n" + "bx lr" "\n" +); + +#elif COMPILER(GCC) && PLATFORM(ARM) + +asm volatile ( +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +SYMBOL_STRING(ctiTrampoline) ":" "\n" + "stmdb sp!, {r1-r3}" "\n" + "stmdb sp!, {r4-r8, lr}" "\n" + "mov r6, pc" "\n" + "add r6, r6, #40" "\n" + "sub sp, sp, #32" "\n" + "ldr r4, [sp, #60]" "\n" + "mov r5, #512" "\n" + // r0 contains the code + "add r8, pc, #4" "\n" + "str r8, [sp, #-4]!" "\n" + "mov pc, r0" "\n" + "add sp, sp, #32" "\n" + "ldmia sp!, {r4-r8, lr}" "\n" + "add sp, sp, #12" "\n" + "mov pc, lr" "\n" + + // the return instruction + "ldr pc, [sp], #4" "\n" +); + +asm volatile ( +".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" + "mov r0, sp" "\n" + "mov lr, r6" "\n" + "add r8, pc, #4" "\n" + "str r8, [sp, #-4]!" "\n" + "b " SYMBOL_STRING(cti_vm_throw) "\n" + +// Both has the same return sequence +".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" + "add sp, sp, #32" "\n" + "ldmia sp!, {r4-r8, lr}" "\n" + "add sp, sp, #12" "\n" + "mov pc, lr" "\n" +); + +#elif COMPILER(MSVC) + +#if USE(JIT_STUB_ARGUMENT_VA_LIST) +#error "JIT_STUB_ARGUMENT_VA_LIST configuration not supported on MSVC." +#endif + +// These ASSERTs remind you that, if you change the layout of JITStackFrame, you +// need to change the assembly trampolines below to match. +COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_callFrame_offset_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_offset_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); + +extern "C" { + + __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue* exception, Profiler**, JSGlobalData*) + { + __asm { + push ebp; + mov ebp, esp; + push esi; + push edi; + push ebx; + sub esp, 0x1c; + mov esi, 512; + mov ecx, esp; + mov edi, [esp + 0x38]; + call [esp + 0x30]; + add esp, 0x1c; + pop ebx; + pop edi; + pop esi; + pop ebp; + ret; + } + } + + __declspec(naked) void ctiVMThrowTrampoline() + { + __asm { + mov ecx, esp; + call cti_vm_throw; + add esp, 0x1c; + pop ebx; + pop edi; + pop esi; + pop ebp; + ret; + } + } + + __declspec(naked) void ctiOpThrowNotCaught() + { + __asm { + add esp, 0x1c; + pop ebx; + pop edi; + pop esi; + pop ebp; + ret; + } + } +} + +#endif // COMPILER(GCC) && PLATFORM(X86) + +#endif // USE(JSVALUE32_64) + #if ENABLE(OPCODE_SAMPLING) #define CTI_SAMPLER stackFrame.globalData->interpreter->sampler() #else @@ -317,12 +634,30 @@ extern "C" { JITThunks::JITThunks(JSGlobalData* globalData) { - JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_ctiArrayLengthTrampoline, &m_ctiStringLengthTrampoline, &m_ctiVirtualCallPreLink, &m_ctiVirtualCallLink, &m_ctiVirtualCall, &m_ctiNativeCallThunk); + JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_ctiStringLengthTrampoline, &m_ctiVirtualCallLink, &m_ctiVirtualCall, &m_ctiNativeCallThunk); + +#if PLATFORM_ARM_ARCH(7) + // Unfortunate the arm compiler does not like the use of offsetof on JITStackFrame (since it contains non POD types), + // and the OBJECT_OFFSETOF macro does not appear constantish enough for it to be happy with its use in COMPILE_ASSERT + // macros. + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == 0x20); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == 0x24); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR5) == 0x28); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR6) == 0x2c); + + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == 0x30); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == 0x34); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, exception) == 0x38); + // The fifth argument is the first item already on the stack. + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == 0x3c); + + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == 0x1C); +#endif } #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) -NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, void* returnAddress, JSValue baseValue, const PutPropertySlot& slot) +NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo) { // The interpreter checks for recursion here; I do not believe this can occur in CTI. @@ -331,7 +666,7 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co // Uncacheable: give up. if (!slot.isCacheable()) { - ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); return; } @@ -339,23 +674,25 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co Structure* structure = baseCell->structure(); if (structure->isDictionary()) { - ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); return; } // If baseCell != base, then baseCell must be a proxy for another object. if (baseCell != slot.base()) { - ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); return; } - StructureStubInfo* stubInfo = &codeBlock->getStubInfo(returnAddress); - // Cache hit: Specialize instruction and ref Structures. // Structure transition, cache transition info if (slot.type() == PutPropertySlot::NewProperty) { StructureChain* prototypeChain = structure->prototypeChain(callFrame); + if (!prototypeChain->isCacheable()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + return; + } stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain); JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress); return; @@ -363,17 +700,17 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co stubInfo->initPutByIdReplace(structure); - JIT::patchPutByIdReplace(stubInfo, structure, slot.cachedOffset(), returnAddress); + JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); } -NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, void* returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot) +NEVER_INLINE void 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(returnAddress, FunctionPtr(JITStubs::cti_op_get_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -387,13 +724,13 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co 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(returnAddress, globalData->jitStubs.ctiStringLengthTrampoline()); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, globalData->jitStubs.ctiStringLengthTrampoline()); return; } // Uncacheable: give up. if (!slot.isCacheable()) { - ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_get_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -401,22 +738,17 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co Structure* structure = baseCell->structure(); if (structure->isDictionary()) { - ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_get_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } - // In the interpreter the last structure is trapped here; in CTI we use the - // *_second method to achieve a similar (but not quite the same) effect. - - StructureStubInfo* stubInfo = &codeBlock->getStubInfo(returnAddress); - // Cache hit: Specialize instruction and ref Structures. if (slot.slotBase() == baseValue) { // set this up, so derefStructures can do it's job. stubInfo->initGetByIdSelf(structure); - JIT::patchGetByIdSelf(stubInfo, structure, slot.cachedOffset(), returnAddress); + JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); return; } @@ -438,16 +770,20 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot); if (!count) { - stubInfo->opcodeID = op_get_by_id_generic; + stubInfo->accessType = access_get_by_id_generic; return; } StructureChain* prototypeChain = structure->prototypeChain(callFrame); + if (!prototypeChain->isCacheable()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); + return; + } stubInfo->initGetByIdChain(structure, prototypeChain); JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, slot.cachedOffset(), returnAddress); } -#endif +#endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) #if USE(JIT_STUB_ARGUMENT_VA_LIST) #define SETUP_VA_LISTL_ARGS va_list vl_args; va_start(vl_args, args) @@ -473,7 +809,7 @@ struct StackHack { : stackFrame(stackFrame) , savedReturnAddress(*stackFrame.returnAddressSlot()) { - *stackFrame.returnAddressSlot() = reinterpret_cast<void*>(jscGeneratedNativeCode); + *stackFrame.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode)); } ALWAYS_INLINE ~StackHack() @@ -482,17 +818,17 @@ struct StackHack { } JITStackFrame& stackFrame; - void* savedReturnAddress; + ReturnAddressPtr savedReturnAddress; }; #define STUB_INIT_STACK_FRAME(stackFrame) SETUP_VA_LISTL_ARGS; JITStackFrame& stackFrame = *reinterpret_cast<JITStackFrame*>(STUB_ARGS); StackHack stackHack(stackFrame) -#define STUB_SET_RETURN_ADDRESS(returnAddress) stackHack.savedReturnAddress = returnAddress +#define STUB_SET_RETURN_ADDRESS(returnAddress) stackHack.savedReturnAddress = ReturnAddressPtr(returnAddress) #define STUB_RETURN_ADDRESS stackHack.savedReturnAddress #else #define STUB_INIT_STACK_FRAME(stackFrame) SETUP_VA_LISTL_ARGS; JITStackFrame& stackFrame = *reinterpret_cast<JITStackFrame*>(STUB_ARGS) -#define STUB_SET_RETURN_ADDRESS(returnAddress) *stackFrame.returnAddressSlot() = returnAddress +#define STUB_SET_RETURN_ADDRESS(returnAddress) *stackFrame.returnAddressSlot() = ReturnAddressPtr(returnAddress) #define STUB_RETURN_ADDRESS *stackFrame.returnAddressSlot() #endif @@ -501,14 +837,14 @@ struct StackHack { // to get the address of the ctiVMThrowTrampoline function. It's also // good to keep the code size down by leaving as much of the exception // handling code out of line as possible. -static NEVER_INLINE void returnToThrowTrampoline(JSGlobalData* globalData, void* exceptionLocation, void*& returnAddressSlot) +static NEVER_INLINE void returnToThrowTrampoline(JSGlobalData* globalData, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot) { ASSERT(globalData->exception); globalData->exceptionLocation = exceptionLocation; - returnAddressSlot = reinterpret_cast<void*>(ctiVMThrowTrampoline); + returnAddressSlot = ReturnAddressPtr(FunctionPtr(ctiVMThrowTrampoline)); } -static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalData* globalData, void* exceptionLocation, void*& returnAddressSlot) +static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalData* globalData, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot) { globalData->exception = createStackOverflowError(callFrame); returnToThrowTrampoline(globalData, exceptionLocation, returnAddressSlot); @@ -524,27 +860,23 @@ static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalD #define CHECK_FOR_EXCEPTION() \ do { \ - if (UNLIKELY(stackFrame.globalData->exception != JSValue())) \ + if (UNLIKELY(stackFrame.globalData->exception)) \ VM_THROW_EXCEPTION(); \ } while (0) #define CHECK_FOR_EXCEPTION_AT_END() \ do { \ - if (UNLIKELY(stackFrame.globalData->exception != JSValue())) \ + if (UNLIKELY(stackFrame.globalData->exception)) \ VM_THROW_EXCEPTION_AT_END(); \ } while (0) #define CHECK_FOR_EXCEPTION_VOID() \ do { \ - if (UNLIKELY(stackFrame.globalData->exception != JSValue())) { \ + if (UNLIKELY(stackFrame.globalData->exception)) { \ VM_THROW_EXCEPTION_AT_END(); \ return; \ } \ } while (0) -namespace JITStubs { - -#if PLATFORM(ARM_V7) - -COMPILE_ASSERT(offsetof(struct JITStackFrame, thunkReturnAddress) == 0x1C, JITStackFrame_outerReturnAddress_offset_matches_ctiTrampoline); +#if PLATFORM_ARM_ARCH(7) #define DEFINE_STUB_FUNCTION(rtype, op) \ extern "C" { \ @@ -568,7 +900,7 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, thunkReturnAddress) == 0x1C, JITSt #define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION) #endif -DEFINE_STUB_FUNCTION(JSObject*, op_convert_this) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this) { STUB_INIT_STACK_FRAME(stackFrame); @@ -577,7 +909,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_convert_this) JSObject* result = v1.toThisObject(callFrame); CHECK_FOR_EXCEPTION_AT_END(); - return result; + return JSValue::encode(result); } DEFINE_STUB_FUNCTION(void, op_end) @@ -617,8 +949,8 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_add) } if (rightIsNumber & leftIsString) { - RefPtr<UString::Rep> value = v2.isInt32Fast() ? - concatenate(asString(v1)->value().rep(), v2.getInt32Fast()) : + RefPtr<UString::Rep> value = v2.isInt32() ? + concatenate(asString(v1)->value().rep(), v2.asInt32()) : concatenate(asString(v1)->value().rep(), right); if (UNLIKELY(!value)) { @@ -672,7 +1004,7 @@ DEFINE_STUB_FUNCTION(void, register_file_check) // moved the call frame forward. CallFrame* oldCallFrame = stackFrame.callFrame->callerFrame(); stackFrame.callFrame = oldCallFrame; - throwStackOverflowError(oldCallFrame, stackFrame.globalData, oldCallFrame->returnPC(), STUB_RETURN_ADDRESS); + throwStackOverflowError(oldCallFrame, stackFrame.globalData, ReturnAddressPtr(oldCallFrame->returnPC()), STUB_RETURN_ADDRESS); } DEFINE_STUB_FUNCTION(int, op_loop_if_less) @@ -737,25 +1069,19 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_generic) DEFINE_STUB_FUNCTION(void, op_put_by_id) { STUB_INIT_STACK_FRAME(stackFrame); - CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); PutPropertySlot slot; stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot); - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_id_second)); - - CHECK_FOR_EXCEPTION_AT_END(); -} - -DEFINE_STUB_FUNCTION(void, op_put_by_id_second) -{ - STUB_INIT_STACK_FRAME(stackFrame); + CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); + StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); + if (!stubInfo->seenOnce()) + stubInfo->setSeen(); + else + JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo); - PutPropertySlot slot; - stackFrame.args[0].jsValue().put(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot); - JITThunks::tryCachePutByID(stackFrame.callFrame, stackFrame.callFrame->codeBlock(), STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot); CHECK_FOR_EXCEPTION_AT_END(); } @@ -772,36 +1098,19 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_fail) CHECK_FOR_EXCEPTION_AT_END(); } - -DEFINE_STUB_FUNCTION(EncodedJSValue, op_put_by_id_transition_realloc) +DEFINE_STUB_FUNCTION(JSObject*, op_put_by_id_transition_realloc) { STUB_INIT_STACK_FRAME(stackFrame); JSValue baseValue = stackFrame.args[0].jsValue(); - int32_t oldSize = stackFrame.args[1].int32(); - int32_t newSize = stackFrame.args[2].int32(); + int32_t oldSize = stackFrame.args[3].int32(); + int32_t newSize = stackFrame.args[4].int32(); ASSERT(baseValue.isObject()); - asObject(baseValue)->allocatePropertyStorage(oldSize, newSize); + JSObject* base = asObject(baseValue); + base->allocatePropertyStorage(oldSize, newSize); - return JSValue::encode(baseValue); -} - -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - CallFrame* callFrame = stackFrame.callFrame; - Identifier& ident = stackFrame.args[1].identifier(); - - JSValue baseValue = stackFrame.args[0].jsValue(); - PropertySlot slot(baseValue); - JSValue result = baseValue.get(callFrame, ident, slot); - - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_second)); - - CHECK_FOR_EXCEPTION_AT_END(); - return JSValue::encode(result); + return base; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) @@ -814,25 +1123,15 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(callFrame, ident, slot); + CHECK_FOR_EXCEPTION(); - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_method_check_second)); - - CHECK_FOR_EXCEPTION_AT_END(); - return JSValue::encode(result); -} - -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check_second) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - CallFrame* callFrame = stackFrame.callFrame; - Identifier& ident = stackFrame.args[1].identifier(); - - JSValue baseValue = stackFrame.args[0].jsValue(); - PropertySlot slot(baseValue); - JSValue result = baseValue.get(callFrame, ident, slot); + CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); + MethodCallLinkInfo& methodCallLinkInfo = codeBlock->getMethodCallLinkInfo(STUB_RETURN_ADDRESS); - CHECK_FOR_EXCEPTION(); + if (!methodCallLinkInfo.seenOnce()) { + methodCallLinkInfo.setSeen(); + return JSValue::encode(result); + } // If we successfully got something, then the base from which it is being accessed must // be an object. (Assertion to ensure asObject() call below is safe, which comes after @@ -863,33 +1162,33 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check_second) // The result fetched should always be the callee! ASSERT(result == JSValue(callee)); - MethodCallLinkInfo& methodCallLinkInfo = callFrame->codeBlock()->getMethodCallLinkInfo(STUB_RETURN_ADDRESS); // Check to see if the function is on the object's prototype. Patch up the code to optimize. - if (slot.slotBase() == structure->prototypeForLookup(callFrame)) - JIT::patchMethodCallProto(methodCallLinkInfo, callee, structure, slotBaseObject); + if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { + JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, slotBaseObject, STUB_RETURN_ADDRESS); + return JSValue::encode(result); + } + // Check to see if the function is on the object itself. // Since we generate the method-check to check both the structure and a prototype-structure (since this // is the common case) we have a problem - we need to patch the prototype structure check to do something // useful. We could try to nop it out altogether, but that's a little messy, so lets do something simpler // for now. For now it performs a check on a special object on the global object only used for this // purpose. The object is in no way exposed, and as such the check will always pass. - else if (slot.slotBase() == baseValue) - JIT::patchMethodCallProto(methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject()->methodCallDummy()); - - // For now let any other case be cached as a normal get_by_id. + if (slot.slotBase() == baseValue) { + JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject()->methodCallDummy(), STUB_RETURN_ADDRESS); + return JSValue::encode(result); + } } // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to. - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id)); - + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id)); return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_second) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id) { STUB_INIT_STACK_FRAME(stackFrame); - CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); @@ -897,7 +1196,12 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_second) PropertySlot slot(baseValue); JSValue result = baseValue.get(callFrame, ident, slot); - JITThunks::tryCacheGetByID(callFrame, callFrame->codeBlock(), STUB_RETURN_ADDRESS, baseValue, ident, slot); + CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); + StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); + if (!stubInfo->seenOnce()) + stubInfo->setSeen(); + else + JITThunks::tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); @@ -929,9 +1233,9 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail) PolymorphicAccessStructureList* polymorphicStructureList; int listIndex = 1; - if (stubInfo->opcodeID == op_get_by_id_self) { + if (stubInfo->accessType == access_get_by_id_self) { ASSERT(!stubInfo->stubRoutine); - polymorphicStructureList = new PolymorphicAccessStructureList(MacroAssembler::CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure); + polymorphicStructureList = new PolymorphicAccessStructureList(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure); stubInfo->initGetByIdSelfList(polymorphicStructureList, 2); } else { polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList; @@ -942,10 +1246,9 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail) JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), slot.cachedOffset()); if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); - } else { - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); - } + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); + } else + ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); return JSValue::encode(result); } @@ -954,18 +1257,18 @@ static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(Str PolymorphicAccessStructureList* prototypeStructureList = 0; listIndex = 1; - switch (stubInfo->opcodeID) { - case op_get_by_id_proto: + switch (stubInfo->accessType) { + case access_get_by_id_proto: prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure); - stubInfo->stubRoutine.reset(); + stubInfo->stubRoutine = CodeLocationLabel(); stubInfo->initGetByIdProtoList(prototypeStructureList, 2); break; - case op_get_by_id_chain: + case access_get_by_id_chain: prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain); - stubInfo->stubRoutine.reset(); + stubInfo->stubRoutine = CodeLocationLabel(); stubInfo->initGetByIdProtoList(prototypeStructureList, 2); break; - case op_get_by_id_proto_list: + case access_get_by_id_proto_list: prototypeStructureList = stubInfo->u.getByIdProtoList.structureList; listIndex = stubInfo->u.getByIdProtoList.listSize; stubInfo->u.getByIdProtoList.listSize++; @@ -991,7 +1294,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) CHECK_FOR_EXCEPTION(); if (!baseValue.isCell() || !slot.isCacheable() || asCell(baseValue)->structure()->isDictionary()) { - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); + ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); return JSValue::encode(result); } @@ -1003,7 +1306,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) JSObject* slotBaseObject = asObject(slot.slotBase()); if (slot.slotBase() == baseValue) - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) { // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. @@ -1016,16 +1319,22 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), slot.cachedOffset()); if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); } else if (size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot)) { + StructureChain* protoChain = structure->prototypeChain(callFrame); + if (!protoChain->isCacheable()) { + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); + return JSValue::encode(result); + } + int listIndex; PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); - JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, structure->prototypeChain(callFrame), count, slot.cachedOffset()); + JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, slot.cachedOffset()); if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); } else - ctiPatchCallByReturnAddress(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); } @@ -1078,7 +1387,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_string_fail) return JSValue::encode(result); } -#endif +#endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof) { @@ -1171,6 +1480,7 @@ DEFINE_STUB_FUNCTION(void*, op_call_JSFunction) #endif JSFunction* function = asFunction(stackFrame.args[0].jsValue()); + ASSERT(!function->isHostFunction()); FunctionBodyNode* body = function->body(); ScopeChainNode* callDataScopeChain = function->scope().node(); body->jitCode(callDataScopeChain); @@ -1184,6 +1494,7 @@ DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck) CallFrame* callFrame = stackFrame.callFrame; CodeBlock* newCodeBlock = stackFrame.args[3].codeBlock(); + ASSERT(newCodeBlock->codeType() != NativeCode); int argCount = stackFrame.args[2].int32(); ASSERT(argCount != newCodeBlock->m_numParameters); @@ -1223,34 +1534,28 @@ DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck) RETURN_POINTER_PAIR(newCodeBlock, callFrame); } -DEFINE_STUB_FUNCTION(void*, vm_dontLazyLinkCall) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - JSGlobalData* globalData = stackFrame.globalData; - JSFunction* callee = asFunction(stackFrame.args[0].jsValue()); - - ctiPatchNearCallByReturnAddress(stackFrame.args[1].returnAddress(), globalData->jitStubs.ctiVirtualCallLink()); - - return callee->body()->generatedJITCode().addressForCall().executableAddress(); -} - +#if ENABLE(JIT_OPTIMIZE_CALL) DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall) { STUB_INIT_STACK_FRAME(stackFrame); - JSFunction* callee = asFunction(stackFrame.args[0].jsValue()); JITCode& jitCode = callee->body()->generatedJITCode(); CodeBlock* codeBlock = 0; if (!callee->isHostFunction()) codeBlock = &callee->body()->bytecode(callee->scope().node()); - + else + codeBlock = &callee->body()->generatedBytecode(); CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(stackFrame.args[1].returnAddress()); - JIT::linkCall(callee, codeBlock, jitCode, callLinkInfo, stackFrame.args[2].int32()); + + if (!callLinkInfo->seenOnce()) + callLinkInfo->setSeen(); + else + JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, jitCode, callLinkInfo, stackFrame.args[2].int32(), stackFrame.globalData); return jitCode.addressForCall().executableAddress(); } +#endif // !ENABLE(JIT_OPTIMIZE_CALL) DEFINE_STUB_FUNCTION(JSObject*, op_push_activation) { @@ -1278,7 +1583,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction) CallFrame* previousCallFrame = stackFrame.callFrame; CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset); - callFrame->init(0, static_cast<Instruction*>(STUB_RETURN_ADDRESS), previousCallFrame->scopeChain(), previousCallFrame, 0, argCount, 0); + callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, 0, argCount, 0); stackFrame.callFrame = callFrame; Register* argv = stackFrame.callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount; @@ -1316,7 +1621,7 @@ DEFINE_STUB_FUNCTION(void, op_create_arguments) Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame); stackFrame.callFrame->setCalleeArguments(arguments); - stackFrame.callFrame[RegisterFile::ArgumentsRegister] = arguments; + stackFrame.callFrame[RegisterFile::ArgumentsRegister] = JSValue(arguments); } DEFINE_STUB_FUNCTION(void, op_create_arguments_no_params) @@ -1325,7 +1630,7 @@ DEFINE_STUB_FUNCTION(void, op_create_arguments_no_params) Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame, Arguments::NoParameters); stackFrame.callFrame->setCalleeArguments(arguments); - stackFrame.callFrame[RegisterFile::ArgumentsRegister] = arguments; + stackFrame.callFrame[RegisterFile::ArgumentsRegister] = JSValue(arguments); } DEFINE_STUB_FUNCTION(void, op_tear_off_activation) @@ -1477,8 +1782,8 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val) JSValue result; - if (LIKELY(subscript.isUInt32Fast())) { - uint32_t i = subscript.getUInt32Fast(); + if (LIKELY(subscript.isUInt32())) { + uint32_t i = subscript.asUInt32(); if (isJSArray(globalData, baseValue)) { JSArray* jsArray = asArray(baseValue); if (jsArray->canGetIndex(i)) @@ -1487,11 +1792,11 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val) result = jsArray->JSArray::get(callFrame, i); } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) { // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_string)); + ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_string)); result = asString(baseValue)->getIndex(stackFrame.globalData, i); } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_byte_array)); + ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_byte_array)); return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i)); } else result = baseValue.get(callFrame, i); @@ -1516,14 +1821,14 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_string) JSValue result; - if (LIKELY(subscript.isUInt32Fast())) { - uint32_t i = subscript.getUInt32Fast(); + if (LIKELY(subscript.isUInt32())) { + uint32_t i = subscript.asUInt32(); if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) result = asString(baseValue)->getIndex(stackFrame.globalData, i); else { result = baseValue.get(callFrame, i); if (!isJSString(globalData, baseValue)) - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val)); + ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val)); } } else { Identifier property(callFrame, subscript.toString(callFrame)); @@ -1534,7 +1839,6 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_string) return JSValue::encode(result); } - DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_byte_array) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1547,8 +1851,8 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_byte_array) JSValue result; - if (LIKELY(subscript.isUInt32Fast())) { - uint32_t i = subscript.getUInt32Fast(); + if (LIKELY(subscript.isUInt32())) { + uint32_t i = subscript.asUInt32(); if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i)); @@ -1556,7 +1860,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_byte_array) result = baseValue.get(callFrame, i); if (!isJSByteArray(globalData, baseValue)) - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val)); + ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val)); } else { Identifier property(callFrame, subscript.toString(callFrame)); result = baseValue.get(callFrame, property); @@ -1566,50 +1870,6 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_byte_array) return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_func) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - CallFrame* callFrame = stackFrame.callFrame; - ScopeChainNode* scopeChain = callFrame->scopeChain(); - - ScopeChainIterator iter = scopeChain->begin(); - ScopeChainIterator end = scopeChain->end(); - - // FIXME: add scopeDepthIsZero optimization - - ASSERT(iter != end); - - Identifier& ident = stackFrame.args[0].identifier(); - JSObject* base; - do { - base = *iter; - PropertySlot slot(base); - if (base->getPropertySlot(callFrame, ident, slot)) { - // ECMA 11.2.3 says that if we hit an activation the this value should be null. - // However, section 10.2.3 says that in the case where the value provided - // by the caller is null, the global object should be used. It also says - // that the section does not apply to internal functions, but for simplicity - // of implementation we use the global object anyway here. This guarantees - // that in host objects you always get a valid object for this. - // We also handle wrapper substitution for the global object at the same time. - JSObject* thisObj = base->toThisObject(callFrame); - JSValue result = slot.getValue(callFrame, ident); - CHECK_FOR_EXCEPTION_AT_END(); - - callFrame->registers()[stackFrame.args[1].int32()] = JSValue(thisObj); - return JSValue::encode(result); - } - ++iter; - } while (iter != end); - - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock); - VM_THROW_EXCEPTION_AT_END(); - return JSValue::encode(JSValue()); -} - DEFINE_STUB_FUNCTION(EncodedJSValue, op_sub) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1639,8 +1899,8 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val) JSValue subscript = stackFrame.args[1].jsValue(); JSValue value = stackFrame.args[2].jsValue(); - if (LIKELY(subscript.isUInt32Fast())) { - uint32_t i = subscript.getUInt32Fast(); + if (LIKELY(subscript.isUInt32())) { + uint32_t i = subscript.asUInt32(); if (isJSArray(globalData, baseValue)) { JSArray* jsArray = asArray(baseValue); if (jsArray->canSetIndex(i)) @@ -1649,10 +1909,10 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val) jsArray->JSArray::put(callFrame, i, value); } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { JSByteArray* jsByteArray = asByteArray(baseValue); - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val_byte_array)); + ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val_byte_array)); // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. - if (value.isInt32Fast()) { - jsByteArray->setIndex(i, value.getInt32Fast()); + if (value.isInt32()) { + jsByteArray->setIndex(i, value.asInt32()); return; } else { double dValue = 0; @@ -1690,14 +1950,9 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val_array) if (LIKELY(i >= 0)) asArray(baseValue)->JSArray::put(callFrame, i, value); else { - // This should work since we're re-boxing an immediate unboxed in JIT code. - ASSERT(JSValue::makeInt32Fast(i)); - Identifier property(callFrame, JSValue::makeInt32Fast(i).toString(callFrame)); - // FIXME: can toString throw an exception here? - if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception. - PutPropertySlot slot; - baseValue.put(callFrame, property, value, slot); - } + Identifier property(callFrame, UString::from(i)); + PutPropertySlot slot; + baseValue.put(callFrame, property, value, slot); } CHECK_FOR_EXCEPTION_AT_END(); @@ -1714,14 +1969,14 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array) JSValue subscript = stackFrame.args[1].jsValue(); JSValue value = stackFrame.args[2].jsValue(); - if (LIKELY(subscript.isUInt32Fast())) { - uint32_t i = subscript.getUInt32Fast(); + if (LIKELY(subscript.isUInt32())) { + uint32_t i = subscript.asUInt32(); if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { JSByteArray* jsByteArray = asByteArray(baseValue); // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. - if (value.isInt32Fast()) { - jsByteArray->setIndex(i, value.getInt32Fast()); + if (value.isInt32()) { + jsByteArray->setIndex(i, value.asInt32()); return; } else { double dValue = 0; @@ -1733,7 +1988,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array) } if (!isJSByteArray(globalData, baseValue)) - ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val)); + ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val)); baseValue.put(callFrame, i, value); } else { Identifier property(callFrame, subscript.toString(callFrame)); @@ -1772,6 +2027,7 @@ DEFINE_STUB_FUNCTION(int, op_loop_if_true) DEFINE_STUB_FUNCTION(int, op_load_varargs) { STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; RegisterFile* registerFile = stackFrame.registerFile; int argsOffset = stackFrame.args[0].int32(); @@ -1786,7 +2042,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs) stackFrame.globalData->exception = createStackOverflowError(callFrame); VM_THROW_EXCEPTION(); } - int32_t expectedParams = asFunction(callFrame->registers()[RegisterFile::Callee].jsValue())->body()->parameterCount(); + int32_t expectedParams = callFrame->callee()->body()->parameterCount(); int32_t inplaceArgs = min(providedParams, expectedParams); Register* inplaceArgsDst = callFrame->registers() + argsOffset; @@ -1918,7 +2174,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global) STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - JSGlobalObject* globalObject = asGlobalObject(stackFrame.args[0].jsValue()); + JSGlobalObject* globalObject = stackFrame.args[0].globalObject(); Identifier& ident = stackFrame.args[1].identifier(); unsigned globalResolveInfoIndex = stackFrame.args[2].int32(); ASSERT(globalObject->isGlobalObject()); @@ -2042,7 +2298,117 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_inc) return JSValue::encode(number); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_eq) +#if USE(JSVALUE32_64) + +DEFINE_STUB_FUNCTION(int, op_eq) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + JSValue src1 = stackFrame.args[0].jsValue(); + JSValue src2 = stackFrame.args[1].jsValue(); + + start: + if (src2.isUndefined()) { + return src1.isNull() || + (src1.isCell() && asCell(src1)->structure()->typeInfo().masqueradesAsUndefined()) || + src1.isUndefined(); + } + + if (src2.isNull()) { + return src1.isUndefined() || + (src1.isCell() && asCell(src1)->structure()->typeInfo().masqueradesAsUndefined()) || + src1.isNull(); + } + + if (src1.isInt32()) { + if (src2.isDouble()) + return src1.asInt32() == src2.asDouble(); + double d = src2.toNumber(stackFrame.callFrame); + CHECK_FOR_EXCEPTION(); + return src1.asInt32() == d; + } + + if (src1.isDouble()) { + if (src2.isInt32()) + return src1.asDouble() == src2.asInt32(); + double d = src2.toNumber(stackFrame.callFrame); + CHECK_FOR_EXCEPTION(); + return src1.asDouble() == d; + } + + if (src1.isTrue()) { + if (src2.isFalse()) + return false; + double d = src2.toNumber(stackFrame.callFrame); + CHECK_FOR_EXCEPTION(); + return d == 1.0; + } + + if (src1.isFalse()) { + if (src2.isTrue()) + return false; + double d = src2.toNumber(stackFrame.callFrame); + CHECK_FOR_EXCEPTION(); + return d == 0.0; + } + + if (src1.isUndefined()) + return src2.isCell() && asCell(src2)->structure()->typeInfo().masqueradesAsUndefined(); + + if (src1.isNull()) + return src2.isCell() && asCell(src2)->structure()->typeInfo().masqueradesAsUndefined(); + + ASSERT(src1.isCell()); + + JSCell* cell1 = asCell(src1); + + if (cell1->isString()) { + if (src2.isInt32()) + return static_cast<JSString*>(cell1)->value().toDouble() == src2.asInt32(); + + if (src2.isDouble()) + return static_cast<JSString*>(cell1)->value().toDouble() == src2.asDouble(); + + if (src2.isTrue()) + return static_cast<JSString*>(cell1)->value().toDouble() == 1.0; + + if (src2.isFalse()) + return static_cast<JSString*>(cell1)->value().toDouble() == 0.0; + + ASSERT(src2.isCell()); + JSCell* cell2 = asCell(src2); + if (cell2->isString()) + return static_cast<JSString*>(cell1)->value() == static_cast<JSString*>(cell2)->value(); + + ASSERT(cell2->isObject()); + src2 = static_cast<JSObject*>(cell2)->toPrimitive(stackFrame.callFrame); + CHECK_FOR_EXCEPTION(); + goto start; + } + + ASSERT(cell1->isObject()); + if (src2.isObject()) + return static_cast<JSObject*>(cell1) == asObject(src2); + src1 = static_cast<JSObject*>(cell1)->toPrimitive(stackFrame.callFrame); + CHECK_FOR_EXCEPTION(); + goto start; +} + +DEFINE_STUB_FUNCTION(int, op_eq_strings) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + JSString* string1 = stackFrame.args[0].jsString(); + JSString* string2 = stackFrame.args[1].jsString(); + + ASSERT(string1->isString()); + ASSERT(string2->isString()); + return string1->value() == string2->value(); +} + +#else // USE(JSVALUE32_64) + +DEFINE_STUB_FUNCTION(int, op_eq) { STUB_INIT_STACK_FRAME(stackFrame); @@ -2051,12 +2417,13 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_eq) CallFrame* callFrame = stackFrame.callFrame; - ASSERT(!JSValue::areBothInt32Fast(src1, src2)); - JSValue result = jsBoolean(JSValue::equalSlowCaseInline(callFrame, src1, src2)); + bool result = JSValue::equalSlowCaseInline(callFrame, src1, src2); CHECK_FOR_EXCEPTION_AT_END(); - return JSValue::encode(result); + return result; } +#endif // USE(JSVALUE32_64) + DEFINE_STUB_FUNCTION(EncodedJSValue, op_lshift) { STUB_INIT_STACK_FRAME(stackFrame); @@ -2064,13 +2431,6 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_lshift) JSValue val = stackFrame.args[0].jsValue(); JSValue shift = stackFrame.args[1].jsValue(); - int32_t left; - uint32_t right; - if (JSValue::areBothInt32Fast(val, shift)) - return JSValue::encode(jsNumber(stackFrame.globalData, val.getInt32Fast() << (shift.getInt32Fast() & 0x1f))); - if (val.numberToInt32(left) && shift.numberToUInt32(right)) - return JSValue::encode(jsNumber(stackFrame.globalData, left << (right & 0x1f))); - CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f)); CHECK_FOR_EXCEPTION_AT_END(); @@ -2084,11 +2444,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitand) JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); - int32_t left; - int32_t right; - if (src1.numberToInt32(left) && src2.numberToInt32(right)) - return JSValue::encode(jsNumber(stackFrame.globalData, left & right)); - + ASSERT(!src1.isInt32() || !src2.isInt32()); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) & src2.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); @@ -2102,15 +2458,9 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_rshift) JSValue val = stackFrame.args[0].jsValue(); JSValue shift = stackFrame.args[1].jsValue(); - int32_t left; - uint32_t right; - if (JSFastMath::canDoFastRshift(val, shift)) - return JSValue::encode(JSFastMath::rightShiftImmediateNumbers(val, shift)); - if (val.numberToInt32(left) && shift.numberToUInt32(right)) - return JSValue::encode(jsNumber(stackFrame.globalData, left >> (right & 0x1f))); - CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); + CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2121,10 +2471,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitnot) JSValue src = stackFrame.args[0].jsValue(); - int value; - if (src.numberToInt32(value)) - return JSValue::encode(jsNumber(stackFrame.globalData, ~value)); - + ASSERT(!src.isInt32()); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(stackFrame.globalData, ~src.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); @@ -2198,21 +2545,6 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_less) return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_neq) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - JSValue src1 = stackFrame.args[0].jsValue(); - JSValue src2 = stackFrame.args[1].jsValue(); - - ASSERT(!JSValue::areBothInt32Fast(src1, src2)); - - CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsBoolean(!JSValue::equalSlowCaseInline(callFrame, src1, src2)); - CHECK_FOR_EXCEPTION_AT_END(); - return JSValue::encode(result); -} - DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_dec) { STUB_INIT_STACK_FRAME(stackFrame); @@ -2236,14 +2568,9 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_urshift) JSValue shift = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - - if (JSFastMath::canDoFastUrshift(val, shift)) - return JSValue::encode(JSFastMath::rightShiftImmediateNumbers(val, shift)); - else { - JSValue result = jsNumber(stackFrame.globalData, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); - CHECK_FOR_EXCEPTION_AT_END(); - return JSValue::encode(result); - } + JSValue result = jsNumber(stackFrame.globalData, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitxor) @@ -2302,7 +2629,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval) if (thisValue == globalObject && funcVal == globalObject->evalFunction()) { JSValue exceptionValue; JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue); - if (UNLIKELY(exceptionValue != JSValue())) { + if (UNLIKELY(exceptionValue)) { stackFrame.globalData->exception = exceptionValue; VM_THROW_EXCEPTION_AT_END(); } @@ -2333,7 +2660,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_throw) } stackFrame.callFrame = callFrame; - void* catchRoutine = handler->nativeCode.addressForExceptionHandler(); + void* catchRoutine = handler->nativeCode.executableAddress(); ASSERT(catchRoutine); STUB_SET_RETURN_ADDRESS(catchRoutine); return JSValue::encode(exceptionValue); @@ -2540,15 +2867,15 @@ DEFINE_STUB_FUNCTION(void*, op_switch_imm) CallFrame* callFrame = stackFrame.callFrame; CodeBlock* codeBlock = callFrame->codeBlock(); - if (scrutinee.isInt32Fast()) - return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(scrutinee.getInt32Fast()).addressForSwitch(); + if (scrutinee.isInt32()) + return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(scrutinee.asInt32()).executableAddress(); else { double value; int32_t intValue; if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value)) - return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(intValue).addressForSwitch(); + return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(intValue).executableAddress(); else - return codeBlock->immediateSwitchJumpTable(tableIndex).ctiDefault.addressForSwitch(); + return codeBlock->immediateSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); } } @@ -2561,12 +2888,12 @@ DEFINE_STUB_FUNCTION(void*, op_switch_char) CallFrame* callFrame = stackFrame.callFrame; CodeBlock* codeBlock = callFrame->codeBlock(); - void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.addressForSwitch(); + void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); if (scrutinee.isString()) { UString::Rep* value = asString(scrutinee)->value().rep(); if (value->size() == 1) - result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->data()[0]).addressForSwitch(); + result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->data()[0]).executableAddress(); } return result; @@ -2581,11 +2908,11 @@ DEFINE_STUB_FUNCTION(void*, op_switch_string) CallFrame* callFrame = stackFrame.callFrame; CodeBlock* codeBlock = callFrame->codeBlock(); - void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.addressForSwitch(); + void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); if (scrutinee.isString()) { UString::Rep* value = asString(scrutinee)->value().rep(); - result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).addressForSwitch(); + result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).executableAddress(); } return result; @@ -2689,14 +3016,12 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, vm_throw) } stackFrame.callFrame = callFrame; - void* catchRoutine = handler->nativeCode.addressForExceptionHandler(); + void* catchRoutine = handler->nativeCode.executableAddress(); ASSERT(catchRoutine); STUB_SET_RETURN_ADDRESS(catchRoutine); return JSValue::encode(exceptionValue); } -} // namespace JITStubs - } // namespace JSC #endif // ENABLE(JIT) |