/* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich * 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 * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #if ENABLE(JIT) #include "JITStubs.h" #include "Arguments.h" #include "CallFrame.h" #include "CodeBlock.h" #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" #include "JSString.h" #include "ObjectPrototype.h" #include "Operations.h" #include "Parser.h" #include "Profiler.h" #include "RegExpObject.h" #include "RegExpPrototype.h" #include "Register.h" #include "SamplingTool.h" #include #include #include using namespace std; namespace JSC { #if OS(DARWIN) || OS(WINDOWS) #define SYMBOL_STRING(name) "_" #name #else #define SYMBOL_STRING(name) #name #endif #if OS(IOS) #define THUMB_FUNC_PARAM(name) SYMBOL_STRING(name) #else #define THUMB_FUNC_PARAM(name) #endif #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) #name #endif #if OS(DARWIN) // Mach-O platform #define HIDE_SYMBOL(name) ".private_extern _" #name #elif OS(AIX) // IBM's own file format #define HIDE_SYMBOL(name) ".lglobl " #name #elif OS(LINUX) \ || OS(FREEBSD) \ || OS(OPENBSD) \ || OS(SOLARIS) \ || (OS(HPUX) && CPU(IA64)) \ || OS(SYMBIAN) \ || OS(NETBSD) // ELF platform #define HIDE_SYMBOL(name) ".hidden " #name #else #define HIDE_SYMBOL(name) #endif #if USE(JSVALUE32_64) #if COMPILER(GCC) && 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, code) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment); COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x3c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline); COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline); asm ( ".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushl %ebp" "\n" "movl %esp, %ebp" "\n" "pushl %esi" "\n" "pushl %edi" "\n" "pushl %ebx" "\n" "subl $0x3c, %esp" "\n" "movl $512, %esi" "\n" "movl 0x58(%esp), %edi" "\n" "call *0x50(%esp)" "\n" "addl $0x3c, %esp" "\n" "popl %ebx" "\n" "popl %edi" "\n" "popl %esi" "\n" "popl %ebp" "\n" "ret" "\n" ); asm ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movl %esp, %ecx" "\n" "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" "int3" "\n" ); asm ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "addl $0x3c, %esp" "\n" "popl %ebx" "\n" "popl %edi" "\n" "popl %esi" "\n" "popl %ebp" "\n" "ret" "\n" ); #elif COMPILER(GCC) && CPU(X86_64) // These ASSERTs remind you that, if you change the layout of JITStackFrame, you // need to change the assembly trampolines below to match. COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 32 == 0x0, JITStackFrame_maintains_32byte_stack_alignment); COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x48, JITStackFrame_stub_argument_space_matches_ctiTrampoline); COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x90, JITStackFrame_callFrame_offset_matches_ctiTrampoline); COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x80, JITStackFrame_code_offset_matches_ctiTrampoline); asm ( ".globl " SYMBOL_STRING(ctiTrampoline) "\n" HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushq %rbp" "\n" "movq %rsp, %rbp" "\n" "pushq %r12" "\n" "pushq %r13" "\n" "pushq %r14" "\n" "pushq %r15" "\n" "pushq %rbx" "\n" "subq $0x48, %rsp" "\n" "movq $512, %r12" "\n" "movq $0xFFFF000000000000, %r14" "\n" "movq $0xFFFF000000000002, %r15" "\n" "movq 0x90(%rsp), %r13" "\n" "call *0x80(%rsp)" "\n" "addq $0x48, %rsp" "\n" "popq %rbx" "\n" "popq %r15" "\n" "popq %r14" "\n" "popq %r13" "\n" "popq %r12" "\n" "popq %rbp" "\n" "ret" "\n" ); asm ( ".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" "int3" "\n" ); asm ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "addq $0x48, %rsp" "\n" "popq %rbx" "\n" "popq %r15" "\n" "popq %r14" "\n" "popq %r13" "\n" "popq %r12" "\n" "popq %rbp" "\n" "ret" "\n" ); #elif COMPILER(GCC) && CPU(ARM_THUMB2) #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 #elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL) #define THUNK_RETURN_ADDRESS_OFFSET 64 #define PRESERVEDR4_OFFSET 68 #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, code) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment); COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x3c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline); COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline); extern "C" { __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*) { __asm { push ebp; mov ebp, esp; push esi; push edi; push ebx; sub esp, 0x3c; mov esi, 512; mov ecx, esp; mov edi, [esp + 0x58]; call [esp + 0x50]; add esp, 0x3c; pop ebx; pop edi; pop esi; pop ebp; ret; } } __declspec(naked) void ctiVMThrowTrampoline() { __asm { mov ecx, esp; call cti_vm_throw; add esp, 0x3c; pop ebx; pop edi; pop esi; pop ebp; ret; } } __declspec(naked) void ctiOpThrowNotCaught() { __asm { add esp, 0x3c; pop ebx; pop edi; pop esi; pop ebp; ret; } } } #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 #else // USE(JSVALUE32_64) #if COMPILER(GCC) && 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); asm ( ".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushl %ebp" "\n" "movl %esp, %ebp" "\n" "pushl %esi" "\n" "pushl %edi" "\n" "pushl %ebx" "\n" "subl $0x1c, %esp" "\n" "movl $512, %esi" "\n" "movl 0x38(%esp), %edi" "\n" "call *0x30(%esp)" "\n" "addl $0x1c, %esp" "\n" "popl %ebx" "\n" "popl %edi" "\n" "popl %esi" "\n" "popl %ebp" "\n" "ret" "\n" ); asm ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movl %esp, %ecx" "\n" "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" "int3" "\n" ); asm ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "addl $0x1c, %esp" "\n" "popl %ebx" "\n" "popl %edi" "\n" "popl %esi" "\n" "popl %ebp" "\n" "ret" "\n" ); #elif COMPILER(GCC) && CPU(X86_64) // 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 ( ".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushq %rbp" "\n" "movq %rsp, %rbp" "\n" "pushq %r12" "\n" "pushq %r13" "\n" "pushq %r14" "\n" "pushq %r15" "\n" "pushq %rbx" "\n" // Form the JIT stubs area "pushq %r9" "\n" "pushq %r8" "\n" "pushq %rcx" "\n" "pushq %rdx" "\n" "pushq %rsi" "\n" "pushq %rdi" "\n" "subq $0x48, %rsp" "\n" "movq $512, %r12" "\n" "movq $0xFFFF000000000000, %r14" "\n" "movq $0xFFFF000000000002, %r15" "\n" "movq %rdx, %r13" "\n" "call *%rdi" "\n" "addq $0x78, %rsp" "\n" "popq %rbx" "\n" "popq %r15" "\n" "popq %r14" "\n" "popq %r13" "\n" "popq %r12" "\n" "popq %rbp" "\n" "ret" "\n" ); asm ( ".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" "int3" "\n" ); asm ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "addq $0x78, %rsp" "\n" "popq %rbx" "\n" "popq %r15" "\n" "popq %r14" "\n" "popq %r13" "\n" "popq %r12" "\n" "popq %rbp" "\n" "ret" "\n" ); #elif COMPILER(GCC) && CPU(ARM_THUMB2) #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 ( ".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 ( ".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 ( ".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 #if COMPILER(GCC) && CPU(ARM_THUMB2) asm ( ".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, #" 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, #" 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 ( ".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, #" 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 ( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" ".thumb" "\n" ".thumb_func " THUMB_FUNC_PARAM(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\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 ( ".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, #" 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, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n" "ldmia sp!, {r4-r8, lr}" "\n" "add sp, sp, #12" "\n" "mov pc, lr" "\n" ); asm ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "mov r0, sp" "\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, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n" "ldmia sp!, {r4-r8, lr}" "\n" "add sp, sp, #12" "\n" "mov pc, lr" "\n" ); #elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL) __asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*) { ARM stmdb sp!, {r1-r3} stmdb sp!, {r4-r8, lr} sub sp, sp, # PRESERVEDR4_OFFSET mov r4, r2 mov r5, #512 mov lr, pc bx r0 add sp, sp, # PRESERVEDR4_OFFSET ldmia sp!, {r4-r8, lr} add sp, sp, #12 bx lr } __asm void ctiVMThrowTrampoline() { ARM PRESERVE8 mov r0, sp bl cti_vm_throw add sp, sp, # PRESERVEDR4_OFFSET ldmia sp!, {r4-r8, lr} add sp, sp, #12 bx lr } __asm void ctiOpThrowNotCaught() { ARM add sp, sp, # PRESERVEDR4_OFFSET ldmia sp!, {r4-r8, lr} add sp, sp, #12 bx lr } #endif #if ENABLE(OPCODE_SAMPLING) #define CTI_SAMPLER stackFrame.globalData->interpreter->sampler() #else #define CTI_SAMPLER 0 #endif JITThunks::JITThunks(JSGlobalData* globalData) { 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) == 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) == 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); #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, bool direct) { // The interpreter checks for recursion here; I do not believe this can occur in CTI. if (!baseValue.isCell()) return; // Uncacheable: give up. if (!slot.isCacheable()) { ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } JSCell* baseCell = baseValue.asCell(); Structure* structure = baseCell->structure(); if (structure->isUncacheableDictionary()) { ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } // If baseCell != base, then baseCell must be a proxy for another object. if (baseCell != slot.base()) { ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } // Cache hit: Specialize instruction and ref Structures. // Structure transition, cache transition info if (slot.type() == PutPropertySlot::NewProperty) { if (structure->isDictionary()) { ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } // put_by_id_transition checks the prototype chain for setters. normalizePrototypeChain(callFrame, baseCell); StructureChain* prototypeChain = structure->prototypeChain(callFrame); stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain); JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct); return; } stubInfo->initPutByIdReplace(structure); 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) { // FIXME: Write a test that proves we need to check for recursion here just // like the interpreter does, then add a check for recursion. // FIXME: Cache property access for immediates. if (!baseValue.isCell()) { ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } JSGlobalData* globalData = &callFrame->globalData(); if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, returnAddress); return; } if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { // The tradeoff of compiling an patched inline string length access routine does not seem // to pay off, so we currently only do this for arrays. ctiPatchCallByReturnAddress(codeBlock, returnAddress, globalData->jitStubs->ctiStringLengthTrampoline()); return; } // Uncacheable: give up. if (!slot.isCacheable()) { ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } JSCell* baseCell = baseValue.asCell(); Structure* structure = baseCell->structure(); if (structure->isUncacheableDictionary()) { ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } // Cache hit: Specialize instruction and ref Structures. if (slot.slotBase() == baseValue) { // set this up, so derefStructures can do it's job. stubInfo->initGetByIdSelf(structure); if (slot.cachedPropertyType() != PropertySlot::Value) ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail)); else JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); return; } if (structure->isDictionary()) { ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { ASSERT(slot.slotBase().isObject()); JSObject* slotBaseObject = asObject(slot.slotBase()); size_t offset = slot.cachedOffset(); // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. if (slotBaseObject->structure()->isDictionary()) { slotBaseObject->flattenDictionaryObject(); offset = slotBaseObject->structure()->get(propertyName); } stubInfo->initGetByIdProto(structure, slotBaseObject->structure()); ASSERT(!structure->isDictionary()); ASSERT(!slotBaseObject->structure()->isDictionary()); JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset, returnAddress); return; } size_t offset = slot.cachedOffset(); size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset); if (!count) { stubInfo->accessType = access_get_by_id_generic; return; } StructureChain* prototypeChain = structure->prototypeChain(callFrame); stubInfo->initGetByIdChain(structure, prototypeChain); JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress); } #endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) #ifndef NDEBUG extern "C" { static void jscGeneratedNativeCode() { // When executing a JIT stub function (which might do an allocation), we hack the return address // to pretend to be executing this function, to keep stack logging tools from blowing out // memory. } } struct StackHack { ALWAYS_INLINE StackHack(JITStackFrame& stackFrame) : stackFrame(stackFrame) , savedReturnAddress(*stackFrame.returnAddressSlot()) { *stackFrame.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode)); } ALWAYS_INLINE ~StackHack() { *stackFrame.returnAddressSlot() = savedReturnAddress; } JITStackFrame& stackFrame; ReturnAddressPtr savedReturnAddress; }; #define STUB_INIT_STACK_FRAME(stackFrame) JITStackFrame& stackFrame = *reinterpret_cast_ptr(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) JITStackFrame& stackFrame = *reinterpret_cast_ptr(STUB_ARGS) #define STUB_SET_RETURN_ADDRESS(returnAddress) *stackFrame.returnAddressSlot() = ReturnAddressPtr(returnAddress) #define STUB_RETURN_ADDRESS *stackFrame.returnAddressSlot() #endif // The reason this is not inlined is to avoid having to do a PIC branch // to get the address of the ctiVMThrowTrampoline function. It's also // good to keep the code size down by leaving as much of the exception // handling code out of line as possible. static NEVER_INLINE void returnToThrowTrampoline(JSGlobalData* globalData, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot) { ASSERT(globalData->exception); globalData->exceptionLocation = exceptionLocation; returnAddressSlot = ReturnAddressPtr(FunctionPtr(ctiVMThrowTrampoline)); } static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalData* globalData, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot) { globalData->exception = createStackOverflowError(callFrame); returnToThrowTrampoline(globalData, exceptionLocation, returnAddressSlot); } #define VM_THROW_EXCEPTION() \ do { \ VM_THROW_EXCEPTION_AT_END(); \ return 0; \ } while (0) #define VM_THROW_EXCEPTION_AT_END() \ do {\ returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS);\ } while (0) #define CHECK_FOR_EXCEPTION() \ do { \ if (UNLIKELY(stackFrame.globalData->exception)) \ VM_THROW_EXCEPTION(); \ } while (0) #define CHECK_FOR_EXCEPTION_AT_END() \ do { \ if (UNLIKELY(stackFrame.globalData->exception)) \ VM_THROW_EXCEPTION_AT_END(); \ } while (0) #define CHECK_FOR_EXCEPTION_VOID() \ do { \ if (UNLIKELY(stackFrame.globalData->exception)) { \ VM_THROW_EXCEPTION_AT_END(); \ return; \ } \ } 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 ( \ ".text" "\n" \ ".align 2" "\n" \ ".globl " SYMBOL_STRING(cti_##op) "\n" \ HIDE_SYMBOL(cti_##op) "\n" \ ".thumb" "\n" \ ".thumb_func " THUMB_FUNC_PARAM(cti_##op) "\n" \ SYMBOL_STRING(cti_##op) ":" "\n" \ "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \ "ldr lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ "bx lr" "\n" \ ); \ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) \ #elif CPU(MIPS) #if WTF_MIPS_PIC #define DEFINE_STUB_FUNCTION(rtype, op) \ extern "C" { \ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ }; \ asm ( \ ".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 ( \ ".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) #endif #elif CPU(ARM_TRADITIONAL) && COMPILER(GCC) #define DEFINE_STUB_FUNCTION(rtype, op) \ extern "C" { \ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ }; \ asm ( \ ".globl " SYMBOL_STRING(cti_##op) "\n" \ SYMBOL_STRING(cti_##op) ":" "\n" \ "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \ "ldr lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ "mov pc, lr" "\n" \ ); \ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) #elif CPU(ARM_TRADITIONAL) && COMPILER(RVCT) #define DEFINE_STUB_FUNCTION(rtype, op) rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) /* The following is a workaround for RVCT toolchain; precompiler macros are not expanded before the code is passed to the assembler */ /* The following section is a template to generate code for GeneratedJITStubs_RVCT.h */ /* The pattern "#xxx#" will be replaced with "xxx" */ /* RVCT(extern "C" #rtype# JITStubThunked_#op#(STUB_ARGS_DECLARATION);) RVCT(__asm #rtype# cti_#op#(STUB_ARGS_DECLARATION)) RVCT({) RVCT( ARM) RVCT( IMPORT JITStubThunked_#op#) RVCT( str lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET]) RVCT( bl JITStubThunked_#op#) RVCT( ldr lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET]) RVCT( bx lr) RVCT(}) 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); JSValue v1 = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSObject* result = v1.toThisObject(callFrame); CHECK_FOR_EXCEPTION_AT_END(); 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); ScopeChainNode* scopeChain = stackFrame.callFrame->scopeChain(); ASSERT(scopeChain->refCount > 1); scopeChain->deref(); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_add) { STUB_INIT_STACK_FRAME(stackFrame); JSValue v1 = stackFrame.args[0].jsValue(); JSValue v2 = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; if (v1.isString()) { JSValue result = v2.isString() ? jsString(callFrame, asString(v1), asString(v2)) : jsString(callFrame, asString(v1), v2.toPrimitiveString(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } double left = 0.0, right; if (v1.getNumber(left) && v2.getNumber(right)) return JSValue::encode(jsNumber(left + right)); // All other cases are pretty uncommon JSValue result = jsAddSlowCase(callFrame, v1, v2); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_inc) { STUB_INIT_STACK_FRAME(stackFrame); JSValue v = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(v.toNumber(callFrame) + 1); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(int, timeout_check) { STUB_INIT_STACK_FRAME(stackFrame); JSGlobalData* globalData = stackFrame.globalData; TimeoutChecker& timeoutChecker = globalData->timeoutChecker; 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) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; 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; } return callFrame; } DEFINE_STUB_FUNCTION(int, op_loop_if_lesseq) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; bool result = jsLessEq(callFrame, src1, src2); CHECK_FOR_EXCEPTION_AT_END(); return result; } DEFINE_STUB_FUNCTION(JSObject*, op_new_object) { STUB_INIT_STACK_FRAME(stackFrame); return constructEmptyObject(stackFrame.callFrame); } DEFINE_STUB_FUNCTION(void, op_put_by_id_generic) { STUB_INIT_STACK_FRAME(stackFrame); 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); CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(callFrame, ident, slot); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 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(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, 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(); } DEFINE_STUB_FUNCTION(void, op_put_by_id_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().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); JSValue baseValue = stackFrame.args[0].jsValue(); int32_t oldSize = stackFrame.args[3].int32(); int32_t newSize = stackFrame.args[4].int32(); ASSERT(baseValue.isObject()); JSObject* base = asObject(baseValue); base->allocatePropertyStorage(oldSize, newSize); return base; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(callFrame, ident, slot); CHECK_FOR_EXCEPTION(); CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); MethodCallLinkInfo& methodCallLinkInfo = codeBlock->getMethodCallLinkInfo(STUB_RETURN_ADDRESS); if (!methodCallLinkInfo.seenOnce()) { methodCallLinkInfo.setSeen(); return JSValue::encode(result); } // If we successfully got something, then the base from which it is being accessed must // be an object. (Assertion to ensure asObject() call below is safe, which comes after // an isCacheable() chceck. ASSERT(!slot.isCacheableValue() || slot.slotBase().isObject()); // Check that: // * We're dealing with a JSCell, // * the property is cachable, // * it's not a dictionary // * there is a function cached. Structure* structure; JSCell* specific; JSObject* slotBaseObject; if (baseValue.isCell() && slot.isCacheableValue() && !(structure = baseValue.asCell()->structure())->isUncacheableDictionary() && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific) && specific ) { JSFunction* callee = (JSFunction*)specific; // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. if (slotBaseObject->structure()->isDictionary()) slotBaseObject->flattenDictionaryObject(); // The result fetched should always be the callee! ASSERT(result == JSValue(callee)); // Check to see if the function is on the object's prototype. Patch up the code to optimize. if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, slotBaseObject, STUB_RETURN_ADDRESS); return JSValue::encode(result); } // Check to see if the function is on the object itself. // Since we generate the method-check to check both the structure and a prototype-structure (since this // is the common case) we have a problem - we need to patch the prototype structure check to do something // useful. We could try to nop it out altogether, but that's a little messy, so lets do something simpler // for now. For now it performs a check on a special object on the global object only used for this // purpose. The object is in no way exposed, and as such the check will always pass. if (slot.slotBase() == baseValue) { JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject->methodCallDummy(), STUB_RETURN_ADDRESS); return JSValue::encode(result); } } // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to. ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id)); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(callFrame, ident, slot); CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); if (!stubInfo->seenOnce()) stubInfo->setSeen(); else JITThunks::tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(callFrame, ident, slot); CHECK_FOR_EXCEPTION(); if (baseValue.isCell() && slot.isCacheable() && !baseValue.asCell()->structure()->isUncacheableDictionary() && slot.slotBase() == baseValue) { CodeBlock* codeBlock = callFrame->codeBlock(); StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); ASSERT(slot.slotBase().isObject()); PolymorphicAccessStructureList* polymorphicStructureList; int listIndex = 1; if (stubInfo->accessType == access_get_by_id_self) { ASSERT(!stubInfo->stubRoutine); polymorphicStructureList = new PolymorphicAccessStructureList(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure); stubInfo->initGetByIdSelfList(polymorphicStructureList, 1); } else { polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList; listIndex = stubInfo->u.getByIdSelfList.listSize; } if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { stubInfo->u.getByIdSelfList.listSize++; JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, baseValue.asCell()->structure(), ident, slot, slot.cachedOffset()); 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); } static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(StructureStubInfo* stubInfo, int& listIndex) { PolymorphicAccessStructureList* prototypeStructureList = 0; listIndex = 1; switch (stubInfo->accessType) { case access_get_by_id_proto: prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure); stubInfo->stubRoutine = CodeLocationLabel(); stubInfo->initGetByIdProtoList(prototypeStructureList, 2); break; case access_get_by_id_chain: prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain); stubInfo->stubRoutine = CodeLocationLabel(); stubInfo->initGetByIdProtoList(prototypeStructureList, 2); break; case access_get_by_id_proto_list: prototypeStructureList = stubInfo->u.getByIdProtoList.structureList; listIndex = stubInfo->u.getByIdProtoList.listSize; if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) stubInfo->u.getByIdProtoList.listSize++; break; default: ASSERT_NOT_REACHED(); } ASSERT(listIndex <= POLYMORPHIC_LIST_CACHE_SIZE); return prototypeStructureList; } 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(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); CallFrame* callFrame = stackFrame.callFrame; const Identifier& propertyName = stackFrame.args[1].identifier(); JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(callFrame, propertyName, slot); CHECK_FOR_EXCEPTION(); 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 = baseValue.asCell()->structure(); CodeBlock* codeBlock = callFrame->codeBlock(); StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); ASSERT(slot.slotBase().isObject()); JSObject* slotBaseObject = asObject(slot.slotBase()); size_t offset = slot.cachedOffset(); if (slot.slotBase() == baseValue) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); else if (slot.slotBase() == 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()) { slotBaseObject->flattenDictionaryObject(); offset = slotBaseObject->structure()->get(propertyName); } int listIndex; PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), propertyName, slot, offset); if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); } } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) { ASSERT(!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); 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)); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list_full) { STUB_INIT_STACK_FRAME(stackFrame); JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_fail) { STUB_INIT_STACK_FRAME(stackFrame); JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_array_fail) { STUB_INIT_STACK_FRAME(stackFrame); JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_string_fail) { STUB_INIT_STACK_FRAME(stackFrame); JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } #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); CallFrame* callFrame = stackFrame.callFrame; JSValue value = stackFrame.args[0].jsValue(); JSValue baseVal = stackFrame.args[1].jsValue(); JSValue proto = stackFrame.args[2].jsValue(); // At least one of these checks must have failed to get to the slow case. ASSERT(!value.isCell() || !baseVal.isCell() || !proto.isCell() || !value.isObject() || !baseVal.isObject() || !proto.isObject() || (asObject(baseVal)->structure()->typeInfo().flags() & (ImplementsHasInstance | OverridesHasInstance)) != ImplementsHasInstance); // 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). TypeInfo typeInfo(UnspecifiedType); if (!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()) { stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "instanceof", baseVal); VM_THROW_EXCEPTION(); } ASSERT(typeInfo.type() != UnspecifiedType); if (!typeInfo.overridesHasInstance()) { if (!value.isObject()) return JSValue::encode(jsBoolean(false)); if (!proto.isObject()) { throwError(callFrame, createTypeError(callFrame, "instanceof called on an object with an invalid prototype property.")); VM_THROW_EXCEPTION(); } } JSValue result = jsBoolean(asObject(baseVal)->hasInstance(callFrame, value, proto)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_id) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSObject* baseObj = stackFrame.args[0].jsValue().toObject(callFrame); 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); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_mul) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); double left; double right; if (src1.getNumber(left) && src2.getNumber(right)) return JSValue::encode(jsNumber(left * right)); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } 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_jitCompile) { STUB_INIT_STACK_FRAME(stackFrame); #if !ASSERT_DISABLED CallData callData; ASSERT(stackFrame.callFrame->callee()->getCallData(callData) == CallTypeJS); #endif JSFunction* function = asFunction(stackFrame.callFrame->callee()); ASSERT(!function->isHostFunction()); FunctionExecutable* executable = function->jsExecutable(); ScopeChainNode* callDataScopeChain = function->scope().node(); 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(void*, op_call_arityCheck) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSFunction* callee = asFunction(callFrame->callee()); ASSERT(!callee->isHostFunction()); 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; 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]; } 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(); } 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; } 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(); } 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); CallFrame* callFrame = stackFrame.callFrame; JSFunction* callee = asFunction(callFrame->callee()); ExecutableBase* executable = callee->executable(); MacroAssemblerCodePtr codePtr; CodeBlock* codeBlock = 0; if (executable->isHostFunction()) codePtr = executable->generatedJITCodeForCall().addressForCall(); else { FunctionExecutable* functionExecutable = static_cast(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(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()) codePtr = executable->generatedJITCodeForConstruct().addressForCall(); else { FunctionExecutable* functionExecutable = static_cast(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(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::linkConstruct(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCountIncludingThis(), stackFrame.globalData); return codePtr.executableAddress(); } #endif // !ENABLE(JIT_OPTIMIZE_CALL) DEFINE_STUB_FUNCTION(JSObject*, op_push_activation) { STUB_INIT_STACK_FRAME(stackFrame); JSActivation* activation = new (stackFrame.globalData) JSActivation(stackFrame.callFrame, static_cast(stackFrame.callFrame->codeBlock()->ownerExecutable())); stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->copy()->push(activation)); return activation; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction) { STUB_INIT_STACK_FRAME(stackFrame); JSValue funcVal = stackFrame.args[0].jsValue(); CallData callData; CallType callType = getCallData(funcVal, callData); ASSERT(callType != CallTypeJS); if (callType == CallTypeHost) { 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((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(funcVal)); EncodedJSValue returnValue; { SamplingTool::HostCallRecord callRecord(CTI_SAMPLER); returnValue = callData.native.function(callFrame); } CHECK_FOR_EXCEPTION_AT_END(); return returnValue; } ASSERT(callType == CallTypeNone); stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal); VM_THROW_EXCEPTION(); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments) { STUB_INIT_STACK_FRAME(stackFrame); Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame); return JSValue::encode(JSValue(arguments)); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments_no_params) { STUB_INIT_STACK_FRAME(stackFrame); Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame, Arguments::NoParameters); return JSValue::encode(JSValue(arguments)); } DEFINE_STUB_FUNCTION(void, op_tear_off_activation) { STUB_INIT_STACK_FRAME(stackFrame); ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain()); 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) { STUB_INIT_STACK_FRAME(stackFrame); ASSERT(stackFrame.callFrame->codeBlock()->usesArguments() && !stackFrame.callFrame->codeBlock()->needsFullScopeChain()); asArguments(stackFrame.args[0].jsValue())->copyRegisters(); } DEFINE_STUB_FUNCTION(void, op_profile_will_call) { STUB_INIT_STACK_FRAME(stackFrame); ASSERT(*stackFrame.enabledProfilerReference); (*stackFrame.enabledProfilerReference)->willExecute(stackFrame.callFrame, stackFrame.args[0].jsValue()); } DEFINE_STUB_FUNCTION(void, op_profile_did_call) { STUB_INIT_STACK_FRAME(stackFrame); ASSERT(*stackFrame.enabledProfilerReference); (*stackFrame.enabledProfilerReference)->didExecute(stackFrame.callFrame, stackFrame.args[0].jsValue()); } DEFINE_STUB_FUNCTION(void, op_ret_scopeChain) { STUB_INIT_STACK_FRAME(stackFrame); ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain()); stackFrame.callFrame->scopeChain()->deref(); } DEFINE_STUB_FUNCTION(JSObject*, op_new_array) { STUB_INIT_STACK_FRAME(stackFrame); ArgList argList(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32()); return constructArray(stackFrame.callFrame, argList); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); ASSERT(iter != end); Identifier& ident = stackFrame.args[0].identifier(); do { JSObject* o = *iter; PropertySlot slot(o); if (o->getPropertySlot(callFrame, ident, slot)) { JSValue result = slot.getValue(callFrame, ident); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } } while (++iter != end); stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION(); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct) { STUB_INIT_STACK_FRAME(stackFrame); JSValue constrVal = stackFrame.args[0].jsValue(); ConstructData constructData; ConstructType constructType = getConstructData(constrVal, constructData); ASSERT(constructType != ConstructTypeJS); if (constructType == ConstructTypeHost) { 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((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(constrVal)); EncodedJSValue returnValue; { SamplingTool::HostCallRecord callRecord(CTI_SAMPLER); returnValue = constructData.native.function(callFrame); } CHECK_FOR_EXCEPTION_AT_END(); return returnValue; } ASSERT(constructType == ConstructTypeNone); stackFrame.globalData->exception = createNotAConstructorError(stackFrame.callFrame, constrVal); VM_THROW_EXCEPTION(); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSGlobalData* globalData = stackFrame.globalData; JSValue baseValue = stackFrame.args[0].jsValue(); JSValue subscript = stackFrame.args[1].jsValue(); 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 (subscript.isUInt32()) { uint32_t i = subscript.asUInt32(); if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) { ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_string)); 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)); } 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); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_string) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSGlobalData* globalData = stackFrame.globalData; JSValue baseValue = stackFrame.args[0].jsValue(); JSValue subscript = stackFrame.args[1].jsValue(); JSValue result; if (LIKELY(subscript.isUInt32())) { uint32_t i = subscript.asUInt32(); if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) result = asString(baseValue)->getIndex(callFrame, i); else { result = baseValue.get(callFrame, i); if (!isJSString(globalData, baseValue)) ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val)); } } else { Identifier property(callFrame, subscript.toString(callFrame)); result = baseValue.get(callFrame, property); } CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_byte_array) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSGlobalData* globalData = stackFrame.globalData; JSValue baseValue = stackFrame.args[0].jsValue(); JSValue subscript = stackFrame.args[1].jsValue(); JSValue result; if (LIKELY(subscript.isUInt32())) { uint32_t i = subscript.asUInt32(); if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i)); } result = baseValue.get(callFrame, i); if (!isJSByteArray(globalData, baseValue)) ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val)); } else { Identifier property(callFrame, subscript.toString(callFrame)); result = baseValue.get(callFrame, property); } CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_sub) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); double left; double right; if (src1.getNumber(left) && src2.getNumber(right)) return JSValue::encode(jsNumber(left - right)); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(void, op_put_by_val) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSGlobalData* globalData = stackFrame.globalData; JSValue baseValue = stackFrame.args[0].jsValue(); JSValue subscript = stackFrame.args[1].jsValue(); JSValue value = stackFrame.args[2].jsValue(); if (LIKELY(subscript.isUInt32())) { uint32_t i = subscript.asUInt32(); if (isJSArray(globalData, baseValue)) { JSArray* jsArray = asArray(baseValue); if (jsArray->canSetIndex(i)) jsArray->setIndex(i, value); else jsArray->JSArray::put(callFrame, i, value); } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { JSByteArray* jsByteArray = asByteArray(baseValue); ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val_byte_array)); // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. if (value.isInt32()) { jsByteArray->setIndex(i, value.asInt32()); return; } else { double dValue = 0; if (value.getNumber(dValue)) { jsByteArray->setIndex(i, dValue); return; } } baseValue.put(callFrame, i, value); } else baseValue.put(callFrame, i, value); } else { Identifier property(callFrame, subscript.toString(callFrame)); if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception. PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); baseValue.put(callFrame, property, value, slot); } } CHECK_FOR_EXCEPTION_AT_END(); } DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSGlobalData* globalData = stackFrame.globalData; JSValue baseValue = stackFrame.args[0].jsValue(); JSValue subscript = stackFrame.args[1].jsValue(); JSValue value = stackFrame.args[2].jsValue(); if (LIKELY(subscript.isUInt32())) { uint32_t i = subscript.asUInt32(); if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { JSByteArray* jsByteArray = asByteArray(baseValue); // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. if (value.isInt32()) { jsByteArray->setIndex(i, value.asInt32()); return; } else { double dValue = 0; if (value.getNumber(dValue)) { jsByteArray->setIndex(i, dValue); return; } } } if (!isJSByteArray(globalData, baseValue)) ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val)); baseValue.put(callFrame, i, value); } else { Identifier property(callFrame, subscript.toString(callFrame)); if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception. PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); baseValue.put(callFrame, property, value, slot); } } CHECK_FOR_EXCEPTION_AT_END(); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_lesseq) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsBoolean(jsLessEq(callFrame, stackFrame.args[0].jsValue(), stackFrame.args[1].jsValue())); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(int, op_load_varargs) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; RegisterFile* registerFile = stackFrame.registerFile; int argsOffset = stackFrame.args[0].int32(); JSValue arguments = callFrame->registers()[argsOffset].jsValue(); uint32_t argCount = 0; if (!arguments) { int providedParams = callFrame->registers()[RegisterFile::ArgumentCount].i() - 1; argCount = providedParams; argCount = min(argCount, static_cast(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 = asFunction(callFrame->callee())->jsExecutable()->parameterCount(); int32_t inplaceArgs = min(providedParams, expectedParams); Register* inplaceArgsDst = callFrame->registers() + argsOffset; Register* inplaceArgsEnd = inplaceArgsDst + inplaceArgs; Register* inplaceArgsEnd2 = inplaceArgsDst + providedParams; Register* inplaceArgsSrc = callFrame->registers() - RegisterFile::CallFrameHeaderSize - expectedParams; Register* inplaceArgsSrc2 = inplaceArgsSrc - providedParams - 1 + inplaceArgs; // First step is to copy the "expected" parameters from their normal location relative to the callframe while (inplaceArgsDst < inplaceArgsEnd) *inplaceArgsDst++ = *inplaceArgsSrc++; // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this') while (inplaceArgsDst < inplaceArgsEnd2) *inplaceArgsDst++ = *inplaceArgsSrc2++; } else if (!arguments.isUndefinedOrNull()) { if (!arguments.isObject()) { 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(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(); } argsObject->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount); } else if (isJSArray(&callFrame->globalData(), arguments)) { JSArray* array = asArray(arguments); argCount = array->length(); argCount = min(argCount, static_cast(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(); } array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount); } 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(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(); } Register* argsBuffer = callFrame->registers() + argsOffset; for (unsigned i = 0; i < argCount; ++i) { argsBuffer[i] = asObject(arguments)->get(callFrame, i); CHECK_FOR_EXCEPTION(); } } else { stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments); VM_THROW_EXCEPTION(); } } return argCount + 1; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_negate) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src = stackFrame.args[0].jsValue(); double v; if (src.getNumber(v)) return JSValue::encode(jsNumber(-v)); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(-src.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } 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(), 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); CallFrame* callFrame = stackFrame.callFrame; ScopeChainNode* scopeChain = callFrame->scopeChain(); int skip = stackFrame.args[1].int32(); 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); } Identifier& ident = stackFrame.args[0].identifier(); do { JSObject* o = *iter; PropertySlot slot(o); if (o->getPropertySlot(callFrame, ident, slot)) { JSValue result = slot.getValue(callFrame, ident); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } } while (++iter != end); stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION(); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; CodeBlock* codeBlock = callFrame->codeBlock(); JSGlobalObject* globalObject = codeBlock->globalObject(); Identifier& ident = stackFrame.args[0].identifier(); unsigned globalResolveInfoIndex = stackFrame.args[1].int32(); ASSERT(globalObject->isGlobalObject()); PropertySlot slot(globalObject); if (globalObject->getPropertySlot(callFrame, ident, slot)) { JSValue result = slot.getValue(callFrame, ident); if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { GlobalResolveInfo& globalResolveInfo = codeBlock->globalResolveInfo(globalResolveInfoIndex); if (globalResolveInfo.structure) globalResolveInfo.structure->deref(); globalObject->structure()->ref(); globalResolveInfo.structure = globalObject->structure(); globalResolveInfo.offset = slot.cachedOffset(); return JSValue::encode(result); } CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION(); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_div) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); double left; double right; if (src1.getNumber(left) && src2.getNumber(right)) return JSValue::encode(jsNumber(left / right)); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(src1.toNumber(callFrame) / src2.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_dec) { STUB_INIT_STACK_FRAME(stackFrame); JSValue v = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(v.toNumber(callFrame) - 1); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(int, op_jless) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; bool result = jsLess(callFrame, src1, src2); CHECK_FOR_EXCEPTION_AT_END(); return result; } DEFINE_STUB_FUNCTION(int, op_jlesseq) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; bool result = jsLessEq(callFrame, src1, src2); CHECK_FOR_EXCEPTION_AT_END(); return result; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_not) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsBoolean(!src.toBoolean(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(int, op_jtrue) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; bool result = src1.toBoolean(callFrame); CHECK_FOR_EXCEPTION_AT_END(); return result; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_inc) { STUB_INIT_STACK_FRAME(stackFrame); JSValue v = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSValue number = v.toJSNumber(callFrame); CHECK_FOR_EXCEPTION_AT_END(); callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number.uncheckedGetNumber() + 1); return JSValue::encode(number); } DEFINE_STUB_FUNCTION(int, op_eq) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); #if USE(JSVALUE32_64) start: if (src2.isUndefined()) { return src1.isNull() || (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined()) || src1.isUndefined(); } if (src2.isNull()) { return src1.isUndefined() || (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined()) || src1.isNull(); } if (src1.isInt32()) { if (src2.isDouble()) return src1.asInt32() == src2.asDouble(); double d = src2.toNumber(stackFrame.callFrame); CHECK_FOR_EXCEPTION(); return src1.asInt32() == d; } if (src1.isDouble()) { if (src2.isInt32()) return src1.asDouble() == src2.asInt32(); double d = src2.toNumber(stackFrame.callFrame); CHECK_FOR_EXCEPTION(); return src1.asDouble() == d; } if (src1.isTrue()) { if (src2.isFalse()) return false; double d = src2.toNumber(stackFrame.callFrame); CHECK_FOR_EXCEPTION(); return d == 1.0; } if (src1.isFalse()) { if (src2.isTrue()) return false; double d = src2.toNumber(stackFrame.callFrame); CHECK_FOR_EXCEPTION(); return d == 0.0; } if (src1.isUndefined()) return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined(); if (src1.isNull()) return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined(); JSCell* cell1 = src1.asCell(); if (cell1->isString()) { if (src2.isInt32()) return jsToNumber(static_cast(cell1)->value(stackFrame.callFrame)) == src2.asInt32(); if (src2.isDouble()) return jsToNumber(static_cast(cell1)->value(stackFrame.callFrame)) == src2.asDouble(); if (src2.isTrue()) return jsToNumber(static_cast(cell1)->value(stackFrame.callFrame)) == 1.0; if (src2.isFalse()) return jsToNumber(static_cast(cell1)->value(stackFrame.callFrame)) == 0.0; JSCell* cell2 = src2.asCell(); if (cell2->isString()) return static_cast(cell1)->value(stackFrame.callFrame) == static_cast(cell2)->value(stackFrame.callFrame); src2 = asObject(cell2)->toPrimitive(stackFrame.callFrame); CHECK_FOR_EXCEPTION(); goto start; } if (src2.isObject()) return asObject(cell1) == asObject(src2); src1 = asObject(cell1)->toPrimitive(stackFrame.callFrame); CHECK_FOR_EXCEPTION(); goto start; #else // USE(JSVALUE32_64) CallFrame* callFrame = stackFrame.callFrame; bool result = JSValue::equalSlowCaseInline(callFrame, src1, src2); CHECK_FOR_EXCEPTION_AT_END(); return result; #endif // 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(); JSString* string2 = stackFrame.args[1].jsString(); 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) { STUB_INIT_STACK_FRAME(stackFrame); JSValue val = stackFrame.args[0].jsValue(); JSValue shift = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitand) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); ASSERT(!src1.isInt32() || !src2.isInt32()); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_rshift) { STUB_INIT_STACK_FRAME(stackFrame); JSValue val = stackFrame.args[0].jsValue(); JSValue shift = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitnot) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src = stackFrame.args[0].jsValue(); ASSERT(!src.isInt32()); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(~src.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); // FIXME: add scopeDepthIsZero optimization ASSERT(iter != end); Identifier& ident = stackFrame.args[0].identifier(); JSObject* base; do { base = *iter; PropertySlot slot(base); if (base->getPropertySlot(callFrame, ident, slot)) { JSValue result = slot.getValue(callFrame, ident); CHECK_FOR_EXCEPTION_AT_END(); callFrame->registers()[stackFrame.args[1].int32()] = JSValue(base); return JSValue::encode(result); } ++iter; } while (iter != end); stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); VM_THROW_EXCEPTION_AT_END(); return JSValue::encode(JSValue()); } DEFINE_STUB_FUNCTION(JSObject*, op_new_func_exp) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; FunctionExecutable* function = stackFrame.args[0].function(); JSFunction* func = function->make(callFrame, callFrame->scopeChain()); ASSERT(callFrame->codeBlock()->codeType() != FunctionCode || !callFrame->codeBlock()->needsFullScopeChain() || callFrame->uncheckedR(callFrame->codeBlock()->activationRegister()).jsValue()); /* The Identifier in a FunctionExpression can be referenced from inside the FunctionExpression's FunctionBody to allow the function to call itself recursively. However, unlike in a FunctionDeclaration, the Identifier in a FunctionExpression cannot be referenced from and does not affect the scope enclosing the FunctionExpression. */ if (!function->name().isNull()) { JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete); func->scope().push(functionScopeObject); } return func; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_mod) { STUB_INIT_STACK_FRAME(stackFrame); JSValue dividendValue = stackFrame.args[0].jsValue(); JSValue divisorValue = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; double d = dividendValue.toNumber(callFrame); JSValue result = jsNumber(fmod(d, divisorValue.toNumber(callFrame))); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_less) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsBoolean(jsLess(callFrame, stackFrame.args[0].jsValue(), stackFrame.args[1].jsValue())); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_dec) { STUB_INIT_STACK_FRAME(stackFrame); JSValue v = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSValue number = v.toJSNumber(callFrame); CHECK_FOR_EXCEPTION_AT_END(); callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number.uncheckedGetNumber() - 1); return JSValue::encode(number); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_urshift) { STUB_INIT_STACK_FRAME(stackFrame); JSValue val = stackFrame.args[0].jsValue(); JSValue shift = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitxor) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(JSObject*, op_new_regexp) { STUB_INIT_STACK_FRAME(stackFrame); return new (stackFrame.globalData) RegExpObject(stackFrame.callFrame->lexicalGlobalObject(), stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), stackFrame.args[0].regExp()); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } 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; Interpreter* interpreter = stackFrame.globalData->interpreter; JSValue funcVal = stackFrame.args[0].jsValue(); int registerOffset = stackFrame.args[1].int32(); int argCount = stackFrame.args[2].int32(); Register* newCallFrame = callFrame->registers() + registerOffset; Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount; JSValue baseValue = argv[0].jsValue(); JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject; 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(void*, op_throw) { STUB_INIT_STACK_FRAME(stackFrame); 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) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSObject* o = stackFrame.args[0].jsObject(); Structure* structure = o->structure(); JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache(); if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame)) jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o); return jsPropertyNameIterator; } DEFINE_STUB_FUNCTION(int, has_property) { STUB_INIT_STACK_FRAME(stackFrame); JSObject* base = stackFrame.args[0].jsObject(); JSString* property = stackFrame.args[1].jsString(); 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) { STUB_INIT_STACK_FRAME(stackFrame); JSObject* o = stackFrame.args[0].jsValue().toObject(stackFrame.callFrame); CHECK_FOR_EXCEPTION(); stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->push(o)); return o; } DEFINE_STUB_FUNCTION(void, op_pop_scope) { STUB_INIT_STACK_FRAME(stackFrame); stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->pop()); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_typeof) { STUB_INIT_STACK_FRAME(stackFrame); return JSValue::encode(jsTypeStringForValue(stackFrame.callFrame, stackFrame.args[0].jsValue())); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_undefined) { STUB_INIT_STACK_FRAME(stackFrame); JSValue v = stackFrame.args[0].jsValue(); return JSValue::encode(jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined())); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_boolean) { STUB_INIT_STACK_FRAME(stackFrame); return JSValue::encode(jsBoolean(stackFrame.args[0].jsValue().isBoolean())); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_number) { STUB_INIT_STACK_FRAME(stackFrame); return JSValue::encode(jsBoolean(stackFrame.args[0].jsValue().isNumber())); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_string) { STUB_INIT_STACK_FRAME(stackFrame); return JSValue::encode(jsBoolean(isJSString(stackFrame.globalData, stackFrame.args[0].jsValue()))); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_object) { STUB_INIT_STACK_FRAME(stackFrame); return JSValue::encode(jsBoolean(jsIsObjectType(stackFrame.args[0].jsValue()))); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_function) { STUB_INIT_STACK_FRAME(stackFrame); return JSValue::encode(jsBoolean(jsIsFunctionType(stackFrame.args[0].jsValue()))); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_stricteq) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); 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) { STUB_INIT_STACK_FRAME(stackFrame); return JSValue::encode(stackFrame.args[0].jsValue().toPrimitive(stackFrame.callFrame)); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_strcat) { STUB_INIT_STACK_FRAME(stackFrame); JSValue result = jsString(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32()); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_nstricteq) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); 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) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; JSValue result = src.toJSNumber(callFrame); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_in) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSValue baseVal = stackFrame.args[1].jsValue(); if (!baseVal.isObject()) { stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "in", baseVal); VM_THROW_EXCEPTION(); } JSValue propName = stackFrame.args[0].jsValue(); JSObject* baseObj = asObject(baseVal); uint32_t i; if (propName.getUInt32(i)) return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, i))); Identifier property(callFrame, propName.toString(callFrame)); CHECK_FOR_EXCEPTION(); return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, property))); } DEFINE_STUB_FUNCTION(JSObject*, op_push_new_scope) { STUB_INIT_STACK_FRAME(stackFrame); JSObject* scope = new (stackFrame.globalData) JSStaticScopeObject(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.args[1].jsValue(), DontDelete); CallFrame* callFrame = stackFrame.callFrame; callFrame->setScopeChain(callFrame->scopeChain()->push(scope)); return scope; } DEFINE_STUB_FUNCTION(void, op_jmp_scopes) { STUB_INIT_STACK_FRAME(stackFrame); unsigned count = stackFrame.args[0].int32(); CallFrame* callFrame = stackFrame.callFrame; ScopeChainNode* tmp = callFrame->scopeChain(); while (count--) tmp = tmp->pop(); callFrame->setScopeChain(tmp); } DEFINE_STUB_FUNCTION(void, op_put_by_index) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; unsigned property = stackFrame.args[1].int32(); stackFrame.args[0].jsValue().put(callFrame, property, stackFrame.args[2].jsValue()); } DEFINE_STUB_FUNCTION(void*, op_switch_imm) { STUB_INIT_STACK_FRAME(stackFrame); JSValue scrutinee = stackFrame.args[0].jsValue(); unsigned tableIndex = stackFrame.args[1].int32(); CallFrame* callFrame = stackFrame.callFrame; CodeBlock* codeBlock = callFrame->codeBlock(); if (scrutinee.isInt32()) return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(scrutinee.asInt32()).executableAddress(); else { double value; int32_t intValue; if (scrutinee.getNumber(value) && ((intValue = static_cast(value)) == value)) return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(intValue).executableAddress(); else return codeBlock->immediateSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); } } DEFINE_STUB_FUNCTION(void*, op_switch_char) { STUB_INIT_STACK_FRAME(stackFrame); JSValue scrutinee = stackFrame.args[0].jsValue(); unsigned tableIndex = stackFrame.args[1].int32(); CallFrame* callFrame = stackFrame.callFrame; CodeBlock* codeBlock = callFrame->codeBlock(); void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); if (scrutinee.isString()) { 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; } DEFINE_STUB_FUNCTION(void*, op_switch_string) { STUB_INIT_STACK_FRAME(stackFrame); JSValue scrutinee = stackFrame.args[0].jsValue(); unsigned tableIndex = stackFrame.args[1].int32(); CallFrame* callFrame = stackFrame.callFrame; CodeBlock* codeBlock = callFrame->codeBlock(); void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); if (scrutinee.isString()) { StringImpl* value = asString(scrutinee)->value(callFrame).impl(); result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).executableAddress(); } CHECK_FOR_EXCEPTION_AT_END(); return result; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; JSValue baseValue = stackFrame.args[0].jsValue(); JSObject* baseObj = baseValue.toObject(callFrame); // may throw JSValue subscript = stackFrame.args[1].jsValue(); bool result; uint32_t i; if (subscript.getUInt32(i)) result = baseObj->deleteProperty(callFrame, i); else { CHECK_FOR_EXCEPTION(); Identifier property(callFrame, subscript.toString(callFrame)); CHECK_FOR_EXCEPTION(); 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(jsBoolean(result)); } DEFINE_STUB_FUNCTION(void, op_put_getter) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; ASSERT(stackFrame.args[0].jsValue().isObject()); JSObject* baseObj = asObject(stackFrame.args[0].jsValue()); ASSERT(stackFrame.args[2].jsValue().isObject()); baseObj->defineGetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue())); } DEFINE_STUB_FUNCTION(void, op_put_setter) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; ASSERT(stackFrame.args[0].jsValue().isObject()); JSObject* baseObj = asObject(stackFrame.args[0].jsValue()); ASSERT(stackFrame.args[2].jsValue().isObject()); baseObj->defineSetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue())); } DEFINE_STUB_FUNCTION(void, op_throw_reference_error) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; 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); 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) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; int debugHookID = stackFrame.args[0].int32(); int firstLine = stackFrame.args[1].int32(); int lastLine = stackFrame.args[2].int32(); stackFrame.globalData->interpreter->debug(callFrame, static_cast(debugHookID), firstLine, lastLine); } DEFINE_STUB_FUNCTION(void*, vm_throw) { STUB_INIT_STACK_FRAME(stackFrame); JSGlobalData* globalData = stackFrame.globalData; 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) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame)); } MacroAssemblerCodePtr JITThunks::ctiStub(JSGlobalData* globalData, ThunkGenerator generator) { std::pair entry = m_ctiStubMap.add(generator, MacroAssemblerCodePtr()); if (entry.second) entry.first->second = generator(globalData, m_executablePool.get()); return entry.first->second; } PassRefPtr JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function) { std::pair 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 JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, ThunkGenerator generator) { std::pair 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)