1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2010 Patrick Gansterer <paroga (at) paroga.com> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 29 #if ENABLE(JIT) 30 #if USE(JSVALUE32_64) 31 #include "JIT.h" 32 33 #include "JITInlineMethods.h" 34 #include "JITStubCall.h" 35 #include "JSArray.h" 36 #include "JSCell.h" 37 #include "JSFunction.h" 38 #include "JSPropertyNameIterator.h" 39 #include "LinkBuffer.h" 40 41 namespace JSC { 42 43 void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* globalData, TrampolineStructure *trampolines) 44 { 45 #if ENABLE(JIT_USE_SOFT_MODULO) 46 Label softModBegin = align(); 47 softModulo(); 48 #endif 49 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 50 // (1) This function provides fast property access for string length 51 Label stringLengthBegin = align(); 52 53 // regT0 holds payload, regT1 holds tag 54 55 Jump string_failureCases1 = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); 56 Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr)); 57 58 // Checks out okay! - get the length from the Ustring. 59 load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_length)), regT2); 60 61 Jump string_failureCases3 = branch32(Above, regT2, TrustedImm32(INT_MAX)); 62 move(regT2, regT0); 63 move(TrustedImm32(JSValue::Int32Tag), regT1); 64 65 ret(); 66 #endif 67 68 JumpList callLinkFailures; 69 // (2) Trampolines for the slow cases of op_call / op_call_eval / op_construct. 70 #if ENABLE(JIT_OPTIMIZE_CALL) 71 // VirtualCallLink Trampoline 72 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. 73 Label virtualCallLinkBegin = align(); 74 compileOpCallInitializeCallFrame(); 75 preserveReturnAddressAfterCall(regT3); 76 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); 77 restoreArgumentReference(); 78 Call callLazyLinkCall = call(); 79 callLinkFailures.append(branchTestPtr(Zero, regT0)); 80 restoreReturnAddressBeforeReturn(regT3); 81 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1); 82 jump(regT0); 83 84 // VirtualConstructLink Trampoline 85 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. 86 Label virtualConstructLinkBegin = align(); 87 compileOpCallInitializeCallFrame(); 88 preserveReturnAddressAfterCall(regT3); 89 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); 90 restoreArgumentReference(); 91 Call callLazyLinkConstruct = call(); 92 restoreReturnAddressBeforeReturn(regT3); 93 callLinkFailures.append(branchTestPtr(Zero, regT0)); 94 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1); 95 jump(regT0); 96 97 #endif // ENABLE(JIT_OPTIMIZE_CALL) 98 99 // VirtualCall Trampoline 100 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. 101 Label virtualCallBegin = align(); 102 compileOpCallInitializeCallFrame(); 103 104 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 105 106 Jump hasCodeBlock3 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), TrustedImm32(0)); 107 preserveReturnAddressAfterCall(regT3); 108 restoreArgumentReference(); 109 Call callCompileCall = call(); 110 callLinkFailures.append(branchTestPtr(Zero, regT0)); 111 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1); 112 restoreReturnAddressBeforeReturn(regT3); 113 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 114 hasCodeBlock3.link(this); 115 116 loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCallWithArityCheck)), regT0); 117 jump(regT0); 118 119 // VirtualConstruct Trampoline 120 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. 121 Label virtualConstructBegin = align(); 122 compileOpCallInitializeCallFrame(); 123 124 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 125 126 Jump hasCodeBlock4 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), TrustedImm32(0)); 127 preserveReturnAddressAfterCall(regT3); 128 restoreArgumentReference(); 129 Call callCompileCconstruct = call(); 130 callLinkFailures.append(branchTestPtr(Zero, regT0)); 131 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1); 132 restoreReturnAddressBeforeReturn(regT3); 133 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 134 hasCodeBlock4.link(this); 135 136 loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstructWithArityCheck)), regT0); 137 jump(regT0); 138 139 // If the parser fails we want to be able to be able to keep going, 140 // So we handle this as a parse failure. 141 callLinkFailures.link(this); 142 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); 143 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); 144 restoreReturnAddressBeforeReturn(regT1); 145 move(TrustedImmPtr(&globalData->exceptionLocation), regT2); 146 storePtr(regT1, regT2); 147 poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); 148 poke(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value())); 149 ret(); 150 151 // NativeCall Trampoline 152 Label nativeCallThunk = privateCompileCTINativeCall(globalData); 153 Label nativeConstructThunk = privateCompileCTINativeCall(globalData, true); 154 155 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 156 Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1); 157 Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2); 158 Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3); 159 #endif 160 161 // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. 162 LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()), 0); 163 164 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 165 patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail)); 166 patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail)); 167 patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail)); 168 #endif 169 #if ENABLE(JIT_OPTIMIZE_CALL) 170 patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall)); 171 patchBuffer.link(callLazyLinkConstruct, FunctionPtr(cti_vm_lazyLinkConstruct)); 172 #endif 173 patchBuffer.link(callCompileCall, FunctionPtr(cti_op_call_jitCompile)); 174 patchBuffer.link(callCompileCconstruct, FunctionPtr(cti_op_construct_jitCompile)); 175 176 CodeRef finalCode = patchBuffer.finalizeCode(); 177 *executablePool = finalCode.m_executablePool; 178 179 trampolines->ctiVirtualCall = patchBuffer.trampolineAt(virtualCallBegin); 180 trampolines->ctiVirtualConstruct = patchBuffer.trampolineAt(virtualConstructBegin); 181 trampolines->ctiNativeCall = patchBuffer.trampolineAt(nativeCallThunk); 182 trampolines->ctiNativeConstruct = patchBuffer.trampolineAt(nativeConstructThunk); 183 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 184 trampolines->ctiStringLengthTrampoline = patchBuffer.trampolineAt(stringLengthBegin); 185 #endif 186 #if ENABLE(JIT_OPTIMIZE_CALL) 187 trampolines->ctiVirtualCallLink = patchBuffer.trampolineAt(virtualCallLinkBegin); 188 trampolines->ctiVirtualConstructLink = patchBuffer.trampolineAt(virtualConstructLinkBegin); 189 #endif 190 #if ENABLE(JIT_USE_SOFT_MODULO) 191 trampolines->ctiSoftModulo = patchBuffer.trampolineAt(softModBegin); 192 #endif 193 } 194 195 JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isConstruct) 196 { 197 int executableOffsetToFunction = isConstruct ? OBJECT_OFFSETOF(NativeExecutable, m_constructor) : OBJECT_OFFSETOF(NativeExecutable, m_function); 198 199 Label nativeCallThunk = align(); 200 201 emitPutImmediateToCallFrameHeader(0, RegisterFile::CodeBlock); 202 203 #if CPU(X86) 204 // Load caller frame's scope chain into this callframe so that whatever we call can 205 // get to its global data. 206 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0); 207 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0); 208 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain); 209 210 peek(regT1); 211 emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC); 212 213 // Calling convention: f(ecx, edx, ...); 214 // Host function signature: f(ExecState*); 215 move(callFrameRegister, X86Registers::ecx); 216 217 subPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call. 218 219 // call the function 220 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT1); 221 loadPtr(Address(regT1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT1); 222 move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. 223 call(Address(regT1, executableOffsetToFunction)); 224 225 addPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); 226 227 #elif CPU(ARM) 228 // Load caller frame's scope chain into this callframe so that whatever we call can 229 // get to its global data. 230 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2); 231 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2); 232 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain); 233 234 preserveReturnAddressAfterCall(regT3); // Callee preserved 235 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); 236 237 // Calling convention: f(r0 == regT0, r1 == regT1, ...); 238 // Host function signature: f(ExecState*); 239 move(callFrameRegister, ARMRegisters::r0); 240 241 // call the function 242 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, ARMRegisters::r1); 243 move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. 244 loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 245 call(Address(regT2, executableOffsetToFunction)); 246 247 restoreReturnAddressBeforeReturn(regT3); 248 #elif CPU(SH4) 249 // Load caller frame's scope chain into this callframe so that whatever we call can 250 // get to its global data. 251 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2); 252 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2); 253 emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); 254 255 preserveReturnAddressAfterCall(regT3); // Callee preserved 256 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); 257 258 // Calling convention: f(r0 == regT4, r1 == regT5, ...); 259 // Host function signature: f(ExecState*); 260 move(callFrameRegister, regT4); 261 262 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT5); 263 move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. 264 loadPtr(Address(regT5, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 265 266 call(Address(regT2, executableOffsetToFunction), regT0); 267 restoreReturnAddressBeforeReturn(regT3); 268 #elif CPU(MIPS) 269 // Load caller frame's scope chain into this callframe so that whatever we call can 270 // get to its global data. 271 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0); 272 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0); 273 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain); 274 275 preserveReturnAddressAfterCall(regT3); // Callee preserved 276 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); 277 278 // Calling convention: f(a0, a1, a2, a3); 279 // Host function signature: f(ExecState*); 280 281 // Allocate stack space for 16 bytes (8-byte aligned) 282 // 16 bytes (unused) for 4 arguments 283 subPtr(TrustedImm32(16), stackPointerRegister); 284 285 // Setup arg0 286 move(callFrameRegister, MIPSRegisters::a0); 287 288 // Call 289 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, MIPSRegisters::a2); 290 loadPtr(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 291 move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. 292 call(Address(regT2, executableOffsetToFunction)); 293 294 // Restore stack space 295 addPtr(TrustedImm32(16), stackPointerRegister); 296 297 restoreReturnAddressBeforeReturn(regT3); 298 299 #elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL) 300 #error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform." 301 #else 302 UNUSED_PARAM(executableOffsetToFunction); 303 breakpoint(); 304 #endif // CPU(X86) 305 306 // Check for an exception 307 Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&globalData->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); 308 309 // Return. 310 ret(); 311 312 // Handle an exception 313 sawException.link(this); 314 315 // Grab the return address. 316 preserveReturnAddressAfterCall(regT1); 317 318 move(TrustedImmPtr(&globalData->exceptionLocation), regT2); 319 storePtr(regT1, regT2); 320 poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); 321 322 // Set the return address. 323 move(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1); 324 restoreReturnAddressBeforeReturn(regT1); 325 326 ret(); 327 328 return nativeCallThunk; 329 } 330 331 JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executablePool, JSGlobalData* globalData, NativeFunction func) 332 { 333 Call nativeCall; 334 Label nativeCallThunk = align(); 335 336 emitPutImmediateToCallFrameHeader(0, RegisterFile::CodeBlock); 337 338 #if CPU(X86) 339 // Load caller frame's scope chain into this callframe so that whatever we call can 340 // get to its global data. 341 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0); 342 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0); 343 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain); 344 345 peek(regT1); 346 emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC); 347 348 // Calling convention: f(ecx, edx, ...); 349 // Host function signature: f(ExecState*); 350 move(callFrameRegister, X86Registers::ecx); 351 352 subPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call. 353 354 move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. 355 356 // call the function 357 nativeCall = call(); 358 359 addPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); 360 361 #elif CPU(ARM) 362 // Load caller frame's scope chain into this callframe so that whatever we call can 363 // get to its global data. 364 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2); 365 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2); 366 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain); 367 368 preserveReturnAddressAfterCall(regT3); // Callee preserved 369 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); 370 371 // Calling convention: f(r0 == regT0, r1 == regT1, ...); 372 // Host function signature: f(ExecState*); 373 move(callFrameRegister, ARMRegisters::r0); 374 375 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, ARMRegisters::r1); 376 move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. 377 loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 378 379 // call the function 380 nativeCall = call(); 381 382 restoreReturnAddressBeforeReturn(regT3); 383 384 #elif CPU(MIPS) 385 // Load caller frame's scope chain into this callframe so that whatever we call can 386 // get to its global data. 387 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0); 388 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0); 389 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain); 390 391 preserveReturnAddressAfterCall(regT3); // Callee preserved 392 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); 393 394 // Calling convention: f(a0, a1, a2, a3); 395 // Host function signature: f(ExecState*); 396 397 // Allocate stack space for 16 bytes (8-byte aligned) 398 // 16 bytes (unused) for 4 arguments 399 subPtr(TrustedImm32(16), stackPointerRegister); 400 401 // Setup arg0 402 move(callFrameRegister, MIPSRegisters::a0); 403 404 // Call 405 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, MIPSRegisters::a2); 406 loadPtr(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 407 move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. 408 409 // call the function 410 nativeCall = call(); 411 412 // Restore stack space 413 addPtr(TrustedImm32(16), stackPointerRegister); 414 415 restoreReturnAddressBeforeReturn(regT3); 416 #elif CPU(SH4) 417 // Load caller frame's scope chain into this callframe so that whatever we call can 418 // get to its global data. 419 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2); 420 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2); 421 emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); 422 423 preserveReturnAddressAfterCall(regT3); // Callee preserved 424 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC); 425 426 // Calling convention: f(r0 == regT4, r1 == regT5, ...); 427 // Host function signature: f(ExecState*); 428 move(callFrameRegister, regT4); 429 430 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT5); 431 move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack. 432 loadPtr(Address(regT5, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 433 434 // call the function 435 nativeCall = call(); 436 437 restoreReturnAddressBeforeReturn(regT3); 438 #elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL) 439 #error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform." 440 #else 441 breakpoint(); 442 #endif // CPU(X86) 443 444 // Check for an exception 445 Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&globalData->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); 446 447 // Return. 448 ret(); 449 450 // Handle an exception 451 sawException.link(this); 452 453 // Grab the return address. 454 preserveReturnAddressAfterCall(regT1); 455 456 move(TrustedImmPtr(&globalData->exceptionLocation), regT2); 457 storePtr(regT1, regT2); 458 poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); 459 460 // Set the return address. 461 move(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1); 462 restoreReturnAddressBeforeReturn(regT1); 463 464 ret(); 465 466 // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. 467 LinkBuffer patchBuffer(this, executablePool, 0); 468 469 patchBuffer.link(nativeCall, FunctionPtr(func)); 470 patchBuffer.finalizeCode(); 471 472 return patchBuffer.trampolineAt(nativeCallThunk); 473 } 474 475 void JIT::emit_op_mov(Instruction* currentInstruction) 476 { 477 unsigned dst = currentInstruction[1].u.operand; 478 unsigned src = currentInstruction[2].u.operand; 479 480 if (m_codeBlock->isConstantRegisterIndex(src)) 481 emitStore(dst, getConstantOperand(src)); 482 else { 483 emitLoad(src, regT1, regT0); 484 emitStore(dst, regT1, regT0); 485 map(m_bytecodeOffset + OPCODE_LENGTH(op_mov), dst, regT1, regT0); 486 } 487 } 488 489 void JIT::emit_op_end(Instruction* currentInstruction) 490 { 491 ASSERT(returnValueRegister != callFrameRegister); 492 emitLoad(currentInstruction[1].u.operand, regT1, regT0); 493 restoreReturnAddressBeforeReturn(Address(callFrameRegister, RegisterFile::ReturnPC * static_cast<int>(sizeof(Register)))); 494 ret(); 495 } 496 497 void JIT::emit_op_jmp(Instruction* currentInstruction) 498 { 499 unsigned target = currentInstruction[1].u.operand; 500 addJump(jump(), target); 501 } 502 503 void JIT::emit_op_loop_if_lesseq(Instruction* currentInstruction) 504 { 505 unsigned op1 = currentInstruction[1].u.operand; 506 unsigned op2 = currentInstruction[2].u.operand; 507 unsigned target = currentInstruction[3].u.operand; 508 509 emitTimeoutCheck(); 510 511 if (isOperandConstantImmediateInt(op1)) { 512 emitLoad(op2, regT1, regT0); 513 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag))); 514 addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op1).asInt32())), target); 515 return; 516 } 517 518 if (isOperandConstantImmediateInt(op2)) { 519 emitLoad(op1, regT1, regT0); 520 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag))); 521 addJump(branch32(LessThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target); 522 return; 523 } 524 525 emitLoad2(op1, regT1, regT0, op2, regT3, regT2); 526 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag))); 527 addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag))); 528 addJump(branch32(LessThanOrEqual, regT0, regT2), target); 529 } 530 531 void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 532 { 533 unsigned op1 = currentInstruction[1].u.operand; 534 unsigned op2 = currentInstruction[2].u.operand; 535 unsigned target = currentInstruction[3].u.operand; 536 537 if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) 538 linkSlowCase(iter); // int32 check 539 linkSlowCase(iter); // int32 check 540 541 JITStubCall stubCall(this, cti_op_loop_if_lesseq); 542 stubCall.addArgument(op1); 543 stubCall.addArgument(op2); 544 stubCall.call(); 545 emitJumpSlowToHot(branchTest32(NonZero, regT0), target); 546 } 547 548 void JIT::emit_op_new_object(Instruction* currentInstruction) 549 { 550 JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand); 551 } 552 553 void JIT::emit_op_check_has_instance(Instruction* currentInstruction) 554 { 555 unsigned baseVal = currentInstruction[1].u.operand; 556 557 emitLoadPayload(baseVal, regT0); 558 559 // Check that baseVal is a cell. 560 emitJumpSlowCaseIfNotJSCell(baseVal); 561 562 // Check that baseVal 'ImplementsHasInstance'. 563 loadPtr(Address(regT0, JSCell::structureOffset()), regT0); 564 addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsHasInstance))); 565 } 566 567 void JIT::emit_op_instanceof(Instruction* currentInstruction) 568 { 569 unsigned dst = currentInstruction[1].u.operand; 570 unsigned value = currentInstruction[2].u.operand; 571 unsigned baseVal = currentInstruction[3].u.operand; 572 unsigned proto = currentInstruction[4].u.operand; 573 574 // Load the operands into registers. 575 // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result. 576 emitLoadPayload(value, regT2); 577 emitLoadPayload(baseVal, regT0); 578 emitLoadPayload(proto, regT1); 579 580 // Check that proto are cells. baseVal must be a cell - this is checked by op_check_has_instance. 581 emitJumpSlowCaseIfNotJSCell(value); 582 emitJumpSlowCaseIfNotJSCell(proto); 583 584 // Check that prototype is an object 585 loadPtr(Address(regT1, JSCell::structureOffset()), regT3); 586 addSlowCase(branch8(NotEqual, Address(regT3, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType))); 587 588 // Fixme: this check is only needed because the JSC API allows HasInstance to be overridden; we should deprecate this. 589 // Check that baseVal 'ImplementsDefaultHasInstance'. 590 loadPtr(Address(regT0, JSCell::structureOffset()), regT0); 591 addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance))); 592 593 // Optimistically load the result true, and start looping. 594 // Initially, regT1 still contains proto and regT2 still contains value. 595 // As we loop regT2 will be updated with its prototype, recursively walking the prototype chain. 596 move(TrustedImm32(1), regT0); 597 Label loop(this); 598 599 // Load the prototype of the cell in regT2. If this is equal to regT1 - WIN! 600 // Otherwise, check if we've hit null - if we have then drop out of the loop, if not go again. 601 loadPtr(Address(regT2, JSCell::structureOffset()), regT2); 602 load32(Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2); 603 Jump isInstance = branchPtr(Equal, regT2, regT1); 604 branchTest32(NonZero, regT2).linkTo(loop, this); 605 606 // We get here either by dropping out of the loop, or if value was not an Object. Result is false. 607 move(TrustedImm32(0), regT0); 608 609 // isInstance jumps right down to here, to skip setting the result to false (it has already set true). 610 isInstance.link(this); 611 emitStoreBool(dst, regT0); 612 } 613 614 void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 615 { 616 unsigned baseVal = currentInstruction[1].u.operand; 617 618 linkSlowCaseIfNotJSCell(iter, baseVal); 619 linkSlowCase(iter); 620 621 JITStubCall stubCall(this, cti_op_check_has_instance); 622 stubCall.addArgument(baseVal); 623 stubCall.call(); 624 } 625 626 void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 627 { 628 unsigned dst = currentInstruction[1].u.operand; 629 unsigned value = currentInstruction[2].u.operand; 630 unsigned baseVal = currentInstruction[3].u.operand; 631 unsigned proto = currentInstruction[4].u.operand; 632 633 linkSlowCaseIfNotJSCell(iter, value); 634 linkSlowCaseIfNotJSCell(iter, proto); 635 linkSlowCase(iter); 636 linkSlowCase(iter); 637 638 JITStubCall stubCall(this, cti_op_instanceof); 639 stubCall.addArgument(value); 640 stubCall.addArgument(baseVal); 641 stubCall.addArgument(proto); 642 stubCall.call(dst); 643 } 644 645 void JIT::emit_op_get_global_var(Instruction* currentInstruction) 646 { 647 int dst = currentInstruction[1].u.operand; 648 JSGlobalObject* globalObject = m_codeBlock->globalObject(); 649 ASSERT(globalObject->isGlobalObject()); 650 int index = currentInstruction[2].u.operand; 651 652 loadPtr(&globalObject->m_registers, regT2); 653 654 emitLoad(index, regT1, regT0, regT2); 655 emitStore(dst, regT1, regT0); 656 map(m_bytecodeOffset + OPCODE_LENGTH(op_get_global_var), dst, regT1, regT0); 657 } 658 659 void JIT::emit_op_put_global_var(Instruction* currentInstruction) 660 { 661 JSGlobalObject* globalObject = m_codeBlock->globalObject(); 662 ASSERT(globalObject->isGlobalObject()); 663 int index = currentInstruction[1].u.operand; 664 int value = currentInstruction[2].u.operand; 665 666 emitLoad(value, regT1, regT0); 667 668 loadPtr(&globalObject->m_registers, regT2); 669 emitStore(index, regT1, regT0, regT2); 670 map(m_bytecodeOffset + OPCODE_LENGTH(op_put_global_var), value, regT1, regT0); 671 } 672 673 void JIT::emit_op_get_scoped_var(Instruction* currentInstruction) 674 { 675 int dst = currentInstruction[1].u.operand; 676 int index = currentInstruction[2].u.operand; 677 int skip = currentInstruction[3].u.operand; 678 679 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2); 680 bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain(); 681 ASSERT(skip || !checkTopLevel); 682 if (checkTopLevel && skip--) { 683 Jump activationNotCreated; 684 if (checkTopLevel) 685 activationNotCreated = branch32(Equal, tagFor(m_codeBlock->activationRegister()), TrustedImm32(JSValue::EmptyValueTag)); 686 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2); 687 activationNotCreated.link(this); 688 } 689 while (skip--) 690 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2); 691 692 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2); 693 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, m_registers)), regT2); 694 695 emitLoad(index, regT1, regT0, regT2); 696 emitStore(dst, regT1, regT0); 697 map(m_bytecodeOffset + OPCODE_LENGTH(op_get_scoped_var), dst, regT1, regT0); 698 } 699 700 void JIT::emit_op_put_scoped_var(Instruction* currentInstruction) 701 { 702 int index = currentInstruction[1].u.operand; 703 int skip = currentInstruction[2].u.operand; 704 int value = currentInstruction[3].u.operand; 705 706 emitLoad(value, regT1, regT0); 707 708 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2); 709 bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain(); 710 ASSERT(skip || !checkTopLevel); 711 if (checkTopLevel && skip--) { 712 Jump activationNotCreated; 713 if (checkTopLevel) 714 activationNotCreated = branch32(Equal, tagFor(m_codeBlock->activationRegister()), TrustedImm32(JSValue::EmptyValueTag)); 715 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2); 716 activationNotCreated.link(this); 717 } 718 while (skip--) 719 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2); 720 721 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2); 722 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, m_registers)), regT2); 723 724 emitStore(index, regT1, regT0, regT2); 725 map(m_bytecodeOffset + OPCODE_LENGTH(op_put_scoped_var), value, regT1, regT0); 726 } 727 728 void JIT::emit_op_tear_off_activation(Instruction* currentInstruction) 729 { 730 unsigned activation = currentInstruction[1].u.operand; 731 unsigned arguments = currentInstruction[2].u.operand; 732 Jump activationCreated = branch32(NotEqual, tagFor(activation), TrustedImm32(JSValue::EmptyValueTag)); 733 Jump argumentsNotCreated = branch32(Equal, tagFor(arguments), TrustedImm32(JSValue::EmptyValueTag)); 734 activationCreated.link(this); 735 JITStubCall stubCall(this, cti_op_tear_off_activation); 736 stubCall.addArgument(currentInstruction[1].u.operand); 737 stubCall.addArgument(unmodifiedArgumentsRegister(currentInstruction[2].u.operand)); 738 stubCall.call(); 739 argumentsNotCreated.link(this); 740 } 741 742 void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction) 743 { 744 int dst = currentInstruction[1].u.operand; 745 746 Jump argsNotCreated = branch32(Equal, tagFor(unmodifiedArgumentsRegister(dst)), TrustedImm32(JSValue::EmptyValueTag)); 747 JITStubCall stubCall(this, cti_op_tear_off_arguments); 748 stubCall.addArgument(unmodifiedArgumentsRegister(dst)); 749 stubCall.call(); 750 argsNotCreated.link(this); 751 } 752 753 void JIT::emit_op_new_array(Instruction* currentInstruction) 754 { 755 JITStubCall stubCall(this, cti_op_new_array); 756 stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); 757 stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); 758 stubCall.call(currentInstruction[1].u.operand); 759 } 760 761 void JIT::emit_op_resolve(Instruction* currentInstruction) 762 { 763 JITStubCall stubCall(this, cti_op_resolve); 764 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 765 stubCall.call(currentInstruction[1].u.operand); 766 } 767 768 void JIT::emit_op_to_primitive(Instruction* currentInstruction) 769 { 770 int dst = currentInstruction[1].u.operand; 771 int src = currentInstruction[2].u.operand; 772 773 emitLoad(src, regT1, regT0); 774 775 Jump isImm = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); 776 addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr))); 777 isImm.link(this); 778 779 if (dst != src) 780 emitStore(dst, regT1, regT0); 781 map(m_bytecodeOffset + OPCODE_LENGTH(op_to_primitive), dst, regT1, regT0); 782 } 783 784 void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 785 { 786 int dst = currentInstruction[1].u.operand; 787 788 linkSlowCase(iter); 789 790 JITStubCall stubCall(this, cti_op_to_primitive); 791 stubCall.addArgument(regT1, regT0); 792 stubCall.call(dst); 793 } 794 795 void JIT::emit_op_strcat(Instruction* currentInstruction) 796 { 797 JITStubCall stubCall(this, cti_op_strcat); 798 stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); 799 stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); 800 stubCall.call(currentInstruction[1].u.operand); 801 } 802 803 void JIT::emit_op_resolve_base(Instruction* currentInstruction) 804 { 805 JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base); 806 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 807 stubCall.call(currentInstruction[1].u.operand); 808 } 809 810 void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction) 811 { 812 JITStubCall stubCall(this, cti_op_ensure_property_exists); 813 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 814 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 815 stubCall.call(currentInstruction[1].u.operand); 816 } 817 818 void JIT::emit_op_resolve_skip(Instruction* currentInstruction) 819 { 820 JITStubCall stubCall(this, cti_op_resolve_skip); 821 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 822 stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); 823 stubCall.call(currentInstruction[1].u.operand); 824 } 825 826 void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool dynamic) 827 { 828 // FIXME: Optimize to use patching instead of so many memory accesses. 829 830 unsigned dst = currentInstruction[1].u.operand; 831 void* globalObject = m_codeBlock->globalObject(); 832 833 unsigned currentIndex = m_globalResolveInfoIndex++; 834 void* structureAddress = &(m_codeBlock->globalResolveInfo(currentIndex).structure); 835 void* offsetAddr = &(m_codeBlock->globalResolveInfo(currentIndex).offset); 836 837 // Verify structure. 838 move(TrustedImmPtr(globalObject), regT0); 839 loadPtr(structureAddress, regT1); 840 addSlowCase(branchPtr(NotEqual, regT1, Address(regT0, JSCell::structureOffset()))); 841 842 // Load property. 843 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_propertyStorage)), regT2); 844 load32(offsetAddr, regT3); 845 load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload 846 load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag 847 emitStore(dst, regT1, regT0); 848 map(m_bytecodeOffset + dynamic ? OPCODE_LENGTH(op_resolve_global_dynamic) : OPCODE_LENGTH(op_resolve_global), dst, regT1, regT0); 849 } 850 851 void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 852 { 853 unsigned dst = currentInstruction[1].u.operand; 854 Identifier* ident = &m_codeBlock->identifier(currentInstruction[2].u.operand); 855 856 unsigned currentIndex = m_globalResolveInfoIndex++; 857 858 linkSlowCase(iter); 859 JITStubCall stubCall(this, cti_op_resolve_global); 860 stubCall.addArgument(TrustedImmPtr(ident)); 861 stubCall.addArgument(Imm32(currentIndex)); 862 stubCall.call(dst); 863 } 864 865 void JIT::emit_op_not(Instruction* currentInstruction) 866 { 867 unsigned dst = currentInstruction[1].u.operand; 868 unsigned src = currentInstruction[2].u.operand; 869 870 emitLoadTag(src, regT0); 871 872 emitLoad(src, regT1, regT0); 873 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::BooleanTag))); 874 xor32(TrustedImm32(1), regT0); 875 876 emitStoreBool(dst, regT0, (dst == src)); 877 } 878 879 void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 880 { 881 unsigned dst = currentInstruction[1].u.operand; 882 unsigned src = currentInstruction[2].u.operand; 883 884 linkSlowCase(iter); 885 886 JITStubCall stubCall(this, cti_op_not); 887 stubCall.addArgument(src); 888 stubCall.call(dst); 889 } 890 891 void JIT::emit_op_jfalse(Instruction* currentInstruction) 892 { 893 unsigned cond = currentInstruction[1].u.operand; 894 unsigned target = currentInstruction[2].u.operand; 895 896 emitLoad(cond, regT1, regT0); 897 898 ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1)); 899 addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag))); 900 addJump(branchTest32(Zero, regT0), target); 901 } 902 903 void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 904 { 905 unsigned cond = currentInstruction[1].u.operand; 906 unsigned target = currentInstruction[2].u.operand; 907 908 linkSlowCase(iter); 909 910 if (supportsFloatingPoint()) { 911 // regT1 contains the tag from the hot path. 912 Jump notNumber = branch32(Above, regT1, Imm32(JSValue::LowestTag)); 913 914 emitLoadDouble(cond, fpRegT0); 915 emitJumpSlowToHot(branchDoubleZeroOrNaN(fpRegT0, fpRegT1), target); 916 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jfalse)); 917 918 notNumber.link(this); 919 } 920 921 JITStubCall stubCall(this, cti_op_jtrue); 922 stubCall.addArgument(cond); 923 stubCall.call(); 924 emitJumpSlowToHot(branchTest32(Zero, regT0), target); // Inverted. 925 } 926 927 void JIT::emit_op_jtrue(Instruction* currentInstruction) 928 { 929 unsigned cond = currentInstruction[1].u.operand; 930 unsigned target = currentInstruction[2].u.operand; 931 932 emitLoad(cond, regT1, regT0); 933 934 ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1)); 935 addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag))); 936 addJump(branchTest32(NonZero, regT0), target); 937 } 938 939 void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 940 { 941 unsigned cond = currentInstruction[1].u.operand; 942 unsigned target = currentInstruction[2].u.operand; 943 944 linkSlowCase(iter); 945 946 if (supportsFloatingPoint()) { 947 // regT1 contains the tag from the hot path. 948 Jump notNumber = branch32(Above, regT1, Imm32(JSValue::LowestTag)); 949 950 emitLoadDouble(cond, fpRegT0); 951 emitJumpSlowToHot(branchDoubleNonZero(fpRegT0, fpRegT1), target); 952 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jtrue)); 953 954 notNumber.link(this); 955 } 956 957 JITStubCall stubCall(this, cti_op_jtrue); 958 stubCall.addArgument(cond); 959 stubCall.call(); 960 emitJumpSlowToHot(branchTest32(NonZero, regT0), target); 961 } 962 963 void JIT::emit_op_jeq_null(Instruction* currentInstruction) 964 { 965 unsigned src = currentInstruction[1].u.operand; 966 unsigned target = currentInstruction[2].u.operand; 967 968 emitLoad(src, regT1, regT0); 969 970 Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); 971 972 // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. 973 loadPtr(Address(regT0, JSCell::structureOffset()), regT2); 974 addJump(branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target); 975 976 Jump wasNotImmediate = jump(); 977 978 // Now handle the immediate cases - undefined & null 979 isImmediate.link(this); 980 981 ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1)); 982 or32(TrustedImm32(1), regT1); 983 addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), target); 984 985 wasNotImmediate.link(this); 986 } 987 988 void JIT::emit_op_jneq_null(Instruction* currentInstruction) 989 { 990 unsigned src = currentInstruction[1].u.operand; 991 unsigned target = currentInstruction[2].u.operand; 992 993 emitLoad(src, regT1, regT0); 994 995 Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); 996 997 // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. 998 loadPtr(Address(regT0, JSCell::structureOffset()), regT2); 999 addJump(branchTest8(Zero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target); 1000 1001 Jump wasNotImmediate = jump(); 1002 1003 // Now handle the immediate cases - undefined & null 1004 isImmediate.link(this); 1005 1006 ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1)); 1007 or32(TrustedImm32(1), regT1); 1008 addJump(branch32(NotEqual, regT1, TrustedImm32(JSValue::NullTag)), target); 1009 1010 wasNotImmediate.link(this); 1011 } 1012 1013 void JIT::emit_op_jneq_ptr(Instruction* currentInstruction) 1014 { 1015 unsigned src = currentInstruction[1].u.operand; 1016 JSCell* ptr = currentInstruction[2].u.jsCell.get(); 1017 unsigned target = currentInstruction[3].u.operand; 1018 1019 emitLoad(src, regT1, regT0); 1020 addJump(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)), target); 1021 addJump(branchPtr(NotEqual, regT0, TrustedImmPtr(ptr)), target); 1022 } 1023 1024 void JIT::emit_op_jsr(Instruction* currentInstruction) 1025 { 1026 int retAddrDst = currentInstruction[1].u.operand; 1027 int target = currentInstruction[2].u.operand; 1028 DataLabelPtr storeLocation = storePtrWithPatch(TrustedImmPtr(0), Address(callFrameRegister, sizeof(Register) * retAddrDst)); 1029 addJump(jump(), target); 1030 m_jsrSites.append(JSRInfo(storeLocation, label())); 1031 } 1032 1033 void JIT::emit_op_sret(Instruction* currentInstruction) 1034 { 1035 jump(Address(callFrameRegister, sizeof(Register) * currentInstruction[1].u.operand)); 1036 } 1037 1038 void JIT::emit_op_eq(Instruction* currentInstruction) 1039 { 1040 unsigned dst = currentInstruction[1].u.operand; 1041 unsigned src1 = currentInstruction[2].u.operand; 1042 unsigned src2 = currentInstruction[3].u.operand; 1043 1044 emitLoad2(src1, regT1, regT0, src2, regT3, regT2); 1045 addSlowCase(branch32(NotEqual, regT1, regT3)); 1046 addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag))); 1047 addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag))); 1048 1049 set32Compare32(Equal, regT0, regT2, regT0); 1050 1051 emitStoreBool(dst, regT0); 1052 } 1053 1054 void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1055 { 1056 unsigned dst = currentInstruction[1].u.operand; 1057 unsigned op1 = currentInstruction[2].u.operand; 1058 unsigned op2 = currentInstruction[3].u.operand; 1059 1060 JumpList storeResult; 1061 JumpList genericCase; 1062 1063 genericCase.append(getSlowCase(iter)); // tags not equal 1064 1065 linkSlowCase(iter); // tags equal and JSCell 1066 genericCase.append(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr))); 1067 genericCase.append(branchPtr(NotEqual, Address(regT2), TrustedImmPtr(m_globalData->jsStringVPtr))); 1068 1069 // String case. 1070 JITStubCall stubCallEqStrings(this, cti_op_eq_strings); 1071 stubCallEqStrings.addArgument(regT0); 1072 stubCallEqStrings.addArgument(regT2); 1073 stubCallEqStrings.call(); 1074 storeResult.append(jump()); 1075 1076 // Generic case. 1077 genericCase.append(getSlowCase(iter)); // doubles 1078 genericCase.link(this); 1079 JITStubCall stubCallEq(this, cti_op_eq); 1080 stubCallEq.addArgument(op1); 1081 stubCallEq.addArgument(op2); 1082 stubCallEq.call(regT0); 1083 1084 storeResult.link(this); 1085 emitStoreBool(dst, regT0); 1086 } 1087 1088 void JIT::emit_op_neq(Instruction* currentInstruction) 1089 { 1090 unsigned dst = currentInstruction[1].u.operand; 1091 unsigned src1 = currentInstruction[2].u.operand; 1092 unsigned src2 = currentInstruction[3].u.operand; 1093 1094 emitLoad2(src1, regT1, regT0, src2, regT3, regT2); 1095 addSlowCase(branch32(NotEqual, regT1, regT3)); 1096 addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag))); 1097 addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag))); 1098 1099 set32Compare32(NotEqual, regT0, regT2, regT0); 1100 1101 emitStoreBool(dst, regT0); 1102 } 1103 1104 void JIT::emitSlow_op_neq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1105 { 1106 unsigned dst = currentInstruction[1].u.operand; 1107 1108 JumpList storeResult; 1109 JumpList genericCase; 1110 1111 genericCase.append(getSlowCase(iter)); // tags not equal 1112 1113 linkSlowCase(iter); // tags equal and JSCell 1114 genericCase.append(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr))); 1115 genericCase.append(branchPtr(NotEqual, Address(regT2), TrustedImmPtr(m_globalData->jsStringVPtr))); 1116 1117 // String case. 1118 JITStubCall stubCallEqStrings(this, cti_op_eq_strings); 1119 stubCallEqStrings.addArgument(regT0); 1120 stubCallEqStrings.addArgument(regT2); 1121 stubCallEqStrings.call(regT0); 1122 storeResult.append(jump()); 1123 1124 // Generic case. 1125 genericCase.append(getSlowCase(iter)); // doubles 1126 genericCase.link(this); 1127 JITStubCall stubCallEq(this, cti_op_eq); 1128 stubCallEq.addArgument(regT1, regT0); 1129 stubCallEq.addArgument(regT3, regT2); 1130 stubCallEq.call(regT0); 1131 1132 storeResult.link(this); 1133 xor32(TrustedImm32(0x1), regT0); 1134 emitStoreBool(dst, regT0); 1135 } 1136 1137 void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqType type) 1138 { 1139 unsigned dst = currentInstruction[1].u.operand; 1140 unsigned src1 = currentInstruction[2].u.operand; 1141 unsigned src2 = currentInstruction[3].u.operand; 1142 1143 emitLoadTag(src1, regT0); 1144 emitLoadTag(src2, regT1); 1145 1146 // Jump to a slow case if either operand is double, or if both operands are 1147 // cells and/or Int32s. 1148 move(regT0, regT2); 1149 and32(regT1, regT2); 1150 addSlowCase(branch32(Below, regT2, TrustedImm32(JSValue::LowestTag))); 1151 addSlowCase(branch32(AboveOrEqual, regT2, TrustedImm32(JSValue::CellTag))); 1152 1153 if (type == OpStrictEq) 1154 set32Compare32(Equal, regT0, regT1, regT0); 1155 else 1156 set32Compare32(NotEqual, regT0, regT1, regT0); 1157 1158 emitStoreBool(dst, regT0); 1159 } 1160 1161 void JIT::emit_op_stricteq(Instruction* currentInstruction) 1162 { 1163 compileOpStrictEq(currentInstruction, OpStrictEq); 1164 } 1165 1166 void JIT::emitSlow_op_stricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1167 { 1168 unsigned dst = currentInstruction[1].u.operand; 1169 unsigned src1 = currentInstruction[2].u.operand; 1170 unsigned src2 = currentInstruction[3].u.operand; 1171 1172 linkSlowCase(iter); 1173 linkSlowCase(iter); 1174 1175 JITStubCall stubCall(this, cti_op_stricteq); 1176 stubCall.addArgument(src1); 1177 stubCall.addArgument(src2); 1178 stubCall.call(dst); 1179 } 1180 1181 void JIT::emit_op_nstricteq(Instruction* currentInstruction) 1182 { 1183 compileOpStrictEq(currentInstruction, OpNStrictEq); 1184 } 1185 1186 void JIT::emitSlow_op_nstricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1187 { 1188 unsigned dst = currentInstruction[1].u.operand; 1189 unsigned src1 = currentInstruction[2].u.operand; 1190 unsigned src2 = currentInstruction[3].u.operand; 1191 1192 linkSlowCase(iter); 1193 linkSlowCase(iter); 1194 1195 JITStubCall stubCall(this, cti_op_nstricteq); 1196 stubCall.addArgument(src1); 1197 stubCall.addArgument(src2); 1198 stubCall.call(dst); 1199 } 1200 1201 void JIT::emit_op_eq_null(Instruction* currentInstruction) 1202 { 1203 unsigned dst = currentInstruction[1].u.operand; 1204 unsigned src = currentInstruction[2].u.operand; 1205 1206 emitLoad(src, regT1, regT0); 1207 Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); 1208 1209 loadPtr(Address(regT0, JSCell::structureOffset()), regT1); 1210 set32Test8(NonZero, Address(regT1, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined), regT1); 1211 1212 Jump wasNotImmediate = jump(); 1213 1214 isImmediate.link(this); 1215 1216 set32Compare32(Equal, regT1, TrustedImm32(JSValue::NullTag), regT2); 1217 set32Compare32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag), regT1); 1218 or32(regT2, regT1); 1219 1220 wasNotImmediate.link(this); 1221 1222 emitStoreBool(dst, regT1); 1223 } 1224 1225 void JIT::emit_op_neq_null(Instruction* currentInstruction) 1226 { 1227 unsigned dst = currentInstruction[1].u.operand; 1228 unsigned src = currentInstruction[2].u.operand; 1229 1230 emitLoad(src, regT1, regT0); 1231 Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); 1232 1233 loadPtr(Address(regT0, JSCell::structureOffset()), regT1); 1234 set32Test8(Zero, Address(regT1, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined), regT1); 1235 1236 Jump wasNotImmediate = jump(); 1237 1238 isImmediate.link(this); 1239 1240 set32Compare32(NotEqual, regT1, TrustedImm32(JSValue::NullTag), regT2); 1241 set32Compare32(NotEqual, regT1, TrustedImm32(JSValue::UndefinedTag), regT1); 1242 and32(regT2, regT1); 1243 1244 wasNotImmediate.link(this); 1245 1246 emitStoreBool(dst, regT1); 1247 } 1248 1249 void JIT::emit_op_resolve_with_base(Instruction* currentInstruction) 1250 { 1251 JITStubCall stubCall(this, cti_op_resolve_with_base); 1252 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); 1253 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 1254 stubCall.call(currentInstruction[2].u.operand); 1255 } 1256 1257 void JIT::emit_op_new_func_exp(Instruction* currentInstruction) 1258 { 1259 JITStubCall stubCall(this, cti_op_new_func_exp); 1260 stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand))); 1261 stubCall.call(currentInstruction[1].u.operand); 1262 } 1263 1264 void JIT::emit_op_throw(Instruction* currentInstruction) 1265 { 1266 unsigned exception = currentInstruction[1].u.operand; 1267 JITStubCall stubCall(this, cti_op_throw); 1268 stubCall.addArgument(exception); 1269 stubCall.call(); 1270 1271 #ifndef NDEBUG 1272 // cti_op_throw always changes it's return address, 1273 // this point in the code should never be reached. 1274 breakpoint(); 1275 #endif 1276 } 1277 1278 void JIT::emit_op_get_pnames(Instruction* currentInstruction) 1279 { 1280 int dst = currentInstruction[1].u.operand; 1281 int base = currentInstruction[2].u.operand; 1282 int i = currentInstruction[3].u.operand; 1283 int size = currentInstruction[4].u.operand; 1284 int breakTarget = currentInstruction[5].u.operand; 1285 1286 JumpList isNotObject; 1287 1288 emitLoad(base, regT1, regT0); 1289 if (!m_codeBlock->isKnownNotImmediate(base)) 1290 isNotObject.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); 1291 if (base != m_codeBlock->thisRegister() || m_codeBlock->isStrictMode()) { 1292 loadPtr(Address(regT0, JSCell::structureOffset()), regT2); 1293 isNotObject.append(branch8(NotEqual, Address(regT2, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType))); 1294 } 1295 1296 // We could inline the case where you have a valid cache, but 1297 // this call doesn't seem to be hot. 1298 Label isObject(this); 1299 JITStubCall getPnamesStubCall(this, cti_op_get_pnames); 1300 getPnamesStubCall.addArgument(regT0); 1301 getPnamesStubCall.call(dst); 1302 load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3); 1303 store32(TrustedImm32(Int32Tag), intTagFor(i)); 1304 store32(TrustedImm32(0), intPayloadFor(i)); 1305 store32(TrustedImm32(Int32Tag), intTagFor(size)); 1306 store32(regT3, payloadFor(size)); 1307 Jump end = jump(); 1308 1309 isNotObject.link(this); 1310 addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), breakTarget); 1311 addJump(branch32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag)), breakTarget); 1312 JITStubCall toObjectStubCall(this, cti_to_object); 1313 toObjectStubCall.addArgument(regT1, regT0); 1314 toObjectStubCall.call(base); 1315 jump().linkTo(isObject, this); 1316 1317 end.link(this); 1318 } 1319 1320 void JIT::emit_op_next_pname(Instruction* currentInstruction) 1321 { 1322 int dst = currentInstruction[1].u.operand; 1323 int base = currentInstruction[2].u.operand; 1324 int i = currentInstruction[3].u.operand; 1325 int size = currentInstruction[4].u.operand; 1326 int it = currentInstruction[5].u.operand; 1327 int target = currentInstruction[6].u.operand; 1328 1329 JumpList callHasProperty; 1330 1331 Label begin(this); 1332 load32(intPayloadFor(i), regT0); 1333 Jump end = branch32(Equal, regT0, intPayloadFor(size)); 1334 1335 // Grab key @ i 1336 loadPtr(payloadFor(it), regT1); 1337 loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2); 1338 load32(BaseIndex(regT2, regT0, TimesEight), regT2); 1339 store32(TrustedImm32(JSValue::CellTag), tagFor(dst)); 1340 store32(regT2, payloadFor(dst)); 1341 1342 // Increment i 1343 add32(TrustedImm32(1), regT0); 1344 store32(regT0, intPayloadFor(i)); 1345 1346 // Verify that i is valid: 1347 loadPtr(payloadFor(base), regT0); 1348 1349 // Test base's structure 1350 loadPtr(Address(regT0, JSCell::structureOffset()), regT2); 1351 callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))))); 1352 1353 // Test base's prototype chain 1354 loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3); 1355 loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3); 1356 addJump(branchTestPtr(Zero, Address(regT3)), target); 1357 1358 Label checkPrototype(this); 1359 callHasProperty.append(branch32(Equal, Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::NullTag))); 1360 loadPtr(Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2); 1361 loadPtr(Address(regT2, JSCell::structureOffset()), regT2); 1362 callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3))); 1363 addPtr(TrustedImm32(sizeof(Structure*)), regT3); 1364 branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this); 1365 1366 // Continue loop. 1367 addJump(jump(), target); 1368 1369 // Slow case: Ask the object if i is valid. 1370 callHasProperty.link(this); 1371 loadPtr(addressFor(dst), regT1); 1372 JITStubCall stubCall(this, cti_has_property); 1373 stubCall.addArgument(regT0); 1374 stubCall.addArgument(regT1); 1375 stubCall.call(); 1376 1377 // Test for valid key. 1378 addJump(branchTest32(NonZero, regT0), target); 1379 jump().linkTo(begin, this); 1380 1381 // End of loop. 1382 end.link(this); 1383 } 1384 1385 void JIT::emit_op_push_scope(Instruction* currentInstruction) 1386 { 1387 JITStubCall stubCall(this, cti_op_push_scope); 1388 stubCall.addArgument(currentInstruction[1].u.operand); 1389 stubCall.call(currentInstruction[1].u.operand); 1390 } 1391 1392 void JIT::emit_op_pop_scope(Instruction*) 1393 { 1394 JITStubCall(this, cti_op_pop_scope).call(); 1395 } 1396 1397 void JIT::emit_op_to_jsnumber(Instruction* currentInstruction) 1398 { 1399 int dst = currentInstruction[1].u.operand; 1400 int src = currentInstruction[2].u.operand; 1401 1402 emitLoad(src, regT1, regT0); 1403 1404 Jump isInt32 = branch32(Equal, regT1, TrustedImm32(JSValue::Int32Tag)); 1405 addSlowCase(branch32(AboveOrEqual, regT1, TrustedImm32(JSValue::EmptyValueTag))); 1406 isInt32.link(this); 1407 1408 if (src != dst) 1409 emitStore(dst, regT1, regT0); 1410 map(m_bytecodeOffset + OPCODE_LENGTH(op_to_jsnumber), dst, regT1, regT0); 1411 } 1412 1413 void JIT::emitSlow_op_to_jsnumber(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1414 { 1415 int dst = currentInstruction[1].u.operand; 1416 1417 linkSlowCase(iter); 1418 1419 JITStubCall stubCall(this, cti_op_to_jsnumber); 1420 stubCall.addArgument(regT1, regT0); 1421 stubCall.call(dst); 1422 } 1423 1424 void JIT::emit_op_push_new_scope(Instruction* currentInstruction) 1425 { 1426 JITStubCall stubCall(this, cti_op_push_new_scope); 1427 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 1428 stubCall.addArgument(currentInstruction[3].u.operand); 1429 stubCall.call(currentInstruction[1].u.operand); 1430 } 1431 1432 void JIT::emit_op_catch(Instruction* currentInstruction) 1433 { 1434 // cti_op_throw returns the callFrame for the handler. 1435 move(regT0, callFrameRegister); 1436 1437 // Now store the exception returned by cti_op_throw. 1438 loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(struct JITStackFrame, globalData)), regT3); 1439 load32(Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); 1440 load32(Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); 1441 store32(TrustedImm32(JSValue().payload()), Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); 1442 store32(TrustedImm32(JSValue().tag()), Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); 1443 1444 unsigned exception = currentInstruction[1].u.operand; 1445 emitStore(exception, regT1, regT0); 1446 map(m_bytecodeOffset + OPCODE_LENGTH(op_catch), exception, regT1, regT0); 1447 } 1448 1449 void JIT::emit_op_jmp_scopes(Instruction* currentInstruction) 1450 { 1451 JITStubCall stubCall(this, cti_op_jmp_scopes); 1452 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 1453 stubCall.call(); 1454 addJump(jump(), currentInstruction[2].u.operand); 1455 } 1456 1457 void JIT::emit_op_switch_imm(Instruction* currentInstruction) 1458 { 1459 unsigned tableIndex = currentInstruction[1].u.operand; 1460 unsigned defaultOffset = currentInstruction[2].u.operand; 1461 unsigned scrutinee = currentInstruction[3].u.operand; 1462 1463 // create jump table for switch destinations, track this switch statement. 1464 SimpleJumpTable* jumpTable = &m_codeBlock->immediateSwitchJumpTable(tableIndex); 1465 m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Immediate)); 1466 jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); 1467 1468 JITStubCall stubCall(this, cti_op_switch_imm); 1469 stubCall.addArgument(scrutinee); 1470 stubCall.addArgument(Imm32(tableIndex)); 1471 stubCall.call(); 1472 jump(regT0); 1473 } 1474 1475 void JIT::emit_op_switch_char(Instruction* currentInstruction) 1476 { 1477 unsigned tableIndex = currentInstruction[1].u.operand; 1478 unsigned defaultOffset = currentInstruction[2].u.operand; 1479 unsigned scrutinee = currentInstruction[3].u.operand; 1480 1481 // create jump table for switch destinations, track this switch statement. 1482 SimpleJumpTable* jumpTable = &m_codeBlock->characterSwitchJumpTable(tableIndex); 1483 m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Character)); 1484 jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); 1485 1486 JITStubCall stubCall(this, cti_op_switch_char); 1487 stubCall.addArgument(scrutinee); 1488 stubCall.addArgument(Imm32(tableIndex)); 1489 stubCall.call(); 1490 jump(regT0); 1491 } 1492 1493 void JIT::emit_op_switch_string(Instruction* currentInstruction) 1494 { 1495 unsigned tableIndex = currentInstruction[1].u.operand; 1496 unsigned defaultOffset = currentInstruction[2].u.operand; 1497 unsigned scrutinee = currentInstruction[3].u.operand; 1498 1499 // create jump table for switch destinations, track this switch statement. 1500 StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTable(tableIndex); 1501 m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset)); 1502 1503 JITStubCall stubCall(this, cti_op_switch_string); 1504 stubCall.addArgument(scrutinee); 1505 stubCall.addArgument(Imm32(tableIndex)); 1506 stubCall.call(); 1507 jump(regT0); 1508 } 1509 1510 void JIT::emit_op_throw_reference_error(Instruction* currentInstruction) 1511 { 1512 unsigned message = currentInstruction[1].u.operand; 1513 1514 JITStubCall stubCall(this, cti_op_throw_reference_error); 1515 stubCall.addArgument(m_codeBlock->getConstant(message)); 1516 stubCall.call(); 1517 } 1518 1519 void JIT::emit_op_debug(Instruction* currentInstruction) 1520 { 1521 #if ENABLE(DEBUG_WITH_BREAKPOINT) 1522 UNUSED_PARAM(currentInstruction); 1523 breakpoint(); 1524 #else 1525 JITStubCall stubCall(this, cti_op_debug); 1526 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 1527 stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); 1528 stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); 1529 stubCall.call(); 1530 #endif 1531 } 1532 1533 1534 void JIT::emit_op_enter(Instruction*) 1535 { 1536 // Even though JIT code doesn't use them, we initialize our constant 1537 // registers to zap stale pointers, to avoid unnecessarily prolonging 1538 // object lifetime and increasing GC pressure. 1539 for (int i = 0; i < m_codeBlock->m_numVars; ++i) 1540 emitStore(i, jsUndefined()); 1541 } 1542 1543 void JIT::emit_op_create_activation(Instruction* currentInstruction) 1544 { 1545 unsigned activation = currentInstruction[1].u.operand; 1546 1547 Jump activationCreated = branch32(NotEqual, tagFor(activation), TrustedImm32(JSValue::EmptyValueTag)); 1548 JITStubCall(this, cti_op_push_activation).call(activation); 1549 activationCreated.link(this); 1550 } 1551 1552 void JIT::emit_op_create_arguments(Instruction* currentInstruction) 1553 { 1554 unsigned dst = currentInstruction[1].u.operand; 1555 1556 Jump argsCreated = branch32(NotEqual, tagFor(dst), TrustedImm32(JSValue::EmptyValueTag)); 1557 1558 if (m_codeBlock->m_numParameters == 1) 1559 JITStubCall(this, cti_op_create_arguments_no_params).call(); 1560 else 1561 JITStubCall(this, cti_op_create_arguments).call(); 1562 1563 emitStore(dst, regT1, regT0); 1564 emitStore(unmodifiedArgumentsRegister(dst), regT1, regT0); 1565 1566 argsCreated.link(this); 1567 } 1568 1569 void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction) 1570 { 1571 unsigned dst = currentInstruction[1].u.operand; 1572 1573 emitStore(dst, JSValue()); 1574 } 1575 1576 void JIT::emit_op_get_callee(Instruction* currentInstruction) 1577 { 1578 int dst = currentInstruction[1].u.operand; 1579 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0); 1580 emitStoreCell(dst, regT0); 1581 } 1582 1583 void JIT::emit_op_create_this(Instruction* currentInstruction) 1584 { 1585 unsigned protoRegister = currentInstruction[2].u.operand; 1586 emitLoad(protoRegister, regT1, regT0); 1587 JITStubCall stubCall(this, cti_op_create_this); 1588 stubCall.addArgument(regT1, regT0); 1589 stubCall.call(currentInstruction[1].u.operand); 1590 } 1591 1592 void JIT::emit_op_convert_this(Instruction* currentInstruction) 1593 { 1594 unsigned thisRegister = currentInstruction[1].u.operand; 1595 1596 emitLoad(thisRegister, regT1, regT0); 1597 1598 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); 1599 1600 loadPtr(Address(regT0, JSCell::structureOffset()), regT2); 1601 addSlowCase(branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(NeedsThisConversion))); 1602 1603 map(m_bytecodeOffset + OPCODE_LENGTH(op_convert_this), thisRegister, regT1, regT0); 1604 } 1605 1606 void JIT::emit_op_convert_this_strict(Instruction* currentInstruction) 1607 { 1608 unsigned thisRegister = currentInstruction[1].u.operand; 1609 1610 emitLoad(thisRegister, regT1, regT0); 1611 1612 Jump notNull = branch32(NotEqual, regT1, TrustedImm32(JSValue::EmptyValueTag)); 1613 emitStore(thisRegister, jsNull()); 1614 Jump setThis = jump(); 1615 notNull.link(this); 1616 Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); 1617 loadPtr(Address(regT0, JSCell::structureOffset()), regT2); 1618 Jump notAnObject = branch8(NotEqual, Address(regT2, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType)); 1619 addSlowCase(branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(NeedsThisConversion))); 1620 isImmediate.link(this); 1621 notAnObject.link(this); 1622 setThis.link(this); 1623 map(m_bytecodeOffset + OPCODE_LENGTH(op_convert_this_strict), thisRegister, regT1, regT0); 1624 } 1625 1626 void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1627 { 1628 unsigned thisRegister = currentInstruction[1].u.operand; 1629 1630 linkSlowCase(iter); 1631 linkSlowCase(iter); 1632 1633 JITStubCall stubCall(this, cti_op_convert_this); 1634 stubCall.addArgument(regT1, regT0); 1635 stubCall.call(thisRegister); 1636 } 1637 1638 void JIT::emitSlow_op_convert_this_strict(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1639 { 1640 unsigned thisRegister = currentInstruction[1].u.operand; 1641 1642 linkSlowCase(iter); 1643 1644 JITStubCall stubCall(this, cti_op_convert_this_strict); 1645 stubCall.addArgument(regT1, regT0); 1646 stubCall.call(thisRegister); 1647 } 1648 1649 void JIT::emit_op_profile_will_call(Instruction* currentInstruction) 1650 { 1651 peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*)); 1652 Jump noProfiler = branchTestPtr(Zero, Address(regT2)); 1653 1654 JITStubCall stubCall(this, cti_op_profile_will_call); 1655 stubCall.addArgument(currentInstruction[1].u.operand); 1656 stubCall.call(); 1657 noProfiler.link(this); 1658 } 1659 1660 void JIT::emit_op_profile_did_call(Instruction* currentInstruction) 1661 { 1662 peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*)); 1663 Jump noProfiler = branchTestPtr(Zero, Address(regT2)); 1664 1665 JITStubCall stubCall(this, cti_op_profile_did_call); 1666 stubCall.addArgument(currentInstruction[1].u.operand); 1667 stubCall.call(); 1668 noProfiler.link(this); 1669 } 1670 1671 void JIT::emit_op_get_arguments_length(Instruction* currentInstruction) 1672 { 1673 int dst = currentInstruction[1].u.operand; 1674 int argumentsRegister = currentInstruction[2].u.operand; 1675 addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), TrustedImm32(JSValue::EmptyValueTag))); 1676 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); 1677 sub32(TrustedImm32(1), regT0); 1678 emitStoreInt32(dst, regT0); 1679 } 1680 1681 void JIT::emitSlow_op_get_arguments_length(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1682 { 1683 linkSlowCase(iter); 1684 int dst = currentInstruction[1].u.operand; 1685 int base = currentInstruction[2].u.operand; 1686 int ident = currentInstruction[3].u.operand; 1687 1688 JITStubCall stubCall(this, cti_op_get_by_id_generic); 1689 stubCall.addArgument(base); 1690 stubCall.addArgument(TrustedImmPtr(&(m_codeBlock->identifier(ident)))); 1691 stubCall.call(dst); 1692 } 1693 1694 void JIT::emit_op_get_argument_by_val(Instruction* currentInstruction) 1695 { 1696 int dst = currentInstruction[1].u.operand; 1697 int argumentsRegister = currentInstruction[2].u.operand; 1698 int property = currentInstruction[3].u.operand; 1699 addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), TrustedImm32(JSValue::EmptyValueTag))); 1700 emitLoad(property, regT1, regT2); 1701 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag))); 1702 add32(TrustedImm32(1), regT2); 1703 // regT2 now contains the integer index of the argument we want, including this 1704 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT3); 1705 addSlowCase(branch32(AboveOrEqual, regT2, regT3)); 1706 1707 Jump skipOutofLineParams; 1708 int numArgs = m_codeBlock->m_numParameters; 1709 if (numArgs) { 1710 Jump notInInPlaceArgs = branch32(AboveOrEqual, regT2, Imm32(numArgs)); 1711 addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT1); 1712 loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); 1713 loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); 1714 skipOutofLineParams = jump(); 1715 notInInPlaceArgs.link(this); 1716 } 1717 1718 addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT1); 1719 mul32(TrustedImm32(sizeof(Register)), regT3, regT3); 1720 subPtr(regT3, regT1); 1721 loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); 1722 loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); 1723 if (numArgs) 1724 skipOutofLineParams.link(this); 1725 emitStore(dst, regT1, regT0); 1726 } 1727 1728 void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1729 { 1730 unsigned dst = currentInstruction[1].u.operand; 1731 unsigned arguments = currentInstruction[2].u.operand; 1732 unsigned property = currentInstruction[3].u.operand; 1733 1734 linkSlowCase(iter); 1735 Jump skipArgumentsCreation = jump(); 1736 1737 linkSlowCase(iter); 1738 linkSlowCase(iter); 1739 if (m_codeBlock->m_numParameters == 1) 1740 JITStubCall(this, cti_op_create_arguments_no_params).call(); 1741 else 1742 JITStubCall(this, cti_op_create_arguments).call(); 1743 1744 emitStore(arguments, regT1, regT0); 1745 emitStore(unmodifiedArgumentsRegister(arguments), regT1, regT0); 1746 1747 skipArgumentsCreation.link(this); 1748 JITStubCall stubCall(this, cti_op_get_by_val); 1749 stubCall.addArgument(arguments); 1750 stubCall.addArgument(property); 1751 stubCall.call(dst); 1752 } 1753 1754 #if ENABLE(JIT_USE_SOFT_MODULO) 1755 void JIT::softModulo() 1756 { 1757 push(regT1); 1758 push(regT3); 1759 move(regT2, regT3); 1760 move(regT0, regT2); 1761 move(TrustedImm32(0), regT1); 1762 1763 // Check for negative result reminder 1764 Jump positiveRegT3 = branch32(GreaterThanOrEqual, regT3, TrustedImm32(0)); 1765 neg32(regT3); 1766 xor32(TrustedImm32(1), regT1); 1767 positiveRegT3.link(this); 1768 1769 Jump positiveRegT2 = branch32(GreaterThanOrEqual, regT2, TrustedImm32(0)); 1770 neg32(regT2); 1771 xor32(TrustedImm32(2), regT1); 1772 positiveRegT2.link(this); 1773 1774 // Save the condition for negative reminder 1775 push(regT1); 1776 1777 Jump exitBranch = branch32(LessThan, regT2, regT3); 1778 1779 // Power of two fast case 1780 move(regT3, regT0); 1781 sub32(TrustedImm32(1), regT0); 1782 Jump powerOfTwo = branchTest32(NotEqual, regT0, regT3); 1783 and32(regT0, regT2); 1784 powerOfTwo.link(this); 1785 1786 and32(regT3, regT0); 1787 1788 Jump exitBranch2 = branchTest32(Zero, regT0); 1789 1790 countLeadingZeros32(regT2, regT0); 1791 countLeadingZeros32(regT3, regT1); 1792 sub32(regT0, regT1); 1793 1794 Jump useFullTable = branch32(Equal, regT1, TrustedImm32(31)); 1795 1796 neg32(regT1); 1797 add32(TrustedImm32(31), regT1); 1798 1799 int elementSizeByShift = -1; 1800 #if CPU(ARM) 1801 elementSizeByShift = 3; 1802 #else 1803 #error "JIT_OPTIMIZE_MOD not yet supported on this platform." 1804 #endif 1805 relativeTableJump(regT1, elementSizeByShift); 1806 1807 useFullTable.link(this); 1808 // Modulo table 1809 for (int i = 31; i > 0; --i) { 1810 #if CPU(ARM_TRADITIONAL) 1811 m_assembler.cmp_r(regT2, m_assembler.lsl(regT3, i)); 1812 m_assembler.sub_r(regT2, regT2, m_assembler.lsl(regT3, i), ARMAssembler::CS); 1813 #elif CPU(ARM_THUMB2) 1814 ShiftTypeAndAmount shift(SRType_LSL, i); 1815 m_assembler.sub_S(regT1, regT2, regT3, shift); 1816 m_assembler.it(ARMv7Assembler::ConditionCS); 1817 m_assembler.mov(regT2, regT1); 1818 #else 1819 #error "JIT_OPTIMIZE_MOD not yet supported on this platform." 1820 #endif 1821 } 1822 1823 Jump lower = branch32(Below, regT2, regT3); 1824 sub32(regT3, regT2); 1825 lower.link(this); 1826 1827 exitBranch.link(this); 1828 exitBranch2.link(this); 1829 1830 // Check for negative reminder 1831 pop(regT1); 1832 Jump positiveResult = branch32(Equal, regT1, TrustedImm32(0)); 1833 neg32(regT2); 1834 positiveResult.link(this); 1835 1836 move(regT2, regT0); 1837 1838 pop(regT3); 1839 pop(regT1); 1840 ret(); 1841 } 1842 #endif // ENABLE(JIT_USE_SOFT_MODULO) 1843 1844 } // namespace JSC 1845 1846 #endif // USE(JSVALUE32_64) 1847 #endif // ENABLE(JIT) 1848