1/* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2010 Patrick Gansterer <paroga@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 40namespace JSC { 41 42#if USE(JSVALUE64) 43 44#define RECORD_JUMP_TARGET(targetOffset) \ 45 do { m_labels[m_bytecodeOffset + (targetOffset)].used(); } while (false) 46 47void 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 189JIT::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 305JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool>, JSGlobalData* globalData, NativeFunction) 306{ 307 return globalData->jitStubs->ctiNativeCall(); 308} 309 310void 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 331void 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 339void 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 346void 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 366void JIT::emit_op_new_object(Instruction* currentInstruction) 367{ 368 JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand); 369} 370 371void 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 385void 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 432void JIT::emit_op_call(Instruction* currentInstruction) 433{ 434 compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++); 435} 436 437void JIT::emit_op_call_eval(Instruction* currentInstruction) 438{ 439 compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++); 440} 441 442void JIT::emit_op_call_varargs(Instruction* currentInstruction) 443{ 444 compileOpCallVarargs(currentInstruction); 445} 446 447void JIT::emit_op_construct(Instruction* currentInstruction) 448{ 449 compileOpCall(op_construct, currentInstruction, m_callLinkInfoIndex++); 450} 451 452void 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 460void 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 468void 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 491void 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 514void 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 528void 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 539void 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 559void 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 597void 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 605void 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 612void 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 628void 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 636void 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 643void 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 651void 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 659void 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 680void 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 695void 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 709void 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 724void 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}; 745void 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 767void 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 779void 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 790void JIT::emit_op_sret(Instruction* currentInstruction) 791{ 792 jump(Address(callFrameRegister, sizeof(Register) * currentInstruction[1].u.operand)); 793 killLastResultRegister(); 794} 795 796void 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 805void 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 814void 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 822void 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 829void 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 844void 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 855void 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 864void 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 872void 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 885void 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 928void 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 994void 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 1001void JIT::emit_op_pop_scope(Instruction*) 1002{ 1003 JITStubCall(this, cti_op_pop_scope).call(); 1004} 1005 1006void 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 1029void JIT::emit_op_stricteq(Instruction* currentInstruction) 1030{ 1031 compileOpStrictEq(currentInstruction, OpStrictEq); 1032} 1033 1034void JIT::emit_op_nstricteq(Instruction* currentInstruction) 1035{ 1036 compileOpStrictEq(currentInstruction, OpNStrictEq); 1037} 1038 1039void 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 1055void 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 1063void 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 1073void 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 1082void 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 1100void 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 1118void 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 1135void 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 1142void 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 1156void 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 1181void 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 1205void 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 1216void 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 1226void 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 1240void 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 1247void 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 1256void 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 1273void 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 1280void 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 1287void 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 1299void 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 1313void 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 1322void 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 1330void 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 1339void 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 1361void 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 1379void 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 1388void 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 1397void 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 1405void 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 1414void 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 1423void 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 1432void 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 1443void 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 1455void 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 1465void 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 1475void 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 1486void 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 1504void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1505{ 1506 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call); 1507} 1508 1509void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1510{ 1511 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call_eval); 1512} 1513 1514void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1515{ 1516 compileOpCallVarargsSlowCase(currentInstruction, iter); 1517} 1518 1519void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1520{ 1521 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_construct); 1522} 1523 1524void 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 1534void 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 1545void 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 1559void 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 1591void 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 1618void 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 1643void 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 1665void 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 1672void 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 1724void 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 1742void 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