X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/ba379fdc102753d6be2c4d937058fe40257329fe..4be4e30906bcb8ee30b4d189205cb70bad6707ce:/jit/JITStubs.cpp diff --git a/jit/JITStubs.cpp b/jit/JITStubs.cpp index a7011e8..815cbf7 100644 --- a/jit/JITStubs.cpp +++ b/jit/JITStubs.cpp @@ -1,6 +1,7 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2013 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich + * Copyright (C) Research In Motion Limited 2010, 2011. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,34 +29,47 @@ */ #include "config.h" -#include "JITStubs.h" #if ENABLE(JIT) +#include "JITStubs.h" +#include "CommonSlowPaths.h" #include "Arguments.h" +#include "ArrayConstructor.h" #include "CallFrame.h" #include "CodeBlock.h" -#include "Collector.h" +#include "CodeProfiling.h" +#include "DFGOSREntry.h" #include "Debugger.h" #include "ExceptionHelpers.h" -#include "GlobalEvalFunction.h" +#include "GetterSetter.h" +#include "Heap.h" +#include #include "JIT.h" +#include "JITExceptions.h" #include "JSActivation.h" #include "JSArray.h" -#include "JSByteArray.h" #include "JSFunction.h" +#include "JSGlobalObjectFunctions.h" +#include "JSNameScope.h" #include "JSNotAnObject.h" #include "JSPropertyNameIterator.h" -#include "JSStaticScopeObject.h" #include "JSString.h" +#include "JSWithScope.h" +#include "LegacyProfiler.h" +#include "NameInstance.h" +#include "ObjectConstructor.h" #include "ObjectPrototype.h" #include "Operations.h" #include "Parser.h" -#include "Profiler.h" #include "RegExpObject.h" #include "RegExpPrototype.h" #include "Register.h" +#include "RepatchBuffer.h" #include "SamplingTool.h" +#include "Strong.h" +#include "StructureRareDataInlines.h" +#include #include #include @@ -63,15 +77,9 @@ using namespace std; namespace JSC { -#if PLATFORM(DARWIN) || PLATFORM(WIN_OS) -#define SYMBOL_STRING(name) "_" #name -#else -#define SYMBOL_STRING(name) #name -#endif - #if USE(JSVALUE32_64) -#if COMPILER(GCC) && PLATFORM(X86) +#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. @@ -80,8 +88,10 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x3c, JITStackFrame_s COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline); COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline); -asm volatile ( +asm ( +".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushl %ebp" "\n" "movl %esp, %ebp" "\n" @@ -89,7 +99,9 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushl %edi" "\n" "pushl %ebx" "\n" "subl $0x3c, %esp" "\n" - "movl $512, %esi" "\n" + "movw $0x02FF, %bx" "\n" + "movw %bx, 0(%esp)" "\n" + "fldcw 0(%esp)" "\n" "movl 0x58(%esp), %edi" "\n" "call *0x50(%esp)" "\n" "addl $0x3c, %esp" "\n" @@ -97,26 +109,25 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "popl %edi" "\n" "popl %esi" "\n" "popl %ebp" "\n" + "ffree %st(1)" "\n" "ret" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" ); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" -#if !USE(JIT_STUB_ARGUMENT_VA_LIST) "movl %esp, %ecx" "\n" -#endif - "call " SYMBOL_STRING(cti_vm_throw) "\n" - "addl $0x3c, %esp" "\n" - "popl %ebx" "\n" - "popl %edi" "\n" - "popl %esi" "\n" - "popl %ebp" "\n" - "ret" "\n" + "call " LOCAL_REFERENCE(cti_vm_throw) "\n" + "int3" "\n" ); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "addl $0x3c, %esp" "\n" "popl %ebx" "\n" @@ -126,11 +137,7 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "ret" "\n" ); -#elif COMPILER(GCC) && PLATFORM(X86_64) - -#if USE(JIT_STUB_ARGUMENT_VA_LIST) -#error "JIT_STUB_ARGUMENT_VA_LIST not supported on x86-64." -#endif +#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. @@ -139,8 +146,9 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x48, JITStackFrame_s COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x90, JITStackFrame_callFrame_offset_matches_ctiTrampoline); COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x80, JITStackFrame_code_offset_matches_ctiTrampoline); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushq %rbp" "\n" "movq %rsp, %rbp" "\n" @@ -163,25 +171,23 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "popq %r12" "\n" "popq %rbp" "\n" "ret" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" ); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movq %rsp, %rdi" "\n" - "call " SYMBOL_STRING(cti_vm_throw) "\n" - "addq $0x48, %rsp" "\n" - "popq %rbx" "\n" - "popq %r15" "\n" - "popq %r14" "\n" - "popq %r13" "\n" - "popq %r12" "\n" - "popq %rbp" "\n" - "ret" "\n" + "call " LOCAL_REFERENCE(cti_vm_throw) "\n" + "int3" "\n" ); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "addq $0x48, %rsp" "\n" "popq %rbx" "\n" @@ -193,75 +199,29 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "ret" "\n" ); -#elif COMPILER(GCC) && PLATFORM_ARM_ARCH(7) - -#if USE(JIT_STUB_ARGUMENT_VA_LIST) -#error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7." -#endif - -asm volatile ( -".text" "\n" -".align 2" "\n" -".globl " SYMBOL_STRING(ctiTrampoline) "\n" -".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiTrampoline) "\n" -SYMBOL_STRING(ctiTrampoline) ":" "\n" - "sub sp, sp, #0x3c" "\n" - "str lr, [sp, #0x20]" "\n" - "str r4, [sp, #0x24]" "\n" - "str r5, [sp, #0x28]" "\n" - "str r6, [sp, #0x2c]" "\n" - "str r1, [sp, #0x30]" "\n" - "str r2, [sp, #0x34]" "\n" - "str r3, [sp, #0x38]" "\n" - "cpy r5, r2" "\n" - "mov r6, #512" "\n" - "blx r0" "\n" - "ldr r6, [sp, #0x2c]" "\n" - "ldr r5, [sp, #0x28]" "\n" - "ldr r4, [sp, #0x24]" "\n" - "ldr lr, [sp, #0x20]" "\n" - "add sp, sp, #0x3c" "\n" - "bx lr" "\n" -); +#elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_THUMB2) -asm volatile ( -".text" "\n" -".align 2" "\n" -".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" -".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" -SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" - "cpy r0, sp" "\n" - "bl " SYMBOL_STRING(cti_vm_throw) "\n" - "ldr r6, [sp, #0x2c]" "\n" - "ldr r5, [sp, #0x28]" "\n" - "ldr r4, [sp, #0x24]" "\n" - "ldr lr, [sp, #0x20]" "\n" - "add sp, sp, #0x3c" "\n" - "bx lr" "\n" -); +#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 PRESERVED_R7_OFFSET 0x4C +#define PRESERVED_R8_OFFSET 0x50 +#define PRESERVED_R9_OFFSET 0x54 +#define PRESERVED_R10_OFFSET 0x58 +#define PRESERVED_R11_OFFSET 0x5C +#define REGISTER_FILE_OFFSET 0x60 +#define FIRST_STACK_ARGUMENT 0x68 -asm volatile ( -".text" "\n" -".align 2" "\n" -".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" -".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" -SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" - "ldr r6, [sp, #0x2c]" "\n" - "ldr r5, [sp, #0x28]" "\n" - "ldr r4, [sp, #0x24]" "\n" - "ldr lr, [sp, #0x20]" "\n" - "add sp, sp, #0x3c" "\n" - "bx lr" "\n" -); +#elif (COMPILER(GCC) || COMPILER(MSVC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL) -#elif COMPILER(MSVC) +// Also update the MSVC section (defined at DEFINE_STUB_FUNCTION) +// when changing one of the following values. +#define THUNK_RETURN_ADDRESS_OFFSET 64 +#define PRESERVEDR4_OFFSET 68 -#if USE(JIT_STUB_ARGUMENT_VA_LIST) -#error "JIT_STUB_ARGUMENT_VA_LIST configuration not supported on MSVC." -#endif +#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. @@ -272,7 +232,7 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_ extern "C" { - __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue* exception, Profiler**, JSGlobalData*) + __declspec(naked) EncodedJSValue ctiTrampoline(void* code, JSStack*, CallFrame*, void* /*unused1*/, void* /*unused2*/, VM*) { __asm { push ebp; @@ -281,7 +241,6 @@ extern "C" { push edi; push ebx; sub esp, 0x3c; - mov esi, 512; mov ecx, esp; mov edi, [esp + 0x58]; call [esp + 0x50]; @@ -321,78 +280,108 @@ extern "C" { } } -#endif // COMPILER(GCC) && PLATFORM(X86) - -#else // USE(JSVALUE32_64) - -#if COMPILER(GCC) && PLATFORM(X86) - -// These ASSERTs remind you that, if you change the layout of JITStackFrame, you -// need to change the assembly trampolines below to match. -COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_callFrame_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); +#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_S3_OFFSET 76 +#define PRESERVED_S4_OFFSET 80 +#define PRESERVED_RETURN_ADDRESS_OFFSET 84 +#define THUNK_RETURN_ADDRESS_OFFSET 88 +#define REGISTER_FILE_OFFSET 92 +#define VM_OFFSET 108 +#define STACK_LENGTH 112 +#elif CPU(SH4) +#define SYMBOL_STRING(name) #name +/* code (r4), JSStack* (r5), CallFrame* (r6), void* unused1 (r7), void* unused2(sp), VM (sp)*/ asm volatile ( +".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" + "mov.l r7, @-r15" "\n" + "mov.l r6, @-r15" "\n" + "mov.l r5, @-r15" "\n" + "mov.l r14, @-r15" "\n" + "sts.l pr, @-r15" "\n" + "mov.l r13, @-r15" "\n" + "mov.l r11, @-r15" "\n" + "mov.l r10, @-r15" "\n" + "add #-60, r15" "\n" + "mov r6, r14" "\n" + "jsr @r4" "\n" + "nop" "\n" + "add #60, r15" "\n" + "mov.l @r15+,r10" "\n" + "mov.l @r15+,r11" "\n" + "mov.l @r15+,r13" "\n" + "lds.l @r15+,pr" "\n" + "mov.l @r15+,r14" "\n" + "add #12, r15" "\n" + "rts" "\n" + "nop" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" ); asm volatile ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" -#if !USE(JIT_STUB_ARGUMENT_VA_LIST) - "movl %esp, %ecx" "\n" -#endif - "call " SYMBOL_STRING(cti_vm_throw) "\n" - "addl $0x1c, %esp" "\n" - "popl %ebx" "\n" - "popl %edi" "\n" - "popl %esi" "\n" - "popl %ebp" "\n" - "ret" "\n" + "mov.l .L2"SYMBOL_STRING(cti_vm_throw)",r0" "\n" + "mov r15, r4" "\n" + "mov.l @(r0,r12),r11" "\n" + "jsr @r11" "\n" + "nop" "\n" + "add #60, r15" "\n" + "mov.l @r15+,r10" "\n" + "mov.l @r15+,r11" "\n" + "mov.l @r15+,r13" "\n" + "lds.l @r15+,pr" "\n" + "mov.l @r15+,r14" "\n" + "add #12, r15" "\n" + "rts" "\n" + "nop" "\n" + ".align 2" "\n" + ".L2"SYMBOL_STRING(cti_vm_throw)":.long " SYMBOL_STRING(cti_vm_throw)"@GOT \n" ); - + asm volatile ( ".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" + "add #60, r15" "\n" + "mov.l @r15+,r10" "\n" + "mov.l @r15+,r11" "\n" + "mov.l @r15+,r13" "\n" + "lds.l @r15+,pr" "\n" + "mov.l @r15+,r14" "\n" + "add #12, r15" "\n" + "rts" "\n" + "nop" "\n" ); - -#elif COMPILER(GCC) && PLATFORM(X86_64) - -#if USE(JIT_STUB_ARGUMENT_VA_LIST) -#error "JIT_STUB_ARGUMENT_VA_LIST not supported on x86-64." +#else + #error "JIT not supported on this platform." #endif +#else // USE(JSVALUE32_64) + +#if COMPILER(GCC) && CPU(X86_64) && !OS(WINDOWS) + // These ASSERTs remind you that, if you change the layout of JITStackFrame, you // need to change the assembly trampolines below to match. -COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x90, JITStackFrame_callFrame_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x80, JITStackFrame_code_offset_matches_ctiTrampoline); -COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x48, JITStackFrame_stub_argument_space_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x48, JITStackFrame_code_offset_matches_ctiTrampoline); +COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x78, JITStackFrame_stub_argument_space_matches_ctiTrampoline); -asm volatile ( +asm ( +".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushq %rbp" "\n" "movq %rsp, %rbp" "\n" @@ -401,13 +390,20 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushq %r14" "\n" "pushq %r15" "\n" "pushq %rbx" "\n" + // Form the JIT stubs area + "pushq %r9" "\n" + "pushq %r8" "\n" + "pushq %rcx" "\n" + "pushq %rdx" "\n" + "pushq %rsi" "\n" + "pushq %rdi" "\n" "subq $0x48, %rsp" "\n" "movq $512, %r12" "\n" "movq $0xFFFF000000000000, %r14" "\n" "movq $0xFFFF000000000002, %r15" "\n" - "movq 0x90(%rsp), %r13" "\n" - "call *0x80(%rsp)" "\n" - "addq $0x48, %rsp" "\n" + "movq %rdx, %r13" "\n" + "call *%rdi" "\n" + "addq $0x78, %rsp" "\n" "popq %rbx" "\n" "popq %r15" "\n" "popq %r14" "\n" @@ -415,14 +411,25 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "popq %r12" "\n" "popq %rbp" "\n" "ret" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" ); -asm volatile ( +asm ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movq %rsp, %rdi" "\n" - "call " SYMBOL_STRING(cti_vm_throw) "\n" - "addq $0x48, %rsp" "\n" + "call " LOCAL_REFERENCE(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" @@ -432,10 +439,66 @@ SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "ret" "\n" ); -asm volatile ( +#elif COMPILER(GCC) && CPU(X86_64) && OS(WINDOWS) + +// 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, savedRBX) == 0x58, JITStackFrame_stub_argument_space_matches_ctiTrampoline); + +asm ( +".text\n" +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" +SYMBOL_STRING(ctiTrampoline) ":" "\n" + // Dump register parameters to their home address + "movq %r9, 0x20(%rsp)" "\n" + "movq %r8, 0x18(%rsp)" "\n" + "movq %rdx, 0x10(%rsp)" "\n" + "movq %rcx, 0x8(%rsp)" "\n" + + "pushq %rbp" "\n" + "movq %rsp, %rbp" "\n" + "pushq %r12" "\n" + "pushq %r13" "\n" + "pushq %r14" "\n" + "pushq %r15" "\n" + "pushq %rbx" "\n" + + // Decrease rsp to point to the start of our JITStackFrame + "subq $0x58, %rsp" "\n" + "movq $512, %r12" "\n" + "movq $0xFFFF000000000000, %r14" "\n" + "movq $0xFFFF000000000002, %r15" "\n" + "movq %r8, %r13" "\n" + "call *%rcx" "\n" + "addq $0x58, %rsp" "\n" + "popq %rbx" "\n" + "popq %r15" "\n" + "popq %r14" "\n" + "popq %r13" "\n" + "popq %r12" "\n" + "popq %rbp" "\n" + "ret" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" +); + +asm ( +".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" +SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" + "movq %rsp, %rcx" "\n" + "call " LOCAL_REFERENCE(cti_vm_throw) "\n" + "int3" "\n" +); + +asm ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" - "addq $0x48, %rsp" "\n" + "addq $0x58, %rsp" "\n" "popq %rbx" "\n" "popq %r15" "\n" "popq %r14" "\n" @@ -445,169 +508,524 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "ret" "\n" ); -#elif COMPILER(GCC) && PLATFORM_ARM_ARCH(7) +#elif COMPILER(GCC) && CPU(ARM64) + +#define THUNK_RETURN_ADDRESS_OFFSET 0x30 +#define PRESERVED_RETURN_ADDRESS_OFFSET 0x38 +#define PRESERVED_X19_OFFSET 0x40 +#define PRESERVED_X20_OFFSET 0x48 +#define PRESERVED_X21_OFFSET 0x50 +#define PRESERVED_X22_OFFSET 0x58 +#define PRESERVED_X23_OFFSET 0x60 +#define PRESERVED_X24_OFFSET 0x68 +#define PRESERVED_X25_OFFSET 0x70 +#define PRESERVED_X26_OFFSET 0x78 +#define PRESERVED_X27_OFFSET 0x80 +#define PRESERVED_X28_OFFSET 0x88 +#define REGISTER_FILE_OFFSET 0x90 +#define CALLFRAME_OFFSET 0x98 +#define PROFILER_REFERENCE_OFFSET 0xa0 +#define VM_OFFSET 0xa8 +#define SIZEOF_JITSTACKFRAME 0xb0 + +asm ( +".section __TEXT,__text,regular,pure_instructions" "\n" +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +".align 2" "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" +SYMBOL_STRING(ctiTrampoline) ":" "\n" + "sub sp, sp, #" STRINGIZE_VALUE_OF(SIZEOF_JITSTACKFRAME) "\n" + "str lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" + "str x19, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X19_OFFSET) "]" "\n" + "str x20, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X20_OFFSET) "]" "\n" + "str x21, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X21_OFFSET) "]" "\n" + "str x22, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X22_OFFSET) "]" "\n" + "str x23, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X23_OFFSET) "]" "\n" + "str x24, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X24_OFFSET) "]" "\n" + "str x25, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X25_OFFSET) "]" "\n" + "str x26, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X26_OFFSET) "]" "\n" + "str x27, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X27_OFFSET) "]" "\n" + "str x28, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X28_OFFSET) "]" "\n" + "str x1, [sp, #" STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET) "]" "\n" + "str x2, [sp, #" STRINGIZE_VALUE_OF(CALLFRAME_OFFSET) "]" "\n" + "str x4, [sp, #" STRINGIZE_VALUE_OF(PROFILER_REFERENCE_OFFSET) "]" "\n" + "str x5, [sp, #" STRINGIZE_VALUE_OF(VM_OFFSET) "]" "\n" + "mov x25, x2" "\n" // callFrameRegister = ARM64Registers::x25 + "mov x26, #512" "\n" // timeoutCheckRegister = ARM64Registers::x26 + "mov x27, #0xFFFF000000000000" "\n" // tagTypeNumberRegister = ARM64Registers::x27 + "add x28, x27, #2" "\n" // ( #0xFFFF000000000002 ) tagMaskRegister = ARM64Registers::x28 + "blr x0" "\n" + "ldr x28, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X28_OFFSET) "]" "\n" + "ldr x27, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X27_OFFSET) "]" "\n" + "ldr x26, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X26_OFFSET) "]" "\n" + "ldr x25, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X25_OFFSET) "]" "\n" + "ldr x24, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X24_OFFSET) "]" "\n" + "ldr x23, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X23_OFFSET) "]" "\n" + "ldr x22, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X22_OFFSET) "]" "\n" + "ldr x21, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X21_OFFSET) "]" "\n" + "ldr x20, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X20_OFFSET) "]" "\n" + "ldr x19, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X19_OFFSET) "]" "\n" + "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(SIZEOF_JITSTACKFRAME) "\n" + "ret" "\n" + +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" +SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" + "ldr x28, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X28_OFFSET) "]" "\n" + "ldr x27, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X27_OFFSET) "]" "\n" + "ldr x26, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X26_OFFSET) "]" "\n" + "ldr x25, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X25_OFFSET) "]" "\n" + "ldr x24, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X24_OFFSET) "]" "\n" + "ldr x23, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X23_OFFSET) "]" "\n" + "ldr x22, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X22_OFFSET) "]" "\n" + "ldr x21, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X21_OFFSET) "]" "\n" + "ldr x20, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X20_OFFSET) "]" "\n" + "ldr x19, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_X19_OFFSET) "]" "\n" + "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(SIZEOF_JITSTACKFRAME) "\n" + "ret" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +".align 2" "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" +); + +asm ( +".section __TEXT,__text,regular,pure_instructions" "\n" +".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +".align 2" "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" +SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" + "mov x0, sp" "\n" + "bl " LOCAL_REFERENCE(cti_vm_throw) "\n" + "hlt 0xdead" "\n" // Should not be reached! +); + +#elif COMPILER(MSVC) && CPU(X86_64) -#if USE(JIT_STUB_ARGUMENT_VA_LIST) -#error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7." +// These ASSERTs remind you that, if you change the layout of JITStackFrame, you +// need to change the assembly trampolines in JITStubsMSVC64.asm to match. +COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment); +COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x58, JITStackFrame_stub_argument_space_matches_ctiTrampoline); + +#else + #error "JIT not supported on this platform." #endif -asm volatile ( +#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 $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n" + "sw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_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" + "move $25,$4 # move executableAddress to t9" "\n" + "sw $5," STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET) "($29) # store JSStack to current stack" "\n" + "lw $9," STRINGIZE_VALUE_OF(STACK_LENGTH + 20) "($29) # load vm from previous stack" "\n" + "jalr $25" "\n" + "sw $9," STRINGIZE_VALUE_OF(VM_OFFSET) "($29) # store vm 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 $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n" + "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_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" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\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 +".set macro" "\n" +".cpload $31" "\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 $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n" + "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_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 $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n" + "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_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 " SYMBOL_STRING(ctiTrampoline) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" - "sub sp, sp, #0x3c" "\n" - "str lr, [sp, #0x20]" "\n" - "str r4, [sp, #0x24]" "\n" - "str r5, [sp, #0x28]" "\n" - "str r6, [sp, #0x2c]" "\n" - "str r1, [sp, #0x30]" "\n" - "str r2, [sp, #0x34]" "\n" - "str r3, [sp, #0x38]" "\n" - "cpy r5, r2" "\n" + "sub sp, sp, #" STRINGIZE_VALUE_OF(FIRST_STACK_ARGUMENT) "\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 r7, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R7_OFFSET) "]" "\n" + "str r8, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R8_OFFSET) "]" "\n" + "str r9, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R9_OFFSET) "]" "\n" + "str r10, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R10_OFFSET) "]" "\n" + "str r11, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R11_OFFSET) "]" "\n" + "str r1, [sp, #" STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET) "]" "\n" + "mov r5, r2" "\n" "mov r6, #512" "\n" "blx r0" "\n" - "ldr r6, [sp, #0x2c]" "\n" - "ldr r5, [sp, #0x28]" "\n" - "ldr r4, [sp, #0x24]" "\n" - "ldr lr, [sp, #0x20]" "\n" - "add sp, sp, #0x3c" "\n" + "ldr r11, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R11_OFFSET) "]" "\n" + "ldr r10, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R10_OFFSET) "]" "\n" + "ldr r9, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R9_OFFSET) "]" "\n" + "ldr r8, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R8_OFFSET) "]" "\n" + "ldr r7, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R7_OFFSET) "]" "\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(FIRST_STACK_ARGUMENT) "\n" "bx lr" "\n" +".align 2" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +".thumb" "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" ); -asm volatile ( +asm ( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" ".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" - "cpy r0, sp" "\n" - "bl " SYMBOL_STRING(cti_vm_throw) "\n" - "ldr r6, [sp, #0x2c]" "\n" - "ldr r5, [sp, #0x28]" "\n" - "ldr r4, [sp, #0x24]" "\n" - "ldr lr, [sp, #0x20]" "\n" - "add sp, sp, #0x3c" "\n" + "mov r0, sp" "\n" + "bl " LOCAL_REFERENCE(cti_vm_throw) "\n" + "ldr r11, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R11_OFFSET) "]" "\n" + "ldr r10, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R10_OFFSET) "]" "\n" + "ldr r9, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R9_OFFSET) "]" "\n" + "ldr r8, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R8_OFFSET) "]" "\n" + "ldr r7, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R7_OFFSET) "]" "\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(FIRST_STACK_ARGUMENT) "\n" "bx lr" "\n" ); -asm volatile ( +asm ( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" ".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" - "ldr r6, [sp, #0x2c]" "\n" - "ldr r5, [sp, #0x28]" "\n" - "ldr r4, [sp, #0x24]" "\n" - "ldr lr, [sp, #0x20]" "\n" - "add sp, sp, #0x3c" "\n" + "ldr r11, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R11_OFFSET) "]" "\n" + "ldr r10, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R10_OFFSET) "]" "\n" + "ldr r9, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R9_OFFSET) "]" "\n" + "ldr r8, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R8_OFFSET) "]" "\n" + "ldr r7, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R7_OFFSET) "]" "\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(FIRST_STACK_ARGUMENT) "\n" "bx lr" "\n" ); -#elif COMPILER(MSVC) - -#if USE(JIT_STUB_ARGUMENT_VA_LIST) -#error "JIT_STUB_ARGUMENT_VA_LIST configuration not supported on MSVC." -#endif - -// These ASSERTs remind you that, if you change the layout of JITStackFrame, you -// need to change the assembly trampolines below to match. -COMPILE_ASSERT(offsetof(struct JITStackFrame, 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); +#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL) -extern "C" { +asm ( +".text" "\n" +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" +INLINE_ARM_FUNCTION(ctiTrampoline) +SYMBOL_STRING(ctiTrampoline) ":" "\n" + "stmdb sp!, {r1-r3}" "\n" + "stmdb sp!, {r4-r6, r8-r11, lr}" "\n" + "sub sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n" + "mov r5, r2" "\n" + "mov r6, #512" "\n" + // r0 contains the code + "blx r0" "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n" + "ldmia sp!, {r4-r6, r8-r11, lr}" "\n" + "add sp, sp, #12" "\n" + "bx lr" "\n" +".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n" +HIDE_SYMBOL(ctiTrampolineEnd) "\n" +SYMBOL_STRING(ctiTrampolineEnd) ":" "\n" +); - __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue* exception, Profiler**, JSGlobalData*) - { - __asm { - push ebp; - mov ebp, esp; - push esi; - push edi; - push ebx; - sub esp, 0x1c; - mov esi, 512; - mov ecx, esp; - mov edi, [esp + 0x38]; - call [esp + 0x30]; - add esp, 0x1c; - pop ebx; - pop edi; - pop esi; - pop ebp; - ret; - } - } +asm ( +".text" "\n" +".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" +INLINE_ARM_FUNCTION(ctiVMThrowTrampoline) +SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" + "mov r0, sp" "\n" + "bl " SYMBOL_STRING(cti_vm_throw) "\n" - __declspec(naked) void ctiVMThrowTrampoline() - { - __asm { - mov ecx, esp; - call cti_vm_throw; - add esp, 0x1c; - pop ebx; - pop edi; - pop esi; - pop ebp; - ret; - } - } - - __declspec(naked) void ctiOpThrowNotCaught() - { - __asm { - add esp, 0x1c; - pop ebx; - pop edi; - pop esi; - pop ebp; - ret; - } - } -} - -#endif // COMPILER(GCC) && PLATFORM(X86) +// Both has the same return sequence +".text" "\n" +".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" +INLINE_ARM_FUNCTION(ctiOpThrowNotCaught) +SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" + "add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n" + "ldmia sp!, {r4-r6, r8-r11, lr}" "\n" + "add sp, sp, #12" "\n" + "bx lr" "\n" +); -#endif // USE(JSVALUE32_64) +#elif COMPILER(RVCT) && CPU(ARM_THUMB2) + +__asm EncodedJSValue ctiTrampoline(void*, JSStack*, CallFrame*, void* /*unused1*/, void* /*unused2*/, VM*) +{ + PRESERVE8 + sub sp, sp, # FIRST_STACK_ARGUMENT + str lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] + str r4, [sp, # PRESERVED_R4_OFFSET ] + str r5, [sp, # PRESERVED_R5_OFFSET ] + str r6, [sp, # PRESERVED_R6_OFFSET ] + str r7, [sp, # PRESERVED_R7_OFFSET ] + str r8, [sp, # PRESERVED_R8_OFFSET ] + str r9, [sp, # PRESERVED_R9_OFFSET ] + str r10, [sp, # PRESERVED_R10_OFFSET ] + str r11, [sp, # PRESERVED_R11_OFFSET ] + str r1, [sp, # REGISTER_FILE_OFFSET ] + mov r5, r2 + mov r6, #512 + blx r0 + ldr r11, [sp, # PRESERVED_R11_OFFSET ] + ldr r10, [sp, # PRESERVED_R10_OFFSET ] + ldr r9, [sp, # PRESERVED_R9_OFFSET ] + ldr r8, [sp, # PRESERVED_R8_OFFSET ] + ldr r7, [sp, # PRESERVED_R7_OFFSET ] + ldr r6, [sp, # PRESERVED_R6_OFFSET ] + ldr r5, [sp, # PRESERVED_R5_OFFSET ] + ldr r4, [sp, # PRESERVED_R4_OFFSET ] + ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] + add sp, sp, # FIRST_STACK_ARGUMENT + bx lr +} + +__asm void ctiVMThrowTrampoline() +{ + PRESERVE8 + mov r0, sp + bl cti_vm_throw + ldr r11, [sp, # PRESERVED_R11_OFFSET ] + ldr r10, [sp, # PRESERVED_R10_OFFSET ] + ldr r9, [sp, # PRESERVED_R9_OFFSET ] + ldr r8, [sp, # PRESERVED_R8_OFFSET ] + ldr r7, [sp, # PRESERVED_R7_OFFSET ] + ldr r6, [sp, # PRESERVED_R6_OFFSET ] + ldr r6, [sp, # PRESERVED_R6_OFFSET ] + ldr r5, [sp, # PRESERVED_R5_OFFSET ] + ldr r4, [sp, # PRESERVED_R4_OFFSET ] + ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] + add sp, sp, # FIRST_STACK_ARGUMENT + bx lr +} + +__asm void ctiOpThrowNotCaught() +{ + PRESERVE8 + ldr r11, [sp, # PRESERVED_R11_OFFSET ] + ldr r10, [sp, # PRESERVED_R10_OFFSET ] + ldr r9, [sp, # PRESERVED_R9_OFFSET ] + ldr r8, [sp, # PRESERVED_R8_OFFSET ] + ldr r7, [sp, # PRESERVED_R7_OFFSET ] + ldr r6, [sp, # PRESERVED_R6_OFFSET ] + ldr r6, [sp, # PRESERVED_R6_OFFSET ] + ldr r5, [sp, # PRESERVED_R5_OFFSET ] + ldr r4, [sp, # PRESERVED_R4_OFFSET ] + ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] + add sp, sp, # FIRST_STACK_ARGUMENT + bx lr +} + +#elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL) + +__asm EncodedJSValue ctiTrampoline(void*, JSStack*, CallFrame*, void* /*unused1*/, void* /*unused2*/, VM*) +{ + ARM + stmdb sp!, {r1-r3} + stmdb sp!, {r4-r6, r8-r11, lr} + sub sp, sp, # PRESERVEDR4_OFFSET + mov r5, r2 + mov r6, #512 + mov lr, pc + bx r0 + add sp, sp, # PRESERVEDR4_OFFSET + ldmia sp!, {r4-r6, r8-r11, lr} + add sp, sp, #12 + bx lr +} +__asm void ctiTrampolineEnd() +{ +} + +__asm void ctiVMThrowTrampoline() +{ + ARM + PRESERVE8 + mov r0, sp + bl cti_vm_throw + add sp, sp, # PRESERVEDR4_OFFSET + ldmia sp!, {r4-r6, r8-r11, 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() + #define CTI_SAMPLER stackFrame.vm->interpreter->sampler() #else #define CTI_SAMPLER 0 #endif -JITThunks::JITThunks(JSGlobalData* globalData) +void performPlatformSpecificJITAssertions(VM* vm) { - JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_ctiStringLengthTrampoline, &m_ctiVirtualCallPreLink, &m_ctiVirtualCallLink, &m_ctiVirtualCall, &m_ctiNativeCallThunk); + if (!vm->canUseJIT()) + return; -#if PLATFORM_ARM_ARCH(7) +#if CPU(ARM_THUMB2) // Unfortunate the arm compiler does not like the use of offsetof on JITStackFrame (since it contains non POD types), // and the OBJECT_OFFSETOF macro does not appear constantish enough for it to be happy with its use in COMPILE_ASSERT // macros. - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == 0x20); - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == 0x24); - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR5) == 0x28); - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR6) == 0x2c); - - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == 0x30); - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == 0x34); - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, exception) == 0x38); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == PRESERVED_RETURN_ADDRESS_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == PRESERVED_R4_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR5) == PRESERVED_R5_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR6) == PRESERVED_R6_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR7) == PRESERVED_R7_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR8) == PRESERVED_R8_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR9) == PRESERVED_R9_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR10) == PRESERVED_R10_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR11) == PRESERVED_R11_OFFSET); + + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, stack) == REGISTER_FILE_OFFSET); // The fifth argument is the first item already on the stack. - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == 0x3c); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, unused1) == FIRST_STACK_ARGUMENT); + + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET); + +#elif CPU(ARM64) + + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == PRESERVED_RETURN_ADDRESS_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedX19) == PRESERVED_X19_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedX20) == PRESERVED_X20_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedX21) == PRESERVED_X21_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedX22) == PRESERVED_X22_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedX23) == PRESERVED_X23_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedX24) == PRESERVED_X24_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedX25) == PRESERVED_X25_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedX26) == PRESERVED_X26_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedX27) == PRESERVED_X27_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedX28) == PRESERVED_X28_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, stack) == REGISTER_FILE_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == PROFILER_REFERENCE_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, vm) == VM_OFFSET); + ASSERT(sizeof(struct JITStackFrame) == SIZEOF_JITSTACKFRAME); + +#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, stack) == REGISTER_FILE_OFFSET); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, vm) == VM_OFFSET); - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == 0x1C); #endif } -#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) - -NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot) +NEVER_INLINE static void 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. @@ -616,46 +1034,58 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co // Uncacheable: give up. if (!slot.isCacheable()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } - JSCell* baseCell = asCell(baseValue); + JSCell* baseCell = baseValue.asCell(); Structure* structure = baseCell->structure(); - if (structure->isUncacheableDictionary()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } // If baseCell != base, then baseCell must be a proxy for another object. if (baseCell != slot.base()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } - - StructureStubInfo* stubInfo = &codeBlock->getStubInfo(returnAddress); - + + // If the offset isn't something we can patch, then bail out. + if (!MacroAssembler::isPtrAlignedAddressOffset(offsetRelativeToPatchedStorage(slot.cachedOffset()))) { + 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) { - StructureChain* prototypeChain = structure->prototypeChain(callFrame); - if (!prototypeChain->isCacheable() || structure->isDictionary()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); + if (structure->isDictionary()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); return; } - stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain); - JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress); + + // put_by_id_transition checks the prototype chain for setters. + if (normalizePrototypeChain(callFrame, baseCell) == InvalidPrototypeChain) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); + return; + } + + StructureChain* prototypeChain = structure->prototypeChain(callFrame); + ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated()); + stubInfo->initPutByIdTransition(callFrame->vm(), codeBlock->ownerExecutable(), structure->previousID(), structure, prototypeChain, direct); + JIT::compilePutByIdTransition(callFrame->scope()->vm(), codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct); return; } - stubInfo->initPutByIdReplace(structure); + stubInfo->initPutByIdReplace(callFrame->vm(), codeBlock->ownerExecutable(), structure); - JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); + JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress, direct); } -NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot) +NEVER_INLINE static void 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. @@ -666,98 +1096,97 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co return; } - JSGlobalData* globalData = &callFrame->globalData(); + VM* vm = &callFrame->vm(); - if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { - JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, returnAddress); + if (isJSArray(baseValue) && propertyName == callFrame->propertyNames().length) { + JIT::compilePatchGetArrayLength(callFrame->scope()->vm(), codeBlock, returnAddress); return; } - if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { + if (isJSString(baseValue) && propertyName == callFrame->propertyNames().length) { // The tradeoff of compiling an patched inline string length access routine does not seem // to pay off, so we currently only do this for arrays. - ctiPatchCallByReturnAddress(codeBlock, returnAddress, globalData->jitStubs.ctiStringLengthTrampoline()); + ctiPatchCallByReturnAddress(codeBlock, returnAddress, vm->getCTIStub(stringLengthTrampolineGenerator).code()); return; } // Uncacheable: give up. if (!slot.isCacheable()) { + stubInfo->accessType = access_get_by_id_generic; ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } - JSCell* baseCell = asCell(baseValue); + JSCell* baseCell = baseValue.asCell(); Structure* structure = baseCell->structure(); - if (structure->isUncacheableDictionary()) { + if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) { + stubInfo->accessType = access_get_by_id_generic; ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } - // In the interpreter the last structure is trapped here; in CTI we use the - // *_second method to achieve a similar (but not quite the same) effect. - - StructureStubInfo* stubInfo = &codeBlock->getStubInfo(returnAddress); - // Cache hit: Specialize instruction and ref Structures. if (slot.slotBase() == baseValue) { - // set this up, so derefStructures can do it's job. - stubInfo->initGetByIdSelf(structure); - - JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); + RELEASE_ASSERT(stubInfo->accessType == access_unset); + if ((slot.cachedPropertyType() != PropertySlot::Value) + || !MacroAssembler::isCompactPtrAlignedAddressOffset(maxOffsetRelativeToPatchedStorage(slot.cachedOffset()))) + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail)); + else { + JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); + stubInfo->initGetByIdSelf(callFrame->vm(), codeBlock->ownerExecutable(), structure); + } return; } if (structure->isDictionary()) { + stubInfo->accessType = access_get_by_id_generic; 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(); + + if (structure->typeInfo().hasImpureGetOwnPropertySlot()) { + stubInfo->accessType = access_get_by_id_generic; + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); + return; + } // 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); + slotBaseObject->flattenDictionaryObject(callFrame->vm()); + offset = slotBaseObject->structure()->get(callFrame->vm(), propertyName); } - stubInfo->initGetByIdProto(structure, slotBaseObject->structure()); + stubInfo->initGetByIdProto(callFrame->vm(), codeBlock->ownerExecutable(), structure, slotBaseObject->structure(), slot.cachedPropertyType() == PropertySlot::Value); - JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), offset, returnAddress); + ASSERT(!structure->isDictionary()); + ASSERT(!slotBaseObject->structure()->isDictionary()); + JIT::compileGetByIdProto(callFrame->scope()->vm(), 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->opcodeID = op_get_by_id_generic; + PropertyOffset offset = slot.cachedOffset(); + size_t count = normalizePrototypeChainForChainAccess(callFrame, baseValue, slot.slotBase(), propertyName, offset); + if (count == InvalidPrototypeChain) { + stubInfo->accessType = access_get_by_id_generic; + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } StructureChain* prototypeChain = structure->prototypeChain(callFrame); - if (!prototypeChain->isCacheable()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); - return; - } - stubInfo->initGetByIdChain(structure, prototypeChain); - JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, offset, returnAddress); + stubInfo->initGetByIdChain(callFrame->vm(), codeBlock->ownerExecutable(), structure, prototypeChain, count, slot.cachedPropertyType() == PropertySlot::Value); + JIT::compileGetByIdChain(callFrame->scope()->vm(), callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress); } -#endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) - -#if USE(JIT_STUB_ARGUMENT_VA_LIST) -#define SETUP_VA_LISTL_ARGS va_list vl_args; va_start(vl_args, args) -#else -#define SETUP_VA_LISTL_ARGS -#endif - -#ifndef NDEBUG +#if !defined(NDEBUG) extern "C" { @@ -775,7 +1204,8 @@ struct StackHack { : stackFrame(stackFrame) , savedReturnAddress(*stackFrame.returnAddressSlot()) { - *stackFrame.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode)); + if (!CodeProfiling::enabled()) + *stackFrame.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode)); } ALWAYS_INLINE ~StackHack() @@ -787,13 +1217,13 @@ struct StackHack { ReturnAddressPtr savedReturnAddress; }; -#define STUB_INIT_STACK_FRAME(stackFrame) SETUP_VA_LISTL_ARGS; JITStackFrame& stackFrame = *reinterpret_cast(STUB_ARGS); StackHack stackHack(stackFrame) +#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) SETUP_VA_LISTL_ARGS; JITStackFrame& stackFrame = *reinterpret_cast(STUB_ARGS) +#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() @@ -803,88 +1233,317 @@ struct StackHack { // to get the address of the ctiVMThrowTrampoline function. It's also // good to keep the code size down by leaving as much of the exception // handling code out of line as possible. -static NEVER_INLINE void returnToThrowTrampoline(JSGlobalData* globalData, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot) +static NEVER_INLINE void returnToThrowTrampoline(VM* vm, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot) { - ASSERT(globalData->exception); - globalData->exceptionLocation = exceptionLocation; + RELEASE_ASSERT(vm->exception); + vm->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() \ - returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS) + do {\ + returnToThrowTrampoline(stackFrame.vm, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS);\ + } while (0) #define CHECK_FOR_EXCEPTION() \ do { \ - if (UNLIKELY(stackFrame.globalData->exception)) \ + if (UNLIKELY(stackFrame.vm->exception)) \ VM_THROW_EXCEPTION(); \ } while (0) #define CHECK_FOR_EXCEPTION_AT_END() \ do { \ - if (UNLIKELY(stackFrame.globalData->exception)) \ + if (UNLIKELY(stackFrame.vm->exception)) \ VM_THROW_EXCEPTION_AT_END(); \ } while (0) #define CHECK_FOR_EXCEPTION_VOID() \ do { \ - if (UNLIKELY(stackFrame.globalData->exception)) { \ + if (UNLIKELY(stackFrame.vm->exception)) { \ VM_THROW_EXCEPTION_AT_END(); \ return; \ } \ } while (0) -#if PLATFORM_ARM_ARCH(7) +// Helper function for JIT stubs that may throw an exception in the middle of +// processing a function call. This function rolls back the stack to +// our caller, so exception processing can proceed from a valid state. +template static T throwExceptionFromOpCall(JITStackFrame& jitStackFrame, CallFrame* newCallFrame, ReturnAddressPtr& returnAddressSlot) +{ + CallFrame* callFrame = newCallFrame->callerFrame(); + ASSERT(callFrame->vm().exception); + jitStackFrame.callFrame = callFrame; + callFrame->vm().topCallFrame = callFrame; + returnToThrowTrampoline(&callFrame->vm(), ReturnAddressPtr(newCallFrame->returnPC()), returnAddressSlot); + return T(); +} + +template static T throwExceptionFromOpCall(JITStackFrame& jitStackFrame, CallFrame* newCallFrame, ReturnAddressPtr& returnAddressSlot, JSValue exception) +{ + newCallFrame->callerFrame()->vm().exception = exception; + return throwExceptionFromOpCall(jitStackFrame, newCallFrame, returnAddressSlot); +} + +#if CPU(ARM_THUMB2) && COMPILER(GCC) #define DEFINE_STUB_FUNCTION(rtype, op) \ extern "C" { \ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ }; \ - asm volatile ( \ + asm ( \ ".text" "\n" \ ".align 2" "\n" \ ".globl " SYMBOL_STRING(cti_##op) "\n" \ + HIDE_SYMBOL(cti_##op) "\n" \ ".thumb" "\n" \ - ".thumb_func " SYMBOL_STRING(cti_##op) "\n" \ + ".thumb_func " THUMB_FUNC_PARAM(cti_##op) "\n" \ SYMBOL_STRING(cti_##op) ":" "\n" \ - "str lr, [sp, #0x1c]" "\n" \ + "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \ - "ldr lr, [sp, #0x1c]" "\n" \ + "ldr lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ "bx lr" "\n" \ ); \ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) \ +#elif CPU(ARM64) && COMPILER(GCC) + +#define DEFINE_STUB_FUNCTION(rtype, op) \ + extern "C" { \ + rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ + }; \ + asm ( \ + ".section __TEXT,__text,regular,pure_instructions" "\n" \ + ".globl " SYMBOL_STRING(cti_##op) "\n" \ + ".align 2" "\n" \ + HIDE_SYMBOL(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" \ + "ret" "\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" \ + ".set macro" "\n" \ + ".cpload $25" "\n" \ + "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ + "la $25," SYMBOL_STRING(JITStubThunked_##op) "\n" \ + ".set nomacro" "\n" \ + ".reloc 1f,R_MIPS_JALR," SYMBOL_STRING(JITStubThunked_##op) "\n" \ + "1: jalr $25" "\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" \ + INLINE_ARM_FUNCTION(cti_##op) \ + 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(ARM_THUMB2) || 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( PRESERVE8) +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 ctiTrampolineEnd) +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-r6, r8-r11, lr}) +MSVC_BEGIN( sub sp, sp, #68 ; sync with PRESERVEDR4_OFFSET) +MSVC_BEGIN( mov r5, r2) +MSVC_BEGIN( mov r6, #512) +MSVC_BEGIN( ; r0 contains the code) +MSVC_BEGIN( mov lr, pc) +MSVC_BEGIN( bx r0) +MSVC_BEGIN( add sp, sp, #68 ; sync with PRESERVEDR4_OFFSET) +MSVC_BEGIN( ldmia sp!, {r4-r6, r8-r11, lr}) +MSVC_BEGIN( add sp, sp, #12) +MSVC_BEGIN( bx lr) +MSVC_BEGIN(ctiTrampolineEnd) +MSVC_BEGIN(ctiTrampoline ENDP) +MSVC_BEGIN() +MSVC_BEGIN(ctiVMThrowTrampoline PROC) +MSVC_BEGIN( mov r0, sp) +MSVC_BEGIN( bl cti_vm_throw) +MSVC_BEGIN(ctiOpThrowNotCaught) +MSVC_BEGIN( add sp, sp, #68 ; sync with PRESERVEDR4_OFFSET) +MSVC_BEGIN( ldmia sp!, {r4-r6, r8-r11, 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, #64] ; sync with THUNK_RETURN_ADDRESS_OFFSET) +MSVC( bl JITStubThunked_#op#) +MSVC( ldr lr, [sp, #64] ; sync with THUNK_RETURN_ADDRESS_OFFSET) +MSVC( bx lr) +MSVC(cti_#op# ENDP) +MSVC() + +MSVC_END( END) +*/ + +#elif CPU(SH4) +#define DEFINE_STUB_FUNCTION(rtype, op) \ + extern "C" { \ + rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ + }; \ + asm volatile( \ + ".align 2" "\n" \ + ".globl " SYMBOL_STRING(cti_##op) "\n" \ + SYMBOL_STRING(cti_##op) ":" "\n" \ + "sts pr, r11" "\n" \ + "mov.l r11, @(0x38, r15)" "\n" \ + "mov.l .L2"SYMBOL_STRING(JITStubThunked_##op)",r0" "\n" \ + "mov.l @(r0,r12),r11" "\n" \ + "jsr @r11" "\n" \ + "nop" "\n" \ + "mov.l @(0x38, r15), r11 " "\n" \ + "lds r11, pr " "\n" \ + "rts" "\n" \ + "nop" "\n" \ + ".align 2" "\n" \ + ".L2"SYMBOL_STRING(JITStubThunked_##op)":.long " SYMBOL_STRING(JITStubThunked_##op)"@GOT \n" \ + ); \ + rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) #else #define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION) #endif -DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_this) { STUB_INIT_STACK_FRAME(stackFrame); - - JSValue v1 = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; + size_t inlineCapacity = stackFrame.args[0].int32(); + + JSFunction* constructor = jsCast(callFrame->callee()); +#if !ASSERT_DISABLED + ConstructData constructData; + ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); +#endif + + Structure* structure = constructor->allocationProfile(callFrame, inlineCapacity)->structure(); + JSValue result = constructEmptyObject(callFrame, structure); - JSObject* result = v1.toThisObject(callFrame); - CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(void, op_end) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this) { STUB_INIT_STACK_FRAME(stackFrame); - ScopeChainNode* scopeChain = stackFrame.callFrame->scopeChain(); - ASSERT(scopeChain->refCount > 1); - scopeChain->deref(); + JSValue v1 = stackFrame.args[0].jsValue(); + CallFrame* callFrame = stackFrame.callFrame; + + ASSERT(v1.isPrimitive()); + + JSObject* result = v1.toThisObject(callFrame); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_add) @@ -893,38 +1552,16 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_add) JSValue v1 = stackFrame.args[0].jsValue(); JSValue v2 = stackFrame.args[1].jsValue(); - - double left; - double right = 0.0; - - bool rightIsNumber = v2.getNumber(right); - if (rightIsNumber && v1.getNumber(left)) - return JSValue::encode(jsNumber(stackFrame.globalData, left + right)); - CallFrame* callFrame = stackFrame.callFrame; - bool leftIsString = v1.isString(); - if (leftIsString && v2.isString()) { - RefPtr value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep()); - if (UNLIKELY(!value)) { - throwOutOfMemoryError(callFrame); - VM_THROW_EXCEPTION(); - } - - return JSValue::encode(jsString(stackFrame.globalData, value.release())); + if (v1.isString() && !v2.isObject()) { + JSValue result = jsString(callFrame, asString(v1), v2.toString(callFrame)); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(result); } - if (rightIsNumber & leftIsString) { - RefPtr value = v2.isInt32() ? - concatenate(asString(v1)->value().rep(), v2.asInt32()) : - concatenate(asString(v1)->value().rep(), right); - - if (UNLIKELY(!value)) { - throwOutOfMemoryError(callFrame); - VM_THROW_EXCEPTION(); - } - return JSValue::encode(jsString(stackFrame.globalData, value.release())); - } + if (v1.isNumber() && v2.isNumber()) + return JSValue::encode(jsNumber(v1.asNumber() + v2.asNumber())); // All other cases are pretty uncommon JSValue result = jsAddSlowCase(callFrame, v1, v2); @@ -932,86 +1569,65 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_add) return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_inc) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_inc) { STUB_INIT_STACK_FRAME(stackFrame); JSValue v = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, v.toNumber(callFrame) + 1); + JSValue result = jsNumber(v.toNumber(callFrame) + 1); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(int, timeout_check) +DEFINE_STUB_FUNCTION(void, handle_watchdog_timer) { STUB_INIT_STACK_FRAME(stackFrame); - - JSGlobalData* globalData = stackFrame.globalData; - TimeoutChecker& timeoutChecker = globalData->timeoutChecker; - - if (timeoutChecker.didTimeOut(stackFrame.callFrame)) { - globalData->exception = createInterruptedExecutionException(globalData); + CallFrame* callFrame = stackFrame.callFrame; + VM* vm = stackFrame.vm; + if (UNLIKELY(vm->watchdog.didFire(callFrame))) { + vm->exception = createTerminatedExecutionException(vm); VM_THROW_EXCEPTION_AT_END(); + return; } - - return timeoutChecker.ticksUntilNextCheck(); } -DEFINE_STUB_FUNCTION(void, register_file_check) +DEFINE_STUB_FUNCTION(void*, stack_check) { STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; - if (LIKELY(stackFrame.registerFile->grow(&stackFrame.callFrame->registers()[stackFrame.callFrame->codeBlock()->m_numCalleeRegisters]))) - return; + if (UNLIKELY(!stackFrame.stack->grow(&callFrame->registers()[callFrame->codeBlock()->m_numCalleeRegisters]))) + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS, createStackOverflowError(callFrame->callerFrame())); - // Rewind to the previous call frame because op_call already optimistically - // moved the call frame forward. - CallFrame* oldCallFrame = stackFrame.callFrame->callerFrame(); - stackFrame.callFrame = oldCallFrame; - throwStackOverflowError(oldCallFrame, stackFrame.globalData, ReturnAddressPtr(oldCallFrame->returnPC()), STUB_RETURN_ADDRESS); + return callFrame; } -DEFINE_STUB_FUNCTION(int, op_loop_if_less) +DEFINE_STUB_FUNCTION(JSObject*, op_new_object) { 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; + return constructEmptyObject(stackFrame.callFrame, stackFrame.args[0].structure()); } -DEFINE_STUB_FUNCTION(int, op_loop_if_lesseq) +DEFINE_STUB_FUNCTION(void, op_put_by_id_generic) { 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); + 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(); - 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) +DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_generic) { STUB_INIT_STACK_FRAME(stackFrame); - - PutPropertySlot slot; - stackFrame.args[0].jsValue().put(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot); + + PutPropertySlot slot(stackFrame.callFrame->codeBlock()->isStrictMode()); + JSValue baseValue = stackFrame.args[0].jsValue(); + ASSERT(baseValue.isObject()); + asObject(baseValue)->putDirect(stackFrame.callFrame->vm(), stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot); CHECK_FOR_EXCEPTION_AT_END(); } @@ -1030,172 +1646,121 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_generic) 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(); + + CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); + StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); + AccessType accessType = static_cast(stubInfo->accessType); - PutPropertySlot slot; + PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot); - - ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_id_second)); - - CHECK_FOR_EXCEPTION_AT_END(); -} - -DEFINE_STUB_FUNCTION(void, op_put_by_id_second) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - PutPropertySlot slot; - stackFrame.args[0].jsValue().put(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot); - JITThunks::tryCachePutByID(stackFrame.callFrame, stackFrame.callFrame->codeBlock(), STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot); + + if (accessType == static_cast(stubInfo->accessType)) { + stubInfo->setSeen(); + 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_fail) +DEFINE_STUB_FUNCTION(void, op_put_by_id_direct) { STUB_INIT_STACK_FRAME(stackFrame); - CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); + + CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); + StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); + AccessType accessType = static_cast(stubInfo->accessType); - PutPropertySlot slot; - stackFrame.args[0].jsValue().put(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); - + PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); 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; + + asObject(baseValue)->putDirect(callFrame->vm(), ident, stackFrame.args[2].jsValue(), slot); + + if (accessType == static_cast(stubInfo->accessType)) { + stubInfo->setSeen(); + tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, true); + } + + CHECK_FOR_EXCEPTION_AT_END(); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id) +DEFINE_STUB_FUNCTION(void, op_put_by_id_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); - - ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_second)); + + PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); + stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot); CHECK_FOR_EXCEPTION_AT_END(); - return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) +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()); JSValue baseValue = stackFrame.args[0].jsValue(); - PropertySlot slot(baseValue); - JSValue result = baseValue.get(callFrame, ident, slot); - - ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_method_check_second)); - + ASSERT(baseValue.isObject()); + asObject(baseValue)->putDirect(callFrame->vm(), ident, stackFrame.args[2].jsValue(), slot); + CHECK_FOR_EXCEPTION_AT_END(); - return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check_second) +DEFINE_STUB_FUNCTION(JSObject*, op_put_by_id_transition_realloc) { 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 we successfully got something, then the base from which it is being accessed must - // be an object. (Assertion to ensure asObject() call below is safe, which comes after - // an isCacheable() chceck. - ASSERT(!slot.isCacheable() || slot.slotBase().isObject()); - - // 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.isCacheable() - && !(structure = asCell(baseValue)->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)); - MethodCallLinkInfo& methodCallLinkInfo = callFrame->codeBlock()->getMethodCallLinkInfo(STUB_RETURN_ADDRESS); - - // Check to see if the function is on the object's prototype. Patch up the code to optimize. - if (slot.slotBase() == structure->prototypeForLookup(callFrame)) - JIT::patchMethodCallProto(callFrame->codeBlock(), methodCallLinkInfo, callee, structure, slotBaseObject); - // Check to see if the function is on the object itself. - // Since we generate the method-check to check both the structure and a prototype-structure (since this - // is the common case) we have a problem - we need to patch the prototype structure check to do something - // useful. We could try to nop it out altogether, but that's a little messy, so lets do something simpler - // for now. For now it performs a check on a special object on the global object only used for this - // purpose. The object is in no way exposed, and as such the check will always pass. - else if (slot.slotBase() == baseValue) - JIT::patchMethodCallProto(callFrame->codeBlock(), methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject()->methodCallDummy()); - - // For now let any other case be cached as a normal get_by_id. - } + int32_t oldSize = stackFrame.args[3].int32(); + Structure* newStructure = stackFrame.args[4].structure(); + int32_t newSize = newStructure->outOfLineCapacity(); + + ASSERT(oldSize >= 0); + ASSERT(newSize > oldSize); - // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to. - ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id)); + ASSERT(baseValue.isObject()); + JSObject* base = asObject(baseValue); + VM& vm = *stackFrame.vm; + Butterfly* butterfly = base->growOutOfLineStorage(vm, oldSize, newSize); + base->setButterfly(vm, butterfly, newStructure); - return JSValue::encode(result); + return base; } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_second) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id) { STUB_INIT_STACK_FRAME(stackFrame); - CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); + CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); + StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); + AccessType accessType = static_cast(stubInfo->accessType); + JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(callFrame, ident, slot); + + if (accessType != static_cast(stubInfo->accessType)) + return JSValue::encode(result); - JITThunks::tryCacheGetByID(callFrame, callFrame->codeBlock(), STUB_RETURN_ADDRESS, baseValue, ident, slot); + if (!stubInfo->seenOnce()) + stubInfo->setSeen(); + else + tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); @@ -1208,132 +1773,190 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail) CallFrame* callFrame = stackFrame.callFrame; Identifier& ident = stackFrame.args[1].identifier(); + CodeBlock* codeBlock = callFrame->codeBlock(); + StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); + AccessType accessType = static_cast(stubInfo->accessType); + JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(callFrame, ident, slot); + + if (accessType != static_cast(stubInfo->accessType)) + return JSValue::encode(result); CHECK_FOR_EXCEPTION(); if (baseValue.isCell() && slot.isCacheable() - && !asCell(baseValue)->structure()->isUncacheableDictionary() + && !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->opcodeID == op_get_by_id_self) { + if (stubInfo->accessType == access_unset) + stubInfo->initGetByIdSelf(callFrame->vm(), codeBlock->ownerExecutable(), baseValue.asCell()->structure()); + + if (stubInfo->accessType == access_get_by_id_self) { ASSERT(!stubInfo->stubRoutine); - polymorphicStructureList = new PolymorphicAccessStructureList(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure); - stubInfo->initGetByIdSelfList(polymorphicStructureList, 2); + polymorphicStructureList = new PolymorphicAccessStructureList(callFrame->vm(), codeBlock->ownerExecutable(), 0, stubInfo->u.getByIdSelf.baseObjectStructure.get(), true); + stubInfo->initGetByIdSelfList(polymorphicStructureList, 1); } else { polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList; listIndex = stubInfo->u.getByIdSelfList.listSize; - stubInfo->u.getByIdSelfList.listSize++; } + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { + stubInfo->u.getByIdSelfList.listSize++; + JIT::compileGetByIdSelfList(callFrame->scope()->vm(), codeBlock, stubInfo, polymorphicStructureList, listIndex, baseValue.asCell()->structure(), ident, slot, slot.cachedOffset()); - JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), slot.cachedOffset()); - - if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); + if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); + } } else ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); return JSValue::encode(result); } -static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(StructureStubInfo* stubInfo, int& listIndex) +static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(VM& vm, ScriptExecutable* owner, StructureStubInfo* stubInfo, int& listIndex) { PolymorphicAccessStructureList* prototypeStructureList = 0; listIndex = 1; - switch (stubInfo->opcodeID) { - case op_get_by_id_proto: - prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure); - stubInfo->stubRoutine = CodeLocationLabel(); + switch (stubInfo->accessType) { + case access_get_by_id_proto: + prototypeStructureList = new PolymorphicAccessStructureList(vm, owner, stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure.get(), stubInfo->u.getByIdProto.prototypeStructure.get(), true); + stubInfo->stubRoutine.clear(); stubInfo->initGetByIdProtoList(prototypeStructureList, 2); break; - case op_get_by_id_chain: - prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain); - stubInfo->stubRoutine = CodeLocationLabel(); + case access_get_by_id_chain: + prototypeStructureList = new PolymorphicAccessStructureList(vm, owner, stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure.get(), stubInfo->u.getByIdChain.chain.get(), true); + stubInfo->stubRoutine.clear(); stubInfo->initGetByIdProtoList(prototypeStructureList, 2); break; - case op_get_by_id_proto_list: + case access_get_by_id_proto_list: prototypeStructureList = stubInfo->u.getByIdProtoList.structureList; listIndex = stubInfo->u.getByIdProtoList.listSize; - stubInfo->u.getByIdProtoList.listSize++; + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) + stubInfo->u.getByIdProtoList.listSize++; break; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } - ASSERT(listIndex < POLYMORPHIC_LIST_CACHE_SIZE); + ASSERT(listIndex <= POLYMORPHIC_LIST_CACHE_SIZE); return prototypeStructureList; } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) +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->methodTable()->getCallData(getter, callData); + JSValue result = call(callFrame, getter, callType, callData, stackFrame.args[1].jsObject(), ArgList()); + if (callFrame->hadException()) + returnToThrowTrampoline(&callFrame->vm(), 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->vm(), 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(); + CodeBlock* codeBlock = callFrame->codeBlock(); + StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); + AccessType accessType = static_cast(stubInfo->accessType); + JSValue baseValue = stackFrame.args[0].jsValue(); PropertySlot slot(baseValue); JSValue result = baseValue.get(callFrame, propertyName, slot); CHECK_FOR_EXCEPTION(); - if (!baseValue.isCell() || !slot.isCacheable() || asCell(baseValue)->structure()->isUncacheableDictionary()) { + if (accessType != static_cast(stubInfo->accessType) + || !baseValue.isCell() + || !slot.isCacheable() + || baseValue.asCell()->structure()->isDictionary() + || baseValue.asCell()->structure()->typeInfo().prohibitsPropertyCaching()) { ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); return JSValue::encode(result); } - Structure* structure = asCell(baseValue)->structure(); - CodeBlock* codeBlock = callFrame->codeBlock(); - StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); + Structure* structure = baseValue.asCell()->structure(); ASSERT(slot.slotBase().isObject()); JSObject* slotBaseObject = asObject(slot.slotBase()); - size_t offset = slot.cachedOffset(); + PropertyOffset offset = slot.cachedOffset(); if (slot.slotBase() == baseValue) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); - else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) { + else if (slot.slotBase() == baseValue.asCell()->structure()->prototypeForLookup(callFrame)) { + ASSERT(!baseValue.asCell()->structure()->isDictionary()); + + if (baseValue.asCell()->structure()->typeInfo().hasImpureGetOwnPropertySlot()) { + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); + return JSValue::encode(result); + } + // 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); + slotBaseObject->flattenDictionaryObject(callFrame->vm()); + offset = slotBaseObject->structure()->get(callFrame->vm(), propertyName); } int listIndex; - PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); - - JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), offset); + PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(callFrame->vm(), codeBlock->ownerExecutable(), stubInfo, listIndex); + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { + JIT::compileGetByIdProtoList(callFrame->scope()->vm(), 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)) { - StructureChain* protoChain = structure->prototypeChain(callFrame); - if (!protoChain->isCacheable()) { + if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); + } + } else { + size_t count = normalizePrototypeChainForChainAccess(callFrame, baseValue, slot.slotBase(), propertyName, offset); + if (count == InvalidPrototypeChain) { ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); return JSValue::encode(result); } + ASSERT(!baseValue.asCell()->structure()->isDictionary()); int listIndex; - PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); - JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, offset); + PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(callFrame->vm(), codeBlock->ownerExecutable(), stubInfo, listIndex); + + if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { + StructureChain* protoChain = structure->prototypeChain(callFrame); + JIT::compileGetByIdChainList(callFrame->scope()->vm(), 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)); + if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) + ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); + } + } return JSValue::encode(result); } @@ -1386,49 +2009,180 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_string_fail) return JSValue::encode(result); } -#endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) - -DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_check_has_instance) { 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, 0); - if (!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()) { - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal, vPCIndex, codeBlock); - VM_THROW_EXCEPTION(); + + if (baseVal.isObject()) { + JSObject* baseObject = asObject(baseVal); + ASSERT(!baseObject->structure()->typeInfo().implementsDefaultHasInstance()); + if (baseObject->structure()->typeInfo().implementsHasInstance()) { + bool result = baseObject->methodTable()->customHasInstance(baseObject, callFrame, value); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(jsBoolean(result)); + } } - ASSERT(typeInfo.type() != UnspecifiedType); - if (!typeInfo.overridesHasInstance()) { - if (!value.isObject()) - return JSValue::encode(jsBoolean(false)); + stackFrame.vm->exception = createInvalidParamError(callFrame, "instanceof", baseVal); + VM_THROW_EXCEPTION_AT_END(); + return JSValue::encode(JSValue()); +} + +#if ENABLE(DFG_JIT) +DEFINE_STUB_FUNCTION(void, optimize) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + CallFrame* callFrame = stackFrame.callFrame; + CodeBlock* codeBlock = callFrame->codeBlock(); + unsigned bytecodeIndex = stackFrame.args[0].int32(); + +#if ENABLE(JIT_VERBOSE_OSR) + dataLog( + *codeBlock, ": Entered optimize with bytecodeIndex = ", bytecodeIndex, + ", executeCounter = ", codeBlock->jitExecuteCounter(), + ", optimizationDelayCounter = ", codeBlock->reoptimizationRetryCounter(), + ", exitCounter = "); + if (codeBlock->hasOptimizedReplacement()) + dataLog(codeBlock->replacement()->osrExitCounter()); + else + dataLog("N/A"); + dataLog("\n"); +#endif + + if (!codeBlock->checkIfOptimizationThresholdReached()) { + codeBlock->updateAllPredictions(); +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("Choosing not to optimize ", *codeBlock, " yet.\n"); +#endif + return; + } - if (!proto.isObject()) { - throwError(callFrame, TypeError, "instanceof called on an object with an invalid prototype property."); - VM_THROW_EXCEPTION(); + if (codeBlock->hasOptimizedReplacement()) { +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("Considering OSR ", *codeBlock, " -> ", *codeBlock->replacement(), ".\n"); +#endif + // If we have an optimized replacement, then it must be the case that we entered + // cti_optimize from a loop. That's because is there's an optimized replacement, + // then all calls to this function will be relinked to the replacement and so + // the prologue OSR will never fire. + + // This is an interesting threshold check. Consider that a function OSR exits + // in the middle of a loop, while having a relatively low exit count. The exit + // will reset the execution counter to some target threshold, meaning that this + // code won't be reached until that loop heats up for >=1000 executions. But then + // we do a second check here, to see if we should either reoptimize, or just + // attempt OSR entry. Hence it might even be correct for + // shouldReoptimizeFromLoopNow() to always return true. But we make it do some + // additional checking anyway, to reduce the amount of recompilation thrashing. + if (codeBlock->replacement()->shouldReoptimizeFromLoopNow()) { +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("Triggering reoptimization of ", *codeBlock, "(", *codeBlock->replacement(), ") (in loop).\n"); +#endif + codeBlock->reoptimize(); + return; + } + } else { + if (!codeBlock->shouldOptimizeNow()) { +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("Delaying optimization for ", *codeBlock, " (in loop) because of insufficient profiling.\n"); +#endif + return; + } + +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("Triggering optimized compilation of ", *codeBlock, "\n"); +#endif + + JSScope* scope = callFrame->scope(); + JSObject* error = codeBlock->compileOptimized(callFrame, scope, bytecodeIndex); +#if ENABLE(JIT_VERBOSE_OSR) + if (error) + dataLog("WARNING: optimized compilation failed.\n"); +#else + UNUSED_PARAM(error); +#endif + + if (codeBlock->replacement() == codeBlock) { +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("Optimizing ", *codeBlock, " failed.\n"); +#endif + + ASSERT(codeBlock->getJITType() == JITCode::BaselineJIT); + codeBlock->dontOptimizeAnytimeSoon(); + return; } } + + CodeBlock* optimizedCodeBlock = codeBlock->replacement(); + ASSERT(optimizedCodeBlock->getJITType() == JITCode::DFGJIT); + + if (void* address = DFG::prepareOSREntry(callFrame, optimizedCodeBlock, bytecodeIndex)) { + if (Options::showDFGDisassembly()) { + dataLog( + "Performing OSR ", *codeBlock, " -> ", *optimizedCodeBlock, ", address ", + RawPointer((STUB_RETURN_ADDRESS).value()), " -> ", RawPointer(address), ".\n"); + } +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("Optimizing ", *codeBlock, " succeeded, performing OSR after a delay of ", codeBlock->optimizationDelayCounter(), ".\n"); +#endif - JSValue result = jsBoolean(asObject(baseVal)->hasInstance(callFrame, value, proto)); - CHECK_FOR_EXCEPTION_AT_END(); + codeBlock->optimizeSoon(); + STUB_SET_RETURN_ADDRESS(address); + return; + } + +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("Optimizing ", *codeBlock, " succeeded, OSR failed, after a delay of ", codeBlock->optimizationDelayCounter(), ".\n"); +#endif - return JSValue::encode(result); + // Count the OSR failure as a speculation failure. If this happens a lot, then + // reoptimize. + optimizedCodeBlock->countOSRExit(); + +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("Encountered OSR failure ", *codeBlock, " -> ", *codeBlock->replacement(), ".\n"); +#endif + + // We are a lot more conservative about triggering reoptimization after OSR failure than + // before it. If we enter the optimize_from_loop trigger with a bucket full of fail + // already, then we really would like to reoptimize immediately. But this case covers + // something else: there weren't many (or any) speculation failures before, but we just + // failed to enter the speculative code because some variable had the wrong value or + // because the OSR code decided for any spurious reason that it did not want to OSR + // right now. So, we only trigger reoptimization only upon the more conservative (non-loop) + // reoptimization trigger. + if (optimizedCodeBlock->shouldReoptimizeNow()) { +#if ENABLE(JIT_VERBOSE_OSR) + dataLog("Triggering reoptimization of ", *codeBlock, " -> ", *codeBlock->replacement(), " (after OSR fail).\n"); +#endif + codeBlock->reoptimize(); + return; + } + + // OSR failed this time, but it might succeed next time! Let the code run a bit + // longer and then try again. + codeBlock->optimizeAfterWarmUp(); +} +#endif // ENABLE(DFG_JIT) + +DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + CallFrame* callFrame = stackFrame.callFrame; + JSValue value = stackFrame.args[0].jsValue(); + JSValue proto = stackFrame.args[1].jsValue(); + + ASSERT(!value.isObject() || !proto.isObject()); + + bool result = JSObject::defaultHasInstance(callFrame, value, proto); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(jsBoolean(result)); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_id) @@ -1439,7 +2193,11 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_id) JSObject* baseObj = stackFrame.args[0].jsValue().toObject(callFrame); - JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, stackFrame.args[1].identifier())); + bool couldDelete = baseObj->methodTable()->deleteProperty(baseObj, callFrame, stackFrame.args[1].identifier()); + JSValue result = jsBoolean(couldDelete); + if (!couldDelete && callFrame->codeBlock()->isStrictMode()) + stackFrame.vm->exception = createTypeError(stackFrame.callFrame, "Unable to delete property."); + CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -1451,13 +2209,11 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_mul) 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(stackFrame.globalData, left * right)); + if (src1.isNumber() && src2.isNumber()) + return JSValue::encode(jsNumber(src1.asNumber() * src2.asNumber())); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) * src2.toNumber(callFrame)); + JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -1465,113 +2221,244 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_mul) DEFINE_STUB_FUNCTION(JSObject*, op_new_func) { STUB_INIT_STACK_FRAME(stackFrame); - - return stackFrame.args[0].funcDeclNode()->makeFunction(stackFrame.callFrame, stackFrame.callFrame->scopeChain()); + + ASSERT(stackFrame.callFrame->codeBlock()->codeType() != FunctionCode || !stackFrame.callFrame->codeBlock()->needsFullScopeChain() || stackFrame.callFrame->uncheckedR(stackFrame.callFrame->codeBlock()->activationRegister()).jsValue()); + return JSFunction::create(stackFrame.callFrame, stackFrame.args[0].function(), stackFrame.callFrame->scope()); +} + +inline void* jitCompileFor(CallFrame* callFrame, CodeSpecializationKind kind) +{ + // This function is called by cti_op_call_jitCompile() and + // cti_op_construct_jitCompile() JIT glue trampolines to compile the + // callee function that we want to call. Both cti glue trampolines are + // called by JIT'ed code which has pushed a frame and initialized most of + // the frame content except for the codeBlock. + // + // Normally, the prologue of the callee is supposed to set the frame's cb + // pointer to the cb of the callee. But in this case, the callee code does + // not exist yet until it is compiled below. The compilation process will + // allocate memory which may trigger a GC. The GC, in turn, will scan the + // JSStack, and will expect the frame's cb to either be valid or 0. If + // we don't initialize it, the GC will be accessing invalid memory and may + // crash. + // + // Hence, we should nullify it here before proceeding with the compilation. + callFrame->setCodeBlock(0); + + JSFunction* function = jsCast(callFrame->callee()); + ASSERT(!function->isHostFunction()); + FunctionExecutable* executable = function->jsExecutable(); + JSScope* callDataScopeChain = function->scope(); + JSObject* error = executable->compileFor(callFrame, callDataScopeChain, kind); + if (!error) + return function; + callFrame->vm().exception = error; + return 0; } -DEFINE_STUB_FUNCTION(void*, op_call_JSFunction) +DEFINE_STUB_FUNCTION(void*, op_call_jitCompile) { STUB_INIT_STACK_FRAME(stackFrame); -#ifndef NDEBUG +#if !ASSERT_DISABLED CallData callData; - ASSERT(stackFrame.args[0].jsValue().getCallData(callData) == CallTypeJS); + ASSERT(stackFrame.callFrame->callee()->methodTable()->getCallData(stackFrame.callFrame->callee(), callData) == CallTypeJS); #endif + + CallFrame* callFrame = stackFrame.callFrame; + void* result = jitCompileFor(callFrame, CodeForCall); + if (!result) + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS); - JSFunction* function = asFunction(stackFrame.args[0].jsValue()); - ASSERT(!function->isHostFunction()); - FunctionBodyNode* body = function->body(); - ScopeChainNode* callDataScopeChain = function->scope().node(); - body->jitCode(callDataScopeChain); + return result; +} + +DEFINE_STUB_FUNCTION(void*, op_construct_jitCompile) +{ + STUB_INIT_STACK_FRAME(stackFrame); - return &(body->generatedBytecode()); +#if !ASSERT_DISABLED + ConstructData constructData; + ASSERT(jsCast(stackFrame.callFrame->callee())->methodTable()->getConstructData(stackFrame.callFrame->callee(), constructData) == ConstructTypeJS); +#endif + + CallFrame* callFrame = stackFrame.callFrame; + void* result = jitCompileFor(callFrame, CodeForConstruct); + if (!result) + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS); + + return result; } -DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck) +DEFINE_STUB_FUNCTION(void*, op_call_arityCheck) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* newCodeBlock = stackFrame.args[3].codeBlock(); - ASSERT(newCodeBlock->codeType() != NativeCode); - int argCount = stackFrame.args[2].int32(); - ASSERT(argCount != newCodeBlock->m_numParameters); + CallFrame* newCallFrame = CommonSlowPaths::arityCheckFor(callFrame, stackFrame.stack, CodeForCall); + if (!newCallFrame) + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS, createStackOverflowError(callFrame->callerFrame())); - CallFrame* oldCallFrame = callFrame->callerFrame(); + return newCallFrame; +} - if (argCount > newCodeBlock->m_numParameters) { - size_t numParameters = newCodeBlock->m_numParameters; - Register* r = callFrame->registers() + numParameters; +DEFINE_STUB_FUNCTION(void*, op_construct_arityCheck) +{ + STUB_INIT_STACK_FRAME(stackFrame); - Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount; - for (size_t i = 0; i < numParameters; ++i) - argv[i + argCount] = argv[i]; + CallFrame* callFrame = stackFrame.callFrame; - callFrame = CallFrame::create(r); - callFrame->setCallerFrame(oldCallFrame); - } else { - size_t omittedArgCount = newCodeBlock->m_numParameters - argCount; - Register* r = callFrame->registers() + omittedArgCount; - Register* newEnd = r + newCodeBlock->m_numCalleeRegisters; - if (!stackFrame.registerFile->grow(newEnd)) { - // Rewind to the previous call frame because op_call already optimistically - // moved the call frame forward. - stackFrame.callFrame = oldCallFrame; - throwStackOverflowError(oldCallFrame, stackFrame.globalData, stackFrame.args[1].returnAddress(), STUB_RETURN_ADDRESS); - RETURN_POINTER_PAIR(0, 0); - } + CallFrame* newCallFrame = CommonSlowPaths::arityCheckFor(callFrame, stackFrame.stack, CodeForConstruct); + if (!newCallFrame) + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS, createStackOverflowError(callFrame->callerFrame())); - Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount; - for (size_t i = 0; i < omittedArgCount; ++i) - argv[i] = jsUndefined(); + return newCallFrame; +} - callFrame = CallFrame::create(r); - callFrame->setCallerFrame(oldCallFrame); +inline void* lazyLinkFor(CallFrame* callFrame, CodeSpecializationKind kind) +{ + JSFunction* callee = jsCast(callFrame->callee()); + ExecutableBase* executable = callee->executable(); + + MacroAssemblerCodePtr codePtr; + CodeBlock* codeBlock = 0; + CallLinkInfo* callLinkInfo = &callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC()); + + // This function is called by cti_vm_lazyLinkCall() and + // cti_lazyLinkConstruct JIT glue trampolines to link the callee function + // that we want to call. Both cti glue trampolines are called by JIT'ed + // code which has pushed a frame and initialized most of the frame content + // except for the codeBlock. + // + // Normally, the prologue of the callee is supposed to set the frame's cb + // field to the cb of the callee. But in this case, the callee may not + // exist yet, and if not, it will be generated in the compilation below. + // The compilation will allocate memory which may trigger a GC. The GC, in + // turn, will scan the JSStack, and will expect the frame's cb to be valid + // or 0. If we don't initialize it, the GC will be accessing invalid + // memory and may crash. + // + // Hence, we should nullify it here before proceeding with the compilation. + callFrame->setCodeBlock(0); + + if (executable->isHostFunction()) + codePtr = executable->generatedJITCodeFor(kind).addressForCall(); + else { + FunctionExecutable* functionExecutable = static_cast(executable); + if (JSObject* error = functionExecutable->compileFor(callFrame, callee->scope(), kind)) { + callFrame->vm().exception = error; + return 0; + } + codeBlock = &functionExecutable->generatedBytecodeFor(kind); + if (callFrame->argumentCountIncludingThis() < static_cast(codeBlock->numParameters()) + || callLinkInfo->callType == CallLinkInfo::CallVarargs) + codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind); + else + codePtr = functionExecutable->generatedJITCodeFor(kind).addressForCall(); } - RETURN_POINTER_PAIR(newCodeBlock, callFrame); + if (!callLinkInfo->seenOnce()) + callLinkInfo->setSeen(); + else + JIT::linkFor(callee, callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, &callFrame->vm(), kind); + + return codePtr.executableAddress(); } -#if ENABLE(JIT_OPTIMIZE_CALL) -DEFINE_STUB_FUNCTION(void*, vm_dontLazyLinkCall) +DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall) { STUB_INIT_STACK_FRAME(stackFrame); - JSGlobalData* globalData = stackFrame.globalData; - JSFunction* callee = asFunction(stackFrame.args[0].jsValue()); - - ctiPatchNearCallByReturnAddress(stackFrame.callFrame->callerFrame()->codeBlock(), stackFrame.args[1].returnAddress(), globalData->jitStubs.ctiVirtualCallLink()); + CallFrame* callFrame = stackFrame.callFrame; + void* result = lazyLinkFor(callFrame, CodeForCall); + if (!result) + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS); - return callee->body()->generatedJITCode().addressForCall().executableAddress(); + return result; } -DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall) +DEFINE_STUB_FUNCTION(void*, vm_lazyLinkClosureCall) { STUB_INIT_STACK_FRAME(stackFrame); - JSFunction* callee = asFunction(stackFrame.args[0].jsValue()); - JITCode& jitCode = callee->body()->generatedJITCode(); + CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = 0; - if (!callee->isHostFunction()) - codeBlock = &callee->body()->bytecode(callee->scope().node()); - else - codeBlock = &callee->body()->generatedBytecode(); + CodeBlock* callerCodeBlock = callFrame->callerFrame()->codeBlock(); + VM* vm = callerCodeBlock->vm(); + CallLinkInfo* callLinkInfo = &callerCodeBlock->getCallLinkInfo(callFrame->returnPC()); + JSFunction* callee = jsCast(callFrame->callee()); + ExecutableBase* executable = callee->executable(); + Structure* structure = callee->structure(); + + ASSERT(callLinkInfo->callType == CallLinkInfo::Call); + ASSERT(callLinkInfo->isLinked()); + ASSERT(callLinkInfo->callee); + ASSERT(callee != callLinkInfo->callee.get()); + + bool shouldLink = false; + CodeBlock* calleeCodeBlock = 0; + MacroAssemblerCodePtr codePtr; + + if (executable == callLinkInfo->callee.get()->executable() + && structure == callLinkInfo->callee.get()->structure()) { + + shouldLink = true; + + ASSERT(executable->hasJITCodeForCall()); + codePtr = executable->generatedJITCodeForCall().addressForCall(); + if (!callee->executable()->isHostFunction()) { + calleeCodeBlock = &jsCast(executable)->generatedBytecodeForCall(); + if (callFrame->argumentCountIncludingThis() < static_cast(calleeCodeBlock->numParameters())) { + shouldLink = false; + codePtr = executable->generatedJITCodeWithArityCheckFor(CodeForCall); + } + } + } else if (callee->isHostFunction()) + codePtr = executable->generatedJITCodeForCall().addressForCall(); + else { + // Need to clear the code block before compilation, because compilation can GC. + callFrame->setCodeBlock(0); + + FunctionExecutable* functionExecutable = jsCast(executable); + JSScope* scopeChain = callee->scope(); + JSObject* error = functionExecutable->compileFor(callFrame, scopeChain, CodeForCall); + if (error) { + callFrame->vm().exception = error; + return 0; + } + + codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(CodeForCall); + } + + if (shouldLink) { + ASSERT(codePtr); + JIT::compileClosureCall(vm, callLinkInfo, callerCodeBlock, calleeCodeBlock, structure, executable, codePtr); + callLinkInfo->hasSeenClosure = true; + } else + JIT::linkSlowCall(callerCodeBlock, callLinkInfo); + + return codePtr.executableAddress(); +} - CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(stackFrame.args[1].returnAddress()); - JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, jitCode, callLinkInfo, stackFrame.args[2].int32(), stackFrame.globalData); +DEFINE_STUB_FUNCTION(void*, vm_lazyLinkConstruct) +{ + STUB_INIT_STACK_FRAME(stackFrame); - return jitCode.addressForCall().executableAddress(); + CallFrame* callFrame = stackFrame.callFrame; + void* result = lazyLinkFor(callFrame, CodeForConstruct); + if (!result) + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS); + + return result; } -#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()->ownerNode())); - stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->copy()->push(activation)); + JSActivation* activation = JSActivation::create(stackFrame.callFrame->vm(), stackFrame.callFrame, stackFrame.callFrame->codeBlock()); + stackFrame.callFrame->setScope(activation); return activation; } @@ -1579,67 +2466,37 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction) { STUB_INIT_STACK_FRAME(stackFrame); - JSValue funcVal = stackFrame.args[0].jsValue(); + CallFrame* callFrame = stackFrame.callFrame; + + JSValue callee = callFrame->calleeAsValue(); CallData callData; - CallType callType = funcVal.getCallData(callData); + CallType callType = getCallData(callee, 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); - - callFrame->init(0, static_cast((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, 0, argCount, 0); - stackFrame.callFrame = callFrame; - - Register* argv = stackFrame.callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount; - ArgList argList(argv + 1, argCount - 1); - - JSValue returnValue; - { - SamplingTool::HostCallRecord callRecord(CTI_SAMPLER); - - // FIXME: All host methods should be calling toThisObject, but this is not presently the case. - JSValue thisValue = argv[0].jsValue(); - if (thisValue == jsNull()) - thisValue = callFrame->globalThisValue(); - - returnValue = callData.native.function(callFrame, asObject(funcVal), thisValue, argList); - } - stackFrame.callFrame = previousCallFrame; - CHECK_FOR_EXCEPTION(); - - return JSValue::encode(returnValue); + if (callType != CallTypeHost) { + ASSERT(callType == CallTypeNone); + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS, createNotAFunctionError(callFrame->callerFrame(), callee)); } - ASSERT(callType == CallTypeNone); - - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal, vPCIndex, codeBlock); - VM_THROW_EXCEPTION(); -} + EncodedJSValue returnValue; + { + SamplingTool::CallRecord callRecord(CTI_SAMPLER, true); + returnValue = callData.native.function(callFrame); + } -DEFINE_STUB_FUNCTION(void, op_create_arguments) -{ - STUB_INIT_STACK_FRAME(stackFrame); + if (stackFrame.vm->exception) + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS); - Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame); - stackFrame.callFrame->setCalleeArguments(arguments); - stackFrame.callFrame[RegisterFile::ArgumentsRegister] = JSValue(arguments); + return returnValue; } -DEFINE_STUB_FUNCTION(void, op_create_arguments_no_params) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments) { STUB_INIT_STACK_FRAME(stackFrame); - Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame, Arguments::NoParameters); - stackFrame.callFrame->setCalleeArguments(arguments); - stackFrame.callFrame[RegisterFile::ArgumentsRegister] = JSValue(arguments); + Arguments* arguments = Arguments::create(*stackFrame.vm, stackFrame.callFrame); + return JSValue::encode(JSValue(arguments)); } DEFINE_STUB_FUNCTION(void, op_tear_off_activation) @@ -1647,102 +2504,89 @@ DEFINE_STUB_FUNCTION(void, op_tear_off_activation) STUB_INIT_STACK_FRAME(stackFrame); ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain()); - asActivation(stackFrame.args[0].jsValue())->copyRegisters(stackFrame.callFrame->optionalCalleeArguments()); + jsCast(stackFrame.args[0].jsValue())->tearOff(*stackFrame.vm); } DEFINE_STUB_FUNCTION(void, op_tear_off_arguments) { STUB_INIT_STACK_FRAME(stackFrame); - ASSERT(stackFrame.callFrame->codeBlock()->usesArguments() && !stackFrame.callFrame->codeBlock()->needsFullScopeChain()); - if (stackFrame.callFrame->optionalCalleeArguments()) - stackFrame.callFrame->optionalCalleeArguments()->copyRegisters(); + CallFrame* callFrame = stackFrame.callFrame; + ASSERT(callFrame->codeBlock()->usesArguments()); + Arguments* arguments = jsCast(stackFrame.args[0].jsValue()); + if (JSValue activationValue = stackFrame.args[1].jsValue()) { + arguments->didTearOffActivation(callFrame, jsCast(activationValue)); + return; + } + arguments->tearOff(callFrame); } 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()); + if (LegacyProfiler* profiler = stackFrame.vm->enabledProfiler()) + profiler->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()); + if (LegacyProfiler* profiler = stackFrame.vm->enabledProfiler()) + profiler->didExecute(stackFrame.callFrame, stackFrame.args[0].jsValue()); } -DEFINE_STUB_FUNCTION(void, op_ret_scopeChain) +DEFINE_STUB_FUNCTION(JSObject*, op_new_array) { STUB_INIT_STACK_FRAME(stackFrame); - ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain()); - stackFrame.callFrame->scopeChain()->deref(); + return constructArray(stackFrame.callFrame, stackFrame.args[2].arrayAllocationProfile(), reinterpret_cast(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()]), stackFrame.args[1].int32()); } -DEFINE_STUB_FUNCTION(JSObject*, op_new_array) +DEFINE_STUB_FUNCTION(JSObject*, op_new_array_with_size) { STUB_INIT_STACK_FRAME(stackFrame); - - ArgList argList(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32()); - return constructArray(stackFrame.callFrame, argList); + + return constructArrayWithSizeQuirk(stackFrame.callFrame, stackFrame.args[1].arrayAllocationProfile(), stackFrame.callFrame->lexicalGlobalObject(), stackFrame.args[0].jsValue()); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve) +DEFINE_STUB_FUNCTION(JSObject*, op_new_array_buffer) { STUB_INIT_STACK_FRAME(stackFrame); + + return constructArray(stackFrame.callFrame, stackFrame.args[2].arrayAllocationProfile(), stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32()); +} +DEFINE_STUB_FUNCTION(void, op_init_global_const_check) +{ + 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); - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock); - VM_THROW_EXCEPTION(); + symbolTablePut(codeBlock->globalObject(), callFrame, codeBlock->identifier(stackFrame.args[1].int32()), stackFrame.args[0].jsValue(), true); } -DEFINE_STUB_FUNCTION(JSObject*, op_construct_JSConstruct) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve) { STUB_INIT_STACK_FRAME(stackFrame); - JSFunction* constructor = asFunction(stackFrame.args[0].jsValue()); - if (constructor->isHostFunction()) { - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createNotAConstructorError(callFrame, constructor, vPCIndex, codeBlock); - VM_THROW_EXCEPTION(); - } + CallFrame* callFrame = stackFrame.callFrame; -#ifndef NDEBUG - ConstructData constructData; - ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS); -#endif + JSValue result = JSScope::resolve(callFrame, stackFrame.args[0].identifier(), stackFrame.args[1].resolveOperations()); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(result); +} - Structure* structure; - if (stackFrame.args[3].jsValue().isObject()) - structure = asObject(stackFrame.args[3].jsValue())->inheritorID(); - else - structure = constructor->scope().node()->globalObject()->emptyObjectStructure(); - return new (stackFrame.globalData) JSObject(structure); +DEFINE_STUB_FUNCTION(void, op_put_to_base) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + CallFrame* callFrame = stackFrame.callFrame; + JSValue base = callFrame->r(stackFrame.args[0].int32()).jsValue(); + JSValue value = callFrame->r(stackFrame.args[2].int32()).jsValue(); + JSScope::resolvePut(callFrame, base, stackFrame.args[1].identifier(), value, stackFrame.args[3].putToBaseOperation()); + CHECK_FOR_EXCEPTION_AT_END(); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct) @@ -1750,33 +2594,51 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct) STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - - JSValue constrVal = stackFrame.args[0].jsValue(); - int argCount = stackFrame.args[2].int32(); - int thisRegister = stackFrame.args[4].int32(); + JSValue callee = callFrame->calleeAsValue(); ConstructData constructData; - ConstructType constructType = constrVal.getConstructData(constructData); + ConstructType constructType = getConstructData(callee, constructData); - if (constructType == ConstructTypeHost) { - ArgList argList(callFrame->registers() + thisRegister + 1, argCount - 1); + ASSERT(constructType != ConstructTypeJS); + if (constructType != ConstructTypeHost) { + ASSERT(constructType == ConstructTypeNone); + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS, createNotAConstructorError(callFrame->callerFrame(), callee)); + } - JSValue returnValue; - { - SamplingTool::HostCallRecord callRecord(CTI_SAMPLER); - returnValue = constructData.native.function(callFrame, asObject(constrVal), argList); - } - CHECK_FOR_EXCEPTION(); + EncodedJSValue returnValue; + { + SamplingTool::CallRecord callRecord(CTI_SAMPLER, true); + returnValue = constructData.native.function(callFrame); + } + + if (stackFrame.vm->exception) + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS); + + return returnValue; +} - return JSValue::encode(returnValue); +static JSValue getByVal( + CallFrame* callFrame, JSValue baseValue, JSValue subscript, ReturnAddressPtr returnAddress) +{ + if (LIKELY(baseValue.isCell() && subscript.isString())) { + if (JSValue result = baseValue.asCell()->fastGetOwnProperty(callFrame, asString(subscript)->value(callFrame))) + return result; } - ASSERT(constructType == ConstructTypeNone); + if (subscript.isUInt32()) { + uint32_t i = subscript.asUInt32(); + if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i)) { + ctiPatchCallByReturnAddress(callFrame->codeBlock(), returnAddress, FunctionPtr(cti_op_get_by_val_string)); + return asString(baseValue)->getIndex(callFrame, i); + } + return baseValue.get(callFrame, i); + } - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createNotAConstructorError(callFrame, constrVal, vPCIndex, codeBlock); - VM_THROW_EXCEPTION(); + if (isName(subscript)) + return baseValue.get(callFrame, jsCast(subscript.asCell())->privateName()); + + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); + return baseValue.get(callFrame, property); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val) @@ -1784,101 +2646,94 @@ 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(); - - JSValue result; - - if (LIKELY(subscript.isUInt32())) { - uint32_t i = subscript.asUInt32(); - if (isJSArray(globalData, baseValue)) { - JSArray* jsArray = asArray(baseValue); - if (jsArray->canGetIndex(i)) - result = jsArray->getIndex(i); - else - result = jsArray->JSArray::get(callFrame, i); - } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) { - // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. - ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_string)); - result = asString(baseValue)->getIndex(stackFrame.globalData, i); - } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { - // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. - ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_byte_array)); - return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i)); - } else - result = baseValue.get(callFrame, i); - } else { - Identifier property(callFrame, subscript.toString(callFrame)); - result = baseValue.get(callFrame, property); + + if (baseValue.isObject() && subscript.isInt32()) { + // See if it's worth optimizing this at all. + JSObject* object = asObject(baseValue); + bool didOptimize = false; + + unsigned bytecodeOffset = callFrame->bytecodeOffsetForNonDFGCode(); + ASSERT(bytecodeOffset); + ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1); + ASSERT(!byValInfo.stubRoutine); + + if (hasOptimizableIndexing(object->structure())) { + // Attempt to optimize. + JITArrayMode arrayMode = jitArrayModeForStructure(object->structure()); + if (arrayMode != byValInfo.arrayMode) { + JIT::compileGetByVal(&callFrame->vm(), callFrame->codeBlock(), &byValInfo, STUB_RETURN_ADDRESS, arrayMode); + didOptimize = true; + } + } + + if (!didOptimize) { + // If we take slow path more than 10 times without patching then make sure we + // never make that mistake again. Or, if we failed to patch and we have some object + // that intercepts indexed get, then don't even wait until 10 times. For cases + // where we see non-index-intercepting objects, this gives 10 iterations worth of + // opportunity for us to observe that the get_by_val may be polymorphic. + if (++byValInfo.slowPathCount >= 10 + || object->structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { + // Don't ever try to optimize. + RepatchBuffer repatchBuffer(callFrame->codeBlock()); + repatchBuffer.relinkCallerToFunction(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_generic)); + } + } } - - CHECK_FOR_EXCEPTION_AT_END(); + + JSValue result = getByVal(callFrame, baseValue, subscript, STUB_RETURN_ADDRESS); + CHECK_FOR_EXCEPTION(); return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_string) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_generic) { 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(stackFrame.globalData, 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(); + JSValue result = getByVal(callFrame, baseValue, subscript, STUB_RETURN_ADDRESS); + CHECK_FOR_EXCEPTION(); return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_byte_array) +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 (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)); + if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i)) + result = asString(baseValue)->getIndex(callFrame, i); + else { + result = baseValue.get(callFrame, i); + if (!isJSString(baseValue)) + ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val)); } - - 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)); + } else if (isName(subscript)) + result = baseValue.get(callFrame, jsCast(subscript.asCell())->privateName()); + else { + Identifier property(callFrame, subscript.toString(callFrame)->value(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); @@ -1886,128 +2741,111 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_sub) 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(stackFrame.globalData, left - right)); + if (src1.isNumber() && src2.isNumber()) + return JSValue::encode(jsNumber(src1.asNumber() - src2.asNumber())); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) - src2.toNumber(callFrame)); + JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } +static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value) +{ + if (LIKELY(subscript.isUInt32())) { + uint32_t i = subscript.asUInt32(); + if (baseValue.isObject()) { + JSObject* object = asObject(baseValue); + if (object->canSetIndexQuickly(i)) + object->setIndexQuickly(callFrame->vm(), i, value); + else + object->methodTable()->putByIndex(object, callFrame, i, value, callFrame->codeBlock()->isStrictMode()); + } else + baseValue.putByIndex(callFrame, i, value, callFrame->codeBlock()->isStrictMode()); + } else if (isName(subscript)) { + PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); + baseValue.put(callFrame, jsCast(subscript.asCell())->privateName(), value, slot); + } else { + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); + if (!callFrame->vm().exception) { // Don't put to an object if toString threw an exception. + PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); + baseValue.put(callFrame, property, value, slot); + } + } +} + 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; - } + + if (baseValue.isObject() && subscript.isInt32()) { + // See if it's worth optimizing at all. + JSObject* object = asObject(baseValue); + bool didOptimize = false; + + unsigned bytecodeOffset = callFrame->bytecodeOffsetForNonDFGCode(); + ASSERT(bytecodeOffset); + ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1); + ASSERT(!byValInfo.stubRoutine); + + if (hasOptimizableIndexing(object->structure())) { + // Attempt to optimize. + JITArrayMode arrayMode = jitArrayModeForStructure(object->structure()); + if (arrayMode != byValInfo.arrayMode) { + JIT::compilePutByVal(&callFrame->vm(), callFrame->codeBlock(), &byValInfo, STUB_RETURN_ADDRESS, arrayMode); + didOptimize = true; } + } - 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; - baseValue.put(callFrame, property, value, slot); + if (!didOptimize) { + // If we take slow path more than 10 times without patching then make sure we + // never make that mistake again. Or, if we failed to patch and we have some object + // that intercepts indexed get, then don't even wait until 10 times. For cases + // where we see non-index-intercepting objects, this gives 10 iterations worth of + // opportunity for us to observe that the get_by_val may be polymorphic. + if (++byValInfo.slowPathCount >= 10 + || object->structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) { + // Don't ever try to optimize. + RepatchBuffer repatchBuffer(callFrame->codeBlock()); + repatchBuffer.relinkCallerToFunction(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val_generic)); + } } } + + putByVal(callFrame, baseValue, subscript, value); CHECK_FOR_EXCEPTION_AT_END(); } -DEFINE_STUB_FUNCTION(void, op_put_by_val_array) +DEFINE_STUB_FUNCTION(void, op_put_by_val_generic) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - JSValue baseValue = stackFrame.args[0].jsValue(); - int i = stackFrame.args[1].int32(); - JSValue value = stackFrame.args[2].jsValue(); - - ASSERT(isJSArray(stackFrame.globalData, baseValue)); - if (LIKELY(i >= 0)) - asArray(baseValue)->JSArray::put(callFrame, i, value); - else { - Identifier property(callFrame, UString::from(i)); - PutPropertySlot slot; - baseValue.put(callFrame, property, value, slot); - } + JSValue baseValue = stackFrame.args[0].jsValue(); + JSValue subscript = stackFrame.args[1].jsValue(); + JSValue value = stackFrame.args[2].jsValue(); + + putByVal(callFrame, baseValue, subscript, value); CHECK_FOR_EXCEPTION_AT_END(); } -DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_less) { 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; - baseValue.put(callFrame, property, value, slot); - } - } - + 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_lesseq) @@ -2015,111 +2853,45 @@ 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())); + 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_loop_if_true) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_greater) { STUB_INIT_STACK_FRAME(stackFrame); - JSValue src1 = stackFrame.args[0].jsValue(); - CallFrame* callFrame = stackFrame.callFrame; + JSValue result = jsBoolean(jsLess(callFrame, stackFrame.args[1].jsValue(), stackFrame.args[0].jsValue())); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(result); +} + +DEFINE_STUB_FUNCTION(EncodedJSValue, op_greatereq) +{ + STUB_INIT_STACK_FRAME(stackFrame); - bool result = src1.toBoolean(callFrame); + CallFrame* callFrame = stackFrame.callFrame; + JSValue result = jsBoolean(jsLessEq(callFrame, stackFrame.args[1].jsValue(), stackFrame.args[0].jsValue())); CHECK_FOR_EXCEPTION_AT_END(); - return result; + return JSValue::encode(result); } - -DEFINE_STUB_FUNCTION(int, op_load_varargs) + +DEFINE_STUB_FUNCTION(void*, 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; - int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; - Register* newEnd = callFrame->registers() + sizeDelta; - if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { - stackFrame.globalData->exception = createStackOverflowError(callFrame); - VM_THROW_EXCEPTION(); - } - int32_t expectedParams = callFrame->callee()->body()->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()) { - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock); - VM_THROW_EXCEPTION(); - } - if (asObject(arguments)->classInfo() == &Arguments::info) { - Arguments* argsObject = asArguments(arguments); - argCount = argsObject->numProvidedArguments(callFrame); - 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(); - 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); - 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 { - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock); - VM_THROW_EXCEPTION(); - } - } + JSStack* stack = stackFrame.stack; + JSValue thisValue = stackFrame.args[0].jsValue(); + JSValue arguments = stackFrame.args[1].jsValue(); + int firstFreeRegister = stackFrame.args[2].int32(); - return argCount + 1; + CallFrame* newCallFrame = loadVarargs(callFrame, stack, thisValue, arguments, firstFreeRegister); + if (!newCallFrame) + VM_THROW_EXCEPTION(); + return newCallFrame; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_negate) @@ -2128,12 +2900,11 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_negate) JSValue src = stackFrame.args[0].jsValue(); - double v; - if (src.getNumber(v)) - return JSValue::encode(jsNumber(stackFrame.globalData, -v)); + if (src.isNumber()) + return JSValue::encode(jsNumber(-src.asNumber())); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, -src.toNumber(callFrame)); + JSValue result = jsNumber(-src.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2142,71 +2913,15 @@ 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())); -} - -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); - 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); - - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock); - VM_THROW_EXCEPTION(); + return JSValue::encode(JSScope::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), false, stackFrame.args[1].resolveOperations(), stackFrame.args[2].putToBaseOperation())); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base_strict_put) { STUB_INIT_STACK_FRAME(stackFrame); - CallFrame* callFrame = stackFrame.callFrame; - JSGlobalObject* globalObject = stackFrame.args[0].globalObject(); - Identifier& ident = stackFrame.args[1].identifier(); - unsigned globalResolveInfoIndex = stackFrame.args[2].int32(); - ASSERT(globalObject->isGlobalObject()); - - PropertySlot slot(globalObject); - if (globalObject->getPropertySlot(callFrame, ident, slot)) { - JSValue result = slot.getValue(callFrame, ident); - if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { - GlobalResolveInfo& globalResolveInfo = callFrame->codeBlock()->globalResolveInfo(globalResolveInfoIndex); - if (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(); + if (JSValue result = JSScope::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), true, stackFrame.args[1].resolveOperations(), stackFrame.args[2].putToBaseOperation())) return JSValue::encode(result); - } - - unsigned vPCIndex = callFrame->codeBlock()->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, callFrame->codeBlock()); VM_THROW_EXCEPTION(); } @@ -2217,25 +2932,23 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_div) 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(stackFrame.globalData, left / right)); + if (src1.isNumber() && src2.isNumber()) + return JSValue::encode(jsNumber(src1.asNumber() / src2.asNumber())); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) / src2.toNumber(callFrame)); + JSValue result = jsNumber(src1.toNumber(callFrame) / src2.toNumber(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_dec) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_dec) { STUB_INIT_STACK_FRAME(stackFrame); JSValue v = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, v.toNumber(callFrame) - 1); + JSValue result = jsNumber(v.toNumber(callFrame) - 1); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2248,7 +2961,7 @@ DEFINE_STUB_FUNCTION(int, op_jless) JSValue src2 = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - bool result = jsLess(callFrame, src1, src2); + bool result = jsLess(callFrame, src1, src2); CHECK_FOR_EXCEPTION_AT_END(); return result; } @@ -2261,53 +2974,58 @@ DEFINE_STUB_FUNCTION(int, op_jlesseq) JSValue src2 = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - bool result = jsLessEq(callFrame, src1, src2); + bool result = jsLessEq(callFrame, src1, src2); CHECK_FOR_EXCEPTION_AT_END(); return result; } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_not) +DEFINE_STUB_FUNCTION(int, op_jgreater) { STUB_INIT_STACK_FRAME(stackFrame); - JSValue src = stackFrame.args[0].jsValue(); - + JSValue src1 = stackFrame.args[0].jsValue(); + JSValue src2 = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsBoolean(!src.toBoolean(callFrame)); + bool result = jsLess(callFrame, src2, src1); CHECK_FOR_EXCEPTION_AT_END(); - return JSValue::encode(result); + return result; } -DEFINE_STUB_FUNCTION(int, op_jtrue) +DEFINE_STUB_FUNCTION(int, op_jgreatereq) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src1 = stackFrame.args[0].jsValue(); - + JSValue src2 = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - bool result = src1.toBoolean(callFrame); + bool result = jsLessEq(callFrame, src2, src1); CHECK_FOR_EXCEPTION_AT_END(); return result; } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_inc) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_not) { STUB_INIT_STACK_FRAME(stackFrame); - JSValue v = stackFrame.args[0].jsValue(); - - CallFrame* callFrame = stackFrame.callFrame; + JSValue src = stackFrame.args[0].jsValue(); - JSValue number = v.toJSNumber(callFrame); + JSValue result = jsBoolean(!src.toBoolean(stackFrame.callFrame)); CHECK_FOR_EXCEPTION_AT_END(); - - callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(stackFrame.globalData, number.uncheckedGetNumber() + 1); - return JSValue::encode(number); + return JSValue::encode(result); } -#if USE(JSVALUE32_64) +DEFINE_STUB_FUNCTION(int, op_jtrue) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + JSValue src1 = stackFrame.args[0].jsValue(); + + bool result = src1.toBoolean(stackFrame.callFrame); + CHECK_FOR_EXCEPTION_AT_END(); + return result; +} DEFINE_STUB_FUNCTION(int, op_eq) { @@ -2316,17 +3034,18 @@ DEFINE_STUB_FUNCTION(int, op_eq) 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() && asCell(src1)->structure()->typeInfo().masqueradesAsUndefined()) || - src1.isUndefined(); + (src1.isCell() && src1.asCell()->structure()->masqueradesAsUndefined(stackFrame.callFrame->lexicalGlobalObject())) + || src1.isUndefined(); } if (src2.isNull()) { return src1.isUndefined() || - (src1.isCell() && asCell(src1)->structure()->typeInfo().masqueradesAsUndefined()) || - src1.isNull(); + (src1.isCell() && src1.asCell()->structure()->masqueradesAsUndefined(stackFrame.callFrame->lexicalGlobalObject())) + || src1.isNull(); } if (src1.isInt32()) { @@ -2362,49 +3081,53 @@ DEFINE_STUB_FUNCTION(int, op_eq) } if (src1.isUndefined()) - return src2.isCell() && asCell(src2)->structure()->typeInfo().masqueradesAsUndefined(); + return src2.isCell() && src2.asCell()->structure()->masqueradesAsUndefined(stackFrame.callFrame->lexicalGlobalObject()); if (src1.isNull()) - return src2.isCell() && asCell(src2)->structure()->typeInfo().masqueradesAsUndefined(); - - ASSERT(src1.isCell()); + return src2.isCell() && src2.asCell()->structure()->masqueradesAsUndefined(stackFrame.callFrame->lexicalGlobalObject()); - JSCell* cell1 = asCell(src1); + JSCell* cell1 = src1.asCell(); if (cell1->isString()) { if (src2.isInt32()) - return static_cast(cell1)->value().toDouble() == src2.asInt32(); + return jsToNumber(jsCast(cell1)->value(stackFrame.callFrame)) == src2.asInt32(); if (src2.isDouble()) - return static_cast(cell1)->value().toDouble() == src2.asDouble(); + return jsToNumber(jsCast(cell1)->value(stackFrame.callFrame)) == src2.asDouble(); if (src2.isTrue()) - return static_cast(cell1)->value().toDouble() == 1.0; + return jsToNumber(jsCast(cell1)->value(stackFrame.callFrame)) == 1.0; if (src2.isFalse()) - return static_cast(cell1)->value().toDouble() == 0.0; + return jsToNumber(jsCast(cell1)->value(stackFrame.callFrame)) == 0.0; - ASSERT(src2.isCell()); - JSCell* cell2 = asCell(src2); + JSCell* cell2 = src2.asCell(); if (cell2->isString()) - return static_cast(cell1)->value() == static_cast(cell2)->value(); + return jsCast(cell1)->value(stackFrame.callFrame) == jsCast(cell2)->value(stackFrame.callFrame); - ASSERT(cell2->isObject()); - src2 = static_cast(cell2)->toPrimitive(stackFrame.callFrame); + src2 = asObject(cell2)->toPrimitive(stackFrame.callFrame); CHECK_FOR_EXCEPTION(); goto start; } - ASSERT(cell1->isObject()); if (src2.isObject()) - return static_cast(cell1) == asObject(src2); - src1 = static_cast(cell1)->toPrimitive(stackFrame.callFrame); + 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(); @@ -2412,27 +3135,14 @@ DEFINE_STUB_FUNCTION(int, op_eq_strings) ASSERT(string1->isString()); ASSERT(string2->isString()); - return string1->value() == string2->value(); -} - -#else // USE(JSVALUE32_64) - -DEFINE_STUB_FUNCTION(int, op_eq) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - JSValue src1 = stackFrame.args[0].jsValue(); - JSValue src2 = stackFrame.args[1].jsValue(); - - CallFrame* callFrame = stackFrame.callFrame; - - bool result = JSValue::equalSlowCaseInline(callFrame, src1, src2); - CHECK_FOR_EXCEPTION_AT_END(); - return result; + return string1->value(stackFrame.callFrame) == string2->value(stackFrame.callFrame); +#else + UNUSED_PARAM(args); + RELEASE_ASSERT_NOT_REACHED(); + return 0; +#endif } -#endif // USE(JSVALUE32_64) - DEFINE_STUB_FUNCTION(EncodedJSValue, op_lshift) { STUB_INIT_STACK_FRAME(stackFrame); @@ -2441,7 +3151,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_lshift) JSValue shift = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f)); + JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2455,7 +3165,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitand) ASSERT(!src1.isInt32() || !src2.isInt32()); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) & src2.toInt32(callFrame)); + JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2468,66 +3178,42 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_rshift) JSValue shift = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); + JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitnot) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base) { STUB_INIT_STACK_FRAME(stackFrame); - JSValue src = stackFrame.args[0].jsValue(); - - ASSERT(!src.isInt32()); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, ~src.toInt32(callFrame)); + JSValue result = JSScope::resolveWithBase(callFrame, stackFrame.args[0].identifier(), &callFrame->registers()[stackFrame.args[1].int32()], stackFrame.args[2].resolveOperations(), stackFrame.args[3].putToBaseOperation()); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_this) { 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); - - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock); - VM_THROW_EXCEPTION_AT_END(); - return JSValue::encode(JSValue()); + JSValue result = JSScope::resolveWithThis(callFrame, stackFrame.args[0].identifier(), &callFrame->registers()[stackFrame.args[1].int32()], stackFrame.args[2].resolveOperations()); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(result); } DEFINE_STUB_FUNCTION(JSObject*, op_new_func_exp) { STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; - return stackFrame.args[0].funcExprNode()->makeFunction(stackFrame.callFrame, stackFrame.callFrame->scopeChain()); + FunctionExecutable* function = stackFrame.args[0].function(); + JSFunction* func = JSFunction::create(callFrame, function, callFrame->scope()); + ASSERT(callFrame->codeBlock()->codeType() != FunctionCode || !callFrame->codeBlock()->needsFullScopeChain() || callFrame->uncheckedR(callFrame->codeBlock()->activationRegister()).jsValue()); + + return func; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_mod) @@ -2539,36 +3225,11 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_mod) CallFrame* callFrame = stackFrame.callFrame; double d = dividendValue.toNumber(callFrame); - JSValue result = jsNumber(stackFrame.globalData, fmod(d, divisorValue.toNumber(callFrame))); - 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())); + JSValue result = jsNumber(fmod(d, divisorValue.toNumber(callFrame))); 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(stackFrame.globalData, number.uncheckedGetNumber() - 1); - return JSValue::encode(number); -} - DEFINE_STUB_FUNCTION(EncodedJSValue, op_urshift) { STUB_INIT_STACK_FRAME(stackFrame); @@ -2577,7 +3238,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_urshift) JSValue shift = stackFrame.args[1].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); + JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2591,7 +3252,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitxor) CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) ^ src2.toInt32(callFrame)); + JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2600,7 +3261,15 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_regexp) { STUB_INIT_STACK_FRAME(stackFrame); - return new (stackFrame.globalData) RegExpObject(stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), stackFrame.args[0].regExp()); + CallFrame* callFrame = stackFrame.callFrame; + + RegExp* regExp = stackFrame.args[0].regExp(); + if (!regExp->isValid()) { + stackFrame.vm->exception = createSyntaxError(callFrame, "Invalid flags supplied to RegExp constructor."); + VM_THROW_EXCEPTION(); + } + + return RegExpObject::create(*stackFrame.vm, stackFrame.callFrame->lexicalGlobalObject(), stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), regExp); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor) @@ -2612,7 +3281,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor) CallFrame* callFrame = stackFrame.callFrame; - JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) | src2.toInt32(callFrame)); + JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame)); CHECK_FOR_EXCEPTION_AT_END(); return JSValue::encode(result); } @@ -2622,92 +3291,71 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval) STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - RegisterFile* registerFile = stackFrame.registerFile; + CallFrame* callerFrame = callFrame->callerFrame(); + ASSERT(callFrame->callerFrame()->codeBlock()->codeType() != FunctionCode + || !callFrame->callerFrame()->codeBlock()->needsFullScopeChain() + || callFrame->callerFrame()->uncheckedR(callFrame->callerFrame()->codeBlock()->activationRegister()).jsValue()); - Interpreter* interpreter = stackFrame.globalData->interpreter; - - JSValue funcVal = stackFrame.args[0].jsValue(); - int registerOffset = stackFrame.args[1].int32(); - int argCount = stackFrame.args[2].int32(); + callFrame->setScope(callerFrame->scope()); + callFrame->setReturnPC(static_cast((STUB_RETURN_ADDRESS).value())); + callFrame->setCodeBlock(0); - Register* newCallFrame = callFrame->registers() + registerOffset; - Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount; - JSValue thisValue = argv[0].jsValue(); - JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject(); + if (!isHostFunction(callFrame->calleeAsValue(), globalFuncEval)) + return JSValue::encode(JSValue()); - if (thisValue == globalObject && funcVal == globalObject->evalFunction()) { - JSValue exceptionValue; - JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue); - if (UNLIKELY(exceptionValue)) { - stackFrame.globalData->exception = exceptionValue; - VM_THROW_EXCEPTION_AT_END(); - } - return JSValue::encode(result); - } + JSValue result = eval(callFrame); + if (stackFrame.vm->exception) + return throwExceptionFromOpCall(stackFrame, callFrame, STUB_RETURN_ADDRESS); - return JSValue::encode(JSValue()); + return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_throw) +DEFINE_STUB_FUNCTION(void*, op_throw) { STUB_INIT_STACK_FRAME(stackFrame); - - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - - JSValue exceptionValue = stackFrame.args[0].jsValue(); - ASSERT(exceptionValue); - - HandlerInfo* handler = stackFrame.globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex, true); - - if (!handler) { - *stackFrame.exception = exceptionValue; - STUB_SET_RETURN_ADDRESS(reinterpret_cast(ctiOpThrowNotCaught)); - return JSValue::encode(jsNull()); - } - - stackFrame.callFrame = callFrame; - void* catchRoutine = handler->nativeCode.executableAddress(); - ASSERT(catchRoutine); - STUB_SET_RETURN_ADDRESS(catchRoutine); - return JSValue::encode(exceptionValue); + ExceptionHandler handler = jitThrow(stackFrame.vm, 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); - return JSPropertyNameIterator::create(stackFrame.callFrame, stackFrame.args[0].jsValue()); + 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(EncodedJSValue, op_next_pname) +DEFINE_STUB_FUNCTION(int, has_property) { STUB_INIT_STACK_FRAME(stackFrame); - JSPropertyNameIterator* it = stackFrame.args[0].propertyNameIterator(); - JSValue temp = it->next(stackFrame.callFrame); - if (!temp) - it->invalidate(); - return JSValue::encode(temp); + 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) +DEFINE_STUB_FUNCTION(void, op_push_with_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; + CHECK_FOR_EXCEPTION_VOID(); + stackFrame.callFrame->setScope(JSWithScope::create(stackFrame.callFrame, o)); } DEFINE_STUB_FUNCTION(void, op_pop_scope) { STUB_INIT_STACK_FRAME(stackFrame); - stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->pop()); + stackFrame.callFrame->setScope(stackFrame.callFrame->scope()->next()); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_typeof) @@ -2717,40 +3365,11 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_typeof) 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()))); + return JSValue::encode(jsBoolean(jsIsObjectType(stackFrame.callFrame, stackFrame.args[0].jsValue()))); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_function) @@ -2766,8 +3385,10 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_stricteq) JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); - - return JSValue::encode(jsBoolean(JSValue::strictEqual(src1, src2))); + + bool result = JSValue::strictEqual(stackFrame.callFrame, src1, src2); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(jsBoolean(result)); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_primitive) @@ -2781,7 +3402,9 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_strcat) { STUB_INIT_STACK_FRAME(stackFrame); - return JSValue::encode(concatenateStrings(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32())); + 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) @@ -2791,19 +3414,21 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_nstricteq) JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); - return JSValue::encode(jsBoolean(!JSValue::strictEqual(src1, src2))); + bool result = !JSValue::strictEqual(stackFrame.callFrame, src1, src2); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(jsBoolean(result)); } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_jsnumber) +DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_number) { STUB_INIT_STACK_FRAME(stackFrame); JSValue src = stackFrame.args[0].jsValue(); CallFrame* callFrame = stackFrame.callFrame; - JSValue result = src.toJSNumber(callFrame); + double number = src.toNumber(callFrame); CHECK_FOR_EXCEPTION_AT_END(); - return JSValue::encode(result); + return JSValue::encode(jsNumber(number)); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_in) @@ -2814,10 +3439,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_in) JSValue baseVal = stackFrame.args[1].jsValue(); if (!baseVal.isObject()) { - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS); - stackFrame.globalData->exception = createInvalidParamError(callFrame, "in", baseVal, vPCIndex, codeBlock); + stackFrame.vm->exception = createInvalidParamError(stackFrame.callFrame, "in", baseVal); VM_THROW_EXCEPTION(); } @@ -2828,33 +3450,22 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_in) if (propName.getUInt32(i)) return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, i))); - Identifier property(callFrame, propName.toString(callFrame)); + if (isName(propName)) + return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, jsCast(propName.asCell())->privateName()))); + + Identifier property(callFrame, propName.toString(callFrame)->value(callFrame)); CHECK_FOR_EXCEPTION(); return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, property))); } -DEFINE_STUB_FUNCTION(JSObject*, op_push_new_scope) +DEFINE_STUB_FUNCTION(void, op_push_name_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); + JSNameScope* scope = JSNameScope::create(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.args[1].jsValue(), stackFrame.args[2].int32()); - unsigned count = stackFrame.args[0].int32(); CallFrame* callFrame = stackFrame.callFrame; - - ScopeChainNode* tmp = callFrame->scopeChain(); - while (count--) - tmp = tmp->pop(); - callFrame->setScopeChain(tmp); + callFrame->setScope(scope); } DEFINE_STUB_FUNCTION(void, op_put_by_index) @@ -2864,7 +3475,9 @@ DEFINE_STUB_FUNCTION(void, op_put_by_index) CallFrame* callFrame = stackFrame.callFrame; unsigned property = stackFrame.args[1].int32(); - stackFrame.args[0].jsValue().put(callFrame, property, stackFrame.args[2].jsValue()); + JSValue arrayValue = stackFrame.args[0].jsValue(); + ASSERT(isJSArray(arrayValue)); + asArray(arrayValue)->putDirectIndex(callFrame, property, stackFrame.args[2].jsValue()); } DEFINE_STUB_FUNCTION(void*, op_switch_imm) @@ -2878,14 +3491,9 @@ DEFINE_STUB_FUNCTION(void*, op_switch_imm) 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(); - } + if (scrutinee.isDouble() && scrutinee.asDouble() == static_cast(scrutinee.asDouble())) + return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(static_cast(scrutinee.asDouble())).executableAddress(); + return codeBlock->immediateSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); } DEFINE_STUB_FUNCTION(void*, op_switch_char) @@ -2900,11 +3508,12 @@ DEFINE_STUB_FUNCTION(void*, op_switch_char) void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); if (scrutinee.isString()) { - UString::Rep* value = asString(scrutinee)->value().rep(); - if (value->size() == 1) - result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->data()[0]).executableAddress(); + StringImpl* value = asString(scrutinee)->value(callFrame).impl(); + if (value->length() == 1) + result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue((*value)[0]).executableAddress(); } + CHECK_FOR_EXCEPTION_AT_END(); return result; } @@ -2920,10 +3529,11 @@ DEFINE_STUB_FUNCTION(void*, op_switch_string) void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); if (scrutinee.isString()) { - UString::Rep* value = asString(scrutinee)->value().rep(); + StringImpl* value = asString(scrutinee)->value(callFrame).impl(); result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).executableAddress(); } + CHECK_FOR_EXCEPTION_AT_END(); return result; } @@ -2937,22 +3547,27 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val) JSObject* baseObj = baseValue.toObject(callFrame); // may throw JSValue subscript = stackFrame.args[1].jsValue(); - JSValue result; + bool result; uint32_t i; if (subscript.getUInt32(i)) - result = jsBoolean(baseObj->deleteProperty(callFrame, i)); + result = baseObj->methodTable()->deletePropertyByIndex(baseObj, callFrame, i); + else if (isName(subscript)) + result = baseObj->methodTable()->deleteProperty(baseObj, callFrame, jsCast(subscript.asCell())->privateName()); else { CHECK_FOR_EXCEPTION(); - Identifier property(callFrame, subscript.toString(callFrame)); + Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame)); CHECK_FOR_EXCEPTION(); - result = jsBoolean(baseObj->deleteProperty(callFrame, property)); + result = baseObj->methodTable()->deleteProperty(baseObj, callFrame, property); } + if (!result && callFrame->codeBlock()->isStrictMode()) + stackFrame.vm->exception = createTypeError(stackFrame.callFrame, "Unable to delete property."); + CHECK_FOR_EXCEPTION_AT_END(); - return JSValue::encode(result); + return JSValue::encode(jsBoolean(result)); } -DEFINE_STUB_FUNCTION(void, op_put_getter) +DEFINE_STUB_FUNCTION(void, op_put_getter_setter) { STUB_INIT_STACK_FRAME(stackFrame); @@ -2960,34 +3575,33 @@ DEFINE_STUB_FUNCTION(void, op_put_getter) 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); + GetterSetter* accessor = GetterSetter::create(callFrame); - CallFrame* callFrame = stackFrame.callFrame; + JSValue getter = stackFrame.args[2].jsValue(); + JSValue setter = stackFrame.args[3].jsValue(); + ASSERT(getter.isObject() || getter.isUndefined()); + ASSERT(setter.isObject() || setter.isUndefined()); + ASSERT(getter.isObject() || setter.isObject()); - 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())); + if (!getter.isUndefined()) + accessor->setGetter(callFrame->vm(), asObject(getter)); + if (!setter.isUndefined()) + accessor->setSetter(callFrame->vm(), asObject(setter)); + baseObj->putDirectAccessor(callFrame, stackFrame.args[1].identifier(), accessor, Accessor); } -DEFINE_STUB_FUNCTION(JSObject*, op_new_error) +DEFINE_STUB_FUNCTION(void, op_throw_static_error) { STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - unsigned type = stackFrame.args[0].int32(); - JSValue message = stackFrame.args[1].jsValue(); - unsigned bytecodeOffset = stackFrame.args[2].int32(); - - unsigned lineNumber = codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset); - return Error::create(callFrame, static_cast(type), message.toString(callFrame), lineNumber, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + String message = stackFrame.args[0].jsValue().toString(callFrame)->value(callFrame); + if (stackFrame.args[1].asInt32) + stackFrame.vm->exception = createReferenceError(callFrame, message); + else + stackFrame.vm->exception = createTypeError(callFrame, message); + VM_THROW_EXCEPTION_AT_END(); } DEFINE_STUB_FUNCTION(void, op_debug) @@ -2999,36 +3613,26 @@ DEFINE_STUB_FUNCTION(void, op_debug) int debugHookID = stackFrame.args[0].int32(); int firstLine = stackFrame.args[1].int32(); int lastLine = stackFrame.args[2].int32(); + int column = stackFrame.args[3].int32(); - stackFrame.globalData->interpreter->debug(callFrame, static_cast(debugHookID), firstLine, lastLine); + stackFrame.vm->interpreter->debug(callFrame, static_cast(debugHookID), firstLine, lastLine, column); } -DEFINE_STUB_FUNCTION(EncodedJSValue, vm_throw) +DEFINE_STUB_FUNCTION(void*, vm_throw) { STUB_INIT_STACK_FRAME(stackFrame); + VM* vm = stackFrame.vm; + ExceptionHandler handler = jitThrow(vm, stackFrame.callFrame, vm->exception, vm->exceptionLocation); + STUB_SET_RETURN_ADDRESS(handler.catchRoutine); + return handler.callFrame; +} - CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* codeBlock = callFrame->codeBlock(); - JSGlobalData* globalData = stackFrame.globalData; - - unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, globalData->exceptionLocation); - - JSValue exceptionValue = globalData->exception; - ASSERT(exceptionValue); - globalData->exception = JSValue(); - - HandlerInfo* handler = globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex, false); - - if (!handler) { - *stackFrame.exception = exceptionValue; - return JSValue::encode(jsNull()); - } +DEFINE_STUB_FUNCTION(EncodedJSValue, to_object) +{ + STUB_INIT_STACK_FRAME(stackFrame); - stackFrame.callFrame = callFrame; - void* catchRoutine = handler->nativeCode.executableAddress(); - ASSERT(catchRoutine); - STUB_SET_RETURN_ADDRESS(catchRoutine); - return JSValue::encode(exceptionValue); + CallFrame* callFrame = stackFrame.callFrame; + return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame)); } } // namespace JSC