diff options
Diffstat (limited to 'JavaScriptCore/jit/JITStubs.cpp')
| -rw-r--r-- | JavaScriptCore/jit/JITStubs.cpp | 1700 |
1 files changed, 1086 insertions, 614 deletions
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp index 85471de..097d55b 100644 --- a/JavaScriptCore/jit/JITStubs.cpp +++ b/JavaScriptCore/jit/JITStubs.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> + * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,9 +29,9 @@ */ #include "config.h" -#include "JITStubs.h" #if ENABLE(JIT) +#include "JITStubs.h" #include "Arguments.h" #include "CallFrame.h" @@ -38,12 +39,14 @@ #include "Collector.h" #include "Debugger.h" #include "ExceptionHelpers.h" +#include "GetterSetter.h" #include "GlobalEvalFunction.h" #include "JIT.h" #include "JSActivation.h" #include "JSArray.h" #include "JSByteArray.h" #include "JSFunction.h" +#include "JSGlobalObjectFunctions.h" #include "JSNotAnObject.h" #include "JSPropertyNameIterator.h" #include "JSStaticScopeObject.h" @@ -70,7 +73,7 @@ namespace JSC { #define SYMBOL_STRING(name) #name #endif -#if OS(IPHONE_OS) +#if OS(IOS) #define THUMB_FUNC_PARAM(name) SYMBOL_STRING(name) #else #define THUMB_FUNC_PARAM(name) @@ -78,8 +81,12 @@ namespace JSC { #if OS(LINUX) && CPU(X86_64) #define SYMBOL_STRING_RELOCATION(name) #name "@plt" +#elif OS(DARWIN) +#define SYMBOL_STRING_RELOCATION(name) "_" #name +#elif CPU(X86) && COMPILER(MINGW) +#define SYMBOL_STRING_RELOCATION(name) "@" #name "@4" #else -#define SYMBOL_STRING_RELOCATION(name) SYMBOL_STRING(name) +#define SYMBOL_STRING_RELOCATION(name) #name #endif #if OS(DARWIN) @@ -112,7 +119,7 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x3c, JITStackFrame_s 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 ( +asm ( ".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" HIDE_SYMBOL(ctiTrampoline) "\n" @@ -134,23 +141,16 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "ret" "\n" ); -asm volatile ( +asm ( ".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_RELOCATION(cti_vm_throw) "\n" - "addl $0x3c, %esp" "\n" - "popl %ebx" "\n" - "popl %edi" "\n" - "popl %esi" "\n" - "popl %ebp" "\n" - "ret" "\n" + "int3" "\n" ); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" @@ -164,10 +164,6 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" #elif COMPILER(GCC) && CPU(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); @@ -175,7 +171,7 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x48, JITStackFrame_s 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 ( +asm ( ".globl " SYMBOL_STRING(ctiTrampoline) "\n" HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" @@ -202,23 +198,16 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "ret" "\n" ); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movq %rsp, %rdi" "\n" "call " SYMBOL_STRING_RELOCATION(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" + "int3" "\n" ); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" @@ -234,110 +223,23 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" #elif COMPILER(GCC) && CPU(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" -HIDE_SYMBOL(ctiTrampoline) "\n" -".thumb" "\n" -".thumb_func " THUMB_FUNC_PARAM(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" -HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" -".thumb" "\n" -".thumb_func " THUMB_FUNC_PARAM(ctiVMThrowTrampoline) "\n" -SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" - "cpy r0, sp" "\n" - "bl " SYMBOL_STRING_RELOCATION(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" -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) && CPU(ARM_TRADITIONAL) - -asm volatile ( -".globl " SYMBOL_STRING(ctiTrampoline) "\n" -SYMBOL_STRING(ctiTrampoline) ":" "\n" - "stmdb sp!, {r1-r3}" "\n" - "stmdb sp!, {r4-r8, lr}" "\n" - "sub sp, sp, #68" "\n" - "mov r4, r2" "\n" - "mov r5, #512" "\n" - // r0 contains the code - "mov lr, pc" "\n" - "mov pc, r0" "\n" - "add sp, sp, #68" "\n" - "ldmia sp!, {r4-r8, lr}" "\n" - "add sp, sp, #12" "\n" - "mov pc, lr" "\n" -); +#define THUNK_RETURN_ADDRESS_OFFSET 0x38 +#define PRESERVED_RETURN_ADDRESS_OFFSET 0x3C +#define PRESERVED_R4_OFFSET 0x40 +#define PRESERVED_R5_OFFSET 0x44 +#define PRESERVED_R6_OFFSET 0x48 +#define REGISTER_FILE_OFFSET 0x4C +#define CALLFRAME_OFFSET 0x50 +#define EXCEPTION_OFFSET 0x54 +#define ENABLE_PROFILER_REFERENCE_OFFSET 0x58 -asm volatile ( -".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" -SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" - "mov r0, sp" "\n" - "bl " SYMBOL_STRING(cti_vm_throw) "\n" +#elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL) -// Both has the same return sequence -".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" -SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" - "add sp, sp, #68" "\n" - "ldmia sp!, {r4-r8, lr}" "\n" - "add sp, sp, #12" "\n" - "mov pc, lr" "\n" -); +#define THUNK_RETURN_ADDRESS_OFFSET 64 +#define PRESERVEDR4_OFFSET 68 #elif COMPILER(MSVC) && CPU(X86) -#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); @@ -347,7 +249,7 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_ extern "C" { - __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue* exception, Profiler**, JSGlobalData*) + __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*) { __asm { push ebp; @@ -396,6 +298,27 @@ extern "C" { } } +#elif COMPILER(MSVC) && CPU(ARM_TRADITIONAL) + +#define THUNK_RETURN_ADDRESS_OFFSET 64 +#define PRESERVEDR4_OFFSET 68 +// See DEFINE_STUB_FUNCTION for more information. + +#elif CPU(MIPS) + +#define PRESERVED_GP_OFFSET 60 +#define PRESERVED_S0_OFFSET 64 +#define PRESERVED_S1_OFFSET 68 +#define PRESERVED_S2_OFFSET 72 +#define PRESERVED_RETURN_ADDRESS_OFFSET 76 +#define THUNK_RETURN_ADDRESS_OFFSET 80 +#define REGISTER_FILE_OFFSET 84 +#define CALLFRAME_OFFSET 88 +#define EXCEPTION_OFFSET 92 +#define ENABLE_PROFILER_REFERENCE_OFFSET 96 +#define GLOBAL_DATA_OFFSET 100 +#define STACK_LENGTH 104 + #else #error "JIT not supported on this platform." #endif @@ -410,7 +333,7 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_ 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 ( +asm ( ".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" HIDE_SYMBOL(ctiTrampoline) "\n" @@ -432,23 +355,16 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "ret" "\n" ); -asm volatile ( +asm ( ".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_RELOCATION(cti_vm_throw) "\n" - "addl $0x1c, %esp" "\n" - "popl %ebx" "\n" - "popl %edi" "\n" - "popl %esi" "\n" - "popl %ebp" "\n" - "ret" "\n" + "int3" "\n" ); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" @@ -462,17 +378,13 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" #elif COMPILER(GCC) && CPU(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 ( +asm ( ".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" HIDE_SYMBOL(ctiTrampoline) "\n" @@ -507,23 +419,16 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "ret" "\n" ); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movq %rsp, %rdi" "\n" "call " SYMBOL_STRING_RELOCATION(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" + "int3" "\n" ); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" @@ -539,11 +444,202 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" #elif COMPILER(GCC) && CPU(ARM_THUMB2) -#if USE(JIT_STUB_ARGUMENT_VA_LIST) -#error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7." +#define THUNK_RETURN_ADDRESS_OFFSET 0x20 +#define PRESERVED_RETURN_ADDRESS_OFFSET 0x24 +#define PRESERVED_R4_OFFSET 0x28 +#define PRESERVED_R5_OFFSET 0x2C +#define PRESERVED_R6_OFFSET 0x30 +#define REGISTER_FILE_OFFSET 0x34 +#define CALLFRAME_OFFSET 0x38 +#define EXCEPTION_OFFSET 0x3C +#define ENABLE_PROFILER_REFERENCE_OFFSET 0x40 + +#elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL) + +#define THUNK_RETURN_ADDRESS_OFFSET 32 +#define PRESERVEDR4_OFFSET 36 + +#elif CPU(MIPS) + +#define PRESERVED_GP_OFFSET 28 +#define PRESERVED_S0_OFFSET 32 +#define PRESERVED_S1_OFFSET 36 +#define PRESERVED_S2_OFFSET 40 +#define PRESERVED_RETURN_ADDRESS_OFFSET 44 +#define THUNK_RETURN_ADDRESS_OFFSET 48 +#define REGISTER_FILE_OFFSET 52 +#define CALLFRAME_OFFSET 56 +#define EXCEPTION_OFFSET 60 +#define ENABLE_PROFILER_REFERENCE_OFFSET 64 +#define GLOBAL_DATA_OFFSET 68 +#define STACK_LENGTH 72 + +#elif COMPILER(MSVC) && CPU(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); + +extern "C" { + + __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, 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; + } + } +} + +#elif COMPILER(MSVC) && CPU(ARM_TRADITIONAL) + +#define THUNK_RETURN_ADDRESS_OFFSET 32 +#define PRESERVEDR4_OFFSET 36 +// See DEFINE_STUB_FUNCTION for more information. + +#else + #error "JIT not supported on this platform." +#endif + +#endif // USE(JSVALUE32_64) + +#if CPU(MIPS) +asm volatile( +".text" "\n" +".align 2" "\n" +".set noreorder" "\n" +".set nomacro" "\n" +".set nomips16" "\n" +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +".ent " SYMBOL_STRING(ctiTrampoline) "\n" +SYMBOL_STRING(ctiTrampoline) ":" "\n" + "addiu $29,$29,-" STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" + "sw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" + "sw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" + "sw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" + "sw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" +#if WTF_MIPS_PIC + "sw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" +#endif + "move $16,$6 # set callFrameRegister" "\n" + "li $17,512 # set timeoutCheckRegister" "\n" + "move $25,$4 # move executableAddress to t9" "\n" + "sw $5," STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET) "($29) # store registerFile to current stack" "\n" + "sw $6," STRINGIZE_VALUE_OF(CALLFRAME_OFFSET) "($29) # store callFrame to curent stack" "\n" + "sw $7," STRINGIZE_VALUE_OF(EXCEPTION_OFFSET) "($29) # store exception to current stack" "\n" + "lw $8," STRINGIZE_VALUE_OF(STACK_LENGTH + 16) "($29) # load enableProfilerReference from previous stack" "\n" + "lw $9," STRINGIZE_VALUE_OF(STACK_LENGTH + 20) "($29) # load globalData from previous stack" "\n" + "sw $8," STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "($29) # store enableProfilerReference to current stack" "\n" + "jalr $25" "\n" + "sw $9," STRINGIZE_VALUE_OF(GLOBAL_DATA_OFFSET) "($29) # store globalData to current stack" "\n" + "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" + "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" + "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" + "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" + "jr $31" "\n" + "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" +".set reorder" "\n" +".set macro" "\n" +".end " SYMBOL_STRING(ctiTrampoline) "\n" +); + +asm volatile( +".text" "\n" +".align 2" "\n" +".set noreorder" "\n" +".set nomacro" "\n" +".set nomips16" "\n" +".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +".ent " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" +#if WTF_MIPS_PIC + "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" +".set macro" "\n" + "la $25," SYMBOL_STRING(cti_vm_throw) "\n" +".set nomacro" "\n" + "bal " SYMBOL_STRING(cti_vm_throw) "\n" + "move $4,$29" "\n" +#else + "jal " SYMBOL_STRING(cti_vm_throw) "\n" + "move $4,$29" "\n" +#endif + "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" + "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" + "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" + "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" + "jr $31" "\n" + "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" +".set reorder" "\n" +".set macro" "\n" +".end " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +); + +asm volatile( +".text" "\n" +".align 2" "\n" +".set noreorder" "\n" +".set nomacro" "\n" +".set nomips16" "\n" +".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +".ent " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" + "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" + "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" + "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" + "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" + "jr $31" "\n" + "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" +".set reorder" "\n" +".set macro" "\n" +".end " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +); #endif -asm volatile ( +#if COMPILER(GCC) && CPU(ARM_THUMB2) + +asm volatile( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" @@ -551,26 +647,26 @@ HIDE_SYMBOL(ctiTrampoline) "\n" ".thumb" "\n" ".thumb_func " THUMB_FUNC_PARAM(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" - "sub sp, sp, #0x40" "\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" + "sub sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" + "str lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" + "str r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" + "str r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" + "str r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n" + "str r1, [sp, #" STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET) "]" "\n" + "str r2, [sp, #" STRINGIZE_VALUE_OF(CALLFRAME_OFFSET) "]" "\n" + "str r3, [sp, #" STRINGIZE_VALUE_OF(EXCEPTION_OFFSET) "]" "\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, #0x40" "\n" + "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n" + "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" + "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" + "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" "bx lr" "\n" ); -asm volatile ( +asm volatile( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" @@ -580,15 +676,15 @@ HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "cpy r0, sp" "\n" "bl " SYMBOL_STRING_RELOCATION(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, #0x40" "\n" + "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n" + "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" + "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" + "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" "bx lr" "\n" ); -asm volatile ( +asm volatile( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" @@ -596,46 +692,46 @@ HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" ".thumb" "\n" ".thumb_func " THUMB_FUNC_PARAM(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" + "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n" + "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" + "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" + "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" "bx lr" "\n" ); #elif COMPILER(GCC) && CPU(ARM_TRADITIONAL) -asm volatile ( -".text\n" +asm volatile( ".globl " SYMBOL_STRING(ctiTrampoline) "\n" HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "stmdb sp!, {r1-r3}" "\n" "stmdb sp!, {r4-r8, lr}" "\n" - "sub sp, sp, #36" "\n" + "sub sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n" "mov r4, r2" "\n" "mov r5, #512" "\n" + // r0 contains the code "mov lr, pc" "\n" "mov pc, r0" "\n" - "add sp, sp, #36" "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n" "ldmia sp!, {r4-r8, lr}" "\n" "add sp, sp, #12" "\n" "mov pc, lr" "\n" ); -asm volatile ( +asm volatile( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "mov r0, sp" "\n" - "bl " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" + "bl " SYMBOL_STRING(cti_vm_throw) "\n" // Both has the same return sequence ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" - "add sp, sp, #36" "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n" "ldmia sp!, {r4-r8, lr}" "\n" "add sp, sp, #12" "\n" "mov pc, lr" "\n" @@ -643,17 +739,17 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" #elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL) -__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*) +__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*) { ARM stmdb sp!, {r1-r3} stmdb sp!, {r4-r8, lr} - sub sp, sp, #36 + sub sp, sp, # PRESERVEDR4_OFFSET mov r4, r2 mov r5, #512 mov lr, pc bx r0 - add sp, sp, #36 + add sp, sp, # PRESERVEDR4_OFFSET ldmia sp!, {r4-r8, lr} add sp, sp, #12 bx lr @@ -665,7 +761,7 @@ __asm void ctiVMThrowTrampoline() PRESERVE8 mov r0, sp bl cti_vm_throw - add sp, sp, #36 + add sp, sp, # PRESERVEDR4_OFFSET ldmia sp!, {r4-r8, lr} add sp, sp, #12 bx lr @@ -674,81 +770,13 @@ __asm void ctiVMThrowTrampoline() __asm void ctiOpThrowNotCaught() { ARM - add sp, sp, #36 + add sp, sp, # PRESERVEDR4_OFFSET ldmia sp!, {r4-r8, lr} add sp, sp, #12 bx lr } - -#elif COMPILER(MSVC) && CPU(X86) - -#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; - } - } -} - -#else - #error "JIT not supported on this platform." #endif -#endif // USE(JSVALUE32_64) - #if ENABLE(OPCODE_SAMPLING) #define CTI_SAMPLER stackFrame.globalData->interpreter->sampler() #else @@ -757,30 +785,56 @@ extern "C" { JITThunks::JITThunks(JSGlobalData* globalData) { - JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_trampolineStructure); + if (!globalData->executableAllocator.isValid()) + return; + JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_trampolineStructure); + ASSERT(m_executablePool); #if CPU(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. - 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); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == PRESERVED_RETURN_ADDRESS_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == PRESERVED_R4_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR5) == PRESERVED_R5_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR6) == PRESERVED_R6_OFFSET); + + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == REGISTER_FILE_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET); // The fifth argument is the first item already on the stack. - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == 0x40); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == ENABLE_PROFILER_REFERENCE_OFFSET); + + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET); + +#elif CPU(ARM_TRADITIONAL) + + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == PRESERVEDR4_OFFSET); + + +#elif CPU(MIPS) + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedGP) == PRESERVED_GP_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS0) == PRESERVED_S0_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS1) == PRESERVED_S1_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS2) == PRESERVED_S2_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == PRESERVED_RETURN_ADDRESS_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == REGISTER_FILE_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, exception) == EXCEPTION_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == ENABLE_PROFILER_REFERENCE_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, globalData) == GLOBAL_DATA_OFFSET); - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == 0x1C); #endif } +JITThunks::~JITThunks() +{ +} + #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) -NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo) +NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo, bool direct) { // The interpreter checks for recursion here; I do not believe this can occur in CTI. @@ -789,21 +843,21 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co // Uncacheable: give up. if (!slot.isCacheable()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } - JSCell* baseCell = asCell(baseValue); + JSCell* baseCell = baseValue.asCell(); Structure* structure = baseCell->structure(); if (structure->isUncacheableDictionary()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } // If baseCell != base, then baseCell must be a proxy for another object. if (baseCell != slot.base()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } @@ -812,7 +866,7 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co // Structure transition, cache transition info if (slot.type() == PutPropertySlot::NewProperty) { if (structure->isDictionary()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } @@ -821,13 +875,13 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co StructureChain* prototypeChain = structure->prototypeChain(callFrame); stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain); - JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress); + JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct); return; } stubInfo->initPutByIdReplace(structure); - JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); + JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress, direct); } NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo) @@ -851,7 +905,7 @@ 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(codeBlock, returnAddress, globalData->jitStubs.ctiStringLengthTrampoline()); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, globalData->jitStubs->ctiStringLengthTrampoline()); return; } @@ -861,7 +915,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co return; } - JSCell* baseCell = asCell(baseValue); + JSCell* baseCell = baseValue.asCell(); Structure* structure = baseCell->structure(); if (structure->isUncacheableDictionary()) { @@ -874,8 +928,10 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co if (slot.slotBase() == baseValue) { // set this up, so derefStructures can do it's job. stubInfo->initGetByIdSelf(structure); - - JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); + if (slot.cachedPropertyType() != PropertySlot::Value) + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail)); + else + JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); return; } @@ -901,7 +957,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co ASSERT(!structure->isDictionary()); ASSERT(!slotBaseObject->structure()->isDictionary()); - JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), offset, returnAddress); + JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset, returnAddress); return; } @@ -914,17 +970,11 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co StructureChain* prototypeChain = structure->prototypeChain(callFrame); stubInfo->initGetByIdChain(structure, prototypeChain); - JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, offset, returnAddress); + JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress); } #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) -#else -#define SETUP_VA_LISTL_ARGS -#endif - #ifndef NDEBUG extern "C" { @@ -955,13 +1005,13 @@ struct StackHack { ReturnAddressPtr savedReturnAddress; }; -#define STUB_INIT_STACK_FRAME(stackFrame) SETUP_VA_LISTL_ARGS; JITStackFrame& stackFrame = *reinterpret_cast<JITStackFrame*>(STUB_ARGS); StackHack stackHack(stackFrame) +#define STUB_INIT_STACK_FRAME(stackFrame) JITStackFrame& stackFrame = *reinterpret_cast_ptr<JITStackFrame*>(STUB_ARGS); StackHack stackHack(stackFrame) #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_INIT_STACK_FRAME(stackFrame) JITStackFrame& stackFrame = *reinterpret_cast_ptr<JITStackFrame*>(STUB_ARGS) #define STUB_SET_RETURN_ADDRESS(returnAddress) *stackFrame.returnAddressSlot() = ReturnAddressPtr(returnAddress) #define STUB_RETURN_ADDRESS *stackFrame.returnAddressSlot() @@ -990,7 +1040,9 @@ static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalD return 0; \ } while (0) #define VM_THROW_EXCEPTION_AT_END() \ - returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS) + do {\ + returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS);\ + } while (0) #define CHECK_FOR_EXCEPTION() \ do { \ @@ -1010,13 +1062,32 @@ static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalD } \ } while (0) +struct ExceptionHandler { + void* catchRoutine; + CallFrame* callFrame; +}; +static ExceptionHandler jitThrow(JSGlobalData* globalData, CallFrame* callFrame, JSValue exceptionValue, ReturnAddressPtr faultLocation) +{ + ASSERT(exceptionValue); + + unsigned vPCIndex = callFrame->codeBlock()->bytecodeOffset(faultLocation); + globalData->exception = JSValue(); + HandlerInfo* handler = globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex); // This may update callFrame & exceptionValue! + globalData->exception = exceptionValue; + + void* catchRoutine = handler ? handler->nativeCode.executableAddress() : FunctionPtr(ctiOpThrowNotCaught).value(); + ASSERT(catchRoutine); + ExceptionHandler exceptionHandler = { catchRoutine, callFrame }; + return exceptionHandler; +} + #if CPU(ARM_THUMB2) #define DEFINE_STUB_FUNCTION(rtype, op) \ extern "C" { \ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ }; \ - asm volatile ( \ + asm ( \ ".text" "\n" \ ".align 2" "\n" \ ".globl " SYMBOL_STRING(cti_##op) "\n" \ @@ -1024,28 +1095,79 @@ static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalD ".thumb" "\n" \ ".thumb_func " THUMB_FUNC_PARAM(cti_##op) "\n" \ SYMBOL_STRING(cti_##op) ":" "\n" \ - "str lr, [sp, #0x1c]" "\n" \ + "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \ - "ldr lr, [sp, #0x1c]" "\n" \ + "ldr lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ "bx lr" "\n" \ ); \ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) \ -#elif CPU(ARM_TRADITIONAL) && COMPILER(GCC) +#elif CPU(MIPS) +#if WTF_MIPS_PIC +#define DEFINE_STUB_FUNCTION(rtype, op) \ + extern "C" { \ + rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ + }; \ + asm volatile( \ + ".text" "\n" \ + ".align 2" "\n" \ + ".set noreorder" "\n" \ + ".set nomacro" "\n" \ + ".set nomips16" "\n" \ + ".globl " SYMBOL_STRING(cti_##op) "\n" \ + ".ent " SYMBOL_STRING(cti_##op) "\n" \ + SYMBOL_STRING(cti_##op) ":" "\n" \ + "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" \ + "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ + ".set macro" "\n" \ + "la $25," SYMBOL_STRING(JITStubThunked_##op) "\n" \ + ".set nomacro" "\n" \ + "bal " SYMBOL_STRING(JITStubThunked_##op) "\n" \ + "nop" "\n" \ + "lw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ + "jr $31" "\n" \ + "nop" "\n" \ + ".set reorder" "\n" \ + ".set macro" "\n" \ + ".end " SYMBOL_STRING(cti_##op) "\n" \ + ); \ + rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) + +#else // WTF_MIPS_PIC +#define DEFINE_STUB_FUNCTION(rtype, op) \ + extern "C" { \ + rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ + }; \ + asm volatile( \ + ".text" "\n" \ + ".align 2" "\n" \ + ".set noreorder" "\n" \ + ".set nomacro" "\n" \ + ".set nomips16" "\n" \ + ".globl " SYMBOL_STRING(cti_##op) "\n" \ + ".ent " SYMBOL_STRING(cti_##op) "\n" \ + SYMBOL_STRING(cti_##op) ":" "\n" \ + "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ + "jal " SYMBOL_STRING(JITStubThunked_##op) "\n" \ + "nop" "\n" \ + "lw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ + "jr $31" "\n" \ + "nop" "\n" \ + ".set reorder" "\n" \ + ".set macro" "\n" \ + ".end " SYMBOL_STRING(cti_##op) "\n" \ + ); \ + rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) -#if USE(JSVALUE32_64) -#define THUNK_RETURN_ADDRESS_OFFSET 64 -#else -#define THUNK_RETURN_ADDRESS_OFFSET 32 #endif -COMPILE_ASSERT(offsetof(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET, JITStackFrame_thunkReturnAddress_offset_mismatch); +#elif CPU(ARM_TRADITIONAL) && COMPILER(GCC) #define DEFINE_STUB_FUNCTION(rtype, op) \ extern "C" { \ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ }; \ - asm volatile ( \ + asm ( \ ".globl " SYMBOL_STRING(cti_##op) "\n" \ SYMBOL_STRING(cti_##op) ":" "\n" \ "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ @@ -1070,9 +1192,9 @@ RVCT(__asm #rtype# cti_#op#(STUB_ARGS_DECLARATION)) RVCT({) RVCT( ARM) RVCT( IMPORT JITStubThunked_#op#) -RVCT( str lr, [sp, #32]) +RVCT( str lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET]) RVCT( bl JITStubThunked_#op#) -RVCT( ldr lr, [sp, #32]) +RVCT( ldr lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET]) RVCT( bx lr) RVCT(}) RVCT() @@ -1081,10 +1203,88 @@ RVCT() /* Include the generated file */ #include "GeneratedJITStubs_RVCT.h" +#elif CPU(ARM_TRADITIONAL) && COMPILER(MSVC) + +#define DEFINE_STUB_FUNCTION(rtype, op) extern "C" rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) + +/* The following is a workaround for MSVC toolchain; inline assembler is not supported */ + +/* The following section is a template to generate code for GeneratedJITStubs_MSVC.asm */ +/* The pattern "#xxx#" will be replaced with "xxx" */ + +/* +MSVC_BEGIN( AREA Trampoline, CODE) +MSVC_BEGIN() +MSVC_BEGIN( EXPORT ctiTrampoline) +MSVC_BEGIN( EXPORT ctiVMThrowTrampoline) +MSVC_BEGIN( EXPORT ctiOpThrowNotCaught) +MSVC_BEGIN() +MSVC_BEGIN(ctiTrampoline PROC) +MSVC_BEGIN( stmdb sp!, {r1-r3}) +MSVC_BEGIN( stmdb sp!, {r4-r8, lr}) +MSVC_BEGIN( sub sp, sp, # THUNK_RETURN_ADDRESS_OFFSET + 4) +MSVC_BEGIN( mov r4, r2) +MSVC_BEGIN( mov r5, #512) +MSVC_BEGIN( ; r0 contains the code) +MSVC_BEGIN( mov lr, pc) +MSVC_BEGIN( bx r0) +MSVC_BEGIN( add sp, sp, # THUNK_RETURN_ADDRESS_OFFSET + 4) +MSVC_BEGIN( ldmia sp!, {r4-r8, lr}) +MSVC_BEGIN( add sp, sp, #12) +MSVC_BEGIN( bx lr) +MSVC_BEGIN(ctiTrampoline ENDP) +MSVC_BEGIN() +MSVC_BEGIN(ctiVMThrowTrampoline PROC) +MSVC_BEGIN( mov r0, sp) +MSVC_BEGIN( mov lr, pc) +MSVC_BEGIN( bl cti_vm_throw) +MSVC_BEGIN(ctiOpThrowNotCaught) +MSVC_BEGIN( add sp, sp, # THUNK_RETURN_ADDRESS_OFFSET + 4) +MSVC_BEGIN( ldmia sp!, {r4-r8, lr}) +MSVC_BEGIN( add sp, sp, #12) +MSVC_BEGIN( bx lr) +MSVC_BEGIN(ctiVMThrowTrampoline ENDP) +MSVC_BEGIN() + +MSVC( EXPORT cti_#op#) +MSVC( IMPORT JITStubThunked_#op#) +MSVC(cti_#op# PROC) +MSVC( str lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET]) +MSVC( bl JITStubThunked_#op#) +MSVC( ldr lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET]) +MSVC( bx lr) +MSVC(cti_#op# ENDP) +MSVC() + +MSVC_END( END) +*/ + #else #define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION) #endif +DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_this) +{ + STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; + + JSFunction* constructor = asFunction(callFrame->callee()); +#if !ASSERT_DISABLED + ConstructData constructData; + ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS); +#endif + + Structure* structure; + JSValue proto = stackFrame.args[0].jsValue(); + if (proto.isObject()) + structure = asObject(proto)->inheritorID(); + else + structure = constructor->scope().node()->globalObject->emptyObjectStructure(); + JSValue result = new (&callFrame->globalData()) JSObject(structure); + + return JSValue::encode(result); +} + DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1097,6 +1297,18 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this) return JSValue::encode(result); } +DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this_strict) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + JSValue v1 = stackFrame.args[0].jsValue(); + CallFrame* callFrame = stackFrame.callFrame; + ASSERT(v1.asCell()->structure()->typeInfo().needsThisConversion()); + JSValue result = v1.toStrictThisObject(callFrame); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(result); +} + DEFINE_STUB_FUNCTION(void, op_end) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1124,7 +1336,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_add) double left = 0.0, right; if (v1.getNumber(left) && v2.getNumber(right)) - return JSValue::encode(jsNumber(stackFrame.globalData, left + right)); + return JSValue::encode(jsNumber(left + right)); // All other cases are pretty uncommon JSValue result = jsAddSlowCase(callFrame, v1, v2); @@ -1139,7 +1351,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_inc) JSValue v = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, v.toNumber(callFrame) + 1); + JSValue result = jsNumber(v.toNumber(callFrame) + 1); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -1147,30 +1359,36 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_inc) DEFINE_STUB_FUNCTION(int, timeout_check) { STUB_INIT_STACK_FRAME(stackFrame); - + JSGlobalData* globalData = stackFrame.globalData; TimeoutChecker& timeoutChecker = globalData->timeoutChecker; - if (timeoutChecker.didTimeOut(stackFrame.callFrame)) { + if (globalData->terminator.shouldTerminate()) { + globalData->exception = createTerminatedExecutionException(globalData); + VM_THROW_EXCEPTION_AT_END(); + } else if (timeoutChecker.didTimeOut(stackFrame.callFrame)) { globalData->exception = createInterruptedExecutionException(globalData); VM_THROW_EXCEPTION_AT_END(); } - + return timeoutChecker.ticksUntilNextCheck(); } -DEFINE_STUB_FUNCTION(void, register_file_check) +DEFINE_STUB_FUNCTION(void*, register_file_check) { STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; - if (LIKELY(stackFrame.registerFile->grow(&stackFrame.callFrame->registers()[stackFrame.callFrame->codeBlock()->m_numCalleeRegisters]))) - return; + if (UNLIKELY(!stackFrame.registerFile->grow(&callFrame->registers()[callFrame->codeBlock()->m_numCalleeRegisters]))) { + // Rewind to the previous call frame because op_call already optimistically + // moved the call frame forward. + CallFrame* oldCallFrame = callFrame->callerFrame(); + ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), ReturnAddressPtr(oldCallFrame->returnPC())); + STUB_SET_RETURN_ADDRESS(handler.catchRoutine); + callFrame = handler.callFrame; + } - // Rewind to the previous call frame because op_call already optimistically - // moved the call frame forward. - CallFrame* oldCallFrame = stackFrame.callFrame->callerFrame(); - stackFrame.callFrame = oldCallFrame; - throwStackOverflowError(oldCallFrame, stackFrame.globalData, ReturnAddressPtr(oldCallFrame->returnPC()), STUB_RETURN_ADDRESS); + return callFrame; } DEFINE_STUB_FUNCTION(int, op_loop_if_lesseq) @@ -1197,11 +1415,20 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_generic) { STUB_INIT_STACK_FRAME(stackFrame); - PutPropertySlot slot; + PutPropertySlot slot(stackFrame.callFrame->codeBlock()->isStrictMode()); stackFrame.args[0].jsValue().put(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot); CHECK_FOR_EXCEPTION_AT_END(); } +DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_generic) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + PutPropertySlot slot(stackFrame.callFrame->codeBlock()->isStrictMode()); + stackFrame.args[0].jsValue().putDirect(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot); + CHECK_FOR_EXCEPTION_AT_END(); +} + DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_generic) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1224,17 +1451,36 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id) STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); - - PutPropertySlot slot; + + PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot); - + CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); if (!stubInfo->seenOnce()) stubInfo->setSeen(); else - JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo); + JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, false); + + CHECK_FOR_EXCEPTION_AT_END(); +} +DEFINE_STUB_FUNCTION(void, op_put_by_id_direct) +{ + STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; + Identifier& ident = stackFrame.args[1].identifier(); + + PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); + stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot); + + CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); + StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); + if (!stubInfo->seenOnce()) + stubInfo->setSeen(); + else + JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, true); + CHECK_FOR_EXCEPTION_AT_END(); } @@ -1244,13 +1490,26 @@ DEFINE_STUB_FUNCTION(void, op_put_by_id_fail) CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); - - PutPropertySlot slot; + + PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot); CHECK_FOR_EXCEPTION_AT_END(); } +DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_fail) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + CallFrame* callFrame = stackFrame.callFrame; + Identifier& ident = stackFrame.args[1].identifier(); + + PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); + stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot); + + CHECK_FOR_EXCEPTION_AT_END(); +} + DEFINE_STUB_FUNCTION(JSObject*, op_put_by_id_transition_realloc) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1289,7 +1548,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) // 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 // an isCacheable() chceck. - ASSERT(!slot.isCacheable() || slot.slotBase().isObject()); + ASSERT(!slot.isCacheableValue() || slot.slotBase().isObject()); // Check that: // * We're dealing with a JSCell, @@ -1300,8 +1559,8 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) JSCell* specific; JSObject* slotBaseObject; if (baseValue.isCell() - && slot.isCacheable() - && !(structure = asCell(baseValue)->structure())->isUncacheableDictionary() + && slot.isCacheableValue() + && !(structure = baseValue.asCell()->structure())->isUncacheableDictionary() && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific) && specific ) { @@ -1375,7 +1634,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail) if (baseValue.isCell() && slot.isCacheable() - && !asCell(baseValue)->structure()->isUncacheableDictionary() + && !baseValue.asCell()->structure()->isUncacheableDictionary() && slot.slotBase() == baseValue) { CodeBlock* codeBlock = callFrame->codeBlock(); @@ -1389,17 +1648,18 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail) if (stubInfo->accessType == access_get_by_id_self) { ASSERT(!stubInfo->stubRoutine); polymorphicStructureList = new PolymorphicAccessStructureList(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure); - stubInfo->initGetByIdSelfList(polymorphicStructureList, 2); + stubInfo->initGetByIdSelfList(polymorphicStructureList, 1); } else { polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList; listIndex = stubInfo->u.getByIdSelfList.listSize; - stubInfo->u.getByIdSelfList.listSize++; } + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { + stubInfo->u.getByIdSelfList.listSize++; + JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, baseValue.asCell()->structure(), ident, slot, slot.cachedOffset()); - JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), slot.cachedOffset()); - - if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); + if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) + 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); @@ -1424,16 +1684,48 @@ static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(Str case access_get_by_id_proto_list: prototypeStructureList = stubInfo->u.getByIdProtoList.structureList; listIndex = stubInfo->u.getByIdProtoList.listSize; - stubInfo->u.getByIdProtoList.listSize++; + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) + stubInfo->u.getByIdProtoList.listSize++; break; default: ASSERT_NOT_REACHED(); } - ASSERT(listIndex < POLYMORPHIC_LIST_CACHE_SIZE); + ASSERT(listIndex <= POLYMORPHIC_LIST_CACHE_SIZE); return prototypeStructureList; } +DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_getter_stub) +{ + STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; + GetterSetter* getterSetter = asGetterSetter(stackFrame.args[0].jsObject()); + if (!getterSetter->getter()) + return JSValue::encode(jsUndefined()); + JSObject* getter = asObject(getterSetter->getter()); + CallData callData; + CallType callType = getter->getCallData(callData); + JSValue result = call(callFrame, getter, callType, callData, stackFrame.args[1].jsObject(), ArgList()); + if (callFrame->hadException()) + returnToThrowTrampoline(&callFrame->globalData(), stackFrame.args[2].returnAddress(), STUB_RETURN_ADDRESS); + + return JSValue::encode(result); +} + +DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_custom_stub) +{ + STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; + JSObject* slotBase = stackFrame.args[0].jsObject(); + PropertySlot::GetValueFunc getter = reinterpret_cast<PropertySlot::GetValueFunc>(stackFrame.args[1].asPointer); + const Identifier& ident = stackFrame.args[2].identifier(); + JSValue result = getter(callFrame, slotBase, ident); + if (callFrame->hadException()) + returnToThrowTrampoline(&callFrame->globalData(), stackFrame.args[3].returnAddress(), STUB_RETURN_ADDRESS); + + return JSValue::encode(result); +} + DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1447,12 +1739,12 @@ 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() || baseValue.asCell()->structure()->isDictionary()) { ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); return JSValue::encode(result); } - Structure* structure = asCell(baseValue)->structure(); + Structure* structure = baseValue.asCell()->structure(); CodeBlock* codeBlock = callFrame->codeBlock(); StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); @@ -1463,8 +1755,8 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) if (slot.slotBase() == baseValue) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); - else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) { - ASSERT(!asCell(baseValue)->structure()->isDictionary()); + else if (slot.slotBase() == baseValue.asCell()->structure()->prototypeForLookup(callFrame)) { + ASSERT(!baseValue.asCell()->structure()->isDictionary()); // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. if (slotBaseObject->structure()->isDictionary()) { @@ -1474,21 +1766,24 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) int listIndex; PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { + JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), propertyName, slot, offset); - JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), offset); - - if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); + if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); + } } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) { - ASSERT(!asCell(baseValue)->structure()->isDictionary()); + ASSERT(!baseValue.asCell()->structure()->isDictionary()); int listIndex; PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); + + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { + StructureChain* protoChain = structure->prototypeChain(callFrame); + JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, propertyName, slot, offset); - StructureChain* protoChain = structure->prototypeChain(callFrame); - JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, offset); - - if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); + if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); + } } else ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); @@ -1545,6 +1840,23 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_string_fail) #endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) +DEFINE_STUB_FUNCTION(void, op_check_has_instance) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + CallFrame* callFrame = stackFrame.callFrame; + JSValue baseVal = stackFrame.args[0].jsValue(); + + // ECMA-262 15.3.5.3: + // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function). +#ifndef NDEBUG + TypeInfo typeInfo(UnspecifiedType); + ASSERT(!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()); +#endif + stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal); + VM_THROW_EXCEPTION_AT_END(); +} + DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1564,10 +1876,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof) // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function). TypeInfo typeInfo(UnspecifiedType); if (!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()) { - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal, vPCIndex, codeBlock); + stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "instanceof", baseVal); VM_THROW_EXCEPTION(); } ASSERT(typeInfo.type() != UnspecifiedType); @@ -1577,7 +1886,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof) return JSValue::encode(jsBoolean(false)); if (!proto.isObject()) { - throwError(callFrame, TypeError, "instanceof called on an object with an invalid prototype property."); + throwError(callFrame, createTypeError(callFrame, "instanceof called on an object with an invalid prototype property.")); VM_THROW_EXCEPTION(); } } @@ -1596,7 +1905,11 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_id) JSObject* baseObj = stackFrame.args[0].jsValue().toObject(callFrame); - JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, stackFrame.args[1].identifier())); + bool couldDelete = baseObj->deleteProperty(callFrame, stackFrame.args[1].identifier()); + JSValue result = jsBoolean(couldDelete); + if (!couldDelete && callFrame->codeBlock()->isStrictMode()) + stackFrame.globalData->exception = createTypeError(stackFrame.callFrame, "Unable to delete property."); + CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -1611,10 +1924,10 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_mul) double left; double right; if (src1.getNumber(left) && src2.getNumber(right)) - return JSValue::encode(jsNumber(stackFrame.globalData, left * right)); + return JSValue::encode(jsNumber(left * right)); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) * src2.toNumber(callFrame)); + JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -1622,94 +1935,238 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_mul) DEFINE_STUB_FUNCTION(JSObject*, op_new_func) { STUB_INIT_STACK_FRAME(stackFrame); - + + ASSERT(stackFrame.callFrame->codeBlock()->codeType() != FunctionCode || !stackFrame.callFrame->codeBlock()->needsFullScopeChain() || stackFrame.callFrame->uncheckedR(stackFrame.callFrame->codeBlock()->activationRegister()).jsValue()); return stackFrame.args[0].function()->make(stackFrame.callFrame, stackFrame.callFrame->scopeChain()); } -DEFINE_STUB_FUNCTION(void*, op_call_JSFunction) +DEFINE_STUB_FUNCTION(void*, op_call_jitCompile) { STUB_INIT_STACK_FRAME(stackFrame); #if !ASSERT_DISABLED CallData callData; - ASSERT(stackFrame.args[0].jsValue().getCallData(callData) == CallTypeJS); + ASSERT(stackFrame.callFrame->callee()->getCallData(callData) == CallTypeJS); #endif - JSFunction* function = asFunction(stackFrame.args[0].jsValue()); + JSFunction* function = asFunction(stackFrame.callFrame->callee()); ASSERT(!function->isHostFunction()); FunctionExecutable* executable = function->jsExecutable(); ScopeChainNode* callDataScopeChain = function->scope().node(); - executable->jitCode(stackFrame.callFrame, callDataScopeChain); + JSObject* error = executable->compileForCall(stackFrame.callFrame, callDataScopeChain); + if (error) { + stackFrame.callFrame->globalData().exception = error; + return 0; + } + return function; +} + +DEFINE_STUB_FUNCTION(void*, op_construct_jitCompile) +{ + STUB_INIT_STACK_FRAME(stackFrame); +#if !ASSERT_DISABLED + ConstructData constructData; + ASSERT(asFunction(stackFrame.callFrame->callee())->getConstructData(constructData) == ConstructTypeJS); +#endif + + JSFunction* function = asFunction(stackFrame.callFrame->callee()); + ASSERT(!function->isHostFunction()); + FunctionExecutable* executable = function->jsExecutable(); + ScopeChainNode* callDataScopeChain = function->scope().node(); + JSObject* error = executable->compileForConstruct(stackFrame.callFrame, callDataScopeChain); + if (error) { + stackFrame.callFrame->globalData().exception = error; + return 0; + } return function; } -DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck) +DEFINE_STUB_FUNCTION(void*, op_call_arityCheck) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - JSFunction* callee = asFunction(stackFrame.args[0].jsValue()); + JSFunction* callee = asFunction(callFrame->callee()); ASSERT(!callee->isHostFunction()); - CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecode(); - int argCount = stackFrame.args[2].int32(); + CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForCall(); + int argCount = callFrame->argumentCountIncludingThis(); + ReturnAddressPtr pc = callFrame->returnPC(); ASSERT(argCount != newCodeBlock->m_numParameters); CallFrame* oldCallFrame = callFrame->callerFrame(); + Register* r; if (argCount > newCodeBlock->m_numParameters) { size_t numParameters = newCodeBlock->m_numParameters; - Register* r = callFrame->registers() + numParameters; + r = callFrame->registers() + numParameters; + Register* newEnd = r + newCodeBlock->m_numCalleeRegisters; + if (!stackFrame.registerFile->grow(newEnd)) { + // Rewind to the previous call frame because op_call already optimistically + // moved the call frame forward. + ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc); + STUB_SET_RETURN_ADDRESS(handler.catchRoutine); + return handler.callFrame; + } Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount; for (size_t i = 0; i < numParameters; ++i) argv[i + argCount] = argv[i]; - - callFrame = CallFrame::create(r); - callFrame->setCallerFrame(oldCallFrame); } else { size_t omittedArgCount = newCodeBlock->m_numParameters - argCount; - Register* r = callFrame->registers() + omittedArgCount; + r = callFrame->registers() + omittedArgCount; Register* newEnd = r + newCodeBlock->m_numCalleeRegisters; if (!stackFrame.registerFile->grow(newEnd)) { // Rewind to the previous call frame because op_call already optimistically // moved the call frame forward. - stackFrame.callFrame = oldCallFrame; - throwStackOverflowError(oldCallFrame, stackFrame.globalData, stackFrame.args[1].returnAddress(), STUB_RETURN_ADDRESS); - RETURN_POINTER_PAIR(0, 0); + ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc); + STUB_SET_RETURN_ADDRESS(handler.catchRoutine); + return handler.callFrame; } Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount; for (size_t i = 0; i < omittedArgCount; ++i) argv[i] = jsUndefined(); + } + + callFrame = CallFrame::create(r); + callFrame->setCallerFrame(oldCallFrame); + callFrame->setArgumentCountIncludingThis(argCount); + callFrame->setCallee(callee); + callFrame->setScopeChain(callee->scope().node()); + callFrame->setReturnPC(pc.value()); + + ASSERT((void*)callFrame <= stackFrame.registerFile->end()); + return callFrame; +} + +DEFINE_STUB_FUNCTION(void*, op_construct_arityCheck) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + CallFrame* callFrame = stackFrame.callFrame; + JSFunction* callee = asFunction(callFrame->callee()); + ASSERT(!callee->isHostFunction()); + CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForConstruct(); + int argCount = callFrame->argumentCountIncludingThis(); + ReturnAddressPtr pc = callFrame->returnPC(); + + ASSERT(argCount != newCodeBlock->m_numParameters); + + CallFrame* oldCallFrame = callFrame->callerFrame(); + + Register* r; + if (argCount > newCodeBlock->m_numParameters) { + size_t numParameters = newCodeBlock->m_numParameters; + r = callFrame->registers() + numParameters; + Register* newEnd = r + newCodeBlock->m_numCalleeRegisters; + if (!stackFrame.registerFile->grow(newEnd)) { + // Rewind to the previous call frame because op_call already optimistically + // moved the call frame forward. + ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc); + STUB_SET_RETURN_ADDRESS(handler.catchRoutine); + return handler.callFrame; + } - callFrame = CallFrame::create(r); - callFrame->setCallerFrame(oldCallFrame); + Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount; + for (size_t i = 0; i < numParameters; ++i) + argv[i + argCount] = argv[i]; + } else { + size_t omittedArgCount = newCodeBlock->m_numParameters - argCount; + r = callFrame->registers() + omittedArgCount; + Register* newEnd = r + newCodeBlock->m_numCalleeRegisters; + if (!stackFrame.registerFile->grow(newEnd)) { + // Rewind to the previous call frame because op_call already optimistically + // moved the call frame forward. + ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc); + STUB_SET_RETURN_ADDRESS(handler.catchRoutine); + return handler.callFrame; + } + + Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount; + for (size_t i = 0; i < omittedArgCount; ++i) + argv[i] = jsUndefined(); } - RETURN_POINTER_PAIR(callee, callFrame); + callFrame = CallFrame::create(r); + callFrame->setCallerFrame(oldCallFrame); + callFrame->setArgumentCountIncludingThis(argCount); + callFrame->setCallee(callee); + callFrame->setScopeChain(callee->scope().node()); + callFrame->setReturnPC(pc.value()); + + ASSERT((void*)callFrame <= stackFrame.registerFile->end()); + return callFrame; } #if ENABLE(JIT_OPTIMIZE_CALL) DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall) { STUB_INIT_STACK_FRAME(stackFrame); - JSFunction* callee = asFunction(stackFrame.args[0].jsValue()); + CallFrame* callFrame = stackFrame.callFrame; + JSFunction* callee = asFunction(callFrame->callee()); ExecutableBase* executable = callee->executable(); - JITCode& jitCode = executable->generatedJITCode(); - + + MacroAssemblerCodePtr codePtr; + CodeBlock* codeBlock = 0; + if (executable->isHostFunction()) + codePtr = executable->generatedJITCodeForCall().addressForCall(); + else { + FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); + JSObject* error = functionExecutable->compileForCall(callFrame, callee->scope().node()); + if (error) { + callFrame->globalData().exception = createStackOverflowError(callFrame); + return 0; + } + codeBlock = &functionExecutable->generatedBytecodeForCall(); + if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters)) + codePtr = functionExecutable->generatedJITCodeForCall().addressForCall(); + else + codePtr = functionExecutable->generatedJITCodeForCallWithArityCheck(); + } + CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC()); + + if (!callLinkInfo->seenOnce()) + callLinkInfo->setSeen(); + else + JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCountIncludingThis(), stackFrame.globalData); + + return codePtr.executableAddress(); +} + +DEFINE_STUB_FUNCTION(void*, vm_lazyLinkConstruct) +{ + STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; + JSFunction* callee = asFunction(callFrame->callee()); + ExecutableBase* executable = callee->executable(); + + MacroAssemblerCodePtr codePtr; CodeBlock* codeBlock = 0; - 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()); + if (executable->isHostFunction()) + codePtr = executable->generatedJITCodeForConstruct().addressForCall(); + else { + FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); + JSObject* error = functionExecutable->compileForConstruct(callFrame, callee->scope().node()); + if (error) { + throwStackOverflowError(callFrame, stackFrame.globalData, ReturnAddressPtr(callFrame->returnPC()), STUB_RETURN_ADDRESS); + return 0; + } + codeBlock = &functionExecutable->generatedBytecodeForConstruct(); + if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters)) + codePtr = functionExecutable->generatedJITCodeForConstruct().addressForCall(); + else + codePtr = functionExecutable->generatedJITCodeForConstructWithArityCheck(); + } + CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC()); if (!callLinkInfo->seenOnce()) callLinkInfo->setSeen(); else - JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, jitCode, callLinkInfo, stackFrame.args[2].int32(), stackFrame.globalData); + JIT::linkConstruct(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCountIncludingThis(), stackFrame.globalData); - return jitCode.addressForCall().executableAddress(); + return codePtr.executableAddress(); } #endif // !ENABLE(JIT_OPTIMIZE_CALL) @@ -1729,7 +2186,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction) JSValue funcVal = stackFrame.args[0].jsValue(); CallData callData; - CallType callType = funcVal.getCallData(callData); + CallType callType = getCallData(funcVal, callData); ASSERT(callType != CallTypeJS); @@ -1738,55 +2195,43 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction) int argCount = stackFrame.args[2].int32(); CallFrame* previousCallFrame = stackFrame.callFrame; CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset); + if (!stackFrame.registerFile->grow(callFrame->registers())) { + throwStackOverflowError(previousCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS); + VM_THROW_EXCEPTION(); + } - 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; - ArgList argList(argv + 1, argCount - 1); + callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(funcVal)); - JSValue returnValue; + EncodedJSValue returnValue; { SamplingTool::HostCallRecord callRecord(CTI_SAMPLER); - - // FIXME: All host methods should be calling toThisObject, but this is not presently the case. - JSValue thisValue = argv[0].jsValue(); - if (thisValue == jsNull()) - thisValue = callFrame->globalThisValue(); - - returnValue = callData.native.function(callFrame, asObject(funcVal), thisValue, argList); + returnValue = callData.native.function(callFrame); } - stackFrame.callFrame = previousCallFrame; - CHECK_FOR_EXCEPTION(); - return JSValue::encode(returnValue); + CHECK_FOR_EXCEPTION_AT_END(); + return returnValue; } ASSERT(callType == CallTypeNone); - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal, vPCIndex, codeBlock); + stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal); VM_THROW_EXCEPTION(); } -DEFINE_STUB_FUNCTION(void, op_create_arguments) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments) { STUB_INIT_STACK_FRAME(stackFrame); Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame); - stackFrame.callFrame->setCalleeArguments(arguments); - stackFrame.callFrame[RegisterFile::ArgumentsRegister] = JSValue(arguments); + return JSValue::encode(JSValue(arguments)); } -DEFINE_STUB_FUNCTION(void, op_create_arguments_no_params) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments_no_params) { STUB_INIT_STACK_FRAME(stackFrame); Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame, Arguments::NoParameters); - stackFrame.callFrame->setCalleeArguments(arguments); - stackFrame.callFrame[RegisterFile::ArgumentsRegister] = JSValue(arguments); + return JSValue::encode(JSValue(arguments)); } DEFINE_STUB_FUNCTION(void, op_tear_off_activation) @@ -1794,7 +2239,20 @@ DEFINE_STUB_FUNCTION(void, op_tear_off_activation) STUB_INIT_STACK_FRAME(stackFrame); ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain()); - asActivation(stackFrame.args[0].jsValue())->copyRegisters(stackFrame.callFrame->optionalCalleeArguments()); + JSValue activationValue = stackFrame.args[0].jsValue(); + if (!activationValue) { + if (JSValue v = stackFrame.args[1].jsValue()) { + if (!stackFrame.callFrame->codeBlock()->isStrictMode()) + asArguments(v)->copyRegisters(); + } + return; + } + JSActivation* activation = asActivation(stackFrame.args[0].jsValue()); + activation->copyRegisters(); + if (JSValue v = stackFrame.args[1].jsValue()) { + if (!stackFrame.callFrame->codeBlock()->isStrictMode()) + asArguments(v)->setActivation(activation); + } } DEFINE_STUB_FUNCTION(void, op_tear_off_arguments) @@ -1802,8 +2260,7 @@ DEFINE_STUB_FUNCTION(void, op_tear_off_arguments) STUB_INIT_STACK_FRAME(stackFrame); ASSERT(stackFrame.callFrame->codeBlock()->usesArguments() && !stackFrame.callFrame->codeBlock()->needsFullScopeChain()); - if (stackFrame.callFrame->optionalCalleeArguments()) - stackFrame.callFrame->optionalCalleeArguments()->copyRegisters(); + asArguments(stackFrame.args[0].jsValue())->copyRegisters(); } DEFINE_STUB_FUNCTION(void, op_profile_will_call) @@ -1860,69 +2317,46 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve) } } while (++iter != end); - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock); + stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION(); } -DEFINE_STUB_FUNCTION(JSObject*, op_construct_JSConstruct) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - JSFunction* constructor = asFunction(stackFrame.args[0].jsValue()); - if (constructor->isHostFunction()) { - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createNotAConstructorError(callFrame, constructor, vPCIndex, codeBlock); - VM_THROW_EXCEPTION(); - } - -#if !ASSERT_DISABLED - ConstructData constructData; - ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS); -#endif - - Structure* structure; - if (stackFrame.args[3].jsValue().isObject()) - structure = asObject(stackFrame.args[3].jsValue())->inheritorID(); - else - structure = constructor->scope().node()->globalObject->emptyObjectStructure(); - return new (stackFrame.globalData) JSObject(structure); -} - DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct) { STUB_INIT_STACK_FRAME(stackFrame); - CallFrame* callFrame = stackFrame.callFrame; - JSValue constrVal = stackFrame.args[0].jsValue(); - int argCount = stackFrame.args[2].int32(); - int thisRegister = stackFrame.args[4].int32(); ConstructData constructData; - ConstructType constructType = constrVal.getConstructData(constructData); + ConstructType constructType = getConstructData(constrVal, constructData); + + ASSERT(constructType != ConstructTypeJS); if (constructType == ConstructTypeHost) { - ArgList argList(callFrame->registers() + thisRegister + 1, argCount - 1); + int registerOffset = stackFrame.args[1].int32(); + int argCount = stackFrame.args[2].int32(); + CallFrame* previousCallFrame = stackFrame.callFrame; + CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset); + if (!stackFrame.registerFile->grow(callFrame->registers())) { + throwStackOverflowError(previousCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS); + VM_THROW_EXCEPTION(); + } + + callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(constrVal)); - JSValue returnValue; + EncodedJSValue returnValue; { SamplingTool::HostCallRecord callRecord(CTI_SAMPLER); - returnValue = constructData.native.function(callFrame, asObject(constrVal), argList); + returnValue = constructData.native.function(callFrame); } - CHECK_FOR_EXCEPTION(); - return JSValue::encode(returnValue); + CHECK_FOR_EXCEPTION_AT_END(); + return returnValue; } ASSERT(constructType == ConstructTypeNone); - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createNotAConstructorError(callFrame, constrVal, vPCIndex, codeBlock); + stackFrame.globalData->exception = createNotAConstructorError(stackFrame.callFrame, constrVal); VM_THROW_EXCEPTION(); } @@ -1936,31 +2370,38 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val) JSValue baseValue = stackFrame.args[0].jsValue(); JSValue subscript = stackFrame.args[1].jsValue(); - JSValue result; + if (LIKELY(baseValue.isCell() && subscript.isString())) { + Identifier propertyName(callFrame, asString(subscript)->value(callFrame)); + PropertySlot slot(baseValue.asCell()); + // JSString::value may have thrown, but we shouldn't find a property with a null identifier, + // so we should miss this case and wind up in the CHECK_FOR_EXCEPTION_AT_END, below. + if (baseValue.asCell()->fastGetOwnPropertySlot(callFrame, propertyName, slot)) { + JSValue result = slot.getValue(callFrame, propertyName); + CHECK_FOR_EXCEPTION(); + return JSValue::encode(result); + } + } - if (LIKELY(subscript.isUInt32())) { + if (subscript.isUInt32()) { uint32_t i = subscript.asUInt32(); - if (isJSArray(globalData, baseValue)) { - JSArray* jsArray = asArray(baseValue); - if (jsArray->canGetIndex(i)) - result = jsArray->getIndex(i); - else - 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. + if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) { ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_string)); - result = asString(baseValue)->getIndex(callFrame, i); - } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { + JSValue result = asString(baseValue)->getIndex(callFrame, i); + CHECK_FOR_EXCEPTION(); + return JSValue::encode(result); + } + 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(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); - } else { - Identifier property(callFrame, subscript.toString(callFrame)); - result = baseValue.get(callFrame, property); + } + JSValue result = baseValue.get(callFrame, i); + CHECK_FOR_EXCEPTION(); + return JSValue::encode(result); } - + + Identifier property(callFrame, subscript.toString(callFrame)); + JSValue result = baseValue.get(callFrame, property); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2036,10 +2477,10 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_sub) double left; double right; if (src1.getNumber(left) && src2.getNumber(right)) - return JSValue::encode(jsNumber(stackFrame.globalData, left - right)); + return JSValue::encode(jsNumber(left - right)); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) - src2.toNumber(callFrame)); + JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2084,7 +2525,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val) } else { Identifier property(callFrame, subscript.toString(callFrame)); if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception. - PutPropertySlot slot; + PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); baseValue.put(callFrame, property, value, slot); } } @@ -2127,7 +2568,7 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array) } else { Identifier property(callFrame, subscript.toString(callFrame)); if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception. - PutPropertySlot slot; + PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); baseValue.put(callFrame, property, value, slot); } } @@ -2157,13 +2598,14 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs) if (!arguments) { int providedParams = callFrame->registers()[RegisterFile::ArgumentCount].i() - 1; argCount = providedParams; + argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments)); int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; Register* newEnd = callFrame->registers() + sizeDelta; if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { stackFrame.globalData->exception = createStackOverflowError(callFrame); VM_THROW_EXCEPTION(); } - int32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount(); + int32_t expectedParams = asFunction(callFrame->callee())->jsExecutable()->parameterCount(); int32_t inplaceArgs = min(providedParams, expectedParams); Register* inplaceArgsDst = callFrame->registers() + argsOffset; @@ -2184,14 +2626,13 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs) } else if (!arguments.isUndefinedOrNull()) { if (!arguments.isObject()) { - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock); + stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments); VM_THROW_EXCEPTION(); } if (asObject(arguments)->classInfo() == &Arguments::info) { Arguments* argsObject = asArguments(arguments); argCount = argsObject->numProvidedArguments(callFrame); + argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments)); int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; Register* newEnd = callFrame->registers() + sizeDelta; if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { @@ -2202,6 +2643,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs) } else if (isJSArray(&callFrame->globalData(), arguments)) { JSArray* array = asArray(arguments); argCount = array->length(); + argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments)); int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; Register* newEnd = callFrame->registers() + sizeDelta; if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { @@ -2212,6 +2654,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs) } else if (asObject(arguments)->inherits(&JSArray::info)) { JSObject* argObject = asObject(arguments); argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame); + argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments)); int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; Register* newEnd = callFrame->registers() + sizeDelta; if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { @@ -2224,9 +2667,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs) CHECK_FOR_EXCEPTION(); } } else { - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock); + stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments); VM_THROW_EXCEPTION(); } } @@ -2242,10 +2683,10 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_negate) double v; if (src.getNumber(v)) - return JSValue::encode(jsNumber(stackFrame.globalData, -v)); + return JSValue::encode(jsNumber(-v)); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, -src.toNumber(callFrame)); + JSValue result = jsNumber(-src.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2254,9 +2695,35 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base) { STUB_INIT_STACK_FRAME(stackFrame); - return JSValue::encode(JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain())); + return JSValue::encode(JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), false)); } +DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base_strict_put) +{ + STUB_INIT_STACK_FRAME(stackFrame); + JSValue base = JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), true); + if (!base) { + stackFrame.globalData->exception = createErrorForInvalidGlobalAssignment(stackFrame.callFrame, stackFrame.args[0].identifier().ustring()); + VM_THROW_EXCEPTION(); + } + return JSValue::encode(base); +} + +DEFINE_STUB_FUNCTION(EncodedJSValue, op_ensure_property_exists) +{ + STUB_INIT_STACK_FRAME(stackFrame); + JSValue base = stackFrame.callFrame->r(stackFrame.args[0].int32()).jsValue(); + JSObject* object = asObject(base); + PropertySlot slot(object); + ASSERT(stackFrame.callFrame->codeBlock()->isStrictMode()); + if (!object->getPropertySlot(stackFrame.callFrame, stackFrame.args[1].identifier(), slot)) { + stackFrame.globalData->exception = createErrorForInvalidGlobalAssignment(stackFrame.callFrame, stackFrame.args[1].identifier().ustring()); + VM_THROW_EXCEPTION(); + } + + return JSValue::encode(base); +} + DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip) { STUB_INIT_STACK_FRAME(stackFrame); @@ -2269,6 +2736,13 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip) ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); ASSERT(iter != end); + CodeBlock* codeBlock = callFrame->codeBlock(); + bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); + ASSERT(skip || !checkTopLevel); + if (checkTopLevel && skip--) { + if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue()) + ++iter; + } while (skip--) { ++iter; ASSERT(iter != end); @@ -2284,9 +2758,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip) } } while (++iter != end); - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock); + stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION(); } @@ -2295,16 +2767,17 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global) STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - JSGlobalObject* globalObject = stackFrame.args[0].globalObject(); - Identifier& ident = stackFrame.args[1].identifier(); - unsigned globalResolveInfoIndex = stackFrame.args[2].int32(); + CodeBlock* codeBlock = callFrame->codeBlock(); + JSGlobalObject* globalObject = codeBlock->globalObject(); + Identifier& ident = stackFrame.args[0].identifier(); + unsigned globalResolveInfoIndex = stackFrame.args[1].int32(); ASSERT(globalObject->isGlobalObject()); PropertySlot slot(globalObject); if (globalObject->getPropertySlot(callFrame, ident, slot)) { JSValue result = slot.getValue(callFrame, ident); - if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { - GlobalResolveInfo& globalResolveInfo = callFrame->codeBlock()->globalResolveInfo(globalResolveInfoIndex); + if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { + GlobalResolveInfo& globalResolveInfo = codeBlock->globalResolveInfo(globalResolveInfoIndex); if (globalResolveInfo.structure) globalResolveInfo.structure->deref(); globalObject->structure()->ref(); @@ -2317,8 +2790,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global) return JSValue::encode(result); } - unsigned vPCIndex = callFrame->codeBlock()->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, callFrame->codeBlock()); + stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION(); } @@ -2332,10 +2804,10 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_div) double left; double right; if (src1.getNumber(left) && src2.getNumber(right)) - return JSValue::encode(jsNumber(stackFrame.globalData, left / right)); + return JSValue::encode(jsNumber(left / right)); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) / src2.toNumber(callFrame)); + JSValue result = jsNumber(src1.toNumber(callFrame) / src2.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2347,7 +2819,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_dec) JSValue v = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, v.toNumber(callFrame) - 1); + JSValue result = jsNumber(v.toNumber(callFrame) - 1); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2415,7 +2887,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_inc) JSValue number = v.toJSNumber(callFrame); CHECK_FOR_EXCEPTION_AT_END(); - callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(stackFrame.globalData, number.uncheckedGetNumber() + 1); + callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number.uncheckedGetNumber() + 1); return JSValue::encode(number); } @@ -2430,14 +2902,14 @@ DEFINE_STUB_FUNCTION(int, op_eq) start: if (src2.isUndefined()) { return src1.isNull() || - (src1.isCell() && asCell(src1)->structure()->typeInfo().masqueradesAsUndefined()) || - src1.isUndefined(); + (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined()) + || src1.isUndefined(); } if (src2.isNull()) { return src1.isUndefined() || - (src1.isCell() && asCell(src1)->structure()->typeInfo().masqueradesAsUndefined()) || - src1.isNull(); + (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined()) + || src1.isNull(); } if (src1.isInt32()) { @@ -2473,27 +2945,27 @@ DEFINE_STUB_FUNCTION(int, op_eq) } if (src1.isUndefined()) - return src2.isCell() && asCell(src2)->structure()->typeInfo().masqueradesAsUndefined(); + return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined(); if (src1.isNull()) - return src2.isCell() && asCell(src2)->structure()->typeInfo().masqueradesAsUndefined(); + return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined(); - JSCell* cell1 = asCell(src1); + JSCell* cell1 = src1.asCell(); if (cell1->isString()) { if (src2.isInt32()) - return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asInt32(); + return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asInt32(); if (src2.isDouble()) - return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asDouble(); + return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asDouble(); if (src2.isTrue()) - return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 1.0; + return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 1.0; if (src2.isFalse()) - return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 0.0; + return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 0.0; - JSCell* cell2 = asCell(src2); + JSCell* cell2 = src2.asCell(); if (cell2->isString()) return static_cast<JSString*>(cell1)->value(stackFrame.callFrame) == static_cast<JSString*>(cell2)->value(stackFrame.callFrame); @@ -2517,10 +2989,9 @@ DEFINE_STUB_FUNCTION(int, op_eq) #endif // USE(JSVALUE32_64) } -#if USE(JSVALUE32_64) - DEFINE_STUB_FUNCTION(int, op_eq_strings) { +#if USE(JSVALUE32_64) STUB_INIT_STACK_FRAME(stackFrame); JSString* string1 = stackFrame.args[0].jsString(); @@ -2529,9 +3000,12 @@ DEFINE_STUB_FUNCTION(int, op_eq_strings) ASSERT(string1->isString()); ASSERT(string2->isString()); return string1->value(stackFrame.callFrame) == string2->value(stackFrame.callFrame); -} - +#else + UNUSED_PARAM(args); + ASSERT_NOT_REACHED(); + return 0; #endif +} DEFINE_STUB_FUNCTION(EncodedJSValue, op_lshift) { @@ -2541,7 +3015,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_lshift) JSValue shift = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f)); + JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2555,7 +3029,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitand) ASSERT(!src1.isInt32() || !src2.isInt32()); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) & src2.toInt32(callFrame)); + JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2568,7 +3042,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_rshift) JSValue shift = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); + JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); @@ -2582,7 +3056,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitnot) ASSERT(!src.isInt32()); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, ~src.toInt32(callFrame)); + JSValue result = jsNumber(~src.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2616,9 +3090,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base) ++iter; } while (iter != end); - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock); + stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION_AT_END(); return JSValue::encode(JSValue()); } @@ -2630,6 +3102,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_func_exp) FunctionExecutable* function = stackFrame.args[0].function(); JSFunction* func = function->make(callFrame, callFrame->scopeChain()); + ASSERT(callFrame->codeBlock()->codeType() != FunctionCode || !callFrame->codeBlock()->needsFullScopeChain() || callFrame->uncheckedR(callFrame->codeBlock()->activationRegister()).jsValue()); /* The Identifier in a FunctionExpression can be referenced from inside @@ -2655,7 +3128,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_mod) CallFrame* callFrame = stackFrame.callFrame; double d = dividendValue.toNumber(callFrame); - JSValue result = jsNumber(stackFrame.globalData, fmod(d, divisorValue.toNumber(callFrame))); + JSValue result = jsNumber(fmod(d, divisorValue.toNumber(callFrame))); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2681,7 +3154,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_dec) JSValue number = v.toJSNumber(callFrame); CHECK_FOR_EXCEPTION_AT_END(); - callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(stackFrame.globalData, number.uncheckedGetNumber() - 1); + callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number.uncheckedGetNumber() - 1); return JSValue::encode(number); } @@ -2693,7 +3166,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_urshift) JSValue shift = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); + JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2707,7 +3180,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitxor) CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) ^ src2.toInt32(callFrame)); + JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2716,7 +3189,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_regexp) { STUB_INIT_STACK_FRAME(stackFrame); - return new (stackFrame.globalData) RegExpObject(stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), stackFrame.args[0].regExp()); + return new (stackFrame.globalData) RegExpObject(stackFrame.callFrame->lexicalGlobalObject(), stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), stackFrame.args[0].regExp()); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor) @@ -2728,7 +3201,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor) CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) | src2.toInt32(callFrame)); + JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2736,6 +3209,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor) DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval) { STUB_INIT_STACK_FRAME(stackFrame); + ASSERT(stackFrame.callFrame->codeBlock()->codeType() != FunctionCode || !stackFrame.callFrame->codeBlock()->needsFullScopeChain() || stackFrame.callFrame->uncheckedR(stackFrame.callFrame->codeBlock()->activationRegister()).jsValue()); CallFrame* callFrame = stackFrame.callFrame; RegisterFile* registerFile = stackFrame.registerFile; @@ -2748,47 +3222,24 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval) Register* newCallFrame = callFrame->registers() + registerOffset; Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount; - JSValue thisValue = argv[0].jsValue(); + JSValue baseValue = argv[0].jsValue(); JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject; - if (thisValue == globalObject && funcVal == globalObject->evalFunction()) { - JSValue exceptionValue; - JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue); - if (UNLIKELY(exceptionValue)) { - stackFrame.globalData->exception = exceptionValue; - VM_THROW_EXCEPTION_AT_END(); - } + if (baseValue == globalObject && funcVal == globalObject->evalFunction()) { + JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset); + CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } return JSValue::encode(JSValue()); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_throw) +DEFINE_STUB_FUNCTION(void*, op_throw) { STUB_INIT_STACK_FRAME(stackFrame); - - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - - JSValue exceptionValue = stackFrame.args[0].jsValue(); - ASSERT(exceptionValue); - - HandlerInfo* handler = stackFrame.globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex, true); - - if (!handler) { - *stackFrame.exception = exceptionValue; - STUB_SET_RETURN_ADDRESS(FunctionPtr(ctiOpThrowNotCaught).value()); - return JSValue::encode(jsNull()); - } - - stackFrame.callFrame = callFrame; - void* catchRoutine = handler->nativeCode.executableAddress(); - ASSERT(catchRoutine); - STUB_SET_RETURN_ADDRESS(catchRoutine); - return JSValue::encode(exceptionValue); + ExceptionHandler handler = jitThrow(stackFrame.globalData, stackFrame.callFrame, stackFrame.args[0].jsValue(), STUB_RETURN_ADDRESS); + STUB_SET_RETURN_ADDRESS(handler.catchRoutine); + return handler.callFrame; } DEFINE_STUB_FUNCTION(JSPropertyNameIterator*, op_get_pnames) @@ -2810,7 +3261,9 @@ DEFINE_STUB_FUNCTION(int, has_property) JSObject* base = stackFrame.args[0].jsObject(); JSString* property = stackFrame.args[1].jsString(); - return base->hasProperty(stackFrame.callFrame, Identifier(stackFrame.callFrame, property->value(stackFrame.callFrame))); + int result = base->hasProperty(stackFrame.callFrame, Identifier(stackFrame.callFrame, property->value(stackFrame.callFrame))); + CHECK_FOR_EXCEPTION_AT_END(); + return result; } DEFINE_STUB_FUNCTION(JSObject*, op_push_scope) @@ -2887,7 +3340,9 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_stricteq) JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); - return JSValue::encode(jsBoolean(JSValue::strictEqual(stackFrame.callFrame, src1, src2))); + bool result = JSValue::strictEqual(stackFrame.callFrame, src1, src2); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(jsBoolean(result)); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_primitive) @@ -2913,7 +3368,9 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_nstricteq) JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); - return JSValue::encode(jsBoolean(!JSValue::strictEqual(stackFrame.callFrame, src1, src2))); + bool result = !JSValue::strictEqual(stackFrame.callFrame, src1, src2); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(jsBoolean(result)); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_jsnumber) @@ -2936,10 +3393,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_in) JSValue baseVal = stackFrame.args[1].jsValue(); if (!baseVal.isObject()) { - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "in", baseVal, vPCIndex, codeBlock); + stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "in", baseVal); VM_THROW_EXCEPTION(); } @@ -3022,11 +3476,12 @@ DEFINE_STUB_FUNCTION(void*, op_switch_char) void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); if (scrutinee.isString()) { - UString::Rep* value = asString(scrutinee)->value(callFrame).rep(); - if (value->size() == 1) - result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->data()[0]).executableAddress(); + StringImpl* value = asString(scrutinee)->value(callFrame).impl(); + if (value->length() == 1) + result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->characters()[0]).executableAddress(); } + CHECK_FOR_EXCEPTION_AT_END(); return result; } @@ -3042,10 +3497,11 @@ DEFINE_STUB_FUNCTION(void*, op_switch_string) void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); if (scrutinee.isString()) { - UString::Rep* value = asString(scrutinee)->value(callFrame).rep(); + StringImpl* value = asString(scrutinee)->value(callFrame).impl(); result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).executableAddress(); } + CHECK_FOR_EXCEPTION_AT_END(); return result; } @@ -3059,19 +3515,22 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val) JSObject* baseObj = baseValue.toObject(callFrame); // may throw JSValue subscript = stackFrame.args[1].jsValue(); - JSValue result; + bool result; uint32_t i; if (subscript.getUInt32(i)) - result = jsBoolean(baseObj->deleteProperty(callFrame, i)); + result = baseObj->deleteProperty(callFrame, i); else { CHECK_FOR_EXCEPTION(); Identifier property(callFrame, subscript.toString(callFrame)); CHECK_FOR_EXCEPTION(); - result = jsBoolean(baseObj->deleteProperty(callFrame, property)); + result = baseObj->deleteProperty(callFrame, property); } + if (!result && callFrame->codeBlock()->isStrictMode()) + stackFrame.globalData->exception = createTypeError(stackFrame.callFrame, "Unable to delete property."); + CHECK_FOR_EXCEPTION_AT_END(); - return JSValue::encode(result); + return JSValue::encode(jsBoolean(result)); } DEFINE_STUB_FUNCTION(void, op_put_getter) @@ -3098,18 +3557,24 @@ DEFINE_STUB_FUNCTION(void, op_put_setter) baseObj->defineSetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue())); } -DEFINE_STUB_FUNCTION(JSObject*, op_new_error) +DEFINE_STUB_FUNCTION(void, op_throw_reference_error) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned type = stackFrame.args[0].int32(); - JSValue message = stackFrame.args[1].jsValue(); - unsigned bytecodeOffset = stackFrame.args[2].int32(); + UString message = stackFrame.args[0].jsValue().toString(callFrame); + stackFrame.globalData->exception = createReferenceError(callFrame, message); + VM_THROW_EXCEPTION_AT_END(); +} + +DEFINE_STUB_FUNCTION(void, op_throw_syntax_error) +{ + STUB_INIT_STACK_FRAME(stackFrame); - unsigned lineNumber = codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset); - return Error::create(callFrame, static_cast<ErrorType>(type), message.toString(callFrame), lineNumber, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()); + CallFrame* callFrame = stackFrame.callFrame; + UString message = stackFrame.args[0].jsValue().toString(callFrame); + stackFrame.globalData->exception = createSyntaxError(callFrame, message); + VM_THROW_EXCEPTION_AT_END(); } DEFINE_STUB_FUNCTION(void, op_debug) @@ -3125,32 +3590,13 @@ DEFINE_STUB_FUNCTION(void, op_debug) stackFrame.globalData->interpreter->debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine); } -DEFINE_STUB_FUNCTION(EncodedJSValue, vm_throw) +DEFINE_STUB_FUNCTION(void*, vm_throw) { STUB_INIT_STACK_FRAME(stackFrame); - - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); JSGlobalData* globalData = stackFrame.globalData; - - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, globalData->exceptionLocation); - - JSValue exceptionValue = globalData->exception; - ASSERT(exceptionValue); - globalData->exception = JSValue(); - - HandlerInfo* handler = globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex, false); - - if (!handler) { - *stackFrame.exception = exceptionValue; - return JSValue::encode(jsNull()); - } - - stackFrame.callFrame = callFrame; - void* catchRoutine = handler->nativeCode.executableAddress(); - ASSERT(catchRoutine); - STUB_SET_RETURN_ADDRESS(catchRoutine); - return JSValue::encode(exceptionValue); + ExceptionHandler handler = jitThrow(globalData, stackFrame.callFrame, globalData->exception, globalData->exceptionLocation); + STUB_SET_RETURN_ADDRESS(handler.catchRoutine); + return handler.callFrame; } DEFINE_STUB_FUNCTION(EncodedJSValue, to_object) @@ -3161,6 +3607,32 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, to_object) return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame)); } +MacroAssemblerCodePtr JITThunks::ctiStub(JSGlobalData* globalData, ThunkGenerator generator) +{ + std::pair<CTIStubMap::iterator, bool> entry = m_ctiStubMap.add(generator, MacroAssemblerCodePtr()); + if (entry.second) + entry.first->second = generator(globalData, m_executablePool.get()); + return entry.first->second; +} + +PassRefPtr<NativeExecutable> JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function) +{ + std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap.add(function, 0); + if (entry.second) + entry.first->second = NativeExecutable::create(JIT::compileCTINativeCall(globalData, m_executablePool, function), function, ctiNativeConstruct(), callHostFunctionAsConstructor); + return entry.first->second; +} + +PassRefPtr<NativeExecutable> JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, ThunkGenerator generator) +{ + std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap.add(function, 0); + if (entry.second) { + MacroAssemblerCodePtr code = globalData->canUseJIT() ? generator(globalData, m_executablePool.get()) : MacroAssemblerCodePtr(); + entry.first->second = NativeExecutable::create(code, function, ctiNativeConstruct(), callHostFunctionAsConstructor); + } + return entry.first->second; +} + } // namespace JSC #endif // ENABLE(JIT) |
