diff options
Diffstat (limited to 'src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp')
-rw-r--r-- | src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp | 880 |
1 files changed, 595 insertions, 285 deletions
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp index 7928593c9d..a110dcd120 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp @@ -56,6 +56,7 @@ #include "RegExpPrototype.h" #include "Register.h" #include "SamplingTool.h" +#include <stdarg.h> #include <stdio.h> #ifdef QT_BUILD_SCRIPT_LIB @@ -66,13 +67,18 @@ using namespace std; namespace JSC { - #if PLATFORM(DARWIN) || PLATFORM(WIN_OS) #define SYMBOL_STRING(name) "_" #name #else #define SYMBOL_STRING(name) #name #endif +#if PLATFORM(IPHONE) +#define THUMB_FUNC_PARAM(name) SYMBOL_STRING(name) +#else +#define THUMB_FUNC_PARAM(name) +#endif + #if PLATFORM(DARWIN) // Mach-O platform #define HIDE_SYMBOL(name) ".private_extern _" #name @@ -86,6 +92,271 @@ namespace JSC { #define HIDE_SYMBOL(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, 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 volatile ( +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" +SYMBOL_STRING(ctiTrampoline) ":" "\n" + "pushl %ebp" "\n" + "movl %esp, %ebp" "\n" + "pushl %esi" "\n" + "pushl %edi" "\n" + "pushl %ebx" "\n" + "subl $0x3c, %esp" "\n" + "movl $512, %esi" "\n" + "movl 0x58(%esp), %edi" "\n" + "call *0x50(%esp)" "\n" + "addl $0x3c, %esp" "\n" + "popl %ebx" "\n" + "popl %edi" "\n" + "popl %esi" "\n" + "popl %ebp" "\n" + "ret" "\n" +); + +asm volatile ( +".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(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" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" +SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" + "addl $0x3c, %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, 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); + +asm volatile ( +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(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" + "subq $0x48, %rsp" "\n" + "movq $512, %r12" "\n" + "movq $0xFFFF000000000000, %r14" "\n" + "movq $0xFFFF000000000002, %r15" "\n" + "movq 0x90(%rsp), %r13" "\n" + "call *0x80(%rsp)" "\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(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(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" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" +SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\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" +); + +#elif COMPILER(GCC) && PLATFORM(ARM_THUMB2) + +#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 " THUMB_FUNC_PARAM(ctiTrampoline) "\n" +HIDE_SYMBOL(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 " THUMB_FUNC_PARAM(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(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 " THUMB_FUNC_PARAM(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(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(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, 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" { + + __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, 0x3c; + mov esi, 512; + mov ecx, esp; + mov edi, [esp + 0x58]; + call [esp + 0x50]; + add esp, 0x3c; + pop ebx; + pop edi; + pop esi; + pop ebp; + ret; + } + } + + __declspec(naked) void ctiVMThrowTrampoline() + { + __asm { + mov ecx, esp; + call cti_vm_throw; + add esp, 0x3c; + pop ebx; + pop edi; + pop esi; + pop ebp; + ret; + } + } + + __declspec(naked) void ctiOpThrowNotCaught() + { + __asm { + add esp, 0x3c; + pop ebx; + pop edi; + pop esi; + pop ebp; + ret; + } + } +} + +#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 @@ -151,9 +422,9 @@ 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) == 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); +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" @@ -166,13 +437,20 @@ SYMBOL_STRING(ctiTrampoline) ":" "\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 0x90(%rsp), %r13" "\n" - "call *0x80(%rsp)" "\n" - "addq $0x48, %rsp" "\n" + "movq %rdx, %r13" "\n" + "call *%rdi" "\n" + "addq $0x78, %rsp" "\n" "popq %rbx" "\n" "popq %r15" "\n" "popq %r14" "\n" @@ -188,7 +466,7 @@ HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movq %rsp, %rdi" "\n" "call " SYMBOL_STRING(cti_vm_throw) "\n" - "addq $0x48, %rsp" "\n" + "addq $0x78, %rsp" "\n" "popq %rbx" "\n" "popq %r15" "\n" "popq %r14" "\n" @@ -202,7 +480,7 @@ asm volatile ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" - "addq $0x48, %rsp" "\n" + "addq $0x78, %rsp" "\n" "popq %rbx" "\n" "popq %r15" "\n" "popq %r14" "\n" @@ -212,7 +490,7 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "ret" "\n" ); -#elif COMPILER(GCC) && PLATFORM_ARM_ARCH(7) +#elif COMPILER(GCC) && PLATFORM(ARM_THUMB2) #if USE(JIT_STUB_ARGUMENT_VA_LIST) #error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7." @@ -224,9 +502,9 @@ asm volatile ( ".globl " SYMBOL_STRING(ctiTrampoline) "\n" HIDE_SYMBOL(ctiTrampoline) "\n" ".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiTrampoline) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" - "sub sp, sp, #0x3c" "\n" + "sub sp, sp, #0x40" "\n" "str lr, [sp, #0x20]" "\n" "str r4, [sp, #0x24]" "\n" "str r5, [sp, #0x28]" "\n" @@ -241,7 +519,7 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "ldr r5, [sp, #0x28]" "\n" "ldr r4, [sp, #0x24]" "\n" "ldr lr, [sp, #0x20]" "\n" - "add sp, sp, #0x3c" "\n" + "add sp, sp, #0x40" "\n" "bx lr" "\n" ); @@ -251,7 +529,7 @@ asm volatile ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" ".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "cpy r0, sp" "\n" "bl " SYMBOL_STRING(cti_vm_throw) "\n" @@ -259,7 +537,7 @@ SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "ldr r5, [sp, #0x28]" "\n" "ldr r4, [sp, #0x24]" "\n" "ldr lr, [sp, #0x20]" "\n" - "add sp, sp, #0x3c" "\n" + "add sp, sp, #0x40" "\n" "bx lr" "\n" ); @@ -269,7 +547,7 @@ asm volatile ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" ".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "ldr r6, [sp, #0x2c]" "\n" "ldr r5, [sp, #0x28]" "\n" @@ -279,6 +557,49 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "bx lr" "\n" ); +#elif COMPILER(GCC) && PLATFORM(ARM_TRADITIONAL) + +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) @@ -319,7 +640,7 @@ extern "C" { { __asm { mov ecx, esp; - call JITStubs::cti_vm_throw; + call cti_vm_throw; add esp, 0x1c; pop ebx; pop edi; @@ -342,7 +663,9 @@ extern "C" { } } -#endif +#endif // COMPILER(GCC) && PLATFORM(X86) + +#endif // USE(JSVALUE32_64) #if ENABLE(OPCODE_SAMPLING) #define CTI_SAMPLER stackFrame.globalData->interpreter->sampler() @@ -352,9 +675,9 @@ 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) +#if PLATFORM(ARM_THUMB2) // 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. @@ -367,7 +690,7 @@ JITThunks::JITThunks(JSGlobalData* globalData) 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, enabledProfilerReference) == 0x40); ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == 0x1C); #endif @@ -375,7 +698,7 @@ JITThunks::JITThunks(JSGlobalData* globalData) #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) -NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr 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. @@ -384,33 +707,31 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co // Uncacheable: give up. if (!slot.isCacheable()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(JITStubs::cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); return; } JSCell* baseCell = asCell(baseValue); Structure* structure = baseCell->structure(); - if (structure->isDictionary()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(JITStubs::cti_op_put_by_id_generic)); + if (structure->isUncacheableDictionary()) { + 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(codeBlock, 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(JITStubs::cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); return; } stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain); @@ -423,14 +744,14 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); } -NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr 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(codeBlock, returnAddress, FunctionPtr(JITStubs::cti_op_get_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -450,23 +771,18 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co // Uncacheable: give up. if (!slot.isCacheable()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(JITStubs::cti_op_get_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } JSCell* baseCell = asCell(baseValue); Structure* structure = baseCell->structure(); - if (structure->isDictionary()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(JITStubs::cti_op_get_by_id_generic)); + if (structure->isUncacheableDictionary()) { + 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) { @@ -495,20 +811,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(JITStubs::cti_op_get_by_id_generic)); + 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) @@ -585,25 +901,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_ARCH(7) +#if PLATFORM(ARM_THUMB2) #define DEFINE_STUB_FUNCTION(rtype, op) \ extern "C" { \ @@ -615,7 +929,7 @@ namespace JITStubs { ".globl " SYMBOL_STRING(cti_##op) "\n" \ HIDE_SYMBOL(cti_##op) "\n" \ ".thumb" "\n" \ - ".thumb_func " SYMBOL_STRING(cti_##op) "\n" \ + ".thumb_func " THUMB_FUNC_PARAM(cti_##op) "\n" \ SYMBOL_STRING(cti_##op) ":" "\n" \ "str lr, [sp, #0x1c]" "\n" \ "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \ @@ -628,7 +942,7 @@ namespace JITStubs { #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); @@ -637,7 +951,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) @@ -677,8 +991,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)) { @@ -717,6 +1031,7 @@ DEFINE_STUB_FUNCTION(int, timeout_check) globalData->exception = createInterruptedExecutionException(globalData); VM_THROW_EXCEPTION_AT_END(); } + CHECK_FOR_EXCEPTION_AT_END(); return timeoutChecker->ticksUntilNextCheck(); } @@ -797,25 +1112,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(callFrame->codeBlock(), 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(); } @@ -832,36 +1141,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); - - 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(); + JSObject* base = asObject(baseValue); + base->allocatePropertyStorage(oldSize, newSize); - JSValue baseValue = stackFrame.args[0].jsValue(); - PropertySlot slot(baseValue); - JSValue result = baseValue.get(callFrame, ident, slot); - - ctiPatchCallByReturnAddress(callFrame->codeBlock(), 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) @@ -874,25 +1166,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(callFrame->codeBlock(), 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 @@ -909,7 +1191,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check_second) JSObject* slotBaseObject; if (baseValue.isCell() && slot.isCacheable() - && !(structure = asCell(baseValue)->structure())->isDictionary() + && !(structure = asCell(baseValue)->structure())->isUncacheableDictionary() && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific) && specific ) { @@ -923,33 +1205,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(callFrame->codeBlock(), 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(callFrame->codeBlock(), 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(callFrame->codeBlock(), 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(); @@ -957,7 +1239,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); @@ -978,7 +1265,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail) if (baseValue.isCell() && slot.isCacheable() - && !asCell(baseValue)->structure()->isDictionary() + && !asCell(baseValue)->structure()->isUncacheableDictionary() && slot.slotBase() == baseValue) { CodeBlock* codeBlock = callFrame->codeBlock(); @@ -989,7 +1276,7 @@ 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(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure); stubInfo->initGetByIdSelfList(polymorphicStructureList, 2); @@ -1013,18 +1300,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 = 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 = 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++; @@ -1049,7 +1336,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) CHECK_FOR_EXCEPTION(); - if (!baseValue.isCell() || !slot.isCacheable() || asCell(baseValue)->structure()->isDictionary()) { + if (!baseValue.isCell() || !slot.isCacheable() || asCell(baseValue)->structure()->isUncacheableDictionary()) { ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); return JSValue::encode(result); } @@ -1143,7 +1430,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) { @@ -1223,7 +1510,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_func) { STUB_INIT_STACK_FRAME(stackFrame); - return stackFrame.args[0].funcDeclNode()->makeFunction(stackFrame.callFrame, stackFrame.callFrame->scopeChain()); + return stackFrame.args[0].function()->make(stackFrame.callFrame, stackFrame.callFrame->scopeChain()); } DEFINE_STUB_FUNCTION(void*, op_call_JSFunction) @@ -1237,11 +1524,11 @@ DEFINE_STUB_FUNCTION(void*, op_call_JSFunction) JSFunction* function = asFunction(stackFrame.args[0].jsValue()); ASSERT(!function->isHostFunction()); - FunctionBodyNode* body = function->body(); + FunctionExecutable* executable = function->jsExecutable(); ScopeChainNode* callDataScopeChain = function->scope().node(); - body->jitCode(callDataScopeChain); + executable->jitCode(stackFrame.callFrame, callDataScopeChain); - return &(body->generatedBytecode()); + return function; } DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck) @@ -1249,8 +1536,9 @@ DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck) STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* newCodeBlock = stackFrame.args[3].codeBlock(); - ASSERT(newCodeBlock->codeType() != NativeCode); + JSFunction* callee = asFunction(stackFrame.args[0].jsValue()); + ASSERT(!callee->isHostFunction()); + CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecode(); int argCount = stackFrame.args[2].int32(); ASSERT(argCount != newCodeBlock->m_numParameters); @@ -1287,45 +1575,36 @@ DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck) callFrame->setCallerFrame(oldCallFrame); } - 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.callFrame->callerFrame()->codeBlock(), stackFrame.args[1].returnAddress(), globalData->jitStubs.ctiVirtualCallLink()); - - return callee->body()->generatedJITCode().addressForCall().executableAddress(); + RETURN_POINTER_PAIR(callee, callFrame); } +#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(); + ExecutableBase* executable = callee->executable(); + JITCode& jitCode = executable->generatedJITCode(); CodeBlock* codeBlock = 0; - if (!callee->isHostFunction()) - codeBlock = &callee->body()->bytecode(callee->scope().node()); - else - codeBlock = &callee->body()->generatedBytecode(); - + if (!executable->isHostFunction()) + codeBlock = &static_cast<FunctionExecutable*>(executable)->bytecode(stackFrame.callFrame, callee->scope().node()); CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(stackFrame.args[1].returnAddress()); - JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, jitCode, callLinkInfo, stackFrame.args[2].int32(), stackFrame.globalData); + + 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) { STUB_INIT_STACK_FRAME(stackFrame); - JSActivation* activation = new (stackFrame.globalData) JSActivation(stackFrame.callFrame, static_cast<FunctionBodyNode*>(stackFrame.callFrame->codeBlock()->ownerNode())); + JSActivation* activation = new (stackFrame.globalData) JSActivation(stackFrame.callFrame, static_cast<FunctionExecutable*>(stackFrame.callFrame->codeBlock()->ownerExecutable())); stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->copy()->push(activation)); return activation; } @@ -1385,7 +1664,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) @@ -1394,7 +1673,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) @@ -1550,8 +1829,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)) @@ -1589,8 +1868,8 @@ 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 { @@ -1607,7 +1886,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); @@ -1620,8 +1898,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)); @@ -1639,50 +1917,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); @@ -1712,8 +1946,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)) @@ -1724,8 +1958,8 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val) JSByteArray* jsByteArray = asByteArray(baseValue); 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; @@ -1763,14 +1997,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(); @@ -1787,14 +2016,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; @@ -1845,6 +2074,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(); @@ -1859,7 +2089,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 = asFunction(callFrame->callee())->jsExecutable()->parameterCount(); int32_t inplaceArgs = min(providedParams, expectedParams); Register* inplaceArgsDst = callFrame->registers() + argsOffset; @@ -1991,7 +2221,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()); @@ -1999,7 +2229,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global) PropertySlot slot(globalObject); if (globalObject->getPropertySlot(callFrame, ident, slot)) { JSValue result = slot.getValue(callFrame, ident); - if (slot.isCacheable() && !globalObject->structure()->isDictionary() && slot.slotBase() == globalObject) { + if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { GlobalResolveInfo& globalResolveInfo = callFrame->codeBlock()->globalResolveInfo(globalResolveInfoIndex); if (globalResolveInfo.structure) globalResolveInfo.structure->deref(); @@ -2115,7 +2345,112 @@ 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(); + + 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; + + JSCell* cell2 = asCell(src2); + if (cell2->isString()) + return static_cast<JSString*>(cell1)->value() == static_cast<JSString*>(cell2)->value(); + + src2 = asObject(cell2)->toPrimitive(stackFrame.callFrame); + CHECK_FOR_EXCEPTION(); + goto start; + } + + if (src2.isObject()) + return asObject(cell1) == asObject(src2); + src1 = asObject(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); @@ -2124,12 +2459,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); @@ -2137,13 +2473,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(); @@ -2157,11 +2486,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(); @@ -2175,15 +2500,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); } @@ -2194,10 +2513,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(); @@ -2243,8 +2559,24 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base) DEFINE_STUB_FUNCTION(JSObject*, op_new_func_exp) { STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; + + FunctionExecutable* function = stackFrame.args[0].function(); + JSFunction* func = function->make(callFrame, callFrame->scopeChain()); + + /* + The Identifier in a FunctionExpression can be referenced from inside + the FunctionExpression's FunctionBody to allow the function to call + itself recursively. However, unlike in a FunctionDeclaration, the + Identifier in a FunctionExpression cannot be referenced from and + does not affect the scope enclosing the FunctionExpression. + */ + if (!function->name().isNull()) { + JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete); + func->scope().push(functionScopeObject); + } - return stackFrame.args[0].funcExprNode()->makeFunction(stackFrame.callFrame, stackFrame.callFrame->scopeChain()); + return func; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_mod) @@ -2271,21 +2603,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); @@ -2309,14 +2626,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) @@ -2375,7 +2687,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(); } @@ -2613,8 +2925,8 @@ 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()).executableAddress(); + if (scrutinee.isInt32()) + return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(scrutinee.asInt32()).executableAddress(); else { double value; int32_t intValue; @@ -2724,7 +3036,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_error) unsigned bytecodeOffset = stackFrame.args[2].int32(); unsigned lineNumber = codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset); - return Error::create(callFrame, static_cast<ErrorType>(type), message.toString(callFrame), lineNumber, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + return Error::create(callFrame, static_cast<ErrorType>(type), message.toString(callFrame), lineNumber, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()); } DEFINE_STUB_FUNCTION(void, op_debug) @@ -2749,7 +3061,7 @@ DEFINE_STUB_FUNCTION(void, op_debug_catch) if (JSC::Debugger* debugger = callFrame->lexicalGlobalObject()->debugger() ) { JSValue exceptionValue = callFrame->r(stackFrame.args[0].int32()).jsValue(); DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue); - debugger->exceptionCatch(debuggerCallFrame, callFrame->codeBlock()->ownerNode()->sourceID()); + debugger->exceptionCatch(debuggerCallFrame, callFrame->codeBlock()->source()->asID()); } } @@ -2759,7 +3071,7 @@ DEFINE_STUB_FUNCTION(void, op_debug_return) CallFrame* callFrame = stackFrame.callFrame; if (JSC::Debugger* debugger = callFrame->lexicalGlobalObject()->debugger() ) { JSValue returnValue = callFrame->r(stackFrame.args[0].int32()).jsValue(); - intptr_t sourceID = callFrame->codeBlock()->ownerNode()->sourceID(); + intptr_t sourceID = callFrame->codeBlock()->source()->asID(); debugger->functionExit(returnValue, sourceID); } } @@ -2794,8 +3106,6 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, vm_throw) return JSValue::encode(exceptionValue); } -} // namespace JITStubs - } // namespace JSC #endif // ENABLE(JIT) |