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