1 /* 2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich (at) uwaterloo.ca> 4 * Copyright (C) Research In Motion Limited 2010, 2011. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 16 * its contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 33 #if ENABLE(JIT) 34 #include "JITStubs.h" 35 36 #include "Arguments.h" 37 #include "CallFrame.h" 38 #include "CodeBlock.h" 39 #include "Heap.h" 40 #include "Debugger.h" 41 #include "ExceptionHelpers.h" 42 #include "GetterSetter.h" 43 #include "Strong.h" 44 #include "JIT.h" 45 #include "JSActivation.h" 46 #include "JSArray.h" 47 #include "JSByteArray.h" 48 #include "JSFunction.h" 49 #include "JSGlobalObjectFunctions.h" 50 #include "JSNotAnObject.h" 51 #include "JSPropertyNameIterator.h" 52 #include "JSStaticScopeObject.h" 53 #include "JSString.h" 54 #include "ObjectPrototype.h" 55 #include "Operations.h" 56 #include "Parser.h" 57 #include "Profiler.h" 58 #include "RegExpObject.h" 59 #include "RegExpPrototype.h" 60 #include "Register.h" 61 #include "SamplingTool.h" 62 #include <wtf/StdLibExtras.h> 63 #include <stdarg.h> 64 #include <stdio.h> 65 66 using namespace std; 67 68 namespace JSC { 69 70 #if OS(DARWIN) || (OS(WINDOWS) && CPU(X86)) 71 #define SYMBOL_STRING(name) "_" #name 72 #else 73 #define SYMBOL_STRING(name) #name 74 #endif 75 76 #if OS(IOS) 77 #define THUMB_FUNC_PARAM(name) SYMBOL_STRING(name) 78 #else 79 #define THUMB_FUNC_PARAM(name) 80 #endif 81 82 #if (OS(LINUX) || OS(FREEBSD)) && CPU(X86_64) 83 #define SYMBOL_STRING_RELOCATION(name) #name "@plt" 84 #elif OS(DARWIN) || (CPU(X86_64) && COMPILER(MINGW) && !GCC_VERSION_AT_LEAST(4, 5, 0)) 85 #define SYMBOL_STRING_RELOCATION(name) "_" #name 86 #elif CPU(X86) && COMPILER(MINGW) 87 #define SYMBOL_STRING_RELOCATION(name) "@" #name "@4" 88 #else 89 #define SYMBOL_STRING_RELOCATION(name) #name 90 #endif 91 92 #if OS(DARWIN) 93 // Mach-O platform 94 #define HIDE_SYMBOL(name) ".private_extern _" #name 95 #elif OS(AIX) 96 // IBM's own file format 97 #define HIDE_SYMBOL(name) ".lglobl " #name 98 #elif OS(LINUX) \ 99 || OS(FREEBSD) \ 100 || OS(OPENBSD) \ 101 || OS(SOLARIS) \ 102 || (OS(HPUX) && CPU(IA64)) \ 103 || OS(SYMBIAN) \ 104 || OS(NETBSD) 105 // ELF platform 106 #define HIDE_SYMBOL(name) ".hidden " #name 107 #else 108 #define HIDE_SYMBOL(name) 109 #endif 110 111 #if USE(JSVALUE32_64) 112 113 #if COMPILER(GCC) && CPU(X86) 114 115 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you 116 // need to change the assembly trampolines below to match. 117 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment); 118 COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x3c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); 119 COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline); 120 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline); 121 122 asm ( 123 ".text\n" 124 ".globl " SYMBOL_STRING(ctiTrampoline) "\n" 125 HIDE_SYMBOL(ctiTrampoline) "\n" 126 SYMBOL_STRING(ctiTrampoline) ":" "\n" 127 "pushl %ebp" "\n" 128 "movl %esp, %ebp" "\n" 129 "pushl %esi" "\n" 130 "pushl %edi" "\n" 131 "pushl %ebx" "\n" 132 "subl $0x3c, %esp" "\n" 133 "movl $512, %esi" "\n" 134 "movl 0x58(%esp), %edi" "\n" 135 "call *0x50(%esp)" "\n" 136 "addl $0x3c, %esp" "\n" 137 "popl %ebx" "\n" 138 "popl %edi" "\n" 139 "popl %esi" "\n" 140 "popl %ebp" "\n" 141 "ret" "\n" 142 ); 143 144 asm ( 145 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" 146 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" 147 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" 148 "movl %esp, %ecx" "\n" 149 "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" 150 "int3" "\n" 151 ); 152 153 asm ( 154 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" 155 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" 156 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" 157 "addl $0x3c, %esp" "\n" 158 "popl %ebx" "\n" 159 "popl %edi" "\n" 160 "popl %esi" "\n" 161 "popl %ebp" "\n" 162 "ret" "\n" 163 ); 164 165 #elif COMPILER(GCC) && CPU(X86_64) 166 167 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you 168 // need to change the assembly trampolines below to match. 169 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 32 == 0x0, JITStackFrame_maintains_32byte_stack_alignment); 170 COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x48, JITStackFrame_stub_argument_space_matches_ctiTrampoline); 171 COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x90, JITStackFrame_callFrame_offset_matches_ctiTrampoline); 172 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x80, JITStackFrame_code_offset_matches_ctiTrampoline); 173 174 asm ( 175 ".globl " SYMBOL_STRING(ctiTrampoline) "\n" 176 HIDE_SYMBOL(ctiTrampoline) "\n" 177 SYMBOL_STRING(ctiTrampoline) ":" "\n" 178 "pushq %rbp" "\n" 179 "movq %rsp, %rbp" "\n" 180 "pushq %r12" "\n" 181 "pushq %r13" "\n" 182 "pushq %r14" "\n" 183 "pushq %r15" "\n" 184 "pushq %rbx" "\n" 185 "subq $0x48, %rsp" "\n" 186 "movq $512, %r12" "\n" 187 "movq $0xFFFF000000000000, %r14" "\n" 188 "movq $0xFFFF000000000002, %r15" "\n" 189 "movq 0x90(%rsp), %r13" "\n" 190 "call *0x80(%rsp)" "\n" 191 "addq $0x48, %rsp" "\n" 192 "popq %rbx" "\n" 193 "popq %r15" "\n" 194 "popq %r14" "\n" 195 "popq %r13" "\n" 196 "popq %r12" "\n" 197 "popq %rbp" "\n" 198 "ret" "\n" 199 ); 200 201 asm ( 202 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" 203 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" 204 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" 205 "movq %rsp, %rdi" "\n" 206 "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" 207 "int3" "\n" 208 ); 209 210 asm ( 211 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" 212 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" 213 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" 214 "addq $0x48, %rsp" "\n" 215 "popq %rbx" "\n" 216 "popq %r15" "\n" 217 "popq %r14" "\n" 218 "popq %r13" "\n" 219 "popq %r12" "\n" 220 "popq %rbp" "\n" 221 "ret" "\n" 222 ); 223 224 #elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_THUMB2) 225 226 #define THUNK_RETURN_ADDRESS_OFFSET 0x38 227 #define PRESERVED_RETURN_ADDRESS_OFFSET 0x3C 228 #define PRESERVED_R4_OFFSET 0x40 229 #define PRESERVED_R5_OFFSET 0x44 230 #define PRESERVED_R6_OFFSET 0x48 231 #define REGISTER_FILE_OFFSET 0x4C 232 #define CALLFRAME_OFFSET 0x50 233 #define EXCEPTION_OFFSET 0x54 234 #define ENABLE_PROFILER_REFERENCE_OFFSET 0x58 235 236 #elif (COMPILER(GCC) || COMPILER(MSVC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL) 237 238 // Also update the MSVC section (defined at DEFINE_STUB_FUNCTION) 239 // when changing one of the following values. 240 #define THUNK_RETURN_ADDRESS_OFFSET 64 241 #define PRESERVEDR4_OFFSET 68 242 243 #elif COMPILER(MSVC) && CPU(X86) 244 245 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you 246 // need to change the assembly trampolines below to match. 247 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment); 248 COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x3c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); 249 COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline); 250 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline); 251 252 extern "C" { 253 254 __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*) 255 { 256 __asm { 257 push ebp; 258 mov ebp, esp; 259 push esi; 260 push edi; 261 push ebx; 262 sub esp, 0x3c; 263 mov esi, 512; 264 mov ecx, esp; 265 mov edi, [esp + 0x58]; 266 call [esp + 0x50]; 267 add esp, 0x3c; 268 pop ebx; 269 pop edi; 270 pop esi; 271 pop ebp; 272 ret; 273 } 274 } 275 276 __declspec(naked) void ctiVMThrowTrampoline() 277 { 278 __asm { 279 mov ecx, esp; 280 call cti_vm_throw; 281 add esp, 0x3c; 282 pop ebx; 283 pop edi; 284 pop esi; 285 pop ebp; 286 ret; 287 } 288 } 289 290 __declspec(naked) void ctiOpThrowNotCaught() 291 { 292 __asm { 293 add esp, 0x3c; 294 pop ebx; 295 pop edi; 296 pop esi; 297 pop ebp; 298 ret; 299 } 300 } 301 } 302 303 #elif CPU(MIPS) 304 305 #define PRESERVED_GP_OFFSET 60 306 #define PRESERVED_S0_OFFSET 64 307 #define PRESERVED_S1_OFFSET 68 308 #define PRESERVED_S2_OFFSET 72 309 #define PRESERVED_RETURN_ADDRESS_OFFSET 76 310 #define THUNK_RETURN_ADDRESS_OFFSET 80 311 #define REGISTER_FILE_OFFSET 84 312 #define CALLFRAME_OFFSET 88 313 #define EXCEPTION_OFFSET 92 314 #define ENABLE_PROFILER_REFERENCE_OFFSET 96 315 #define GLOBAL_DATA_OFFSET 100 316 #define STACK_LENGTH 104 317 #elif CPU(SH4) 318 #define SYMBOL_STRING(name) #name 319 /* code (r4), RegisterFile* (r5), CallFrame* (r6), JSValue* exception (r7), Profiler**(sp), JSGlobalData (sp)*/ 320 321 asm volatile ( 322 ".text\n" 323 ".globl " SYMBOL_STRING(ctiTrampoline) "\n" 324 HIDE_SYMBOL(ctiTrampoline) "\n" 325 SYMBOL_STRING(ctiTrampoline) ":" "\n" 326 "mov.l r7, @-r15" "\n" 327 "mov.l r6, @-r15" "\n" 328 "mov.l r5, @-r15" "\n" 329 "mov.l r8, @-r15" "\n" 330 "mov #127, r8" "\n" 331 "mov.l r14, @-r15" "\n" 332 "sts.l pr, @-r15" "\n" 333 "mov.l r13, @-r15" "\n" 334 "mov.l r11, @-r15" "\n" 335 "mov.l r10, @-r15" "\n" 336 "add #-60, r15" "\n" 337 "mov r6, r14" "\n" 338 "jsr @r4" "\n" 339 "nop" "\n" 340 "add #60, r15" "\n" 341 "mov.l @r15+,r10" "\n" 342 "mov.l @r15+,r11" "\n" 343 "mov.l @r15+,r13" "\n" 344 "lds.l @r15+,pr" "\n" 345 "mov.l @r15+,r14" "\n" 346 "mov.l @r15+,r8" "\n" 347 "add #12, r15" "\n" 348 "rts" "\n" 349 "nop" "\n" 350 ); 351 352 asm volatile ( 353 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" 354 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" 355 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" 356 "mov.l .L2"SYMBOL_STRING(cti_vm_throw)",r0" "\n" 357 "mov r15, r4" "\n" 358 "mov.l @(r0,r12),r11" "\n" 359 "jsr @r11" "\n" 360 "nop" "\n" 361 "add #60, r15" "\n" 362 "mov.l @r15+,r10" "\n" 363 "mov.l @r15+,r11" "\n" 364 "mov.l @r15+,r13" "\n" 365 "lds.l @r15+,pr" "\n" 366 "mov.l @r15+,r14" "\n" 367 "mov.l @r15+,r8" "\n" 368 "add #12, r15" "\n" 369 "rts" "\n" 370 "nop" "\n" 371 ".align 2" "\n" 372 ".L2"SYMBOL_STRING(cti_vm_throw)":.long " SYMBOL_STRING(cti_vm_throw)"@GOT \n" 373 ); 374 375 asm volatile ( 376 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" 377 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" 378 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" 379 "add #60, r15" "\n" 380 "mov.l @r15+,r10" "\n" 381 "mov.l @r15+,r11" "\n" 382 "mov.l @r15+,r13" "\n" 383 "lds.l @r15+,pr" "\n" 384 "mov.l @r15+,r14" "\n" 385 "mov.l @r15+,r8" "\n" 386 "add #12, r15" "\n" 387 "rts" "\n" 388 "nop" "\n" 389 ); 390 #else 391 #error "JIT not supported on this platform." 392 #endif 393 394 #else // USE(JSVALUE32_64) 395 396 #if COMPILER(GCC) && CPU(X86_64) 397 398 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you 399 // need to change the assembly trampolines below to match. 400 COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline); 401 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x48, JITStackFrame_code_offset_matches_ctiTrampoline); 402 COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x78, JITStackFrame_stub_argument_space_matches_ctiTrampoline); 403 404 asm ( 405 ".text\n" 406 ".globl " SYMBOL_STRING(ctiTrampoline) "\n" 407 HIDE_SYMBOL(ctiTrampoline) "\n" 408 SYMBOL_STRING(ctiTrampoline) ":" "\n" 409 "pushq %rbp" "\n" 410 "movq %rsp, %rbp" "\n" 411 "pushq %r12" "\n" 412 "pushq %r13" "\n" 413 "pushq %r14" "\n" 414 "pushq %r15" "\n" 415 "pushq %rbx" "\n" 416 // Form the JIT stubs area 417 "pushq %r9" "\n" 418 "pushq %r8" "\n" 419 "pushq %rcx" "\n" 420 "pushq %rdx" "\n" 421 "pushq %rsi" "\n" 422 "pushq %rdi" "\n" 423 "subq $0x48, %rsp" "\n" 424 "movq $512, %r12" "\n" 425 "movq $0xFFFF000000000000, %r14" "\n" 426 "movq $0xFFFF000000000002, %r15" "\n" 427 "movq %rdx, %r13" "\n" 428 "call *%rdi" "\n" 429 "addq $0x78, %rsp" "\n" 430 "popq %rbx" "\n" 431 "popq %r15" "\n" 432 "popq %r14" "\n" 433 "popq %r13" "\n" 434 "popq %r12" "\n" 435 "popq %rbp" "\n" 436 "ret" "\n" 437 ); 438 439 asm ( 440 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" 441 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" 442 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" 443 "movq %rsp, %rdi" "\n" 444 "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" 445 "int3" "\n" 446 ); 447 448 asm ( 449 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" 450 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" 451 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" 452 "addq $0x78, %rsp" "\n" 453 "popq %rbx" "\n" 454 "popq %r15" "\n" 455 "popq %r14" "\n" 456 "popq %r13" "\n" 457 "popq %r12" "\n" 458 "popq %rbp" "\n" 459 "ret" "\n" 460 ); 461 462 #else 463 #error "JIT not supported on this platform." 464 #endif 465 466 #endif // USE(JSVALUE32_64) 467 468 #if CPU(MIPS) 469 asm ( 470 ".text" "\n" 471 ".align 2" "\n" 472 ".set noreorder" "\n" 473 ".set nomacro" "\n" 474 ".set nomips16" "\n" 475 ".globl " SYMBOL_STRING(ctiTrampoline) "\n" 476 ".ent " SYMBOL_STRING(ctiTrampoline) "\n" 477 SYMBOL_STRING(ctiTrampoline) ":" "\n" 478 "addiu $29,$29,-" STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" 479 "sw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" 480 "sw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" 481 "sw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" 482 "sw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" 483 #if WTF_MIPS_PIC 484 "sw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" 485 #endif 486 "move $16,$6 # set callFrameRegister" "\n" 487 "li $17,512 # set timeoutCheckRegister" "\n" 488 "move $25,$4 # move executableAddress to t9" "\n" 489 "sw $5," STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET) "($29) # store registerFile to current stack" "\n" 490 "sw $6," STRINGIZE_VALUE_OF(CALLFRAME_OFFSET) "($29) # store callFrame to curent stack" "\n" 491 "sw $7," STRINGIZE_VALUE_OF(EXCEPTION_OFFSET) "($29) # store exception to current stack" "\n" 492 "lw $8," STRINGIZE_VALUE_OF(STACK_LENGTH + 16) "($29) # load enableProfilerReference from previous stack" "\n" 493 "lw $9," STRINGIZE_VALUE_OF(STACK_LENGTH + 20) "($29) # load globalData from previous stack" "\n" 494 "sw $8," STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "($29) # store enableProfilerReference to current stack" "\n" 495 "jalr $25" "\n" 496 "sw $9," STRINGIZE_VALUE_OF(GLOBAL_DATA_OFFSET) "($29) # store globalData to current stack" "\n" 497 "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" 498 "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" 499 "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" 500 "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" 501 "jr $31" "\n" 502 "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" 503 ".set reorder" "\n" 504 ".set macro" "\n" 505 ".end " SYMBOL_STRING(ctiTrampoline) "\n" 506 ); 507 508 asm ( 509 ".text" "\n" 510 ".align 2" "\n" 511 ".set noreorder" "\n" 512 ".set nomacro" "\n" 513 ".set nomips16" "\n" 514 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" 515 ".ent " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" 516 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" 517 #if WTF_MIPS_PIC 518 "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" 519 ".set macro" "\n" 520 "la $25," SYMBOL_STRING(cti_vm_throw) "\n" 521 ".set nomacro" "\n" 522 "bal " SYMBOL_STRING(cti_vm_throw) "\n" 523 "move $4,$29" "\n" 524 #else 525 "jal " SYMBOL_STRING(cti_vm_throw) "\n" 526 "move $4,$29" "\n" 527 #endif 528 "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" 529 "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" 530 "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" 531 "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" 532 "jr $31" "\n" 533 "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" 534 ".set reorder" "\n" 535 ".set macro" "\n" 536 ".end " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" 537 ); 538 539 asm ( 540 ".text" "\n" 541 ".align 2" "\n" 542 ".set noreorder" "\n" 543 ".set nomacro" "\n" 544 ".set nomips16" "\n" 545 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" 546 ".ent " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" 547 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" 548 "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n" 549 "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n" 550 "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n" 551 "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n" 552 "jr $31" "\n" 553 "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n" 554 ".set reorder" "\n" 555 ".set macro" "\n" 556 ".end " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" 557 ); 558 #endif 559 560 #if COMPILER(GCC) && CPU(ARM_THUMB2) 561 562 asm ( 563 ".text" "\n" 564 ".align 2" "\n" 565 ".globl " SYMBOL_STRING(ctiTrampoline) "\n" 566 HIDE_SYMBOL(ctiTrampoline) "\n" 567 ".thumb" "\n" 568 ".thumb_func " THUMB_FUNC_PARAM(ctiTrampoline) "\n" 569 SYMBOL_STRING(ctiTrampoline) ":" "\n" 570 "sub sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" 571 "str lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" 572 "str r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" 573 "str r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" 574 "str r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n" 575 "str r1, [sp, #" STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET) "]" "\n" 576 "str r2, [sp, #" STRINGIZE_VALUE_OF(CALLFRAME_OFFSET) "]" "\n" 577 "str r3, [sp, #" STRINGIZE_VALUE_OF(EXCEPTION_OFFSET) "]" "\n" 578 "cpy r5, r2" "\n" 579 "mov r6, #512" "\n" 580 "blx r0" "\n" 581 "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n" 582 "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" 583 "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" 584 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" 585 "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" 586 "bx lr" "\n" 587 ); 588 589 asm ( 590 ".text" "\n" 591 ".align 2" "\n" 592 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" 593 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" 594 ".thumb" "\n" 595 ".thumb_func " THUMB_FUNC_PARAM(ctiVMThrowTrampoline) "\n" 596 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" 597 "cpy r0, sp" "\n" 598 "bl " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" 599 "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n" 600 "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" 601 "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" 602 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" 603 "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" 604 "bx lr" "\n" 605 ); 606 607 asm ( 608 ".text" "\n" 609 ".align 2" "\n" 610 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" 611 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" 612 ".thumb" "\n" 613 ".thumb_func " THUMB_FUNC_PARAM(ctiOpThrowNotCaught) "\n" 614 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" 615 "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n" 616 "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n" 617 "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n" 618 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n" 619 "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n" 620 "bx lr" "\n" 621 ); 622 623 #elif COMPILER(GCC) && CPU(ARM_TRADITIONAL) 624 625 asm ( 626 ".globl " SYMBOL_STRING(ctiTrampoline) "\n" 627 HIDE_SYMBOL(ctiTrampoline) "\n" 628 SYMBOL_STRING(ctiTrampoline) ":" "\n" 629 "stmdb sp!, {r1-r3}" "\n" 630 "stmdb sp!, {r4-r8, lr}" "\n" 631 "sub sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n" 632 "mov r4, r2" "\n" 633 "mov r5, #512" "\n" 634 // r0 contains the code 635 "mov lr, pc" "\n" 636 "mov pc, r0" "\n" 637 "add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n" 638 "ldmia sp!, {r4-r8, lr}" "\n" 639 "add sp, sp, #12" "\n" 640 "mov pc, lr" "\n" 641 ); 642 643 asm ( 644 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" 645 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" 646 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" 647 "mov r0, sp" "\n" 648 "bl " SYMBOL_STRING(cti_vm_throw) "\n" 649 650 // Both has the same return sequence 651 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" 652 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" 653 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" 654 "add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n" 655 "ldmia sp!, {r4-r8, lr}" "\n" 656 "add sp, sp, #12" "\n" 657 "mov pc, lr" "\n" 658 ); 659 660 #elif COMPILER(RVCT) && CPU(ARM_THUMB2) 661 662 __asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*) 663 { 664 PRESERVE8 665 sub sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET 666 str lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] 667 str r4, [sp, # PRESERVED_R4_OFFSET ] 668 str r5, [sp, # PRESERVED_R5_OFFSET ] 669 str r6, [sp, # PRESERVED_R6_OFFSET ] 670 str r1, [sp, # REGISTER_FILE_OFFSET ] 671 str r2, [sp, # CALLFRAME_OFFSET ] 672 str r3, [sp, # EXCEPTION_OFFSET ] 673 cpy r5, r2 674 mov r6, #512 675 blx r0 676 ldr r6, [sp, # PRESERVED_R6_OFFSET ] 677 ldr r5, [sp, # PRESERVED_R5_OFFSET ] 678 ldr r4, [sp, # PRESERVED_R4_OFFSET ] 679 ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] 680 add sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET 681 bx lr 682 } 683 684 __asm void ctiVMThrowTrampoline() 685 { 686 PRESERVE8 687 cpy r0, sp 688 bl cti_vm_throw 689 ldr r6, [sp, # PRESERVED_R6_OFFSET ] 690 ldr r5, [sp, # PRESERVED_R5_OFFSET ] 691 ldr r4, [sp, # PRESERVED_R4_OFFSET ] 692 ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] 693 add sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET 694 bx lr 695 } 696 697 __asm void ctiOpThrowNotCaught() 698 { 699 PRESERVE8 700 ldr r6, [sp, # PRESERVED_R6_OFFSET ] 701 ldr r5, [sp, # PRESERVED_R5_OFFSET ] 702 ldr r4, [sp, # PRESERVED_R4_OFFSET ] 703 ldr lr, [sp, # PRESERVED_RETURN_ADDRESS_OFFSET ] 704 add sp, sp, # ENABLE_PROFILER_REFERENCE_OFFSET 705 bx lr 706 } 707 708 #elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL) 709 710 __asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*) 711 { 712 ARM 713 stmdb sp!, {r1-r3} 714 stmdb sp!, {r4-r8, lr} 715 sub sp, sp, # PRESERVEDR4_OFFSET 716 mov r4, r2 717 mov r5, #512 718 mov lr, pc 719 bx r0 720 add sp, sp, # PRESERVEDR4_OFFSET 721 ldmia sp!, {r4-r8, lr} 722 add sp, sp, #12 723 bx lr 724 } 725 726 __asm void ctiVMThrowTrampoline() 727 { 728 ARM 729 PRESERVE8 730 mov r0, sp 731 bl cti_vm_throw 732 add sp, sp, # PRESERVEDR4_OFFSET 733 ldmia sp!, {r4-r8, lr} 734 add sp, sp, #12 735 bx lr 736 } 737 738 __asm void ctiOpThrowNotCaught() 739 { 740 ARM 741 add sp, sp, # PRESERVEDR4_OFFSET 742 ldmia sp!, {r4-r8, lr} 743 add sp, sp, #12 744 bx lr 745 } 746 #endif 747 748 #if ENABLE(OPCODE_SAMPLING) 749 #define CTI_SAMPLER stackFrame.globalData->interpreter->sampler() 750 #else 751 #define CTI_SAMPLER 0 752 #endif 753 754 JITThunks::JITThunks(JSGlobalData* globalData) 755 : m_hostFunctionStubMap(new HostFunctionStubMap) 756 { 757 if (!globalData->executableAllocator.isValid()) 758 return; 759 760 JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_trampolineStructure); 761 ASSERT(m_executablePool); 762 #if CPU(ARM_THUMB2) 763 // Unfortunate the arm compiler does not like the use of offsetof on JITStackFrame (since it contains non POD types), 764 // and the OBJECT_OFFSETOF macro does not appear constantish enough for it to be happy with its use in COMPILE_ASSERT 765 // macros. 766 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == PRESERVED_RETURN_ADDRESS_OFFSET); 767 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == PRESERVED_R4_OFFSET); 768 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR5) == PRESERVED_R5_OFFSET); 769 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR6) == PRESERVED_R6_OFFSET); 770 771 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == REGISTER_FILE_OFFSET); 772 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET); 773 // The fifth argument is the first item already on the stack. 774 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == ENABLE_PROFILER_REFERENCE_OFFSET); 775 776 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET); 777 778 #elif CPU(ARM_TRADITIONAL) 779 780 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET); 781 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == PRESERVEDR4_OFFSET); 782 783 784 #elif CPU(MIPS) 785 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedGP) == PRESERVED_GP_OFFSET); 786 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS0) == PRESERVED_S0_OFFSET); 787 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS1) == PRESERVED_S1_OFFSET); 788 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS2) == PRESERVED_S2_OFFSET); 789 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == PRESERVED_RETURN_ADDRESS_OFFSET); 790 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET); 791 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == REGISTER_FILE_OFFSET); 792 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET); 793 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, unused1) == EXCEPTION_OFFSET); 794 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == ENABLE_PROFILER_REFERENCE_OFFSET); 795 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, globalData) == GLOBAL_DATA_OFFSET); 796 797 #endif 798 } 799 800 JITThunks::~JITThunks() 801 { 802 } 803 804 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 805 806 NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo, bool direct) 807 { 808 // The interpreter checks for recursion here; I do not believe this can occur in CTI. 809 810 if (!baseValue.isCell()) 811 return; 812 813 // Uncacheable: give up. 814 if (!slot.isCacheable()) { 815 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); 816 return; 817 } 818 819 JSCell* baseCell = baseValue.asCell(); 820 Structure* structure = baseCell->structure(); 821 822 if (structure->isUncacheableDictionary()) { 823 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); 824 return; 825 } 826 827 // If baseCell != base, then baseCell must be a proxy for another object. 828 if (baseCell != slot.base()) { 829 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); 830 return; 831 } 832 833 // Cache hit: Specialize instruction and ref Structures. 834 835 // Structure transition, cache transition info 836 if (slot.type() == PutPropertySlot::NewProperty) { 837 if (structure->isDictionary()) { 838 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic)); 839 return; 840 } 841 842 // put_by_id_transition checks the prototype chain for setters. 843 normalizePrototypeChain(callFrame, baseCell); 844 845 StructureChain* prototypeChain = structure->prototypeChain(callFrame); 846 stubInfo->initPutByIdTransition(callFrame->globalData(), codeBlock->ownerExecutable(), structure->previousID(), structure, prototypeChain); 847 JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct); 848 return; 849 } 850 851 stubInfo->initPutByIdReplace(callFrame->globalData(), codeBlock->ownerExecutable(), structure); 852 853 JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress, direct); 854 } 855 856 NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo) 857 { 858 // FIXME: Write a test that proves we need to check for recursion here just 859 // like the interpreter does, then add a check for recursion. 860 861 // FIXME: Cache property access for immediates. 862 if (!baseValue.isCell()) { 863 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); 864 return; 865 } 866 867 JSGlobalData* globalData = &callFrame->globalData(); 868 869 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { 870 JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, returnAddress); 871 return; 872 } 873 874 if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { 875 // The tradeoff of compiling an patched inline string length access routine does not seem 876 // to pay off, so we currently only do this for arrays. 877 ctiPatchCallByReturnAddress(codeBlock, returnAddress, globalData->jitStubs->ctiStringLengthTrampoline()); 878 return; 879 } 880 881 // Uncacheable: give up. 882 if (!slot.isCacheable()) { 883 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); 884 return; 885 } 886 887 JSCell* baseCell = baseValue.asCell(); 888 Structure* structure = baseCell->structure(); 889 890 if (structure->isUncacheableDictionary()) { 891 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); 892 return; 893 } 894 895 // Cache hit: Specialize instruction and ref Structures. 896 897 if (slot.slotBase() == baseValue) { 898 // set this up, so derefStructures can do it's job. 899 stubInfo->initGetByIdSelf(callFrame->globalData(), codeBlock->ownerExecutable(), structure); 900 if (slot.cachedPropertyType() != PropertySlot::Value) 901 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail)); 902 else 903 JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress); 904 return; 905 } 906 907 if (structure->isDictionary()) { 908 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); 909 return; 910 } 911 912 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { 913 ASSERT(slot.slotBase().isObject()); 914 915 JSObject* slotBaseObject = asObject(slot.slotBase()); 916 size_t offset = slot.cachedOffset(); 917 918 // Since we're accessing a prototype in a loop, it's a good bet that it 919 // should not be treated as a dictionary. 920 if (slotBaseObject->structure()->isDictionary()) { 921 slotBaseObject->flattenDictionaryObject(callFrame->globalData()); 922 offset = slotBaseObject->structure()->get(callFrame->globalData(), propertyName); 923 } 924 925 stubInfo->initGetByIdProto(callFrame->globalData(), codeBlock->ownerExecutable(), structure, slotBaseObject->structure()); 926 927 ASSERT(!structure->isDictionary()); 928 ASSERT(!slotBaseObject->structure()->isDictionary()); 929 JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset, returnAddress); 930 return; 931 } 932 933 size_t offset = slot.cachedOffset(); 934 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset); 935 if (!count) { 936 stubInfo->accessType = access_get_by_id_generic; 937 return; 938 } 939 940 StructureChain* prototypeChain = structure->prototypeChain(callFrame); 941 stubInfo->initGetByIdChain(callFrame->globalData(), codeBlock->ownerExecutable(), structure, prototypeChain); 942 JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress); 943 } 944 945 #endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 946 947 #ifndef NDEBUG 948 949 extern "C" { 950 951 static void jscGeneratedNativeCode() 952 { 953 // When executing a JIT stub function (which might do an allocation), we hack the return address 954 // to pretend to be executing this function, to keep stack logging tools from blowing out 955 // memory. 956 } 957 958 } 959 960 struct StackHack { 961 ALWAYS_INLINE StackHack(JITStackFrame& stackFrame) 962 : stackFrame(stackFrame) 963 , savedReturnAddress(*stackFrame.returnAddressSlot()) 964 { 965 *stackFrame.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode)); 966 } 967 968 ALWAYS_INLINE ~StackHack() 969 { 970 *stackFrame.returnAddressSlot() = savedReturnAddress; 971 } 972 973 JITStackFrame& stackFrame; 974 ReturnAddressPtr savedReturnAddress; 975 }; 976 977 #define STUB_INIT_STACK_FRAME(stackFrame) JITStackFrame& stackFrame = *reinterpret_cast_ptr<JITStackFrame*>(STUB_ARGS); StackHack stackHack(stackFrame) 978 #define STUB_SET_RETURN_ADDRESS(returnAddress) stackHack.savedReturnAddress = ReturnAddressPtr(returnAddress) 979 #define STUB_RETURN_ADDRESS stackHack.savedReturnAddress 980 981 #else 982 983 #define STUB_INIT_STACK_FRAME(stackFrame) JITStackFrame& stackFrame = *reinterpret_cast_ptr<JITStackFrame*>(STUB_ARGS) 984 #define STUB_SET_RETURN_ADDRESS(returnAddress) *stackFrame.returnAddressSlot() = ReturnAddressPtr(returnAddress) 985 #define STUB_RETURN_ADDRESS *stackFrame.returnAddressSlot() 986 987 #endif 988 989 // The reason this is not inlined is to avoid having to do a PIC branch 990 // to get the address of the ctiVMThrowTrampoline function. It's also 991 // good to keep the code size down by leaving as much of the exception 992 // handling code out of line as possible. 993 static NEVER_INLINE void returnToThrowTrampoline(JSGlobalData* globalData, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot) 994 { 995 ASSERT(globalData->exception); 996 globalData->exceptionLocation = exceptionLocation; 997 returnAddressSlot = ReturnAddressPtr(FunctionPtr(ctiVMThrowTrampoline)); 998 } 999 1000 static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalData* globalData, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot) 1001 { 1002 globalData->exception = createStackOverflowError(callFrame); 1003 returnToThrowTrampoline(globalData, exceptionLocation, returnAddressSlot); 1004 } 1005 1006 #define VM_THROW_EXCEPTION() \ 1007 do { \ 1008 VM_THROW_EXCEPTION_AT_END(); \ 1009 return 0; \ 1010 } while (0) 1011 #define VM_THROW_EXCEPTION_AT_END() \ 1012 do {\ 1013 returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS);\ 1014 } while (0) 1015 1016 #define CHECK_FOR_EXCEPTION() \ 1017 do { \ 1018 if (UNLIKELY(stackFrame.globalData->exception)) \ 1019 VM_THROW_EXCEPTION(); \ 1020 } while (0) 1021 #define CHECK_FOR_EXCEPTION_AT_END() \ 1022 do { \ 1023 if (UNLIKELY(stackFrame.globalData->exception)) \ 1024 VM_THROW_EXCEPTION_AT_END(); \ 1025 } while (0) 1026 #define CHECK_FOR_EXCEPTION_VOID() \ 1027 do { \ 1028 if (UNLIKELY(stackFrame.globalData->exception)) { \ 1029 VM_THROW_EXCEPTION_AT_END(); \ 1030 return; \ 1031 } \ 1032 } while (0) 1033 1034 struct ExceptionHandler { 1035 void* catchRoutine; 1036 CallFrame* callFrame; 1037 }; 1038 static ExceptionHandler jitThrow(JSGlobalData* globalData, CallFrame* callFrame, JSValue exceptionValue, ReturnAddressPtr faultLocation) 1039 { 1040 ASSERT(exceptionValue); 1041 1042 unsigned vPCIndex = callFrame->codeBlock()->bytecodeOffset(faultLocation); 1043 globalData->exception = JSValue(); 1044 HandlerInfo* handler = globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex); // This may update callFrame & exceptionValue! 1045 globalData->exception = exceptionValue; 1046 1047 void* catchRoutine = handler ? handler->nativeCode.executableAddress() : FunctionPtr(ctiOpThrowNotCaught).value(); 1048 ASSERT(catchRoutine); 1049 ExceptionHandler exceptionHandler = { catchRoutine, callFrame }; 1050 return exceptionHandler; 1051 } 1052 1053 #if CPU(ARM_THUMB2) && COMPILER(GCC) 1054 1055 #define DEFINE_STUB_FUNCTION(rtype, op) \ 1056 extern "C" { \ 1057 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ 1058 }; \ 1059 asm ( \ 1060 ".text" "\n" \ 1061 ".align 2" "\n" \ 1062 ".globl " SYMBOL_STRING(cti_##op) "\n" \ 1063 HIDE_SYMBOL(cti_##op) "\n" \ 1064 ".thumb" "\n" \ 1065 ".thumb_func " THUMB_FUNC_PARAM(cti_##op) "\n" \ 1066 SYMBOL_STRING(cti_##op) ":" "\n" \ 1067 "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ 1068 "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \ 1069 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ 1070 "bx lr" "\n" \ 1071 ); \ 1072 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) \ 1073 1074 #elif CPU(MIPS) 1075 #if WTF_MIPS_PIC 1076 #define DEFINE_STUB_FUNCTION(rtype, op) \ 1077 extern "C" { \ 1078 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ 1079 }; \ 1080 asm ( \ 1081 ".text" "\n" \ 1082 ".align 2" "\n" \ 1083 ".set noreorder" "\n" \ 1084 ".set nomacro" "\n" \ 1085 ".set nomips16" "\n" \ 1086 ".globl " SYMBOL_STRING(cti_##op) "\n" \ 1087 ".ent " SYMBOL_STRING(cti_##op) "\n" \ 1088 SYMBOL_STRING(cti_##op) ":" "\n" \ 1089 "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" \ 1090 "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ 1091 ".set macro" "\n" \ 1092 "la $25," SYMBOL_STRING(JITStubThunked_##op) "\n" \ 1093 ".set nomacro" "\n" \ 1094 "bal " SYMBOL_STRING(JITStubThunked_##op) "\n" \ 1095 "nop" "\n" \ 1096 "lw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ 1097 "jr $31" "\n" \ 1098 "nop" "\n" \ 1099 ".set reorder" "\n" \ 1100 ".set macro" "\n" \ 1101 ".end " SYMBOL_STRING(cti_##op) "\n" \ 1102 ); \ 1103 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) 1104 1105 #else // WTF_MIPS_PIC 1106 #define DEFINE_STUB_FUNCTION(rtype, op) \ 1107 extern "C" { \ 1108 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ 1109 }; \ 1110 asm ( \ 1111 ".text" "\n" \ 1112 ".align 2" "\n" \ 1113 ".set noreorder" "\n" \ 1114 ".set nomacro" "\n" \ 1115 ".set nomips16" "\n" \ 1116 ".globl " SYMBOL_STRING(cti_##op) "\n" \ 1117 ".ent " SYMBOL_STRING(cti_##op) "\n" \ 1118 SYMBOL_STRING(cti_##op) ":" "\n" \ 1119 "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ 1120 "jal " SYMBOL_STRING(JITStubThunked_##op) "\n" \ 1121 "nop" "\n" \ 1122 "lw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \ 1123 "jr $31" "\n" \ 1124 "nop" "\n" \ 1125 ".set reorder" "\n" \ 1126 ".set macro" "\n" \ 1127 ".end " SYMBOL_STRING(cti_##op) "\n" \ 1128 ); \ 1129 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) 1130 1131 #endif 1132 1133 #elif CPU(ARM_TRADITIONAL) && COMPILER(GCC) 1134 1135 #define DEFINE_STUB_FUNCTION(rtype, op) \ 1136 extern "C" { \ 1137 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ 1138 }; \ 1139 asm ( \ 1140 ".globl " SYMBOL_STRING(cti_##op) "\n" \ 1141 SYMBOL_STRING(cti_##op) ":" "\n" \ 1142 "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ 1143 "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \ 1144 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ 1145 "mov pc, lr" "\n" \ 1146 ); \ 1147 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) 1148 1149 #elif (CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)) && COMPILER(RVCT) 1150 1151 #define DEFINE_STUB_FUNCTION(rtype, op) rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) 1152 1153 /* The following is a workaround for RVCT toolchain; precompiler macros are not expanded before the code is passed to the assembler */ 1154 1155 /* The following section is a template to generate code for GeneratedJITStubs_RVCT.h */ 1156 /* The pattern "#xxx#" will be replaced with "xxx" */ 1157 1158 /* 1159 RVCT(extern "C" #rtype# JITStubThunked_#op#(STUB_ARGS_DECLARATION);) 1160 RVCT(__asm #rtype# cti_#op#(STUB_ARGS_DECLARATION)) 1161 RVCT({) 1162 RVCT( PRESERVE8) 1163 RVCT( IMPORT JITStubThunked_#op#) 1164 RVCT( str lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET]) 1165 RVCT( bl JITStubThunked_#op#) 1166 RVCT( ldr lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET]) 1167 RVCT( bx lr) 1168 RVCT(}) 1169 RVCT() 1170 */ 1171 1172 /* Include the generated file */ 1173 #include "GeneratedJITStubs_RVCT.h" 1174 1175 #elif CPU(ARM_TRADITIONAL) && COMPILER(MSVC) 1176 1177 #define DEFINE_STUB_FUNCTION(rtype, op) extern "C" rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) 1178 1179 /* The following is a workaround for MSVC toolchain; inline assembler is not supported */ 1180 1181 /* The following section is a template to generate code for GeneratedJITStubs_MSVC.asm */ 1182 /* The pattern "#xxx#" will be replaced with "xxx" */ 1183 1184 /* 1185 MSVC_BEGIN( AREA Trampoline, CODE) 1186 MSVC_BEGIN() 1187 MSVC_BEGIN( EXPORT ctiTrampoline) 1188 MSVC_BEGIN( EXPORT ctiVMThrowTrampoline) 1189 MSVC_BEGIN( EXPORT ctiOpThrowNotCaught) 1190 MSVC_BEGIN() 1191 MSVC_BEGIN(ctiTrampoline PROC) 1192 MSVC_BEGIN( stmdb sp!, {r1-r3}) 1193 MSVC_BEGIN( stmdb sp!, {r4-r8, lr}) 1194 MSVC_BEGIN( sub sp, sp, #68 ; sync with PRESERVEDR4_OFFSET) 1195 MSVC_BEGIN( mov r4, r2) 1196 MSVC_BEGIN( mov r5, #512) 1197 MSVC_BEGIN( ; r0 contains the code) 1198 MSVC_BEGIN( mov lr, pc) 1199 MSVC_BEGIN( bx r0) 1200 MSVC_BEGIN( add sp, sp, #68 ; sync with PRESERVEDR4_OFFSET) 1201 MSVC_BEGIN( ldmia sp!, {r4-r8, lr}) 1202 MSVC_BEGIN( add sp, sp, #12) 1203 MSVC_BEGIN( bx lr) 1204 MSVC_BEGIN(ctiTrampoline ENDP) 1205 MSVC_BEGIN() 1206 MSVC_BEGIN(ctiVMThrowTrampoline PROC) 1207 MSVC_BEGIN( mov r0, sp) 1208 MSVC_BEGIN( mov lr, pc) 1209 MSVC_BEGIN( bl cti_vm_throw) 1210 MSVC_BEGIN(ctiOpThrowNotCaught) 1211 MSVC_BEGIN( add sp, sp, #68 ; sync with PRESERVEDR4_OFFSET) 1212 MSVC_BEGIN( ldmia sp!, {r4-r8, lr}) 1213 MSVC_BEGIN( add sp, sp, #12) 1214 MSVC_BEGIN( bx lr) 1215 MSVC_BEGIN(ctiVMThrowTrampoline ENDP) 1216 MSVC_BEGIN() 1217 1218 MSVC( EXPORT cti_#op#) 1219 MSVC( IMPORT JITStubThunked_#op#) 1220 MSVC(cti_#op# PROC) 1221 MSVC( str lr, [sp, #64] ; sync with THUNK_RETURN_ADDRESS_OFFSET) 1222 MSVC( bl JITStubThunked_#op#) 1223 MSVC( ldr lr, [sp, #64] ; sync with THUNK_RETURN_ADDRESS_OFFSET) 1224 MSVC( bx lr) 1225 MSVC(cti_#op# ENDP) 1226 MSVC() 1227 1228 MSVC_END( END) 1229 */ 1230 1231 #elif CPU(SH4) 1232 #define DEFINE_STUB_FUNCTION(rtype, op) \ 1233 extern "C" { \ 1234 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ 1235 }; \ 1236 asm volatile( \ 1237 ".align 2" "\n" \ 1238 ".globl " SYMBOL_STRING(cti_##op) "\n" \ 1239 SYMBOL_STRING(cti_##op) ":" "\n" \ 1240 "sts pr, r11" "\n" \ 1241 "mov.l r11, @(0x38, r15)" "\n" \ 1242 "mov.l .L2"SYMBOL_STRING(JITStubThunked_##op)",r0" "\n" \ 1243 "mov.l @(r0,r12),r11" "\n" \ 1244 "jsr @r11" "\n" \ 1245 "nop" "\n" \ 1246 "mov.l @(0x38, r15), r11 " "\n" \ 1247 "lds r11, pr " "\n" \ 1248 "rts" "\n" \ 1249 "nop" "\n" \ 1250 ".align 2" "\n" \ 1251 ".L2"SYMBOL_STRING(JITStubThunked_##op)":.long " SYMBOL_STRING(JITStubThunked_##op)"@GOT \n" \ 1252 ); \ 1253 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) 1254 #else 1255 #define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION) 1256 #endif 1257 1258 DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_this) 1259 { 1260 STUB_INIT_STACK_FRAME(stackFrame); 1261 CallFrame* callFrame = stackFrame.callFrame; 1262 1263 JSFunction* constructor = asFunction(callFrame->callee()); 1264 #if !ASSERT_DISABLED 1265 ConstructData constructData; 1266 ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS); 1267 #endif 1268 1269 Structure* structure; 1270 JSValue proto = stackFrame.args[0].jsValue(); 1271 if (proto.isObject()) 1272 structure = asObject(proto)->inheritorID(*stackFrame.globalData); 1273 else 1274 structure = constructor->scope()->globalObject->emptyObjectStructure(); 1275 JSValue result = constructEmptyObject(callFrame, structure); 1276 1277 return JSValue::encode(result); 1278 } 1279 1280 DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this) 1281 { 1282 STUB_INIT_STACK_FRAME(stackFrame); 1283 1284 JSValue v1 = stackFrame.args[0].jsValue(); 1285 CallFrame* callFrame = stackFrame.callFrame; 1286 1287 JSObject* result = v1.toThisObject(callFrame); 1288 CHECK_FOR_EXCEPTION_AT_END(); 1289 return JSValue::encode(result); 1290 } 1291 1292 DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this_strict) 1293 { 1294 STUB_INIT_STACK_FRAME(stackFrame); 1295 1296 JSValue v1 = stackFrame.args[0].jsValue(); 1297 CallFrame* callFrame = stackFrame.callFrame; 1298 ASSERT(v1.asCell()->structure()->typeInfo().needsThisConversion()); 1299 JSValue result = v1.toStrictThisObject(callFrame); 1300 CHECK_FOR_EXCEPTION_AT_END(); 1301 return JSValue::encode(result); 1302 } 1303 1304 DEFINE_STUB_FUNCTION(EncodedJSValue, op_add) 1305 { 1306 STUB_INIT_STACK_FRAME(stackFrame); 1307 1308 JSValue v1 = stackFrame.args[0].jsValue(); 1309 JSValue v2 = stackFrame.args[1].jsValue(); 1310 CallFrame* callFrame = stackFrame.callFrame; 1311 1312 if (v1.isString()) { 1313 JSValue result = v2.isString() 1314 ? jsString(callFrame, asString(v1), asString(v2)) 1315 : jsString(callFrame, asString(v1), v2.toPrimitiveString(callFrame)); 1316 CHECK_FOR_EXCEPTION_AT_END(); 1317 return JSValue::encode(result); 1318 } 1319 1320 double left = 0.0, right; 1321 if (v1.getNumber(left) && v2.getNumber(right)) 1322 return JSValue::encode(jsNumber(left + right)); 1323 1324 // All other cases are pretty uncommon 1325 JSValue result = jsAddSlowCase(callFrame, v1, v2); 1326 CHECK_FOR_EXCEPTION_AT_END(); 1327 return JSValue::encode(result); 1328 } 1329 1330 DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_inc) 1331 { 1332 STUB_INIT_STACK_FRAME(stackFrame); 1333 1334 JSValue v = stackFrame.args[0].jsValue(); 1335 1336 CallFrame* callFrame = stackFrame.callFrame; 1337 JSValue result = jsNumber(v.toNumber(callFrame) + 1); 1338 CHECK_FOR_EXCEPTION_AT_END(); 1339 return JSValue::encode(result); 1340 } 1341 1342 DEFINE_STUB_FUNCTION(int, timeout_check) 1343 { 1344 STUB_INIT_STACK_FRAME(stackFrame); 1345 1346 JSGlobalData* globalData = stackFrame.globalData; 1347 TimeoutChecker& timeoutChecker = globalData->timeoutChecker; 1348 1349 if (globalData->terminator.shouldTerminate()) { 1350 globalData->exception = createTerminatedExecutionException(globalData); 1351 VM_THROW_EXCEPTION_AT_END(); 1352 } else if (timeoutChecker.didTimeOut(stackFrame.callFrame)) { 1353 globalData->exception = createInterruptedExecutionException(globalData); 1354 VM_THROW_EXCEPTION_AT_END(); 1355 } 1356 1357 return timeoutChecker.ticksUntilNextCheck(); 1358 } 1359 1360 DEFINE_STUB_FUNCTION(void*, register_file_check) 1361 { 1362 STUB_INIT_STACK_FRAME(stackFrame); 1363 CallFrame* callFrame = stackFrame.callFrame; 1364 1365 if (UNLIKELY(!stackFrame.registerFile->grow(&callFrame->registers()[callFrame->codeBlock()->m_numCalleeRegisters]))) { 1366 // Rewind to the previous call frame because op_call already optimistically 1367 // moved the call frame forward. 1368 CallFrame* oldCallFrame = callFrame->callerFrame(); 1369 ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), ReturnAddressPtr(callFrame->returnPC())); 1370 STUB_SET_RETURN_ADDRESS(handler.catchRoutine); 1371 callFrame = handler.callFrame; 1372 } 1373 1374 return callFrame; 1375 } 1376 1377 DEFINE_STUB_FUNCTION(int, op_loop_if_lesseq) 1378 { 1379 STUB_INIT_STACK_FRAME(stackFrame); 1380 1381 JSValue src1 = stackFrame.args[0].jsValue(); 1382 JSValue src2 = stackFrame.args[1].jsValue(); 1383 CallFrame* callFrame = stackFrame.callFrame; 1384 1385 bool result = jsLessEq(callFrame, src1, src2); 1386 CHECK_FOR_EXCEPTION_AT_END(); 1387 return result; 1388 } 1389 1390 DEFINE_STUB_FUNCTION(JSObject*, op_new_object) 1391 { 1392 STUB_INIT_STACK_FRAME(stackFrame); 1393 1394 return constructEmptyObject(stackFrame.callFrame); 1395 } 1396 1397 DEFINE_STUB_FUNCTION(void, op_put_by_id_generic) 1398 { 1399 STUB_INIT_STACK_FRAME(stackFrame); 1400 1401 PutPropertySlot slot(stackFrame.callFrame->codeBlock()->isStrictMode()); 1402 stackFrame.args[0].jsValue().put(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot); 1403 CHECK_FOR_EXCEPTION_AT_END(); 1404 } 1405 1406 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_generic) 1407 { 1408 STUB_INIT_STACK_FRAME(stackFrame); 1409 1410 PutPropertySlot slot(stackFrame.callFrame->codeBlock()->isStrictMode()); 1411 stackFrame.args[0].jsValue().putDirect(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot); 1412 CHECK_FOR_EXCEPTION_AT_END(); 1413 } 1414 1415 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_generic) 1416 { 1417 STUB_INIT_STACK_FRAME(stackFrame); 1418 1419 CallFrame* callFrame = stackFrame.callFrame; 1420 Identifier& ident = stackFrame.args[1].identifier(); 1421 1422 JSValue baseValue = stackFrame.args[0].jsValue(); 1423 PropertySlot slot(baseValue); 1424 JSValue result = baseValue.get(callFrame, ident, slot); 1425 1426 CHECK_FOR_EXCEPTION_AT_END(); 1427 return JSValue::encode(result); 1428 } 1429 1430 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 1431 1432 DEFINE_STUB_FUNCTION(void, op_put_by_id) 1433 { 1434 STUB_INIT_STACK_FRAME(stackFrame); 1435 CallFrame* callFrame = stackFrame.callFrame; 1436 Identifier& ident = stackFrame.args[1].identifier(); 1437 1438 PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); 1439 stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot); 1440 1441 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); 1442 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); 1443 if (!stubInfo->seenOnce()) 1444 stubInfo->setSeen(); 1445 else 1446 JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, false); 1447 1448 CHECK_FOR_EXCEPTION_AT_END(); 1449 } 1450 1451 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct) 1452 { 1453 STUB_INIT_STACK_FRAME(stackFrame); 1454 CallFrame* callFrame = stackFrame.callFrame; 1455 Identifier& ident = stackFrame.args[1].identifier(); 1456 1457 PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); 1458 stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot); 1459 1460 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); 1461 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); 1462 if (!stubInfo->seenOnce()) 1463 stubInfo->setSeen(); 1464 else 1465 JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, true); 1466 1467 CHECK_FOR_EXCEPTION_AT_END(); 1468 } 1469 1470 DEFINE_STUB_FUNCTION(void, op_put_by_id_fail) 1471 { 1472 STUB_INIT_STACK_FRAME(stackFrame); 1473 1474 CallFrame* callFrame = stackFrame.callFrame; 1475 Identifier& ident = stackFrame.args[1].identifier(); 1476 1477 PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); 1478 stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot); 1479 1480 CHECK_FOR_EXCEPTION_AT_END(); 1481 } 1482 1483 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_fail) 1484 { 1485 STUB_INIT_STACK_FRAME(stackFrame); 1486 1487 CallFrame* callFrame = stackFrame.callFrame; 1488 Identifier& ident = stackFrame.args[1].identifier(); 1489 1490 PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); 1491 stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot); 1492 1493 CHECK_FOR_EXCEPTION_AT_END(); 1494 } 1495 1496 DEFINE_STUB_FUNCTION(JSObject*, op_put_by_id_transition_realloc) 1497 { 1498 STUB_INIT_STACK_FRAME(stackFrame); 1499 1500 JSValue baseValue = stackFrame.args[0].jsValue(); 1501 int32_t oldSize = stackFrame.args[3].int32(); 1502 int32_t newSize = stackFrame.args[4].int32(); 1503 1504 ASSERT(baseValue.isObject()); 1505 JSObject* base = asObject(baseValue); 1506 base->allocatePropertyStorage(oldSize, newSize); 1507 1508 return base; 1509 } 1510 1511 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) 1512 { 1513 STUB_INIT_STACK_FRAME(stackFrame); 1514 1515 CallFrame* callFrame = stackFrame.callFrame; 1516 Identifier& ident = stackFrame.args[1].identifier(); 1517 1518 JSValue baseValue = stackFrame.args[0].jsValue(); 1519 PropertySlot slot(baseValue); 1520 JSValue result = baseValue.get(callFrame, ident, slot); 1521 CHECK_FOR_EXCEPTION(); 1522 1523 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); 1524 MethodCallLinkInfo& methodCallLinkInfo = codeBlock->getMethodCallLinkInfo(STUB_RETURN_ADDRESS); 1525 1526 if (!methodCallLinkInfo.seenOnce()) { 1527 methodCallLinkInfo.setSeen(); 1528 return JSValue::encode(result); 1529 } 1530 1531 // If we successfully got something, then the base from which it is being accessed must 1532 // be an object. (Assertion to ensure asObject() call below is safe, which comes after 1533 // an isCacheable() chceck. 1534 ASSERT(!slot.isCacheableValue() || slot.slotBase().isObject()); 1535 1536 // Check that: 1537 // * We're dealing with a JSCell, 1538 // * the property is cachable, 1539 // * it's not a dictionary 1540 // * there is a function cached. 1541 Structure* structure; 1542 JSCell* specific; 1543 JSObject* slotBaseObject; 1544 if (baseValue.isCell() 1545 && slot.isCacheableValue() 1546 && !(structure = baseValue.asCell()->structure())->isUncacheableDictionary() 1547 && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific) 1548 && specific 1549 ) { 1550 1551 JSFunction* callee = (JSFunction*)specific; 1552 1553 // Since we're accessing a prototype in a loop, it's a good bet that it 1554 // should not be treated as a dictionary. 1555 if (slotBaseObject->structure()->isDictionary()) 1556 slotBaseObject->flattenDictionaryObject(callFrame->globalData()); 1557 1558 // The result fetched should always be the callee! 1559 ASSERT(result == JSValue(callee)); 1560 1561 // Check to see if the function is on the object's prototype. Patch up the code to optimize. 1562 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { 1563 JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, callee, structure, slotBaseObject, STUB_RETURN_ADDRESS); 1564 return JSValue::encode(result); 1565 } 1566 1567 // Check to see if the function is on the object itself. 1568 // Since we generate the method-check to check both the structure and a prototype-structure (since this 1569 // is the common case) we have a problem - we need to patch the prototype structure check to do something 1570 // useful. We could try to nop it out altogether, but that's a little messy, so lets do something simpler 1571 // for now. For now it performs a check on a special object on the global object only used for this 1572 // purpose. The object is in no way exposed, and as such the check will always pass. 1573 if (slot.slotBase() == baseValue) { 1574 JIT::patchMethodCallProto(callFrame->globalData(), codeBlock, methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject->methodCallDummy(), STUB_RETURN_ADDRESS); 1575 return JSValue::encode(result); 1576 } 1577 } 1578 1579 // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to. 1580 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id)); 1581 return JSValue::encode(result); 1582 } 1583 1584 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id) 1585 { 1586 STUB_INIT_STACK_FRAME(stackFrame); 1587 CallFrame* callFrame = stackFrame.callFrame; 1588 Identifier& ident = stackFrame.args[1].identifier(); 1589 1590 JSValue baseValue = stackFrame.args[0].jsValue(); 1591 PropertySlot slot(baseValue); 1592 JSValue result = baseValue.get(callFrame, ident, slot); 1593 1594 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock(); 1595 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); 1596 if (!stubInfo->seenOnce()) 1597 stubInfo->setSeen(); 1598 else 1599 JITThunks::tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo); 1600 1601 CHECK_FOR_EXCEPTION_AT_END(); 1602 return JSValue::encode(result); 1603 } 1604 1605 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail) 1606 { 1607 STUB_INIT_STACK_FRAME(stackFrame); 1608 1609 CallFrame* callFrame = stackFrame.callFrame; 1610 Identifier& ident = stackFrame.args[1].identifier(); 1611 1612 JSValue baseValue = stackFrame.args[0].jsValue(); 1613 PropertySlot slot(baseValue); 1614 JSValue result = baseValue.get(callFrame, ident, slot); 1615 1616 CHECK_FOR_EXCEPTION(); 1617 1618 if (baseValue.isCell() 1619 && slot.isCacheable() 1620 && !baseValue.asCell()->structure()->isUncacheableDictionary() 1621 && slot.slotBase() == baseValue) { 1622 1623 CodeBlock* codeBlock = callFrame->codeBlock(); 1624 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); 1625 1626 ASSERT(slot.slotBase().isObject()); 1627 1628 PolymorphicAccessStructureList* polymorphicStructureList; 1629 int listIndex = 1; 1630 1631 if (stubInfo->accessType == access_get_by_id_self) { 1632 ASSERT(!stubInfo->stubRoutine); 1633 polymorphicStructureList = new PolymorphicAccessStructureList(callFrame->globalData(), codeBlock->ownerExecutable(), CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure.get()); 1634 stubInfo->initGetByIdSelfList(polymorphicStructureList, 1); 1635 } else { 1636 polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList; 1637 listIndex = stubInfo->u.getByIdSelfList.listSize; 1638 } 1639 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { 1640 stubInfo->u.getByIdSelfList.listSize++; 1641 JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, baseValue.asCell()->structure(), ident, slot, slot.cachedOffset()); 1642 1643 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) 1644 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); 1645 } 1646 } else 1647 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic)); 1648 return JSValue::encode(result); 1649 } 1650 1651 static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(JSGlobalData& globalData, ScriptExecutable* owner, StructureStubInfo* stubInfo, int& listIndex) 1652 { 1653 PolymorphicAccessStructureList* prototypeStructureList = 0; 1654 listIndex = 1; 1655 1656 switch (stubInfo->accessType) { 1657 case access_get_by_id_proto: 1658 prototypeStructureList = new PolymorphicAccessStructureList(globalData, owner, stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure.get(), stubInfo->u.getByIdProto.prototypeStructure.get()); 1659 stubInfo->stubRoutine = CodeLocationLabel(); 1660 stubInfo->initGetByIdProtoList(prototypeStructureList, 2); 1661 break; 1662 case access_get_by_id_chain: 1663 prototypeStructureList = new PolymorphicAccessStructureList(globalData, owner, stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure.get(), stubInfo->u.getByIdChain.chain.get()); 1664 stubInfo->stubRoutine = CodeLocationLabel(); 1665 stubInfo->initGetByIdProtoList(prototypeStructureList, 2); 1666 break; 1667 case access_get_by_id_proto_list: 1668 prototypeStructureList = stubInfo->u.getByIdProtoList.structureList; 1669 listIndex = stubInfo->u.getByIdProtoList.listSize; 1670 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) 1671 stubInfo->u.getByIdProtoList.listSize++; 1672 break; 1673 default: 1674 ASSERT_NOT_REACHED(); 1675 } 1676 1677 ASSERT(listIndex <= POLYMORPHIC_LIST_CACHE_SIZE); 1678 return prototypeStructureList; 1679 } 1680 1681 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_getter_stub) 1682 { 1683 STUB_INIT_STACK_FRAME(stackFrame); 1684 CallFrame* callFrame = stackFrame.callFrame; 1685 GetterSetter* getterSetter = asGetterSetter(stackFrame.args[0].jsObject()); 1686 if (!getterSetter->getter()) 1687 return JSValue::encode(jsUndefined()); 1688 JSObject* getter = asObject(getterSetter->getter()); 1689 CallData callData; 1690 CallType callType = getter->getCallData(callData); 1691 JSValue result = call(callFrame, getter, callType, callData, stackFrame.args[1].jsObject(), ArgList()); 1692 if (callFrame->hadException()) 1693 returnToThrowTrampoline(&callFrame->globalData(), stackFrame.args[2].returnAddress(), STUB_RETURN_ADDRESS); 1694 1695 return JSValue::encode(result); 1696 } 1697 1698 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_custom_stub) 1699 { 1700 STUB_INIT_STACK_FRAME(stackFrame); 1701 CallFrame* callFrame = stackFrame.callFrame; 1702 JSObject* slotBase = stackFrame.args[0].jsObject(); 1703 PropertySlot::GetValueFunc getter = reinterpret_cast<PropertySlot::GetValueFunc>(stackFrame.args[1].asPointer); 1704 const Identifier& ident = stackFrame.args[2].identifier(); 1705 JSValue result = getter(callFrame, slotBase, ident); 1706 if (callFrame->hadException()) 1707 returnToThrowTrampoline(&callFrame->globalData(), stackFrame.args[3].returnAddress(), STUB_RETURN_ADDRESS); 1708 1709 return JSValue::encode(result); 1710 } 1711 1712 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) 1713 { 1714 STUB_INIT_STACK_FRAME(stackFrame); 1715 1716 CallFrame* callFrame = stackFrame.callFrame; 1717 const Identifier& propertyName = stackFrame.args[1].identifier(); 1718 1719 JSValue baseValue = stackFrame.args[0].jsValue(); 1720 PropertySlot slot(baseValue); 1721 JSValue result = baseValue.get(callFrame, propertyName, slot); 1722 1723 CHECK_FOR_EXCEPTION(); 1724 1725 if (!baseValue.isCell() || !slot.isCacheable() || baseValue.asCell()->structure()->isDictionary()) { 1726 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); 1727 return JSValue::encode(result); 1728 } 1729 1730 Structure* structure = baseValue.asCell()->structure(); 1731 CodeBlock* codeBlock = callFrame->codeBlock(); 1732 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS); 1733 1734 ASSERT(slot.slotBase().isObject()); 1735 JSObject* slotBaseObject = asObject(slot.slotBase()); 1736 1737 size_t offset = slot.cachedOffset(); 1738 1739 if (slot.slotBase() == baseValue) 1740 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); 1741 else if (slot.slotBase() == baseValue.asCell()->structure()->prototypeForLookup(callFrame)) { 1742 ASSERT(!baseValue.asCell()->structure()->isDictionary()); 1743 // Since we're accessing a prototype in a loop, it's a good bet that it 1744 // should not be treated as a dictionary. 1745 if (slotBaseObject->structure()->isDictionary()) { 1746 slotBaseObject->flattenDictionaryObject(callFrame->globalData()); 1747 offset = slotBaseObject->structure()->get(callFrame->globalData(), propertyName); 1748 } 1749 1750 int listIndex; 1751 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(callFrame->globalData(), codeBlock->ownerExecutable(), stubInfo, listIndex); 1752 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { 1753 JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), propertyName, slot, offset); 1754 1755 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) 1756 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); 1757 } 1758 } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) { 1759 ASSERT(!baseValue.asCell()->structure()->isDictionary()); 1760 int listIndex; 1761 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(callFrame->globalData(), codeBlock->ownerExecutable(), stubInfo, listIndex); 1762 1763 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) { 1764 StructureChain* protoChain = structure->prototypeChain(callFrame); 1765 JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, propertyName, slot, offset); 1766 1767 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) 1768 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); 1769 } 1770 } else 1771 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); 1772 1773 return JSValue::encode(result); 1774 } 1775 1776 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list_full) 1777 { 1778 STUB_INIT_STACK_FRAME(stackFrame); 1779 1780 JSValue baseValue = stackFrame.args[0].jsValue(); 1781 PropertySlot slot(baseValue); 1782 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot); 1783 1784 CHECK_FOR_EXCEPTION_AT_END(); 1785 return JSValue::encode(result); 1786 } 1787 1788 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_fail) 1789 { 1790 STUB_INIT_STACK_FRAME(stackFrame); 1791 1792 JSValue baseValue = stackFrame.args[0].jsValue(); 1793 PropertySlot slot(baseValue); 1794 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot); 1795 1796 CHECK_FOR_EXCEPTION_AT_END(); 1797 return JSValue::encode(result); 1798 } 1799 1800 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_array_fail) 1801 { 1802 STUB_INIT_STACK_FRAME(stackFrame); 1803 1804 JSValue baseValue = stackFrame.args[0].jsValue(); 1805 PropertySlot slot(baseValue); 1806 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot); 1807 1808 CHECK_FOR_EXCEPTION_AT_END(); 1809 return JSValue::encode(result); 1810 } 1811 1812 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_string_fail) 1813 { 1814 STUB_INIT_STACK_FRAME(stackFrame); 1815 1816 JSValue baseValue = stackFrame.args[0].jsValue(); 1817 PropertySlot slot(baseValue); 1818 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot); 1819 1820 CHECK_FOR_EXCEPTION_AT_END(); 1821 return JSValue::encode(result); 1822 } 1823 1824 #endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 1825 1826 DEFINE_STUB_FUNCTION(void, op_check_has_instance) 1827 { 1828 STUB_INIT_STACK_FRAME(stackFrame); 1829 1830 CallFrame* callFrame = stackFrame.callFrame; 1831 JSValue baseVal = stackFrame.args[0].jsValue(); 1832 1833 // ECMA-262 15.3.5.3: 1834 // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function). 1835 #ifndef NDEBUG 1836 TypeInfo typeInfo(UnspecifiedType); 1837 ASSERT(!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()); 1838 #endif 1839 stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal); 1840 VM_THROW_EXCEPTION_AT_END(); 1841 } 1842 1843 DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof) 1844 { 1845 STUB_INIT_STACK_FRAME(stackFrame); 1846 1847 CallFrame* callFrame = stackFrame.callFrame; 1848 JSValue value = stackFrame.args[0].jsValue(); 1849 JSValue baseVal = stackFrame.args[1].jsValue(); 1850 JSValue proto = stackFrame.args[2].jsValue(); 1851 1852 // At least one of these checks must have failed to get to the slow case. 1853 ASSERT(!value.isCell() || !baseVal.isCell() || !proto.isCell() 1854 || !value.isObject() || !baseVal.isObject() || !proto.isObject() 1855 || (asObject(baseVal)->structure()->typeInfo().flags() & (ImplementsHasInstance | OverridesHasInstance)) != ImplementsHasInstance); 1856 1857 1858 // ECMA-262 15.3.5.3: 1859 // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function). 1860 TypeInfo typeInfo(UnspecifiedType); 1861 if (!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()) { 1862 stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "instanceof", baseVal); 1863 VM_THROW_EXCEPTION(); 1864 } 1865 ASSERT(typeInfo.type() != UnspecifiedType); 1866 1867 if (!typeInfo.overridesHasInstance()) { 1868 if (!value.isObject()) 1869 return JSValue::encode(jsBoolean(false)); 1870 1871 if (!proto.isObject()) { 1872 throwError(callFrame, createTypeError(callFrame, "instanceof called on an object with an invalid prototype property.")); 1873 VM_THROW_EXCEPTION(); 1874 } 1875 } 1876 1877 JSValue result = jsBoolean(asObject(baseVal)->hasInstance(callFrame, value, proto)); 1878 CHECK_FOR_EXCEPTION_AT_END(); 1879 1880 return JSValue::encode(result); 1881 } 1882 1883 DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_id) 1884 { 1885 STUB_INIT_STACK_FRAME(stackFrame); 1886 1887 CallFrame* callFrame = stackFrame.callFrame; 1888 1889 JSObject* baseObj = stackFrame.args[0].jsValue().toObject(callFrame); 1890 1891 bool couldDelete = baseObj->deleteProperty(callFrame, stackFrame.args[1].identifier()); 1892 JSValue result = jsBoolean(couldDelete); 1893 if (!couldDelete && callFrame->codeBlock()->isStrictMode()) 1894 stackFrame.globalData->exception = createTypeError(stackFrame.callFrame, "Unable to delete property."); 1895 1896 CHECK_FOR_EXCEPTION_AT_END(); 1897 return JSValue::encode(result); 1898 } 1899 1900 DEFINE_STUB_FUNCTION(EncodedJSValue, op_mul) 1901 { 1902 STUB_INIT_STACK_FRAME(stackFrame); 1903 1904 JSValue src1 = stackFrame.args[0].jsValue(); 1905 JSValue src2 = stackFrame.args[1].jsValue(); 1906 1907 double left; 1908 double right; 1909 if (src1.getNumber(left) && src2.getNumber(right)) 1910 return JSValue::encode(jsNumber(left * right)); 1911 1912 CallFrame* callFrame = stackFrame.callFrame; 1913 JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame)); 1914 CHECK_FOR_EXCEPTION_AT_END(); 1915 return JSValue::encode(result); 1916 } 1917 1918 DEFINE_STUB_FUNCTION(JSObject*, op_new_func) 1919 { 1920 STUB_INIT_STACK_FRAME(stackFrame); 1921 1922 ASSERT(stackFrame.callFrame->codeBlock()->codeType() != FunctionCode || !stackFrame.callFrame->codeBlock()->needsFullScopeChain() || stackFrame.callFrame->uncheckedR(stackFrame.callFrame->codeBlock()->activationRegister()).jsValue()); 1923 return stackFrame.args[0].function()->make(stackFrame.callFrame, stackFrame.callFrame->scopeChain()); 1924 } 1925 1926 DEFINE_STUB_FUNCTION(void*, op_call_jitCompile) 1927 { 1928 STUB_INIT_STACK_FRAME(stackFrame); 1929 1930 #if !ASSERT_DISABLED 1931 CallData callData; 1932 ASSERT(stackFrame.callFrame->callee()->getCallData(callData) == CallTypeJS); 1933 #endif 1934 1935 JSFunction* function = asFunction(stackFrame.callFrame->callee()); 1936 ASSERT(!function->isHostFunction()); 1937 FunctionExecutable* executable = function->jsExecutable(); 1938 ScopeChainNode* callDataScopeChain = function->scope(); 1939 JSObject* error = executable->compileForCall(stackFrame.callFrame, callDataScopeChain); 1940 if (error) { 1941 stackFrame.callFrame->globalData().exception = error; 1942 return 0; 1943 } 1944 return function; 1945 } 1946 1947 DEFINE_STUB_FUNCTION(void*, op_construct_jitCompile) 1948 { 1949 STUB_INIT_STACK_FRAME(stackFrame); 1950 1951 #if !ASSERT_DISABLED 1952 ConstructData constructData; 1953 ASSERT(asFunction(stackFrame.callFrame->callee())->getConstructData(constructData) == ConstructTypeJS); 1954 #endif 1955 1956 JSFunction* function = asFunction(stackFrame.callFrame->callee()); 1957 ASSERT(!function->isHostFunction()); 1958 FunctionExecutable* executable = function->jsExecutable(); 1959 ScopeChainNode* callDataScopeChain = function->scope(); 1960 JSObject* error = executable->compileForConstruct(stackFrame.callFrame, callDataScopeChain); 1961 if (error) { 1962 stackFrame.callFrame->globalData().exception = error; 1963 return 0; 1964 } 1965 return function; 1966 } 1967 1968 DEFINE_STUB_FUNCTION(void*, op_call_arityCheck) 1969 { 1970 STUB_INIT_STACK_FRAME(stackFrame); 1971 1972 CallFrame* callFrame = stackFrame.callFrame; 1973 JSFunction* callee = asFunction(callFrame->callee()); 1974 ASSERT(!callee->isHostFunction()); 1975 CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForCall(); 1976 int argCount = callFrame->argumentCountIncludingThis(); 1977 ReturnAddressPtr pc = callFrame->returnPC(); 1978 1979 ASSERT(argCount != newCodeBlock->m_numParameters); 1980 1981 CallFrame* oldCallFrame = callFrame->callerFrame(); 1982 1983 Register* r; 1984 if (argCount > newCodeBlock->m_numParameters) { 1985 size_t numParameters = newCodeBlock->m_numParameters; 1986 r = callFrame->registers() + numParameters; 1987 Register* newEnd = r + newCodeBlock->m_numCalleeRegisters; 1988 if (!stackFrame.registerFile->grow(newEnd)) { 1989 // Rewind to the previous call frame because op_call already optimistically 1990 // moved the call frame forward. 1991 ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc); 1992 STUB_SET_RETURN_ADDRESS(handler.catchRoutine); 1993 return handler.callFrame; 1994 } 1995 1996 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount; 1997 for (size_t i = 0; i < numParameters; ++i) 1998 argv[i + argCount] = argv[i]; 1999 } else { 2000 size_t omittedArgCount = newCodeBlock->m_numParameters - argCount; 2001 r = callFrame->registers() + omittedArgCount; 2002 Register* newEnd = r + newCodeBlock->m_numCalleeRegisters; 2003 if (!stackFrame.registerFile->grow(newEnd)) { 2004 // Rewind to the previous call frame because op_call already optimistically 2005 // moved the call frame forward. 2006 ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc); 2007 STUB_SET_RETURN_ADDRESS(handler.catchRoutine); 2008 return handler.callFrame; 2009 } 2010 2011 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount; 2012 for (size_t i = 0; i < omittedArgCount; ++i) 2013 argv[i] = jsUndefined(); 2014 } 2015 2016 callFrame = CallFrame::create(r); 2017 callFrame->setCallerFrame(oldCallFrame); 2018 callFrame->setArgumentCountIncludingThis(argCount); 2019 callFrame->setCallee(callee); 2020 callFrame->setScopeChain(callee->scope()); 2021 callFrame->setReturnPC(pc.value()); 2022 2023 ASSERT((void*)callFrame <= stackFrame.registerFile->end()); 2024 return callFrame; 2025 } 2026 2027 DEFINE_STUB_FUNCTION(void*, op_construct_arityCheck) 2028 { 2029 STUB_INIT_STACK_FRAME(stackFrame); 2030 2031 CallFrame* callFrame = stackFrame.callFrame; 2032 JSFunction* callee = asFunction(callFrame->callee()); 2033 ASSERT(!callee->isHostFunction()); 2034 CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForConstruct(); 2035 int argCount = callFrame->argumentCountIncludingThis(); 2036 ReturnAddressPtr pc = callFrame->returnPC(); 2037 2038 ASSERT(argCount != newCodeBlock->m_numParameters); 2039 2040 CallFrame* oldCallFrame = callFrame->callerFrame(); 2041 2042 Register* r; 2043 if (argCount > newCodeBlock->m_numParameters) { 2044 size_t numParameters = newCodeBlock->m_numParameters; 2045 r = callFrame->registers() + numParameters; 2046 Register* newEnd = r + newCodeBlock->m_numCalleeRegisters; 2047 if (!stackFrame.registerFile->grow(newEnd)) { 2048 // Rewind to the previous call frame because op_call already optimistically 2049 // moved the call frame forward. 2050 ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc); 2051 STUB_SET_RETURN_ADDRESS(handler.catchRoutine); 2052 return handler.callFrame; 2053 } 2054 2055 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount; 2056 for (size_t i = 0; i < numParameters; ++i) 2057 argv[i + argCount] = argv[i]; 2058 } else { 2059 size_t omittedArgCount = newCodeBlock->m_numParameters - argCount; 2060 r = callFrame->registers() + omittedArgCount; 2061 Register* newEnd = r + newCodeBlock->m_numCalleeRegisters; 2062 if (!stackFrame.registerFile->grow(newEnd)) { 2063 // Rewind to the previous call frame because op_call already optimistically 2064 // moved the call frame forward. 2065 ExceptionHandler handler = jitThrow(stackFrame.globalData, oldCallFrame, createStackOverflowError(oldCallFrame), pc); 2066 STUB_SET_RETURN_ADDRESS(handler.catchRoutine); 2067 return handler.callFrame; 2068 } 2069 2070 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount; 2071 for (size_t i = 0; i < omittedArgCount; ++i) 2072 argv[i] = jsUndefined(); 2073 } 2074 2075 callFrame = CallFrame::create(r); 2076 callFrame->setCallerFrame(oldCallFrame); 2077 callFrame->setArgumentCountIncludingThis(argCount); 2078 callFrame->setCallee(callee); 2079 callFrame->setScopeChain(callee->scope()); 2080 callFrame->setReturnPC(pc.value()); 2081 2082 ASSERT((void*)callFrame <= stackFrame.registerFile->end()); 2083 return callFrame; 2084 } 2085 2086 #if ENABLE(JIT_OPTIMIZE_CALL) 2087 DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall) 2088 { 2089 STUB_INIT_STACK_FRAME(stackFrame); 2090 CallFrame* callFrame = stackFrame.callFrame; 2091 JSFunction* callee = asFunction(callFrame->callee()); 2092 ExecutableBase* executable = callee->executable(); 2093 2094 MacroAssemblerCodePtr codePtr; 2095 CodeBlock* codeBlock = 0; 2096 if (executable->isHostFunction()) 2097 codePtr = executable->generatedJITCodeForCall().addressForCall(); 2098 else { 2099 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); 2100 JSObject* error = functionExecutable->compileForCall(callFrame, callee->scope()); 2101 if (error) { 2102 callFrame->globalData().exception = createStackOverflowError(callFrame); 2103 return 0; 2104 } 2105 codeBlock = &functionExecutable->generatedBytecodeForCall(); 2106 if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters)) 2107 codePtr = functionExecutable->generatedJITCodeForCall().addressForCall(); 2108 else 2109 codePtr = functionExecutable->generatedJITCodeForCallWithArityCheck(); 2110 } 2111 CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC()); 2112 2113 if (!callLinkInfo->seenOnce()) 2114 callLinkInfo->setSeen(); 2115 else 2116 JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCountIncludingThis(), stackFrame.globalData); 2117 2118 return codePtr.executableAddress(); 2119 } 2120 2121 DEFINE_STUB_FUNCTION(void*, vm_lazyLinkConstruct) 2122 { 2123 STUB_INIT_STACK_FRAME(stackFrame); 2124 CallFrame* callFrame = stackFrame.callFrame; 2125 JSFunction* callee = asFunction(callFrame->callee()); 2126 ExecutableBase* executable = callee->executable(); 2127 2128 MacroAssemblerCodePtr codePtr; 2129 CodeBlock* codeBlock = 0; 2130 if (executable->isHostFunction()) 2131 codePtr = executable->generatedJITCodeForConstruct().addressForCall(); 2132 else { 2133 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); 2134 JSObject* error = functionExecutable->compileForConstruct(callFrame, callee->scope()); 2135 if (error) { 2136 throwStackOverflowError(callFrame, stackFrame.globalData, ReturnAddressPtr(callFrame->returnPC()), STUB_RETURN_ADDRESS); 2137 return 0; 2138 } 2139 codeBlock = &functionExecutable->generatedBytecodeForConstruct(); 2140 if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters)) 2141 codePtr = functionExecutable->generatedJITCodeForConstruct().addressForCall(); 2142 else 2143 codePtr = functionExecutable->generatedJITCodeForConstructWithArityCheck(); 2144 } 2145 CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC()); 2146 2147 if (!callLinkInfo->seenOnce()) 2148 callLinkInfo->setSeen(); 2149 else 2150 JIT::linkConstruct(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCountIncludingThis(), stackFrame.globalData); 2151 2152 return codePtr.executableAddress(); 2153 } 2154 #endif // !ENABLE(JIT_OPTIMIZE_CALL) 2155 2156 DEFINE_STUB_FUNCTION(JSObject*, op_push_activation) 2157 { 2158 STUB_INIT_STACK_FRAME(stackFrame); 2159 2160 JSActivation* activation = new (stackFrame.globalData) JSActivation(stackFrame.callFrame, static_cast<FunctionExecutable*>(stackFrame.callFrame->codeBlock()->ownerExecutable())); 2161 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->push(activation)); 2162 return activation; 2163 } 2164 2165 DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction) 2166 { 2167 STUB_INIT_STACK_FRAME(stackFrame); 2168 2169 JSValue funcVal = stackFrame.args[0].jsValue(); 2170 2171 CallData callData; 2172 CallType callType = getCallData(funcVal, callData); 2173 2174 ASSERT(callType != CallTypeJS); 2175 2176 if (callType == CallTypeHost) { 2177 int registerOffset = stackFrame.args[1].int32(); 2178 int argCount = stackFrame.args[2].int32(); 2179 CallFrame* previousCallFrame = stackFrame.callFrame; 2180 CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset); 2181 if (!stackFrame.registerFile->grow(callFrame->registers())) { 2182 throwStackOverflowError(previousCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS); 2183 VM_THROW_EXCEPTION(); 2184 } 2185 2186 callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(funcVal)); 2187 2188 EncodedJSValue returnValue; 2189 { 2190 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER); 2191 returnValue = callData.native.function(callFrame); 2192 } 2193 2194 CHECK_FOR_EXCEPTION_AT_END(); 2195 return returnValue; 2196 } 2197 2198 ASSERT(callType == CallTypeNone); 2199 2200 stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal); 2201 VM_THROW_EXCEPTION(); 2202 } 2203 2204 DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments) 2205 { 2206 STUB_INIT_STACK_FRAME(stackFrame); 2207 2208 Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame); 2209 return JSValue::encode(JSValue(arguments)); 2210 } 2211 2212 DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments_no_params) 2213 { 2214 STUB_INIT_STACK_FRAME(stackFrame); 2215 2216 Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame, Arguments::NoParameters); 2217 return JSValue::encode(JSValue(arguments)); 2218 } 2219 2220 DEFINE_STUB_FUNCTION(void, op_tear_off_activation) 2221 { 2222 STUB_INIT_STACK_FRAME(stackFrame); 2223 2224 ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain()); 2225 JSValue activationValue = stackFrame.args[0].jsValue(); 2226 if (!activationValue) { 2227 if (JSValue v = stackFrame.args[1].jsValue()) { 2228 if (!stackFrame.callFrame->codeBlock()->isStrictMode()) 2229 asArguments(v)->copyRegisters(*stackFrame.globalData); 2230 } 2231 return; 2232 } 2233 JSActivation* activation = asActivation(stackFrame.args[0].jsValue()); 2234 activation->copyRegisters(*stackFrame.globalData); 2235 if (JSValue v = stackFrame.args[1].jsValue()) { 2236 if (!stackFrame.callFrame->codeBlock()->isStrictMode()) 2237 asArguments(v)->setActivation(*stackFrame.globalData, activation); 2238 } 2239 } 2240 2241 DEFINE_STUB_FUNCTION(void, op_tear_off_arguments) 2242 { 2243 STUB_INIT_STACK_FRAME(stackFrame); 2244 2245 ASSERT(stackFrame.callFrame->codeBlock()->usesArguments() && !stackFrame.callFrame->codeBlock()->needsFullScopeChain()); 2246 asArguments(stackFrame.args[0].jsValue())->copyRegisters(*stackFrame.globalData); 2247 } 2248 2249 DEFINE_STUB_FUNCTION(void, op_profile_will_call) 2250 { 2251 STUB_INIT_STACK_FRAME(stackFrame); 2252 2253 ASSERT(*stackFrame.enabledProfilerReference); 2254 (*stackFrame.enabledProfilerReference)->willExecute(stackFrame.callFrame, stackFrame.args[0].jsValue()); 2255 } 2256 2257 DEFINE_STUB_FUNCTION(void, op_profile_did_call) 2258 { 2259 STUB_INIT_STACK_FRAME(stackFrame); 2260 2261 ASSERT(*stackFrame.enabledProfilerReference); 2262 (*stackFrame.enabledProfilerReference)->didExecute(stackFrame.callFrame, stackFrame.args[0].jsValue()); 2263 } 2264 2265 DEFINE_STUB_FUNCTION(JSObject*, op_new_array) 2266 { 2267 STUB_INIT_STACK_FRAME(stackFrame); 2268 2269 ArgList argList(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32()); 2270 return constructArray(stackFrame.callFrame, argList); 2271 } 2272 2273 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve) 2274 { 2275 STUB_INIT_STACK_FRAME(stackFrame); 2276 2277 CallFrame* callFrame = stackFrame.callFrame; 2278 ScopeChainNode* scopeChain = callFrame->scopeChain(); 2279 2280 ScopeChainIterator iter = scopeChain->begin(); 2281 ScopeChainIterator end = scopeChain->end(); 2282 ASSERT(iter != end); 2283 2284 Identifier& ident = stackFrame.args[0].identifier(); 2285 do { 2286 JSObject* o = iter->get(); 2287 PropertySlot slot(o); 2288 if (o->getPropertySlot(callFrame, ident, slot)) { 2289 JSValue result = slot.getValue(callFrame, ident); 2290 CHECK_FOR_EXCEPTION_AT_END(); 2291 return JSValue::encode(result); 2292 } 2293 } while (++iter != end); 2294 2295 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); 2296 VM_THROW_EXCEPTION(); 2297 } 2298 2299 DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct) 2300 { 2301 STUB_INIT_STACK_FRAME(stackFrame); 2302 2303 JSValue constrVal = stackFrame.args[0].jsValue(); 2304 2305 ConstructData constructData; 2306 ConstructType constructType = getConstructData(constrVal, constructData); 2307 2308 ASSERT(constructType != ConstructTypeJS); 2309 2310 if (constructType == ConstructTypeHost) { 2311 int registerOffset = stackFrame.args[1].int32(); 2312 int argCount = stackFrame.args[2].int32(); 2313 CallFrame* previousCallFrame = stackFrame.callFrame; 2314 CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset); 2315 if (!stackFrame.registerFile->grow(callFrame->registers())) { 2316 throwStackOverflowError(previousCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS); 2317 VM_THROW_EXCEPTION(); 2318 } 2319 2320 callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(constrVal)); 2321 2322 EncodedJSValue returnValue; 2323 { 2324 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER); 2325 returnValue = constructData.native.function(callFrame); 2326 } 2327 2328 CHECK_FOR_EXCEPTION_AT_END(); 2329 return returnValue; 2330 } 2331 2332 ASSERT(constructType == ConstructTypeNone); 2333 2334 stackFrame.globalData->exception = createNotAConstructorError(stackFrame.callFrame, constrVal); 2335 VM_THROW_EXCEPTION(); 2336 } 2337 2338 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val) 2339 { 2340 STUB_INIT_STACK_FRAME(stackFrame); 2341 2342 CallFrame* callFrame = stackFrame.callFrame; 2343 JSGlobalData* globalData = stackFrame.globalData; 2344 2345 JSValue baseValue = stackFrame.args[0].jsValue(); 2346 JSValue subscript = stackFrame.args[1].jsValue(); 2347 2348 if (LIKELY(baseValue.isCell() && subscript.isString())) { 2349 Identifier propertyName(callFrame, asString(subscript)->value(callFrame)); 2350 PropertySlot slot(baseValue.asCell()); 2351 // JSString::value may have thrown, but we shouldn't find a property with a null identifier, 2352 // so we should miss this case and wind up in the CHECK_FOR_EXCEPTION_AT_END, below. 2353 if (baseValue.asCell()->fastGetOwnPropertySlot(callFrame, propertyName, slot)) { 2354 JSValue result = slot.getValue(callFrame, propertyName); 2355 CHECK_FOR_EXCEPTION(); 2356 return JSValue::encode(result); 2357 } 2358 } 2359 2360 if (subscript.isUInt32()) { 2361 uint32_t i = subscript.asUInt32(); 2362 if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) { 2363 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_string)); 2364 JSValue result = asString(baseValue)->getIndex(callFrame, i); 2365 CHECK_FOR_EXCEPTION(); 2366 return JSValue::encode(result); 2367 } 2368 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { 2369 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. 2370 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_byte_array)); 2371 return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i)); 2372 } 2373 JSValue result = baseValue.get(callFrame, i); 2374 CHECK_FOR_EXCEPTION(); 2375 return JSValue::encode(result); 2376 } 2377 2378 Identifier property(callFrame, subscript.toString(callFrame)); 2379 JSValue result = baseValue.get(callFrame, property); 2380 CHECK_FOR_EXCEPTION_AT_END(); 2381 return JSValue::encode(result); 2382 } 2383 2384 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_string) 2385 { 2386 STUB_INIT_STACK_FRAME(stackFrame); 2387 2388 CallFrame* callFrame = stackFrame.callFrame; 2389 JSGlobalData* globalData = stackFrame.globalData; 2390 2391 JSValue baseValue = stackFrame.args[0].jsValue(); 2392 JSValue subscript = stackFrame.args[1].jsValue(); 2393 2394 JSValue result; 2395 2396 if (LIKELY(subscript.isUInt32())) { 2397 uint32_t i = subscript.asUInt32(); 2398 if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) 2399 result = asString(baseValue)->getIndex(callFrame, i); 2400 else { 2401 result = baseValue.get(callFrame, i); 2402 if (!isJSString(globalData, baseValue)) 2403 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val)); 2404 } 2405 } else { 2406 Identifier property(callFrame, subscript.toString(callFrame)); 2407 result = baseValue.get(callFrame, property); 2408 } 2409 2410 CHECK_FOR_EXCEPTION_AT_END(); 2411 return JSValue::encode(result); 2412 } 2413 2414 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_byte_array) 2415 { 2416 STUB_INIT_STACK_FRAME(stackFrame); 2417 2418 CallFrame* callFrame = stackFrame.callFrame; 2419 JSGlobalData* globalData = stackFrame.globalData; 2420 2421 JSValue baseValue = stackFrame.args[0].jsValue(); 2422 JSValue subscript = stackFrame.args[1].jsValue(); 2423 2424 JSValue result; 2425 2426 if (LIKELY(subscript.isUInt32())) { 2427 uint32_t i = subscript.asUInt32(); 2428 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { 2429 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. 2430 return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i)); 2431 } 2432 2433 result = baseValue.get(callFrame, i); 2434 if (!isJSByteArray(globalData, baseValue)) 2435 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val)); 2436 } else { 2437 Identifier property(callFrame, subscript.toString(callFrame)); 2438 result = baseValue.get(callFrame, property); 2439 } 2440 2441 CHECK_FOR_EXCEPTION_AT_END(); 2442 return JSValue::encode(result); 2443 } 2444 2445 DEFINE_STUB_FUNCTION(EncodedJSValue, op_sub) 2446 { 2447 STUB_INIT_STACK_FRAME(stackFrame); 2448 2449 JSValue src1 = stackFrame.args[0].jsValue(); 2450 JSValue src2 = stackFrame.args[1].jsValue(); 2451 2452 double left; 2453 double right; 2454 if (src1.getNumber(left) && src2.getNumber(right)) 2455 return JSValue::encode(jsNumber(left - right)); 2456 2457 CallFrame* callFrame = stackFrame.callFrame; 2458 JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame)); 2459 CHECK_FOR_EXCEPTION_AT_END(); 2460 return JSValue::encode(result); 2461 } 2462 2463 DEFINE_STUB_FUNCTION(void, op_put_by_val) 2464 { 2465 STUB_INIT_STACK_FRAME(stackFrame); 2466 2467 CallFrame* callFrame = stackFrame.callFrame; 2468 JSGlobalData* globalData = stackFrame.globalData; 2469 2470 JSValue baseValue = stackFrame.args[0].jsValue(); 2471 JSValue subscript = stackFrame.args[1].jsValue(); 2472 JSValue value = stackFrame.args[2].jsValue(); 2473 2474 if (LIKELY(subscript.isUInt32())) { 2475 uint32_t i = subscript.asUInt32(); 2476 if (isJSArray(globalData, baseValue)) { 2477 JSArray* jsArray = asArray(baseValue); 2478 if (jsArray->canSetIndex(i)) 2479 jsArray->setIndex(*globalData, i, value); 2480 else 2481 jsArray->JSArray::put(callFrame, i, value); 2482 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { 2483 JSByteArray* jsByteArray = asByteArray(baseValue); 2484 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val_byte_array)); 2485 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. 2486 if (value.isInt32()) { 2487 jsByteArray->setIndex(i, value.asInt32()); 2488 return; 2489 } else { 2490 double dValue = 0; 2491 if (value.getNumber(dValue)) { 2492 jsByteArray->setIndex(i, dValue); 2493 return; 2494 } 2495 } 2496 2497 baseValue.put(callFrame, i, value); 2498 } else 2499 baseValue.put(callFrame, i, value); 2500 } else { 2501 Identifier property(callFrame, subscript.toString(callFrame)); 2502 if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception. 2503 PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); 2504 baseValue.put(callFrame, property, value, slot); 2505 } 2506 } 2507 2508 CHECK_FOR_EXCEPTION_AT_END(); 2509 } 2510 2511 DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array) 2512 { 2513 STUB_INIT_STACK_FRAME(stackFrame); 2514 2515 CallFrame* callFrame = stackFrame.callFrame; 2516 JSGlobalData* globalData = stackFrame.globalData; 2517 2518 JSValue baseValue = stackFrame.args[0].jsValue(); 2519 JSValue subscript = stackFrame.args[1].jsValue(); 2520 JSValue value = stackFrame.args[2].jsValue(); 2521 2522 if (LIKELY(subscript.isUInt32())) { 2523 uint32_t i = subscript.asUInt32(); 2524 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { 2525 JSByteArray* jsByteArray = asByteArray(baseValue); 2526 2527 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. 2528 if (value.isInt32()) { 2529 jsByteArray->setIndex(i, value.asInt32()); 2530 return; 2531 } else { 2532 double dValue = 0; 2533 if (value.getNumber(dValue)) { 2534 jsByteArray->setIndex(i, dValue); 2535 return; 2536 } 2537 } 2538 } 2539 2540 if (!isJSByteArray(globalData, baseValue)) 2541 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val)); 2542 baseValue.put(callFrame, i, value); 2543 } else { 2544 Identifier property(callFrame, subscript.toString(callFrame)); 2545 if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception. 2546 PutPropertySlot slot(callFrame->codeBlock()->isStrictMode()); 2547 baseValue.put(callFrame, property, value, slot); 2548 } 2549 } 2550 2551 CHECK_FOR_EXCEPTION_AT_END(); 2552 } 2553 2554 DEFINE_STUB_FUNCTION(EncodedJSValue, op_lesseq) 2555 { 2556 STUB_INIT_STACK_FRAME(stackFrame); 2557 2558 CallFrame* callFrame = stackFrame.callFrame; 2559 JSValue result = jsBoolean(jsLessEq(callFrame, stackFrame.args[0].jsValue(), stackFrame.args[1].jsValue())); 2560 CHECK_FOR_EXCEPTION_AT_END(); 2561 return JSValue::encode(result); 2562 } 2563 2564 DEFINE_STUB_FUNCTION(int, op_load_varargs) 2565 { 2566 STUB_INIT_STACK_FRAME(stackFrame); 2567 2568 CallFrame* callFrame = stackFrame.callFrame; 2569 RegisterFile* registerFile = stackFrame.registerFile; 2570 int argsOffset = stackFrame.args[0].int32(); 2571 JSValue arguments = callFrame->registers()[argsOffset].jsValue(); 2572 uint32_t argCount = 0; 2573 if (!arguments) { 2574 int providedParams = callFrame->registers()[RegisterFile::ArgumentCount].i() - 1; 2575 argCount = providedParams; 2576 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments)); 2577 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; 2578 Register* newEnd = callFrame->registers() + sizeDelta; 2579 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { 2580 stackFrame.globalData->exception = createStackOverflowError(callFrame); 2581 VM_THROW_EXCEPTION(); 2582 } 2583 int32_t expectedParams = asFunction(callFrame->callee())->jsExecutable()->parameterCount(); 2584 int32_t inplaceArgs = min(providedParams, expectedParams); 2585 2586 Register* inplaceArgsDst = callFrame->registers() + argsOffset; 2587 2588 Register* inplaceArgsEnd = inplaceArgsDst + inplaceArgs; 2589 Register* inplaceArgsEnd2 = inplaceArgsDst + providedParams; 2590 2591 Register* inplaceArgsSrc = callFrame->registers() - RegisterFile::CallFrameHeaderSize - expectedParams; 2592 Register* inplaceArgsSrc2 = inplaceArgsSrc - providedParams - 1 + inplaceArgs; 2593 2594 // First step is to copy the "expected" parameters from their normal location relative to the callframe 2595 while (inplaceArgsDst < inplaceArgsEnd) 2596 *inplaceArgsDst++ = *inplaceArgsSrc++; 2597 2598 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this') 2599 while (inplaceArgsDst < inplaceArgsEnd2) 2600 *inplaceArgsDst++ = *inplaceArgsSrc2++; 2601 2602 } else if (!arguments.isUndefinedOrNull()) { 2603 if (!arguments.isObject()) { 2604 stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments); 2605 VM_THROW_EXCEPTION(); 2606 } 2607 if (asObject(arguments)->classInfo() == &Arguments::s_info) { 2608 Arguments* argsObject = asArguments(arguments); 2609 argCount = argsObject->numProvidedArguments(callFrame); 2610 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments)); 2611 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; 2612 Register* newEnd = callFrame->registers() + sizeDelta; 2613 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { 2614 stackFrame.globalData->exception = createStackOverflowError(callFrame); 2615 VM_THROW_EXCEPTION(); 2616 } 2617 argsObject->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount); 2618 } else if (isJSArray(&callFrame->globalData(), arguments)) { 2619 JSArray* array = asArray(arguments); 2620 argCount = array->length(); 2621 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments)); 2622 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; 2623 Register* newEnd = callFrame->registers() + sizeDelta; 2624 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { 2625 stackFrame.globalData->exception = createStackOverflowError(callFrame); 2626 VM_THROW_EXCEPTION(); 2627 } 2628 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount); 2629 } else if (asObject(arguments)->inherits(&JSArray::s_info)) { 2630 JSObject* argObject = asObject(arguments); 2631 argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame); 2632 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments)); 2633 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; 2634 Register* newEnd = callFrame->registers() + sizeDelta; 2635 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { 2636 stackFrame.globalData->exception = createStackOverflowError(callFrame); 2637 VM_THROW_EXCEPTION(); 2638 } 2639 Register* argsBuffer = callFrame->registers() + argsOffset; 2640 for (unsigned i = 0; i < argCount; ++i) { 2641 argsBuffer[i] = asObject(arguments)->get(callFrame, i); 2642 CHECK_FOR_EXCEPTION(); 2643 } 2644 } else { 2645 stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments); 2646 VM_THROW_EXCEPTION(); 2647 } 2648 } 2649 2650 return argCount + 1; 2651 } 2652 2653 DEFINE_STUB_FUNCTION(EncodedJSValue, op_negate) 2654 { 2655 STUB_INIT_STACK_FRAME(stackFrame); 2656 2657 JSValue src = stackFrame.args[0].jsValue(); 2658 2659 double v; 2660 if (src.getNumber(v)) 2661 return JSValue::encode(jsNumber(-v)); 2662 2663 CallFrame* callFrame = stackFrame.callFrame; 2664 JSValue result = jsNumber(-src.toNumber(callFrame)); 2665 CHECK_FOR_EXCEPTION_AT_END(); 2666 return JSValue::encode(result); 2667 } 2668 2669 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base) 2670 { 2671 STUB_INIT_STACK_FRAME(stackFrame); 2672 2673 return JSValue::encode(JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), false)); 2674 } 2675 2676 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base_strict_put) 2677 { 2678 STUB_INIT_STACK_FRAME(stackFrame); 2679 JSValue base = JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), true); 2680 if (!base) { 2681 stackFrame.globalData->exception = createErrorForInvalidGlobalAssignment(stackFrame.callFrame, stackFrame.args[0].identifier().ustring()); 2682 VM_THROW_EXCEPTION(); 2683 } 2684 return JSValue::encode(base); 2685 } 2686 2687 DEFINE_STUB_FUNCTION(EncodedJSValue, op_ensure_property_exists) 2688 { 2689 STUB_INIT_STACK_FRAME(stackFrame); 2690 JSValue base = stackFrame.callFrame->r(stackFrame.args[0].int32()).jsValue(); 2691 JSObject* object = asObject(base); 2692 PropertySlot slot(object); 2693 ASSERT(stackFrame.callFrame->codeBlock()->isStrictMode()); 2694 if (!object->getPropertySlot(stackFrame.callFrame, stackFrame.args[1].identifier(), slot)) { 2695 stackFrame.globalData->exception = createErrorForInvalidGlobalAssignment(stackFrame.callFrame, stackFrame.args[1].identifier().ustring()); 2696 VM_THROW_EXCEPTION(); 2697 } 2698 2699 return JSValue::encode(base); 2700 } 2701 2702 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip) 2703 { 2704 STUB_INIT_STACK_FRAME(stackFrame); 2705 2706 CallFrame* callFrame = stackFrame.callFrame; 2707 ScopeChainNode* scopeChain = callFrame->scopeChain(); 2708 2709 int skip = stackFrame.args[1].int32(); 2710 2711 ScopeChainIterator iter = scopeChain->begin(); 2712 ScopeChainIterator end = scopeChain->end(); 2713 ASSERT(iter != end); 2714 CodeBlock* codeBlock = callFrame->codeBlock(); 2715 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain(); 2716 ASSERT(skip || !checkTopLevel); 2717 if (checkTopLevel && skip--) { 2718 if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue()) 2719 ++iter; 2720 } 2721 while (skip--) { 2722 ++iter; 2723 ASSERT(iter != end); 2724 } 2725 Identifier& ident = stackFrame.args[0].identifier(); 2726 do { 2727 JSObject* o = iter->get(); 2728 PropertySlot slot(o); 2729 if (o->getPropertySlot(callFrame, ident, slot)) { 2730 JSValue result = slot.getValue(callFrame, ident); 2731 CHECK_FOR_EXCEPTION_AT_END(); 2732 return JSValue::encode(result); 2733 } 2734 } while (++iter != end); 2735 2736 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); 2737 VM_THROW_EXCEPTION(); 2738 } 2739 2740 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global) 2741 { 2742 STUB_INIT_STACK_FRAME(stackFrame); 2743 2744 CallFrame* callFrame = stackFrame.callFrame; 2745 CodeBlock* codeBlock = callFrame->codeBlock(); 2746 JSGlobalObject* globalObject = codeBlock->globalObject(); 2747 Identifier& ident = stackFrame.args[0].identifier(); 2748 unsigned globalResolveInfoIndex = stackFrame.args[1].int32(); 2749 ASSERT(globalObject->isGlobalObject()); 2750 2751 PropertySlot slot(globalObject); 2752 if (globalObject->getPropertySlot(callFrame, ident, slot)) { 2753 JSValue result = slot.getValue(callFrame, ident); 2754 if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { 2755 GlobalResolveInfo& globalResolveInfo = codeBlock->globalResolveInfo(globalResolveInfoIndex); 2756 globalResolveInfo.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure()); 2757 globalResolveInfo.offset = slot.cachedOffset(); 2758 return JSValue::encode(result); 2759 } 2760 2761 CHECK_FOR_EXCEPTION_AT_END(); 2762 return JSValue::encode(result); 2763 } 2764 2765 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); 2766 VM_THROW_EXCEPTION(); 2767 } 2768 2769 DEFINE_STUB_FUNCTION(EncodedJSValue, op_div) 2770 { 2771 STUB_INIT_STACK_FRAME(stackFrame); 2772 2773 JSValue src1 = stackFrame.args[0].jsValue(); 2774 JSValue src2 = stackFrame.args[1].jsValue(); 2775 2776 double left; 2777 double right; 2778 if (src1.getNumber(left) && src2.getNumber(right)) 2779 return JSValue::encode(jsNumber(left / right)); 2780 2781 CallFrame* callFrame = stackFrame.callFrame; 2782 JSValue result = jsNumber(src1.toNumber(callFrame) / src2.toNumber(callFrame)); 2783 CHECK_FOR_EXCEPTION_AT_END(); 2784 return JSValue::encode(result); 2785 } 2786 2787 DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_dec) 2788 { 2789 STUB_INIT_STACK_FRAME(stackFrame); 2790 2791 JSValue v = stackFrame.args[0].jsValue(); 2792 2793 CallFrame* callFrame = stackFrame.callFrame; 2794 JSValue result = jsNumber(v.toNumber(callFrame) - 1); 2795 CHECK_FOR_EXCEPTION_AT_END(); 2796 return JSValue::encode(result); 2797 } 2798 2799 DEFINE_STUB_FUNCTION(int, op_jless) 2800 { 2801 STUB_INIT_STACK_FRAME(stackFrame); 2802 2803 JSValue src1 = stackFrame.args[0].jsValue(); 2804 JSValue src2 = stackFrame.args[1].jsValue(); 2805 CallFrame* callFrame = stackFrame.callFrame; 2806 2807 bool result = jsLess(callFrame, src1, src2); 2808 CHECK_FOR_EXCEPTION_AT_END(); 2809 return result; 2810 } 2811 2812 DEFINE_STUB_FUNCTION(int, op_jlesseq) 2813 { 2814 STUB_INIT_STACK_FRAME(stackFrame); 2815 2816 JSValue src1 = stackFrame.args[0].jsValue(); 2817 JSValue src2 = stackFrame.args[1].jsValue(); 2818 CallFrame* callFrame = stackFrame.callFrame; 2819 2820 bool result = jsLessEq(callFrame, src1, src2); 2821 CHECK_FOR_EXCEPTION_AT_END(); 2822 return result; 2823 } 2824 2825 DEFINE_STUB_FUNCTION(EncodedJSValue, op_not) 2826 { 2827 STUB_INIT_STACK_FRAME(stackFrame); 2828 2829 JSValue src = stackFrame.args[0].jsValue(); 2830 2831 CallFrame* callFrame = stackFrame.callFrame; 2832 2833 JSValue result = jsBoolean(!src.toBoolean(callFrame)); 2834 CHECK_FOR_EXCEPTION_AT_END(); 2835 return JSValue::encode(result); 2836 } 2837 2838 DEFINE_STUB_FUNCTION(int, op_jtrue) 2839 { 2840 STUB_INIT_STACK_FRAME(stackFrame); 2841 2842 JSValue src1 = stackFrame.args[0].jsValue(); 2843 2844 CallFrame* callFrame = stackFrame.callFrame; 2845 2846 bool result = src1.toBoolean(callFrame); 2847 CHECK_FOR_EXCEPTION_AT_END(); 2848 return result; 2849 } 2850 2851 DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_inc) 2852 { 2853 STUB_INIT_STACK_FRAME(stackFrame); 2854 2855 JSValue v = stackFrame.args[0].jsValue(); 2856 2857 CallFrame* callFrame = stackFrame.callFrame; 2858 2859 JSValue number = v.toJSNumber(callFrame); 2860 CHECK_FOR_EXCEPTION_AT_END(); 2861 2862 callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number.uncheckedGetNumber() + 1); 2863 return JSValue::encode(number); 2864 } 2865 2866 DEFINE_STUB_FUNCTION(int, op_eq) 2867 { 2868 STUB_INIT_STACK_FRAME(stackFrame); 2869 2870 JSValue src1 = stackFrame.args[0].jsValue(); 2871 JSValue src2 = stackFrame.args[1].jsValue(); 2872 2873 #if USE(JSVALUE32_64) 2874 start: 2875 if (src2.isUndefined()) { 2876 return src1.isNull() || 2877 (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined()) 2878 || src1.isUndefined(); 2879 } 2880 2881 if (src2.isNull()) { 2882 return src1.isUndefined() || 2883 (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined()) 2884 || src1.isNull(); 2885 } 2886 2887 if (src1.isInt32()) { 2888 if (src2.isDouble()) 2889 return src1.asInt32() == src2.asDouble(); 2890 double d = src2.toNumber(stackFrame.callFrame); 2891 CHECK_FOR_EXCEPTION(); 2892 return src1.asInt32() == d; 2893 } 2894 2895 if (src1.isDouble()) { 2896 if (src2.isInt32()) 2897 return src1.asDouble() == src2.asInt32(); 2898 double d = src2.toNumber(stackFrame.callFrame); 2899 CHECK_FOR_EXCEPTION(); 2900 return src1.asDouble() == d; 2901 } 2902 2903 if (src1.isTrue()) { 2904 if (src2.isFalse()) 2905 return false; 2906 double d = src2.toNumber(stackFrame.callFrame); 2907 CHECK_FOR_EXCEPTION(); 2908 return d == 1.0; 2909 } 2910 2911 if (src1.isFalse()) { 2912 if (src2.isTrue()) 2913 return false; 2914 double d = src2.toNumber(stackFrame.callFrame); 2915 CHECK_FOR_EXCEPTION(); 2916 return d == 0.0; 2917 } 2918 2919 if (src1.isUndefined()) 2920 return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined(); 2921 2922 if (src1.isNull()) 2923 return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined(); 2924 2925 JSCell* cell1 = src1.asCell(); 2926 2927 if (cell1->isString()) { 2928 if (src2.isInt32()) 2929 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asInt32(); 2930 2931 if (src2.isDouble()) 2932 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asDouble(); 2933 2934 if (src2.isTrue()) 2935 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 1.0; 2936 2937 if (src2.isFalse()) 2938 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 0.0; 2939 2940 JSCell* cell2 = src2.asCell(); 2941 if (cell2->isString()) 2942 return static_cast<JSString*>(cell1)->value(stackFrame.callFrame) == static_cast<JSString*>(cell2)->value(stackFrame.callFrame); 2943 2944 src2 = asObject(cell2)->toPrimitive(stackFrame.callFrame); 2945 CHECK_FOR_EXCEPTION(); 2946 goto start; 2947 } 2948 2949 if (src2.isObject()) 2950 return asObject(cell1) == asObject(src2); 2951 src1 = asObject(cell1)->toPrimitive(stackFrame.callFrame); 2952 CHECK_FOR_EXCEPTION(); 2953 goto start; 2954 2955 #else // USE(JSVALUE32_64) 2956 CallFrame* callFrame = stackFrame.callFrame; 2957 2958 bool result = JSValue::equalSlowCaseInline(callFrame, src1, src2); 2959 CHECK_FOR_EXCEPTION_AT_END(); 2960 return result; 2961 #endif // USE(JSVALUE32_64) 2962 } 2963 2964 DEFINE_STUB_FUNCTION(int, op_eq_strings) 2965 { 2966 #if USE(JSVALUE32_64) 2967 STUB_INIT_STACK_FRAME(stackFrame); 2968 2969 JSString* string1 = stackFrame.args[0].jsString(); 2970 JSString* string2 = stackFrame.args[1].jsString(); 2971 2972 ASSERT(string1->isString()); 2973 ASSERT(string2->isString()); 2974 return string1->value(stackFrame.callFrame) == string2->value(stackFrame.callFrame); 2975 #else 2976 UNUSED_PARAM(args); 2977 ASSERT_NOT_REACHED(); 2978 return 0; 2979 #endif 2980 } 2981 2982 DEFINE_STUB_FUNCTION(EncodedJSValue, op_lshift) 2983 { 2984 STUB_INIT_STACK_FRAME(stackFrame); 2985 2986 JSValue val = stackFrame.args[0].jsValue(); 2987 JSValue shift = stackFrame.args[1].jsValue(); 2988 2989 CallFrame* callFrame = stackFrame.callFrame; 2990 JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f)); 2991 CHECK_FOR_EXCEPTION_AT_END(); 2992 return JSValue::encode(result); 2993 } 2994 2995 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitand) 2996 { 2997 STUB_INIT_STACK_FRAME(stackFrame); 2998 2999 JSValue src1 = stackFrame.args[0].jsValue(); 3000 JSValue src2 = stackFrame.args[1].jsValue(); 3001 3002 ASSERT(!src1.isInt32() || !src2.isInt32()); 3003 CallFrame* callFrame = stackFrame.callFrame; 3004 JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame)); 3005 CHECK_FOR_EXCEPTION_AT_END(); 3006 return JSValue::encode(result); 3007 } 3008 3009 DEFINE_STUB_FUNCTION(EncodedJSValue, op_rshift) 3010 { 3011 STUB_INIT_STACK_FRAME(stackFrame); 3012 3013 JSValue val = stackFrame.args[0].jsValue(); 3014 JSValue shift = stackFrame.args[1].jsValue(); 3015 3016 CallFrame* callFrame = stackFrame.callFrame; 3017 JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); 3018 3019 CHECK_FOR_EXCEPTION_AT_END(); 3020 return JSValue::encode(result); 3021 } 3022 3023 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitnot) 3024 { 3025 STUB_INIT_STACK_FRAME(stackFrame); 3026 3027 JSValue src = stackFrame.args[0].jsValue(); 3028 3029 ASSERT(!src.isInt32()); 3030 CallFrame* callFrame = stackFrame.callFrame; 3031 JSValue result = jsNumber(~src.toInt32(callFrame)); 3032 CHECK_FOR_EXCEPTION_AT_END(); 3033 return JSValue::encode(result); 3034 } 3035 3036 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base) 3037 { 3038 STUB_INIT_STACK_FRAME(stackFrame); 3039 3040 CallFrame* callFrame = stackFrame.callFrame; 3041 ScopeChainNode* scopeChain = callFrame->scopeChain(); 3042 3043 ScopeChainIterator iter = scopeChain->begin(); 3044 ScopeChainIterator end = scopeChain->end(); 3045 3046 // FIXME: add scopeDepthIsZero optimization 3047 3048 ASSERT(iter != end); 3049 3050 Identifier& ident = stackFrame.args[0].identifier(); 3051 JSObject* base; 3052 do { 3053 base = iter->get(); 3054 PropertySlot slot(base); 3055 if (base->getPropertySlot(callFrame, ident, slot)) { 3056 JSValue result = slot.getValue(callFrame, ident); 3057 CHECK_FOR_EXCEPTION_AT_END(); 3058 3059 callFrame->registers()[stackFrame.args[1].int32()] = JSValue(base); 3060 return JSValue::encode(result); 3061 } 3062 ++iter; 3063 } while (iter != end); 3064 3065 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident); 3066 VM_THROW_EXCEPTION_AT_END(); 3067 return JSValue::encode(JSValue()); 3068 } 3069 3070 DEFINE_STUB_FUNCTION(JSObject*, op_new_func_exp) 3071 { 3072 STUB_INIT_STACK_FRAME(stackFrame); 3073 CallFrame* callFrame = stackFrame.callFrame; 3074 3075 FunctionExecutable* function = stackFrame.args[0].function(); 3076 JSFunction* func = function->make(callFrame, callFrame->scopeChain()); 3077 ASSERT(callFrame->codeBlock()->codeType() != FunctionCode || !callFrame->codeBlock()->needsFullScopeChain() || callFrame->uncheckedR(callFrame->codeBlock()->activationRegister()).jsValue()); 3078 3079 /* 3080 The Identifier in a FunctionExpression can be referenced from inside 3081 the FunctionExpression's FunctionBody to allow the function to call 3082 itself recursively. However, unlike in a FunctionDeclaration, the 3083 Identifier in a FunctionExpression cannot be referenced from and 3084 does not affect the scope enclosing the FunctionExpression. 3085 */ 3086 if (!function->name().isNull()) { 3087 JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete); 3088 func->setScope(callFrame->globalData(), func->scope()->push(functionScopeObject)); 3089 } 3090 3091 return func; 3092 } 3093 3094 DEFINE_STUB_FUNCTION(EncodedJSValue, op_mod) 3095 { 3096 STUB_INIT_STACK_FRAME(stackFrame); 3097 3098 JSValue dividendValue = stackFrame.args[0].jsValue(); 3099 JSValue divisorValue = stackFrame.args[1].jsValue(); 3100 3101 CallFrame* callFrame = stackFrame.callFrame; 3102 double d = dividendValue.toNumber(callFrame); 3103 JSValue result = jsNumber(fmod(d, divisorValue.toNumber(callFrame))); 3104 CHECK_FOR_EXCEPTION_AT_END(); 3105 return JSValue::encode(result); 3106 } 3107 3108 DEFINE_STUB_FUNCTION(EncodedJSValue, op_less) 3109 { 3110 STUB_INIT_STACK_FRAME(stackFrame); 3111 3112 CallFrame* callFrame = stackFrame.callFrame; 3113 JSValue result = jsBoolean(jsLess(callFrame, stackFrame.args[0].jsValue(), stackFrame.args[1].jsValue())); 3114 CHECK_FOR_EXCEPTION_AT_END(); 3115 return JSValue::encode(result); 3116 } 3117 3118 DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_dec) 3119 { 3120 STUB_INIT_STACK_FRAME(stackFrame); 3121 3122 JSValue v = stackFrame.args[0].jsValue(); 3123 3124 CallFrame* callFrame = stackFrame.callFrame; 3125 3126 JSValue number = v.toJSNumber(callFrame); 3127 CHECK_FOR_EXCEPTION_AT_END(); 3128 3129 callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number.uncheckedGetNumber() - 1); 3130 return JSValue::encode(number); 3131 } 3132 3133 DEFINE_STUB_FUNCTION(EncodedJSValue, op_urshift) 3134 { 3135 STUB_INIT_STACK_FRAME(stackFrame); 3136 3137 JSValue val = stackFrame.args[0].jsValue(); 3138 JSValue shift = stackFrame.args[1].jsValue(); 3139 3140 CallFrame* callFrame = stackFrame.callFrame; 3141 JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); 3142 CHECK_FOR_EXCEPTION_AT_END(); 3143 return JSValue::encode(result); 3144 } 3145 3146 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitxor) 3147 { 3148 STUB_INIT_STACK_FRAME(stackFrame); 3149 3150 JSValue src1 = stackFrame.args[0].jsValue(); 3151 JSValue src2 = stackFrame.args[1].jsValue(); 3152 3153 CallFrame* callFrame = stackFrame.callFrame; 3154 3155 JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame)); 3156 CHECK_FOR_EXCEPTION_AT_END(); 3157 return JSValue::encode(result); 3158 } 3159 3160 DEFINE_STUB_FUNCTION(JSObject*, op_new_regexp) 3161 { 3162 STUB_INIT_STACK_FRAME(stackFrame); 3163 3164 CallFrame* callFrame = stackFrame.callFrame; 3165 3166 RegExp* regExp = stackFrame.args[0].regExp(); 3167 if (!regExp->isValid()) { 3168 stackFrame.globalData->exception = createSyntaxError(callFrame, "Invalid flags supplied to RegExp constructor."); 3169 VM_THROW_EXCEPTION(); 3170 } 3171 3172 return new (stackFrame.globalData) RegExpObject(stackFrame.callFrame->lexicalGlobalObject(), stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), regExp); 3173 } 3174 3175 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor) 3176 { 3177 STUB_INIT_STACK_FRAME(stackFrame); 3178 3179 JSValue src1 = stackFrame.args[0].jsValue(); 3180 JSValue src2 = stackFrame.args[1].jsValue(); 3181 3182 CallFrame* callFrame = stackFrame.callFrame; 3183 3184 JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame)); 3185 CHECK_FOR_EXCEPTION_AT_END(); 3186 return JSValue::encode(result); 3187 } 3188 3189 DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval) 3190 { 3191 STUB_INIT_STACK_FRAME(stackFrame); 3192 ASSERT(stackFrame.callFrame->codeBlock()->codeType() != FunctionCode || !stackFrame.callFrame->codeBlock()->needsFullScopeChain() || stackFrame.callFrame->uncheckedR(stackFrame.callFrame->codeBlock()->activationRegister()).jsValue()); 3193 3194 CallFrame* callFrame = stackFrame.callFrame; 3195 RegisterFile* registerFile = stackFrame.registerFile; 3196 3197 Interpreter* interpreter = stackFrame.globalData->interpreter; 3198 3199 JSValue funcVal = stackFrame.args[0].jsValue(); 3200 int registerOffset = stackFrame.args[1].int32(); 3201 int argCount = stackFrame.args[2].int32(); 3202 3203 Register* newCallFrame = callFrame->registers() + registerOffset; 3204 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount; 3205 JSValue baseValue = argv[0].jsValue(); 3206 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject.get(); 3207 3208 if (baseValue == globalObject && funcVal == globalObject->evalFunction()) { 3209 JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset); 3210 CHECK_FOR_EXCEPTION_AT_END(); 3211 return JSValue::encode(result); 3212 } 3213 3214 return JSValue::encode(JSValue()); 3215 } 3216 3217 DEFINE_STUB_FUNCTION(void*, op_throw) 3218 { 3219 STUB_INIT_STACK_FRAME(stackFrame); 3220 ExceptionHandler handler = jitThrow(stackFrame.globalData, stackFrame.callFrame, stackFrame.args[0].jsValue(), STUB_RETURN_ADDRESS); 3221 STUB_SET_RETURN_ADDRESS(handler.catchRoutine); 3222 return handler.callFrame; 3223 } 3224 3225 DEFINE_STUB_FUNCTION(JSPropertyNameIterator*, op_get_pnames) 3226 { 3227 STUB_INIT_STACK_FRAME(stackFrame); 3228 3229 CallFrame* callFrame = stackFrame.callFrame; 3230 JSObject* o = stackFrame.args[0].jsObject(); 3231 Structure* structure = o->structure(); 3232 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache(); 3233 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame)) 3234 jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o); 3235 return jsPropertyNameIterator; 3236 } 3237 3238 DEFINE_STUB_FUNCTION(int, has_property) 3239 { 3240 STUB_INIT_STACK_FRAME(stackFrame); 3241 3242 JSObject* base = stackFrame.args[0].jsObject(); 3243 JSString* property = stackFrame.args[1].jsString(); 3244 int result = base->hasProperty(stackFrame.callFrame, Identifier(stackFrame.callFrame, property->value(stackFrame.callFrame))); 3245 CHECK_FOR_EXCEPTION_AT_END(); 3246 return result; 3247 } 3248 3249 DEFINE_STUB_FUNCTION(JSObject*, op_push_scope) 3250 { 3251 STUB_INIT_STACK_FRAME(stackFrame); 3252 3253 JSObject* o = stackFrame.args[0].jsValue().toObject(stackFrame.callFrame); 3254 CHECK_FOR_EXCEPTION(); 3255 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->push(o)); 3256 return o; 3257 } 3258 3259 DEFINE_STUB_FUNCTION(void, op_pop_scope) 3260 { 3261 STUB_INIT_STACK_FRAME(stackFrame); 3262 3263 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->pop()); 3264 } 3265 3266 DEFINE_STUB_FUNCTION(EncodedJSValue, op_typeof) 3267 { 3268 STUB_INIT_STACK_FRAME(stackFrame); 3269 3270 return JSValue::encode(jsTypeStringForValue(stackFrame.callFrame, stackFrame.args[0].jsValue())); 3271 } 3272 3273 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_undefined) 3274 { 3275 STUB_INIT_STACK_FRAME(stackFrame); 3276 3277 JSValue v = stackFrame.args[0].jsValue(); 3278 return JSValue::encode(jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined())); 3279 } 3280 3281 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_boolean) 3282 { 3283 STUB_INIT_STACK_FRAME(stackFrame); 3284 3285 return JSValue::encode(jsBoolean(stackFrame.args[0].jsValue().isBoolean())); 3286 } 3287 3288 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_number) 3289 { 3290 STUB_INIT_STACK_FRAME(stackFrame); 3291 3292 return JSValue::encode(jsBoolean(stackFrame.args[0].jsValue().isNumber())); 3293 } 3294 3295 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_string) 3296 { 3297 STUB_INIT_STACK_FRAME(stackFrame); 3298 3299 return JSValue::encode(jsBoolean(isJSString(stackFrame.globalData, stackFrame.args[0].jsValue()))); 3300 } 3301 3302 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_object) 3303 { 3304 STUB_INIT_STACK_FRAME(stackFrame); 3305 3306 return JSValue::encode(jsBoolean(jsIsObjectType(stackFrame.args[0].jsValue()))); 3307 } 3308 3309 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_function) 3310 { 3311 STUB_INIT_STACK_FRAME(stackFrame); 3312 3313 return JSValue::encode(jsBoolean(jsIsFunctionType(stackFrame.args[0].jsValue()))); 3314 } 3315 3316 DEFINE_STUB_FUNCTION(EncodedJSValue, op_stricteq) 3317 { 3318 STUB_INIT_STACK_FRAME(stackFrame); 3319 3320 JSValue src1 = stackFrame.args[0].jsValue(); 3321 JSValue src2 = stackFrame.args[1].jsValue(); 3322 3323 bool result = JSValue::strictEqual(stackFrame.callFrame, src1, src2); 3324 CHECK_FOR_EXCEPTION_AT_END(); 3325 return JSValue::encode(jsBoolean(result)); 3326 } 3327 3328 DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_primitive) 3329 { 3330 STUB_INIT_STACK_FRAME(stackFrame); 3331 3332 return JSValue::encode(stackFrame.args[0].jsValue().toPrimitive(stackFrame.callFrame)); 3333 } 3334 3335 DEFINE_STUB_FUNCTION(EncodedJSValue, op_strcat) 3336 { 3337 STUB_INIT_STACK_FRAME(stackFrame); 3338 3339 JSValue result = jsString(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32()); 3340 CHECK_FOR_EXCEPTION_AT_END(); 3341 return JSValue::encode(result); 3342 } 3343 3344 DEFINE_STUB_FUNCTION(EncodedJSValue, op_nstricteq) 3345 { 3346 STUB_INIT_STACK_FRAME(stackFrame); 3347 3348 JSValue src1 = stackFrame.args[0].jsValue(); 3349 JSValue src2 = stackFrame.args[1].jsValue(); 3350 3351 bool result = !JSValue::strictEqual(stackFrame.callFrame, src1, src2); 3352 CHECK_FOR_EXCEPTION_AT_END(); 3353 return JSValue::encode(jsBoolean(result)); 3354 } 3355 3356 DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_jsnumber) 3357 { 3358 STUB_INIT_STACK_FRAME(stackFrame); 3359 3360 JSValue src = stackFrame.args[0].jsValue(); 3361 CallFrame* callFrame = stackFrame.callFrame; 3362 3363 JSValue result = src.toJSNumber(callFrame); 3364 CHECK_FOR_EXCEPTION_AT_END(); 3365 return JSValue::encode(result); 3366 } 3367 3368 DEFINE_STUB_FUNCTION(EncodedJSValue, op_in) 3369 { 3370 STUB_INIT_STACK_FRAME(stackFrame); 3371 3372 CallFrame* callFrame = stackFrame.callFrame; 3373 JSValue baseVal = stackFrame.args[1].jsValue(); 3374 3375 if (!baseVal.isObject()) { 3376 stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "in", baseVal); 3377 VM_THROW_EXCEPTION(); 3378 } 3379 3380 JSValue propName = stackFrame.args[0].jsValue(); 3381 JSObject* baseObj = asObject(baseVal); 3382 3383 uint32_t i; 3384 if (propName.getUInt32(i)) 3385 return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, i))); 3386 3387 Identifier property(callFrame, propName.toString(callFrame)); 3388 CHECK_FOR_EXCEPTION(); 3389 return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, property))); 3390 } 3391 3392 DEFINE_STUB_FUNCTION(JSObject*, op_push_new_scope) 3393 { 3394 STUB_INIT_STACK_FRAME(stackFrame); 3395 3396 JSObject* scope = new (stackFrame.globalData) JSStaticScopeObject(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.args[1].jsValue(), DontDelete); 3397 3398 CallFrame* callFrame = stackFrame.callFrame; 3399 callFrame->setScopeChain(callFrame->scopeChain()->push(scope)); 3400 return scope; 3401 } 3402 3403 DEFINE_STUB_FUNCTION(void, op_jmp_scopes) 3404 { 3405 STUB_INIT_STACK_FRAME(stackFrame); 3406 3407 unsigned count = stackFrame.args[0].int32(); 3408 CallFrame* callFrame = stackFrame.callFrame; 3409 3410 ScopeChainNode* tmp = callFrame->scopeChain(); 3411 while (count--) 3412 tmp = tmp->pop(); 3413 callFrame->setScopeChain(tmp); 3414 } 3415 3416 DEFINE_STUB_FUNCTION(void, op_put_by_index) 3417 { 3418 STUB_INIT_STACK_FRAME(stackFrame); 3419 3420 CallFrame* callFrame = stackFrame.callFrame; 3421 unsigned property = stackFrame.args[1].int32(); 3422 3423 stackFrame.args[0].jsValue().put(callFrame, property, stackFrame.args[2].jsValue()); 3424 } 3425 3426 DEFINE_STUB_FUNCTION(void*, op_switch_imm) 3427 { 3428 STUB_INIT_STACK_FRAME(stackFrame); 3429 3430 JSValue scrutinee = stackFrame.args[0].jsValue(); 3431 unsigned tableIndex = stackFrame.args[1].int32(); 3432 CallFrame* callFrame = stackFrame.callFrame; 3433 CodeBlock* codeBlock = callFrame->codeBlock(); 3434 3435 if (scrutinee.isInt32()) 3436 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(scrutinee.asInt32()).executableAddress(); 3437 else { 3438 double value; 3439 int32_t intValue; 3440 if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value)) 3441 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(intValue).executableAddress(); 3442 else 3443 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); 3444 } 3445 } 3446 3447 DEFINE_STUB_FUNCTION(void*, op_switch_char) 3448 { 3449 STUB_INIT_STACK_FRAME(stackFrame); 3450 3451 JSValue scrutinee = stackFrame.args[0].jsValue(); 3452 unsigned tableIndex = stackFrame.args[1].int32(); 3453 CallFrame* callFrame = stackFrame.callFrame; 3454 CodeBlock* codeBlock = callFrame->codeBlock(); 3455 3456 void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); 3457 3458 if (scrutinee.isString()) { 3459 StringImpl* value = asString(scrutinee)->value(callFrame).impl(); 3460 if (value->length() == 1) 3461 result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->characters()[0]).executableAddress(); 3462 } 3463 3464 CHECK_FOR_EXCEPTION_AT_END(); 3465 return result; 3466 } 3467 3468 DEFINE_STUB_FUNCTION(void*, op_switch_string) 3469 { 3470 STUB_INIT_STACK_FRAME(stackFrame); 3471 3472 JSValue scrutinee = stackFrame.args[0].jsValue(); 3473 unsigned tableIndex = stackFrame.args[1].int32(); 3474 CallFrame* callFrame = stackFrame.callFrame; 3475 CodeBlock* codeBlock = callFrame->codeBlock(); 3476 3477 void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); 3478 3479 if (scrutinee.isString()) { 3480 StringImpl* value = asString(scrutinee)->value(callFrame).impl(); 3481 result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).executableAddress(); 3482 } 3483 3484 CHECK_FOR_EXCEPTION_AT_END(); 3485 return result; 3486 } 3487 3488 DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val) 3489 { 3490 STUB_INIT_STACK_FRAME(stackFrame); 3491 3492 CallFrame* callFrame = stackFrame.callFrame; 3493 3494 JSValue baseValue = stackFrame.args[0].jsValue(); 3495 JSObject* baseObj = baseValue.toObject(callFrame); // may throw 3496 3497 JSValue subscript = stackFrame.args[1].jsValue(); 3498 bool result; 3499 uint32_t i; 3500 if (subscript.getUInt32(i)) 3501 result = baseObj->deleteProperty(callFrame, i); 3502 else { 3503 CHECK_FOR_EXCEPTION(); 3504 Identifier property(callFrame, subscript.toString(callFrame)); 3505 CHECK_FOR_EXCEPTION(); 3506 result = baseObj->deleteProperty(callFrame, property); 3507 } 3508 3509 if (!result && callFrame->codeBlock()->isStrictMode()) 3510 stackFrame.globalData->exception = createTypeError(stackFrame.callFrame, "Unable to delete property."); 3511 3512 CHECK_FOR_EXCEPTION_AT_END(); 3513 return JSValue::encode(jsBoolean(result)); 3514 } 3515 3516 DEFINE_STUB_FUNCTION(void, op_put_getter) 3517 { 3518 STUB_INIT_STACK_FRAME(stackFrame); 3519 3520 CallFrame* callFrame = stackFrame.callFrame; 3521 3522 ASSERT(stackFrame.args[0].jsValue().isObject()); 3523 JSObject* baseObj = asObject(stackFrame.args[0].jsValue()); 3524 ASSERT(stackFrame.args[2].jsValue().isObject()); 3525 baseObj->defineGetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue())); 3526 } 3527 3528 DEFINE_STUB_FUNCTION(void, op_put_setter) 3529 { 3530 STUB_INIT_STACK_FRAME(stackFrame); 3531 3532 CallFrame* callFrame = stackFrame.callFrame; 3533 3534 ASSERT(stackFrame.args[0].jsValue().isObject()); 3535 JSObject* baseObj = asObject(stackFrame.args[0].jsValue()); 3536 ASSERT(stackFrame.args[2].jsValue().isObject()); 3537 baseObj->defineSetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue())); 3538 } 3539 3540 DEFINE_STUB_FUNCTION(void, op_throw_reference_error) 3541 { 3542 STUB_INIT_STACK_FRAME(stackFrame); 3543 3544 CallFrame* callFrame = stackFrame.callFrame; 3545 UString message = stackFrame.args[0].jsValue().toString(callFrame); 3546 stackFrame.globalData->exception = createReferenceError(callFrame, message); 3547 VM_THROW_EXCEPTION_AT_END(); 3548 } 3549 3550 DEFINE_STUB_FUNCTION(void, op_debug) 3551 { 3552 STUB_INIT_STACK_FRAME(stackFrame); 3553 3554 CallFrame* callFrame = stackFrame.callFrame; 3555 3556 int debugHookID = stackFrame.args[0].int32(); 3557 int firstLine = stackFrame.args[1].int32(); 3558 int lastLine = stackFrame.args[2].int32(); 3559 3560 stackFrame.globalData->interpreter->debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine); 3561 } 3562 3563 DEFINE_STUB_FUNCTION(void*, vm_throw) 3564 { 3565 STUB_INIT_STACK_FRAME(stackFrame); 3566 JSGlobalData* globalData = stackFrame.globalData; 3567 ExceptionHandler handler = jitThrow(globalData, stackFrame.callFrame, globalData->exception, globalData->exceptionLocation); 3568 STUB_SET_RETURN_ADDRESS(handler.catchRoutine); 3569 return handler.callFrame; 3570 } 3571 3572 DEFINE_STUB_FUNCTION(EncodedJSValue, to_object) 3573 { 3574 STUB_INIT_STACK_FRAME(stackFrame); 3575 3576 CallFrame* callFrame = stackFrame.callFrame; 3577 return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame)); 3578 } 3579 3580 MacroAssemblerCodePtr JITThunks::ctiStub(JSGlobalData* globalData, ThunkGenerator generator) 3581 { 3582 std::pair<CTIStubMap::iterator, bool> entry = m_ctiStubMap.add(generator, MacroAssemblerCodePtr()); 3583 if (entry.second) 3584 entry.first->second = generator(globalData, m_executablePool.get()); 3585 return entry.first->second; 3586 } 3587 3588 NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function) 3589 { 3590 std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Strong<NativeExecutable>()); 3591 if (entry.second) 3592 entry.first->second.set(*globalData, NativeExecutable::create(*globalData, JIT::compileCTINativeCall(globalData, m_executablePool, function), function, ctiNativeConstruct(), callHostFunctionAsConstructor)); 3593 return entry.first->second.get(); 3594 } 3595 3596 NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, ThunkGenerator generator) 3597 { 3598 std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Strong<NativeExecutable>()); 3599 if (entry.second) { 3600 MacroAssemblerCodePtr code = globalData->canUseJIT() ? generator(globalData, m_executablePool.get()) : MacroAssemblerCodePtr(); 3601 entry.first->second.set(*globalData, NativeExecutable::create(*globalData, code, function, ctiNativeConstruct(), callHostFunctionAsConstructor)); 3602 } 3603 return entry.first->second.get(); 3604 } 3605 3606 void JITThunks::clearHostFunctionStubs() 3607 { 3608 m_hostFunctionStubMap.clear(); 3609 } 3610 3611 } // namespace JSC 3612 3613 #endif // ENABLE(JIT) 3614