1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "JIT.h" 28 29 #if ENABLE(JIT) 30 31 #include "JITInlineMethods.h" 32 #include "JITStubCall.h" 33 #include "JSArray.h" 34 #include "JSCell.h" 35 #include "JSFunction.h" 36 #include "JSPropertyNameIterator.h" 37 #include "LinkBuffer.h" 38 39 namespace JSC { 40 41 #if USE(JSVALUE32_64) 42 43 void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* globalData, TrampolineStructure *trampolines) 44 { 45 #if ENABLE(JIT_OPTIMIZE_MOD) 46 Label softModBegin = align(); 47 softModulo(); 48 #endif 49 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 50 // (1) This function provides fast property access for string length 51 Label stringLengthBegin = align(); 52 53 // regT0 holds payload, regT1 holds tag 54 55 Jump string_failureCases1 = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); 56 Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr)); 57 58 // Checks out okay! - get the length from the Ustring. 59 load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_stringLength)), regT2); 60 61 Jump string_failureCases3 = branch32(Above, regT2, Imm32(INT_MAX)); 62 move(regT2, regT0); 63 move(Imm32(JSValue::Int32Tag), regT1); 64 65 ret(); 66 #endif 67 68 // (2) Trampolines for the slow cases of op_call / op_call_eval / op_construct. 69 70 #if ENABLE(JIT_OPTIMIZE_CALL) 71 // VirtualCallLink Trampoline 72 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. 73 Label virtualCallLinkBegin = align(); 74 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 75 76 Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); 77 78 Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); 79 preserveReturnAddressAfterCall(regT3); 80 restoreArgumentReference(); 81 Call callJSFunction2 = call(); 82 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 83 emitGetJITStubArg(2, regT1); // argCount 84 restoreReturnAddressBeforeReturn(regT3); 85 hasCodeBlock2.link(this); 86 87 // Check argCount matches callee arity. 88 Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); 89 preserveReturnAddressAfterCall(regT3); 90 emitPutJITStubArg(regT3, 1); // return address 91 restoreArgumentReference(); 92 Call callArityCheck2 = call(); 93 move(regT1, callFrameRegister); 94 emitGetJITStubArg(2, regT1); // argCount 95 restoreReturnAddressBeforeReturn(regT3); 96 arityCheckOkay2.link(this); 97 98 isNativeFunc2.link(this); 99 100 compileOpCallInitializeCallFrame(); 101 102 preserveReturnAddressAfterCall(regT3); 103 emitPutJITStubArg(regT3, 1); // return address 104 restoreArgumentReference(); 105 Call callLazyLinkCall = call(); 106 restoreReturnAddressBeforeReturn(regT3); 107 jump(regT0); 108 #endif // ENABLE(JIT_OPTIMIZE_CALL) 109 110 // VirtualCall Trampoline 111 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. 112 Label virtualCallBegin = align(); 113 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 114 115 Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); 116 117 Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); 118 preserveReturnAddressAfterCall(regT3); 119 restoreArgumentReference(); 120 Call callJSFunction1 = call(); 121 emitGetJITStubArg(2, regT1); // argCount 122 restoreReturnAddressBeforeReturn(regT3); 123 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 124 hasCodeBlock3.link(this); 125 126 // Check argCount matches callee arity. 127 Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); 128 preserveReturnAddressAfterCall(regT3); 129 emitPutJITStubArg(regT3, 1); // return address 130 restoreArgumentReference(); 131 Call callArityCheck1 = call(); 132 move(regT1, callFrameRegister); 133 emitGetJITStubArg(2, regT1); // argCount 134 restoreReturnAddressBeforeReturn(regT3); 135 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 136 arityCheckOkay3.link(this); 137 138 isNativeFunc3.link(this); 139 140 compileOpCallInitializeCallFrame(); 141 loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCode)), regT0); 142 jump(regT0); 143 144 #if CPU(X86) || CPU(ARM_TRADITIONAL) 145 Label nativeCallThunk = align(); 146 preserveReturnAddressAfterCall(regT0); 147 emitPutToCallFrameHeader(regT0, RegisterFile::ReturnPC); // Push return address 148 149 // Load caller frame's scope chain into this callframe so that whatever we call can 150 // get to its global data. 151 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT1); 152 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT1); 153 emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); 154 155 #if CPU(X86) 156 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); 157 158 /* We have two structs that we use to describe the stackframe we set up for our 159 * call to native code. NativeCallFrameStructure describes the how we set up the stack 160 * in advance of the call. NativeFunctionCalleeSignature describes the callframe 161 * as the native code expects it. We do this as we are using the fastcall calling 162 * convention which results in the callee popping its arguments off the stack, but 163 * not the rest of the callframe so we need a nice way to ensure we increment the 164 * stack pointer by the right amount after the call. 165 */ 166 167 #if COMPILER(MSVC) || OS(LINUX) 168 #if COMPILER(MSVC) 169 #pragma pack(push) 170 #pragma pack(4) 171 #endif // COMPILER(MSVC) 172 struct NativeCallFrameStructure { 173 // CallFrame* callFrame; // passed in EDX 174 JSObject* callee; 175 JSValue thisValue; 176 ArgList* argPointer; 177 ArgList args; 178 JSValue result; 179 }; 180 struct NativeFunctionCalleeSignature { 181 JSObject* callee; 182 JSValue thisValue; 183 ArgList* argPointer; 184 }; 185 #if COMPILER(MSVC) 186 #pragma pack(pop) 187 #endif // COMPILER(MSVC) 188 #else 189 struct NativeCallFrameStructure { 190 // CallFrame* callFrame; // passed in ECX 191 // JSObject* callee; // passed in EDX 192 JSValue thisValue; 193 ArgList* argPointer; 194 ArgList args; 195 }; 196 struct NativeFunctionCalleeSignature { 197 JSValue thisValue; 198 ArgList* argPointer; 199 }; 200 #endif 201 202 const int NativeCallFrameSize = (sizeof(NativeCallFrameStructure) + 15) & ~15; 203 // Allocate system stack frame 204 subPtr(Imm32(NativeCallFrameSize), stackPointerRegister); 205 206 // Set up arguments 207 subPtr(Imm32(1), regT0); // Don't include 'this' in argcount 208 209 // push argcount 210 storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_argCount))); 211 212 // Calculate the start of the callframe header, and store in regT1 213 addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int)sizeof(Register)), callFrameRegister, regT1); 214 215 // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT0) 216 mul32(Imm32(sizeof(Register)), regT0, regT0); 217 subPtr(regT0, regT1); 218 storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_args))); 219 220 // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register) 221 addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, args)), stackPointerRegister, regT0); 222 storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, argPointer))); 223 224 // regT1 currently points to the first argument, regT1 - sizeof(Register) points to 'this' 225 loadPtr(Address(regT1, -(int)sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2); 226 loadPtr(Address(regT1, -(int)sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT3); 227 storePtr(regT2, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); 228 storePtr(regT3, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); 229 230 #if COMPILER(MSVC) || OS(LINUX) 231 // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register) 232 addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86Registers::ecx); 233 234 // Plant callee 235 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::eax); 236 storePtr(X86Registers::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee))); 237 238 // Plant callframe 239 move(callFrameRegister, X86Registers::edx); 240 241 call(Address(X86Registers::eax, OBJECT_OFFSETOF(JSFunction, m_data))); 242 243 // JSValue is a non-POD type, so eax points to it 244 emitLoad(0, regT1, regT0, X86Registers::eax); 245 #else 246 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::edx); // callee 247 move(callFrameRegister, X86Registers::ecx); // callFrame 248 call(Address(X86Registers::edx, OBJECT_OFFSETOF(JSFunction, m_data))); 249 #endif 250 251 // We've put a few temporaries on the stack in addition to the actual arguments 252 // so pull them off now 253 addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister); 254 255 #elif CPU(ARM_TRADITIONAL) 256 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); 257 258 // Allocate stack space for our arglist 259 COMPILE_ASSERT((sizeof(ArgList) & 0x7) == 0 && sizeof(JSValue) == 8 && sizeof(Register) == 8, ArgList_should_by_8byte_aligned); 260 subPtr(Imm32(sizeof(ArgList)), stackPointerRegister); 261 262 // Set up arguments 263 subPtr(Imm32(1), regT0); // Don't include 'this' in argcount 264 265 // Push argcount 266 storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount))); 267 268 // Calculate the start of the callframe header, and store in regT1 269 move(callFrameRegister, regT1); 270 sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1); 271 272 // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1) 273 mul32(Imm32(sizeof(Register)), regT0, regT0); 274 subPtr(regT0, regT1); 275 276 // push pointer to arguments 277 storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args))); 278 279 // Argument passing method: 280 // r0 - points to return value 281 // r1 - callFrame 282 // r2 - callee 283 // stack: this(JSValue) and a pointer to ArgList 284 285 move(stackPointerRegister, regT3); 286 subPtr(Imm32(8), stackPointerRegister); 287 move(stackPointerRegister, regT0); 288 subPtr(Imm32(8 + 4 + 4 /* padding */), stackPointerRegister); 289 290 // Setup arg4: 291 storePtr(regT3, Address(stackPointerRegister, 8)); 292 293 // Setup arg3 294 // regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this' 295 load32(Address(regT1, -(int32_t)sizeof(void*) * 2), regT3); 296 storePtr(regT3, Address(stackPointerRegister, 0)); 297 load32(Address(regT1, -(int32_t)sizeof(void*)), regT3); 298 storePtr(regT3, Address(stackPointerRegister, 4)); 299 300 // Setup arg2: 301 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT2); 302 303 // Setup arg1: 304 move(callFrameRegister, regT1); 305 306 call(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_data))); 307 308 // Load return value 309 load32(Address(stackPointerRegister, 16), regT0); 310 load32(Address(stackPointerRegister, 20), regT1); 311 312 addPtr(Imm32(sizeof(ArgList) + 16 + 8), stackPointerRegister); 313 #endif 314 315 // Check for an exception 316 move(ImmPtr(&globalData->exception), regT2); 317 Jump sawException = branch32(NotEqual, tagFor(0, regT2), Imm32(JSValue::EmptyValueTag)); 318 319 // Grab the return address. 320 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT3); 321 322 // Restore our caller's "r". 323 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); 324 325 // Return. 326 restoreReturnAddressBeforeReturn(regT3); 327 ret(); 328 329 // Handle an exception 330 sawException.link(this); 331 // Grab the return address. 332 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); 333 move(ImmPtr(&globalData->exceptionLocation), regT2); 334 storePtr(regT1, regT2); 335 move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT2); 336 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); 337 poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); 338 restoreReturnAddressBeforeReturn(regT2); 339 ret(); 340 341 #elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL) 342 #error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform." 343 #else 344 breakpoint(); 345 #endif 346 347 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 348 Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1); 349 Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2); 350 Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3); 351 #endif 352 353 // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. 354 LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size())); 355 356 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 357 patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail)); 358 patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail)); 359 patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail)); 360 #endif 361 patchBuffer.link(callArityCheck1, FunctionPtr(cti_op_call_arityCheck)); 362 patchBuffer.link(callJSFunction1, FunctionPtr(cti_op_call_JSFunction)); 363 #if ENABLE(JIT_OPTIMIZE_CALL) 364 patchBuffer.link(callArityCheck2, FunctionPtr(cti_op_call_arityCheck)); 365 patchBuffer.link(callJSFunction2, FunctionPtr(cti_op_call_JSFunction)); 366 patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall)); 367 #endif 368 369 CodeRef finalCode = patchBuffer.finalizeCode(); 370 *executablePool = finalCode.m_executablePool; 371 372 trampolines->ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin); 373 trampolines->ctiNativeCallThunk = trampolineAt(finalCode, nativeCallThunk); 374 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 375 trampolines->ctiStringLengthTrampoline = trampolineAt(finalCode, stringLengthBegin); 376 #else 377 UNUSED_PARAM(ctiStringLengthTrampoline); 378 #endif 379 #if ENABLE(JIT_OPTIMIZE_CALL) 380 trampolines->ctiVirtualCallLink = trampolineAt(finalCode, virtualCallLinkBegin); 381 #else 382 UNUSED_PARAM(ctiVirtualCallLink); 383 #endif 384 #if ENABLE(JIT_OPTIMIZE_MOD) 385 trampolines->ctiSoftModulo = trampolineAt(finalCode, softModBegin); 386 #endif 387 } 388 389 void JIT::emit_op_mov(Instruction* currentInstruction) 390 { 391 unsigned dst = currentInstruction[1].u.operand; 392 unsigned src = currentInstruction[2].u.operand; 393 394 if (m_codeBlock->isConstantRegisterIndex(src)) 395 emitStore(dst, getConstantOperand(src)); 396 else { 397 emitLoad(src, regT1, regT0); 398 emitStore(dst, regT1, regT0); 399 map(m_bytecodeIndex + OPCODE_LENGTH(op_mov), dst, regT1, regT0); 400 } 401 } 402 403 void JIT::emit_op_end(Instruction* currentInstruction) 404 { 405 if (m_codeBlock->needsFullScopeChain()) 406 JITStubCall(this, cti_op_end).call(); 407 ASSERT(returnValueRegister != callFrameRegister); 408 emitLoad(currentInstruction[1].u.operand, regT1, regT0); 409 restoreReturnAddressBeforeReturn(Address(callFrameRegister, RegisterFile::ReturnPC * static_cast<int>(sizeof(Register)))); 410 ret(); 411 } 412 413 void JIT::emit_op_jmp(Instruction* currentInstruction) 414 { 415 unsigned target = currentInstruction[1].u.operand; 416 addJump(jump(), target); 417 } 418 419 void JIT::emit_op_loop_if_lesseq(Instruction* currentInstruction) 420 { 421 unsigned op1 = currentInstruction[1].u.operand; 422 unsigned op2 = currentInstruction[2].u.operand; 423 unsigned target = currentInstruction[3].u.operand; 424 425 emitTimeoutCheck(); 426 427 if (isOperandConstantImmediateInt(op1)) { 428 emitLoad(op2, regT1, regT0); 429 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); 430 addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op1).asInt32())), target); 431 return; 432 } 433 434 if (isOperandConstantImmediateInt(op2)) { 435 emitLoad(op1, regT1, regT0); 436 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); 437 addJump(branch32(LessThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target); 438 return; 439 } 440 441 emitLoad2(op1, regT1, regT0, op2, regT3, regT2); 442 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); 443 addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); 444 addJump(branch32(LessThanOrEqual, regT0, regT2), target); 445 } 446 447 void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 448 { 449 unsigned op1 = currentInstruction[1].u.operand; 450 unsigned op2 = currentInstruction[2].u.operand; 451 unsigned target = currentInstruction[3].u.operand; 452 453 if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) 454 linkSlowCase(iter); // int32 check 455 linkSlowCase(iter); // int32 check 456 457 JITStubCall stubCall(this, cti_op_loop_if_lesseq); 458 stubCall.addArgument(op1); 459 stubCall.addArgument(op2); 460 stubCall.call(); 461 emitJumpSlowToHot(branchTest32(NonZero, regT0), target); 462 } 463 464 void JIT::emit_op_new_object(Instruction* currentInstruction) 465 { 466 JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand); 467 } 468 469 void JIT::emit_op_instanceof(Instruction* currentInstruction) 470 { 471 unsigned dst = currentInstruction[1].u.operand; 472 unsigned value = currentInstruction[2].u.operand; 473 unsigned baseVal = currentInstruction[3].u.operand; 474 unsigned proto = currentInstruction[4].u.operand; 475 476 // Load the operands into registers. 477 // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result. 478 emitLoadPayload(value, regT2); 479 emitLoadPayload(baseVal, regT0); 480 emitLoadPayload(proto, regT1); 481 482 // Check that value, baseVal, and proto are cells. 483 emitJumpSlowCaseIfNotJSCell(value); 484 emitJumpSlowCaseIfNotJSCell(baseVal); 485 emitJumpSlowCaseIfNotJSCell(proto); 486 487 // Check that baseVal 'ImplementsDefaultHasInstance'. 488 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); 489 addSlowCase(branchTest32(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsDefaultHasInstance))); 490 491 // Optimistically load the result true, and start looping. 492 // Initially, regT1 still contains proto and regT2 still contains value. 493 // As we loop regT2 will be updated with its prototype, recursively walking the prototype chain. 494 move(Imm32(JSValue::TrueTag), regT0); 495 Label loop(this); 496 497 // Load the prototype of the cell in regT2. If this is equal to regT1 - WIN! 498 // Otherwise, check if we've hit null - if we have then drop out of the loop, if not go again. 499 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 500 load32(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2); 501 Jump isInstance = branchPtr(Equal, regT2, regT1); 502 branchTest32(NonZero, regT2).linkTo(loop, this); 503 504 // We get here either by dropping out of the loop, or if value was not an Object. Result is false. 505 move(Imm32(JSValue::FalseTag), regT0); 506 507 // isInstance jumps right down to here, to skip setting the result to false (it has already set true). 508 isInstance.link(this); 509 emitStoreBool(dst, regT0); 510 } 511 512 void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 513 { 514 unsigned dst = currentInstruction[1].u.operand; 515 unsigned value = currentInstruction[2].u.operand; 516 unsigned baseVal = currentInstruction[3].u.operand; 517 unsigned proto = currentInstruction[4].u.operand; 518 519 linkSlowCaseIfNotJSCell(iter, value); 520 linkSlowCaseIfNotJSCell(iter, baseVal); 521 linkSlowCaseIfNotJSCell(iter, proto); 522 linkSlowCase(iter); 523 524 JITStubCall stubCall(this, cti_op_instanceof); 525 stubCall.addArgument(value); 526 stubCall.addArgument(baseVal); 527 stubCall.addArgument(proto); 528 stubCall.call(dst); 529 } 530 531 void JIT::emit_op_new_func(Instruction* currentInstruction) 532 { 533 JITStubCall stubCall(this, cti_op_new_func); 534 stubCall.addArgument(ImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand))); 535 stubCall.call(currentInstruction[1].u.operand); 536 } 537 538 void JIT::emit_op_get_global_var(Instruction* currentInstruction) 539 { 540 int dst = currentInstruction[1].u.operand; 541 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(currentInstruction[2].u.jsCell); 542 ASSERT(globalObject->isGlobalObject()); 543 int index = currentInstruction[3].u.operand; 544 545 loadPtr(&globalObject->d()->registers, regT2); 546 547 emitLoad(index, regT1, regT0, regT2); 548 emitStore(dst, regT1, regT0); 549 map(m_bytecodeIndex + OPCODE_LENGTH(op_get_global_var), dst, regT1, regT0); 550 } 551 552 void JIT::emit_op_put_global_var(Instruction* currentInstruction) 553 { 554 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(currentInstruction[1].u.jsCell); 555 ASSERT(globalObject->isGlobalObject()); 556 int index = currentInstruction[2].u.operand; 557 int value = currentInstruction[3].u.operand; 558 559 emitLoad(value, regT1, regT0); 560 561 loadPtr(&globalObject->d()->registers, regT2); 562 emitStore(index, regT1, regT0, regT2); 563 map(m_bytecodeIndex + OPCODE_LENGTH(op_put_global_var), value, regT1, regT0); 564 } 565 566 void JIT::emit_op_get_scoped_var(Instruction* currentInstruction) 567 { 568 int dst = currentInstruction[1].u.operand; 569 int index = currentInstruction[2].u.operand; 570 int skip = currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain(); 571 572 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2); 573 while (skip--) 574 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2); 575 576 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2); 577 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, d)), regT2); 578 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject::JSVariableObjectData, registers)), regT2); 579 580 emitLoad(index, regT1, regT0, regT2); 581 emitStore(dst, regT1, regT0); 582 map(m_bytecodeIndex + OPCODE_LENGTH(op_get_scoped_var), dst, regT1, regT0); 583 } 584 585 void JIT::emit_op_put_scoped_var(Instruction* currentInstruction) 586 { 587 int index = currentInstruction[1].u.operand; 588 int skip = currentInstruction[2].u.operand + m_codeBlock->needsFullScopeChain(); 589 int value = currentInstruction[3].u.operand; 590 591 emitLoad(value, regT1, regT0); 592 593 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2); 594 while (skip--) 595 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2); 596 597 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2); 598 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, d)), regT2); 599 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject::JSVariableObjectData, registers)), regT2); 600 601 emitStore(index, regT1, regT0, regT2); 602 map(m_bytecodeIndex + OPCODE_LENGTH(op_put_scoped_var), value, regT1, regT0); 603 } 604 605 void JIT::emit_op_tear_off_activation(Instruction* currentInstruction) 606 { 607 JITStubCall stubCall(this, cti_op_tear_off_activation); 608 stubCall.addArgument(currentInstruction[1].u.operand); 609 stubCall.call(); 610 } 611 612 void JIT::emit_op_tear_off_arguments(Instruction*) 613 { 614 JITStubCall(this, cti_op_tear_off_arguments).call(); 615 } 616 617 void JIT::emit_op_new_array(Instruction* currentInstruction) 618 { 619 JITStubCall stubCall(this, cti_op_new_array); 620 stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); 621 stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); 622 stubCall.call(currentInstruction[1].u.operand); 623 } 624 625 void JIT::emit_op_resolve(Instruction* currentInstruction) 626 { 627 JITStubCall stubCall(this, cti_op_resolve); 628 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 629 stubCall.call(currentInstruction[1].u.operand); 630 } 631 632 void JIT::emit_op_to_primitive(Instruction* currentInstruction) 633 { 634 int dst = currentInstruction[1].u.operand; 635 int src = currentInstruction[2].u.operand; 636 637 emitLoad(src, regT1, regT0); 638 639 Jump isImm = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); 640 addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr))); 641 isImm.link(this); 642 643 if (dst != src) 644 emitStore(dst, regT1, regT0); 645 map(m_bytecodeIndex + OPCODE_LENGTH(op_to_primitive), dst, regT1, regT0); 646 } 647 648 void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 649 { 650 int dst = currentInstruction[1].u.operand; 651 652 linkSlowCase(iter); 653 654 JITStubCall stubCall(this, cti_op_to_primitive); 655 stubCall.addArgument(regT1, regT0); 656 stubCall.call(dst); 657 } 658 659 void JIT::emit_op_strcat(Instruction* currentInstruction) 660 { 661 JITStubCall stubCall(this, cti_op_strcat); 662 stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); 663 stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); 664 stubCall.call(currentInstruction[1].u.operand); 665 } 666 667 void JIT::emit_op_resolve_base(Instruction* currentInstruction) 668 { 669 JITStubCall stubCall(this, cti_op_resolve_base); 670 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 671 stubCall.call(currentInstruction[1].u.operand); 672 } 673 674 void JIT::emit_op_resolve_skip(Instruction* currentInstruction) 675 { 676 JITStubCall stubCall(this, cti_op_resolve_skip); 677 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 678 stubCall.addArgument(Imm32(currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain())); 679 stubCall.call(currentInstruction[1].u.operand); 680 } 681 682 void JIT::emit_op_resolve_global(Instruction* currentInstruction) 683 { 684 // FIXME: Optimize to use patching instead of so many memory accesses. 685 686 unsigned dst = currentInstruction[1].u.operand; 687 void* globalObject = currentInstruction[2].u.jsCell; 688 689 unsigned currentIndex = m_globalResolveInfoIndex++; 690 void* structureAddress = &(m_codeBlock->globalResolveInfo(currentIndex).structure); 691 void* offsetAddr = &(m_codeBlock->globalResolveInfo(currentIndex).offset); 692 693 // Verify structure. 694 move(ImmPtr(globalObject), regT0); 695 loadPtr(structureAddress, regT1); 696 addSlowCase(branchPtr(NotEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)))); 697 698 // Load property. 699 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_externalStorage)), regT2); 700 load32(offsetAddr, regT3); 701 load32(BaseIndex(regT2, regT3, TimesEight), regT0); // payload 702 load32(BaseIndex(regT2, regT3, TimesEight, 4), regT1); // tag 703 emitStore(dst, regT1, regT0); 704 map(m_bytecodeIndex + OPCODE_LENGTH(op_resolve_global), dst, regT1, regT0); 705 } 706 707 void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 708 { 709 unsigned dst = currentInstruction[1].u.operand; 710 void* globalObject = currentInstruction[2].u.jsCell; 711 Identifier* ident = &m_codeBlock->identifier(currentInstruction[3].u.operand); 712 713 unsigned currentIndex = m_globalResolveInfoIndex++; 714 715 linkSlowCase(iter); 716 JITStubCall stubCall(this, cti_op_resolve_global); 717 stubCall.addArgument(ImmPtr(globalObject)); 718 stubCall.addArgument(ImmPtr(ident)); 719 stubCall.addArgument(Imm32(currentIndex)); 720 stubCall.call(dst); 721 } 722 723 void JIT::emit_op_not(Instruction* currentInstruction) 724 { 725 unsigned dst = currentInstruction[1].u.operand; 726 unsigned src = currentInstruction[2].u.operand; 727 728 emitLoadTag(src, regT0); 729 730 xor32(Imm32(JSValue::FalseTag), regT0); 731 addSlowCase(branchTest32(NonZero, regT0, Imm32(~1))); 732 xor32(Imm32(JSValue::TrueTag), regT0); 733 734 emitStoreBool(dst, regT0, (dst == src)); 735 } 736 737 void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 738 { 739 unsigned dst = currentInstruction[1].u.operand; 740 unsigned src = currentInstruction[2].u.operand; 741 742 linkSlowCase(iter); 743 744 JITStubCall stubCall(this, cti_op_not); 745 stubCall.addArgument(src); 746 stubCall.call(dst); 747 } 748 749 void JIT::emit_op_jfalse(Instruction* currentInstruction) 750 { 751 unsigned cond = currentInstruction[1].u.operand; 752 unsigned target = currentInstruction[2].u.operand; 753 754 emitLoad(cond, regT1, regT0); 755 756 Jump isTrue = branch32(Equal, regT1, Imm32(JSValue::TrueTag)); 757 addJump(branch32(Equal, regT1, Imm32(JSValue::FalseTag)), target); 758 759 Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); 760 Jump isTrue2 = branch32(NotEqual, regT0, Imm32(0)); 761 addJump(jump(), target); 762 763 if (supportsFloatingPoint()) { 764 isNotInteger.link(this); 765 766 addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); 767 768 zeroDouble(fpRegT0); 769 emitLoadDouble(cond, fpRegT1); 770 addJump(branchDouble(DoubleEqualOrUnordered, fpRegT0, fpRegT1), target); 771 } else 772 addSlowCase(isNotInteger); 773 774 isTrue.link(this); 775 isTrue2.link(this); 776 } 777 778 void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 779 { 780 unsigned cond = currentInstruction[1].u.operand; 781 unsigned target = currentInstruction[2].u.operand; 782 783 linkSlowCase(iter); 784 JITStubCall stubCall(this, cti_op_jtrue); 785 stubCall.addArgument(cond); 786 stubCall.call(); 787 emitJumpSlowToHot(branchTest32(Zero, regT0), target); // Inverted. 788 } 789 790 void JIT::emit_op_jtrue(Instruction* currentInstruction) 791 { 792 unsigned cond = currentInstruction[1].u.operand; 793 unsigned target = currentInstruction[2].u.operand; 794 795 emitLoad(cond, regT1, regT0); 796 797 Jump isFalse = branch32(Equal, regT1, Imm32(JSValue::FalseTag)); 798 addJump(branch32(Equal, regT1, Imm32(JSValue::TrueTag)), target); 799 800 Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); 801 Jump isFalse2 = branch32(Equal, regT0, Imm32(0)); 802 addJump(jump(), target); 803 804 if (supportsFloatingPoint()) { 805 isNotInteger.link(this); 806 807 addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); 808 809 zeroDouble(fpRegT0); 810 emitLoadDouble(cond, fpRegT1); 811 addJump(branchDouble(DoubleNotEqual, fpRegT0, fpRegT1), target); 812 } else 813 addSlowCase(isNotInteger); 814 815 isFalse.link(this); 816 isFalse2.link(this); 817 } 818 819 void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 820 { 821 unsigned cond = currentInstruction[1].u.operand; 822 unsigned target = currentInstruction[2].u.operand; 823 824 linkSlowCase(iter); 825 JITStubCall stubCall(this, cti_op_jtrue); 826 stubCall.addArgument(cond); 827 stubCall.call(); 828 emitJumpSlowToHot(branchTest32(NonZero, regT0), target); 829 } 830 831 void JIT::emit_op_jeq_null(Instruction* currentInstruction) 832 { 833 unsigned src = currentInstruction[1].u.operand; 834 unsigned target = currentInstruction[2].u.operand; 835 836 emitLoad(src, regT1, regT0); 837 838 Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); 839 840 // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. 841 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 842 addJump(branchTest32(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target); 843 844 Jump wasNotImmediate = jump(); 845 846 // Now handle the immediate cases - undefined & null 847 isImmediate.link(this); 848 849 set32(Equal, regT1, Imm32(JSValue::NullTag), regT2); 850 set32(Equal, regT1, Imm32(JSValue::UndefinedTag), regT1); 851 or32(regT2, regT1); 852 853 addJump(branchTest32(NonZero, regT1), target); 854 855 wasNotImmediate.link(this); 856 } 857 858 void JIT::emit_op_jneq_null(Instruction* currentInstruction) 859 { 860 unsigned src = currentInstruction[1].u.operand; 861 unsigned target = currentInstruction[2].u.operand; 862 863 emitLoad(src, regT1, regT0); 864 865 Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); 866 867 // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. 868 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 869 addJump(branchTest32(Zero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target); 870 871 Jump wasNotImmediate = jump(); 872 873 // Now handle the immediate cases - undefined & null 874 isImmediate.link(this); 875 876 set32(Equal, regT1, Imm32(JSValue::NullTag), regT2); 877 set32(Equal, regT1, Imm32(JSValue::UndefinedTag), regT1); 878 or32(regT2, regT1); 879 880 addJump(branchTest32(Zero, regT1), target); 881 882 wasNotImmediate.link(this); 883 } 884 885 void JIT::emit_op_jneq_ptr(Instruction* currentInstruction) 886 { 887 unsigned src = currentInstruction[1].u.operand; 888 JSCell* ptr = currentInstruction[2].u.jsCell; 889 unsigned target = currentInstruction[3].u.operand; 890 891 emitLoad(src, regT1, regT0); 892 addJump(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)), target); 893 addJump(branchPtr(NotEqual, regT0, ImmPtr(ptr)), target); 894 } 895 896 void JIT::emit_op_jsr(Instruction* currentInstruction) 897 { 898 int retAddrDst = currentInstruction[1].u.operand; 899 int target = currentInstruction[2].u.operand; 900 DataLabelPtr storeLocation = storePtrWithPatch(ImmPtr(0), Address(callFrameRegister, sizeof(Register) * retAddrDst)); 901 addJump(jump(), target); 902 m_jsrSites.append(JSRInfo(storeLocation, label())); 903 } 904 905 void JIT::emit_op_sret(Instruction* currentInstruction) 906 { 907 jump(Address(callFrameRegister, sizeof(Register) * currentInstruction[1].u.operand)); 908 } 909 910 void JIT::emit_op_eq(Instruction* currentInstruction) 911 { 912 unsigned dst = currentInstruction[1].u.operand; 913 unsigned src1 = currentInstruction[2].u.operand; 914 unsigned src2 = currentInstruction[3].u.operand; 915 916 emitLoad2(src1, regT1, regT0, src2, regT3, regT2); 917 addSlowCase(branch32(NotEqual, regT1, regT3)); 918 addSlowCase(branch32(Equal, regT1, Imm32(JSValue::CellTag))); 919 addSlowCase(branch32(Below, regT1, Imm32(JSValue::LowestTag))); 920 921 set8(Equal, regT0, regT2, regT0); 922 or32(Imm32(JSValue::FalseTag), regT0); 923 924 emitStoreBool(dst, regT0); 925 } 926 927 void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 928 { 929 unsigned dst = currentInstruction[1].u.operand; 930 unsigned op1 = currentInstruction[2].u.operand; 931 unsigned op2 = currentInstruction[3].u.operand; 932 933 JumpList storeResult; 934 JumpList genericCase; 935 936 genericCase.append(getSlowCase(iter)); // tags not equal 937 938 linkSlowCase(iter); // tags equal and JSCell 939 genericCase.append(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr))); 940 genericCase.append(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsStringVPtr))); 941 942 // String case. 943 JITStubCall stubCallEqStrings(this, cti_op_eq_strings); 944 stubCallEqStrings.addArgument(regT0); 945 stubCallEqStrings.addArgument(regT2); 946 stubCallEqStrings.call(); 947 storeResult.append(jump()); 948 949 // Generic case. 950 genericCase.append(getSlowCase(iter)); // doubles 951 genericCase.link(this); 952 JITStubCall stubCallEq(this, cti_op_eq); 953 stubCallEq.addArgument(op1); 954 stubCallEq.addArgument(op2); 955 stubCallEq.call(regT0); 956 957 storeResult.link(this); 958 or32(Imm32(JSValue::FalseTag), regT0); 959 emitStoreBool(dst, regT0); 960 } 961 962 void JIT::emit_op_neq(Instruction* currentInstruction) 963 { 964 unsigned dst = currentInstruction[1].u.operand; 965 unsigned src1 = currentInstruction[2].u.operand; 966 unsigned src2 = currentInstruction[3].u.operand; 967 968 emitLoad2(src1, regT1, regT0, src2, regT3, regT2); 969 addSlowCase(branch32(NotEqual, regT1, regT3)); 970 addSlowCase(branch32(Equal, regT1, Imm32(JSValue::CellTag))); 971 addSlowCase(branch32(Below, regT1, Imm32(JSValue::LowestTag))); 972 973 set8(NotEqual, regT0, regT2, regT0); 974 or32(Imm32(JSValue::FalseTag), regT0); 975 976 emitStoreBool(dst, regT0); 977 } 978 979 void JIT::emitSlow_op_neq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 980 { 981 unsigned dst = currentInstruction[1].u.operand; 982 983 JumpList storeResult; 984 JumpList genericCase; 985 986 genericCase.append(getSlowCase(iter)); // tags not equal 987 988 linkSlowCase(iter); // tags equal and JSCell 989 genericCase.append(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr))); 990 genericCase.append(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsStringVPtr))); 991 992 // String case. 993 JITStubCall stubCallEqStrings(this, cti_op_eq_strings); 994 stubCallEqStrings.addArgument(regT0); 995 stubCallEqStrings.addArgument(regT2); 996 stubCallEqStrings.call(regT0); 997 storeResult.append(jump()); 998 999 // Generic case. 1000 genericCase.append(getSlowCase(iter)); // doubles 1001 genericCase.link(this); 1002 JITStubCall stubCallEq(this, cti_op_eq); 1003 stubCallEq.addArgument(regT1, regT0); 1004 stubCallEq.addArgument(regT3, regT2); 1005 stubCallEq.call(regT0); 1006 1007 storeResult.link(this); 1008 xor32(Imm32(0x1), regT0); 1009 or32(Imm32(JSValue::FalseTag), regT0); 1010 emitStoreBool(dst, regT0); 1011 } 1012 1013 void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqType type) 1014 { 1015 unsigned dst = currentInstruction[1].u.operand; 1016 unsigned src1 = currentInstruction[2].u.operand; 1017 unsigned src2 = currentInstruction[3].u.operand; 1018 1019 emitLoadTag(src1, regT0); 1020 emitLoadTag(src2, regT1); 1021 1022 // Jump to a slow case if either operand is double, or if both operands are 1023 // cells and/or Int32s. 1024 move(regT0, regT2); 1025 and32(regT1, regT2); 1026 addSlowCase(branch32(Below, regT2, Imm32(JSValue::LowestTag))); 1027 addSlowCase(branch32(AboveOrEqual, regT2, Imm32(JSValue::CellTag))); 1028 1029 if (type == OpStrictEq) 1030 set8(Equal, regT0, regT1, regT0); 1031 else 1032 set8(NotEqual, regT0, regT1, regT0); 1033 1034 or32(Imm32(JSValue::FalseTag), regT0); 1035 1036 emitStoreBool(dst, regT0); 1037 } 1038 1039 void JIT::emit_op_stricteq(Instruction* currentInstruction) 1040 { 1041 compileOpStrictEq(currentInstruction, OpStrictEq); 1042 } 1043 1044 void JIT::emitSlow_op_stricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1045 { 1046 unsigned dst = currentInstruction[1].u.operand; 1047 unsigned src1 = currentInstruction[2].u.operand; 1048 unsigned src2 = currentInstruction[3].u.operand; 1049 1050 linkSlowCase(iter); 1051 linkSlowCase(iter); 1052 1053 JITStubCall stubCall(this, cti_op_stricteq); 1054 stubCall.addArgument(src1); 1055 stubCall.addArgument(src2); 1056 stubCall.call(dst); 1057 } 1058 1059 void JIT::emit_op_nstricteq(Instruction* currentInstruction) 1060 { 1061 compileOpStrictEq(currentInstruction, OpNStrictEq); 1062 } 1063 1064 void JIT::emitSlow_op_nstricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1065 { 1066 unsigned dst = currentInstruction[1].u.operand; 1067 unsigned src1 = currentInstruction[2].u.operand; 1068 unsigned src2 = currentInstruction[3].u.operand; 1069 1070 linkSlowCase(iter); 1071 linkSlowCase(iter); 1072 1073 JITStubCall stubCall(this, cti_op_nstricteq); 1074 stubCall.addArgument(src1); 1075 stubCall.addArgument(src2); 1076 stubCall.call(dst); 1077 } 1078 1079 void JIT::emit_op_eq_null(Instruction* currentInstruction) 1080 { 1081 unsigned dst = currentInstruction[1].u.operand; 1082 unsigned src = currentInstruction[2].u.operand; 1083 1084 emitLoad(src, regT1, regT0); 1085 Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); 1086 1087 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT1); 1088 setTest8(NonZero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined), regT1); 1089 1090 Jump wasNotImmediate = jump(); 1091 1092 isImmediate.link(this); 1093 1094 set8(Equal, regT1, Imm32(JSValue::NullTag), regT2); 1095 set8(Equal, regT1, Imm32(JSValue::UndefinedTag), regT1); 1096 or32(regT2, regT1); 1097 1098 wasNotImmediate.link(this); 1099 1100 or32(Imm32(JSValue::FalseTag), regT1); 1101 1102 emitStoreBool(dst, regT1); 1103 } 1104 1105 void JIT::emit_op_neq_null(Instruction* currentInstruction) 1106 { 1107 unsigned dst = currentInstruction[1].u.operand; 1108 unsigned src = currentInstruction[2].u.operand; 1109 1110 emitLoad(src, regT1, regT0); 1111 Jump isImmediate = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); 1112 1113 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT1); 1114 setTest8(Zero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined), regT1); 1115 1116 Jump wasNotImmediate = jump(); 1117 1118 isImmediate.link(this); 1119 1120 set8(NotEqual, regT1, Imm32(JSValue::NullTag), regT2); 1121 set8(NotEqual, regT1, Imm32(JSValue::UndefinedTag), regT1); 1122 and32(regT2, regT1); 1123 1124 wasNotImmediate.link(this); 1125 1126 or32(Imm32(JSValue::FalseTag), regT1); 1127 1128 emitStoreBool(dst, regT1); 1129 } 1130 1131 void JIT::emit_op_resolve_with_base(Instruction* currentInstruction) 1132 { 1133 JITStubCall stubCall(this, cti_op_resolve_with_base); 1134 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); 1135 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 1136 stubCall.call(currentInstruction[2].u.operand); 1137 } 1138 1139 void JIT::emit_op_new_func_exp(Instruction* currentInstruction) 1140 { 1141 JITStubCall stubCall(this, cti_op_new_func_exp); 1142 stubCall.addArgument(ImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand))); 1143 stubCall.call(currentInstruction[1].u.operand); 1144 } 1145 1146 void JIT::emit_op_new_regexp(Instruction* currentInstruction) 1147 { 1148 JITStubCall stubCall(this, cti_op_new_regexp); 1149 stubCall.addArgument(ImmPtr(m_codeBlock->regexp(currentInstruction[2].u.operand))); 1150 stubCall.call(currentInstruction[1].u.operand); 1151 } 1152 1153 void JIT::emit_op_throw(Instruction* currentInstruction) 1154 { 1155 unsigned exception = currentInstruction[1].u.operand; 1156 JITStubCall stubCall(this, cti_op_throw); 1157 stubCall.addArgument(exception); 1158 stubCall.call(); 1159 1160 #ifndef NDEBUG 1161 // cti_op_throw always changes it's return address, 1162 // this point in the code should never be reached. 1163 breakpoint(); 1164 #endif 1165 } 1166 1167 void JIT::emit_op_get_pnames(Instruction* currentInstruction) 1168 { 1169 int dst = currentInstruction[1].u.operand; 1170 int base = currentInstruction[2].u.operand; 1171 int i = currentInstruction[3].u.operand; 1172 int size = currentInstruction[4].u.operand; 1173 int breakTarget = currentInstruction[5].u.operand; 1174 1175 JumpList isNotObject; 1176 1177 emitLoad(base, regT1, regT0); 1178 if (!m_codeBlock->isKnownNotImmediate(base)) 1179 isNotObject.append(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); 1180 if (base != m_codeBlock->thisRegister()) { 1181 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 1182 isNotObject.append(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); 1183 } 1184 1185 // We could inline the case where you have a valid cache, but 1186 // this call doesn't seem to be hot. 1187 Label isObject(this); 1188 JITStubCall getPnamesStubCall(this, cti_op_get_pnames); 1189 getPnamesStubCall.addArgument(regT0); 1190 getPnamesStubCall.call(dst); 1191 load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3); 1192 store32(Imm32(0), addressFor(i)); 1193 store32(regT3, addressFor(size)); 1194 Jump end = jump(); 1195 1196 isNotObject.link(this); 1197 addJump(branch32(Equal, regT1, Imm32(JSValue::NullTag)), breakTarget); 1198 addJump(branch32(Equal, regT1, Imm32(JSValue::UndefinedTag)), breakTarget); 1199 JITStubCall toObjectStubCall(this, cti_to_object); 1200 toObjectStubCall.addArgument(regT1, regT0); 1201 toObjectStubCall.call(base); 1202 jump().linkTo(isObject, this); 1203 1204 end.link(this); 1205 } 1206 1207 void JIT::emit_op_next_pname(Instruction* currentInstruction) 1208 { 1209 int dst = currentInstruction[1].u.operand; 1210 int base = currentInstruction[2].u.operand; 1211 int i = currentInstruction[3].u.operand; 1212 int size = currentInstruction[4].u.operand; 1213 int it = currentInstruction[5].u.operand; 1214 int target = currentInstruction[6].u.operand; 1215 1216 JumpList callHasProperty; 1217 1218 Label begin(this); 1219 load32(addressFor(i), regT0); 1220 Jump end = branch32(Equal, regT0, addressFor(size)); 1221 1222 // Grab key @ i 1223 loadPtr(addressFor(it), regT1); 1224 loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2); 1225 load32(BaseIndex(regT2, regT0, TimesEight), regT2); 1226 store32(Imm32(JSValue::CellTag), tagFor(dst)); 1227 store32(regT2, payloadFor(dst)); 1228 1229 // Increment i 1230 add32(Imm32(1), regT0); 1231 store32(regT0, addressFor(i)); 1232 1233 // Verify that i is valid: 1234 loadPtr(addressFor(base), regT0); 1235 1236 // Test base's structure 1237 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 1238 callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))))); 1239 1240 // Test base's prototype chain 1241 loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3); 1242 loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3); 1243 addJump(branchTestPtr(Zero, Address(regT3)), target); 1244 1245 Label checkPrototype(this); 1246 callHasProperty.append(branch32(Equal, Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::NullTag))); 1247 loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2); 1248 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 1249 callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3))); 1250 addPtr(Imm32(sizeof(Structure*)), regT3); 1251 branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this); 1252 1253 // Continue loop. 1254 addJump(jump(), target); 1255 1256 // Slow case: Ask the object if i is valid. 1257 callHasProperty.link(this); 1258 loadPtr(addressFor(dst), regT1); 1259 JITStubCall stubCall(this, cti_has_property); 1260 stubCall.addArgument(regT0); 1261 stubCall.addArgument(regT1); 1262 stubCall.call(); 1263 1264 // Test for valid key. 1265 addJump(branchTest32(NonZero, regT0), target); 1266 jump().linkTo(begin, this); 1267 1268 // End of loop. 1269 end.link(this); 1270 } 1271 1272 void JIT::emit_op_push_scope(Instruction* currentInstruction) 1273 { 1274 JITStubCall stubCall(this, cti_op_push_scope); 1275 stubCall.addArgument(currentInstruction[1].u.operand); 1276 stubCall.call(currentInstruction[1].u.operand); 1277 } 1278 1279 void JIT::emit_op_pop_scope(Instruction*) 1280 { 1281 JITStubCall(this, cti_op_pop_scope).call(); 1282 } 1283 1284 void JIT::emit_op_to_jsnumber(Instruction* currentInstruction) 1285 { 1286 int dst = currentInstruction[1].u.operand; 1287 int src = currentInstruction[2].u.operand; 1288 1289 emitLoad(src, regT1, regT0); 1290 1291 Jump isInt32 = branch32(Equal, regT1, Imm32(JSValue::Int32Tag)); 1292 addSlowCase(branch32(AboveOrEqual, regT1, Imm32(JSValue::EmptyValueTag))); 1293 isInt32.link(this); 1294 1295 if (src != dst) 1296 emitStore(dst, regT1, regT0); 1297 map(m_bytecodeIndex + OPCODE_LENGTH(op_to_jsnumber), dst, regT1, regT0); 1298 } 1299 1300 void JIT::emitSlow_op_to_jsnumber(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1301 { 1302 int dst = currentInstruction[1].u.operand; 1303 1304 linkSlowCase(iter); 1305 1306 JITStubCall stubCall(this, cti_op_to_jsnumber); 1307 stubCall.addArgument(regT1, regT0); 1308 stubCall.call(dst); 1309 } 1310 1311 void JIT::emit_op_push_new_scope(Instruction* currentInstruction) 1312 { 1313 JITStubCall stubCall(this, cti_op_push_new_scope); 1314 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 1315 stubCall.addArgument(currentInstruction[3].u.operand); 1316 stubCall.call(currentInstruction[1].u.operand); 1317 } 1318 1319 void JIT::emit_op_catch(Instruction* currentInstruction) 1320 { 1321 unsigned exception = currentInstruction[1].u.operand; 1322 1323 // This opcode only executes after a return from cti_op_throw. 1324 1325 // cti_op_throw may have taken us to a call frame further up the stack; reload 1326 // the call frame pointer to adjust. 1327 peek(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); 1328 1329 // Now store the exception returned by cti_op_throw. 1330 emitStore(exception, regT1, regT0); 1331 map(m_bytecodeIndex + OPCODE_LENGTH(op_catch), exception, regT1, regT0); 1332 } 1333 1334 void JIT::emit_op_jmp_scopes(Instruction* currentInstruction) 1335 { 1336 JITStubCall stubCall(this, cti_op_jmp_scopes); 1337 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 1338 stubCall.call(); 1339 addJump(jump(), currentInstruction[2].u.operand); 1340 } 1341 1342 void JIT::emit_op_switch_imm(Instruction* currentInstruction) 1343 { 1344 unsigned tableIndex = currentInstruction[1].u.operand; 1345 unsigned defaultOffset = currentInstruction[2].u.operand; 1346 unsigned scrutinee = currentInstruction[3].u.operand; 1347 1348 // create jump table for switch destinations, track this switch statement. 1349 SimpleJumpTable* jumpTable = &m_codeBlock->immediateSwitchJumpTable(tableIndex); 1350 m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Immediate)); 1351 jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); 1352 1353 JITStubCall stubCall(this, cti_op_switch_imm); 1354 stubCall.addArgument(scrutinee); 1355 stubCall.addArgument(Imm32(tableIndex)); 1356 stubCall.call(); 1357 jump(regT0); 1358 } 1359 1360 void JIT::emit_op_switch_char(Instruction* currentInstruction) 1361 { 1362 unsigned tableIndex = currentInstruction[1].u.operand; 1363 unsigned defaultOffset = currentInstruction[2].u.operand; 1364 unsigned scrutinee = currentInstruction[3].u.operand; 1365 1366 // create jump table for switch destinations, track this switch statement. 1367 SimpleJumpTable* jumpTable = &m_codeBlock->characterSwitchJumpTable(tableIndex); 1368 m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Character)); 1369 jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); 1370 1371 JITStubCall stubCall(this, cti_op_switch_char); 1372 stubCall.addArgument(scrutinee); 1373 stubCall.addArgument(Imm32(tableIndex)); 1374 stubCall.call(); 1375 jump(regT0); 1376 } 1377 1378 void JIT::emit_op_switch_string(Instruction* currentInstruction) 1379 { 1380 unsigned tableIndex = currentInstruction[1].u.operand; 1381 unsigned defaultOffset = currentInstruction[2].u.operand; 1382 unsigned scrutinee = currentInstruction[3].u.operand; 1383 1384 // create jump table for switch destinations, track this switch statement. 1385 StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTable(tableIndex); 1386 m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset)); 1387 1388 JITStubCall stubCall(this, cti_op_switch_string); 1389 stubCall.addArgument(scrutinee); 1390 stubCall.addArgument(Imm32(tableIndex)); 1391 stubCall.call(); 1392 jump(regT0); 1393 } 1394 1395 void JIT::emit_op_new_error(Instruction* currentInstruction) 1396 { 1397 unsigned dst = currentInstruction[1].u.operand; 1398 unsigned type = currentInstruction[2].u.operand; 1399 unsigned message = currentInstruction[3].u.operand; 1400 1401 JITStubCall stubCall(this, cti_op_new_error); 1402 stubCall.addArgument(Imm32(type)); 1403 stubCall.addArgument(m_codeBlock->getConstant(message)); 1404 stubCall.addArgument(Imm32(m_bytecodeIndex)); 1405 stubCall.call(dst); 1406 } 1407 1408 void JIT::emit_op_debug(Instruction* currentInstruction) 1409 { 1410 JITStubCall stubCall(this, cti_op_debug); 1411 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 1412 stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); 1413 stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); 1414 stubCall.call(); 1415 } 1416 1417 1418 void JIT::emit_op_enter(Instruction*) 1419 { 1420 // Even though JIT code doesn't use them, we initialize our constant 1421 // registers to zap stale pointers, to avoid unnecessarily prolonging 1422 // object lifetime and increasing GC pressure. 1423 for (int i = 0; i < m_codeBlock->m_numVars; ++i) 1424 emitStore(i, jsUndefined()); 1425 } 1426 1427 void JIT::emit_op_enter_with_activation(Instruction* currentInstruction) 1428 { 1429 emit_op_enter(currentInstruction); 1430 1431 JITStubCall(this, cti_op_push_activation).call(currentInstruction[1].u.operand); 1432 } 1433 1434 void JIT::emit_op_create_arguments(Instruction*) 1435 { 1436 Jump argsCreated = branch32(NotEqual, tagFor(RegisterFile::ArgumentsRegister, callFrameRegister), Imm32(JSValue::EmptyValueTag)); 1437 1438 // If we get here the arguments pointer is a null cell - i.e. arguments need lazy creation. 1439 if (m_codeBlock->m_numParameters == 1) 1440 JITStubCall(this, cti_op_create_arguments_no_params).call(); 1441 else 1442 JITStubCall(this, cti_op_create_arguments).call(); 1443 1444 argsCreated.link(this); 1445 } 1446 1447 void JIT::emit_op_init_arguments(Instruction*) 1448 { 1449 emitStore(RegisterFile::ArgumentsRegister, JSValue(), callFrameRegister); 1450 } 1451 1452 void JIT::emit_op_convert_this(Instruction* currentInstruction) 1453 { 1454 unsigned thisRegister = currentInstruction[1].u.operand; 1455 1456 emitLoad(thisRegister, regT1, regT0); 1457 1458 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); 1459 1460 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 1461 addSlowCase(branchTest32(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(NeedsThisConversion))); 1462 1463 map(m_bytecodeIndex + OPCODE_LENGTH(op_convert_this), thisRegister, regT1, regT0); 1464 } 1465 1466 void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1467 { 1468 unsigned thisRegister = currentInstruction[1].u.operand; 1469 1470 linkSlowCase(iter); 1471 linkSlowCase(iter); 1472 1473 JITStubCall stubCall(this, cti_op_convert_this); 1474 stubCall.addArgument(regT1, regT0); 1475 stubCall.call(thisRegister); 1476 } 1477 1478 void JIT::emit_op_profile_will_call(Instruction* currentInstruction) 1479 { 1480 peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof (void*)); 1481 Jump noProfiler = branchTestPtr(Zero, Address(regT2)); 1482 1483 JITStubCall stubCall(this, cti_op_profile_will_call); 1484 stubCall.addArgument(currentInstruction[1].u.operand); 1485 stubCall.call(); 1486 noProfiler.link(this); 1487 } 1488 1489 void JIT::emit_op_profile_did_call(Instruction* currentInstruction) 1490 { 1491 peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof (void*)); 1492 Jump noProfiler = branchTestPtr(Zero, Address(regT2)); 1493 1494 JITStubCall stubCall(this, cti_op_profile_did_call); 1495 stubCall.addArgument(currentInstruction[1].u.operand); 1496 stubCall.call(); 1497 noProfiler.link(this); 1498 } 1499 1500 #else // USE(JSVALUE32_64) 1501 1502 #define RECORD_JUMP_TARGET(targetOffset) \ 1503 do { m_labels[m_bytecodeIndex + (targetOffset)].used(); } while (false) 1504 1505 void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* globalData, TrampolineStructure *trampolines) 1506 { 1507 #if ENABLE(JIT_OPTIMIZE_MOD) 1508 Label softModBegin = align(); 1509 softModulo(); 1510 #endif 1511 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 1512 // (2) The second function provides fast property access for string length 1513 Label stringLengthBegin = align(); 1514 1515 // Check eax is a string 1516 Jump string_failureCases1 = emitJumpIfNotJSCell(regT0); 1517 Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr)); 1518 1519 // Checks out okay! - get the length from the Ustring. 1520 load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_stringLength)), regT0); 1521 1522 Jump string_failureCases3 = branch32(Above, regT0, Imm32(JSImmediate::maxImmediateInt)); 1523 1524 // regT0 contains a 64 bit value (is positive, is zero extended) so we don't need sign extend here. 1525 emitFastArithIntToImmNoCheck(regT0, regT0); 1526 1527 ret(); 1528 #endif 1529 1530 // (3) Trampolines for the slow cases of op_call / op_call_eval / op_construct. 1531 COMPILE_ASSERT(sizeof(CodeType) == 4, CodeTypeEnumMustBe32Bit); 1532 1533 // VirtualCallLink Trampoline 1534 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. 1535 Label virtualCallLinkBegin = align(); 1536 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 1537 1538 Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); 1539 1540 Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); 1541 preserveReturnAddressAfterCall(regT3); 1542 restoreArgumentReference(); 1543 Call callJSFunction2 = call(); 1544 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 1545 emitGetJITStubArg(2, regT1); // argCount 1546 restoreReturnAddressBeforeReturn(regT3); 1547 hasCodeBlock2.link(this); 1548 1549 // Check argCount matches callee arity. 1550 Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); 1551 preserveReturnAddressAfterCall(regT3); 1552 emitPutJITStubArg(regT3, 1); // return address 1553 restoreArgumentReference(); 1554 Call callArityCheck2 = call(); 1555 move(regT1, callFrameRegister); 1556 emitGetJITStubArg(2, regT1); // argCount 1557 restoreReturnAddressBeforeReturn(regT3); 1558 arityCheckOkay2.link(this); 1559 1560 isNativeFunc2.link(this); 1561 1562 compileOpCallInitializeCallFrame(); 1563 preserveReturnAddressAfterCall(regT3); 1564 emitPutJITStubArg(regT3, 1); // return address 1565 restoreArgumentReference(); 1566 Call callLazyLinkCall = call(); 1567 restoreReturnAddressBeforeReturn(regT3); 1568 jump(regT0); 1569 1570 // VirtualCall Trampoline 1571 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. 1572 Label virtualCallBegin = align(); 1573 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 1574 1575 Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); 1576 1577 Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); 1578 preserveReturnAddressAfterCall(regT3); 1579 restoreArgumentReference(); 1580 Call callJSFunction1 = call(); 1581 emitGetJITStubArg(2, regT1); // argCount 1582 restoreReturnAddressBeforeReturn(regT3); 1583 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 1584 hasCodeBlock3.link(this); 1585 1586 // Check argCount matches callee arity. 1587 Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); 1588 preserveReturnAddressAfterCall(regT3); 1589 emitPutJITStubArg(regT3, 1); // return address 1590 restoreArgumentReference(); 1591 Call callArityCheck1 = call(); 1592 move(regT1, callFrameRegister); 1593 emitGetJITStubArg(2, regT1); // argCount 1594 restoreReturnAddressBeforeReturn(regT3); 1595 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); 1596 arityCheckOkay3.link(this); 1597 1598 isNativeFunc3.link(this); 1599 1600 compileOpCallInitializeCallFrame(); 1601 loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCode)), regT0); 1602 jump(regT0); 1603 1604 Label nativeCallThunk = align(); 1605 preserveReturnAddressAfterCall(regT0); 1606 emitPutToCallFrameHeader(regT0, RegisterFile::ReturnPC); // Push return address 1607 1608 // Load caller frame's scope chain into this callframe so that whatever we call can 1609 // get to its global data. 1610 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT1); 1611 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT1); 1612 emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); 1613 1614 1615 #if CPU(X86_64) 1616 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, X86Registers::ecx); 1617 1618 // Allocate stack space for our arglist 1619 subPtr(Imm32(sizeof(ArgList)), stackPointerRegister); 1620 COMPILE_ASSERT((sizeof(ArgList) & 0xf) == 0, ArgList_should_by_16byte_aligned); 1621 1622 // Set up arguments 1623 subPtr(Imm32(1), X86Registers::ecx); // Don't include 'this' in argcount 1624 1625 // Push argcount 1626 storePtr(X86Registers::ecx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount))); 1627 1628 // Calculate the start of the callframe header, and store in edx 1629 addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), callFrameRegister, X86Registers::edx); 1630 1631 // Calculate start of arguments as callframe header - sizeof(Register) * argcount (ecx) 1632 mul32(Imm32(sizeof(Register)), X86Registers::ecx, X86Registers::ecx); 1633 subPtr(X86Registers::ecx, X86Registers::edx); 1634 1635 // push pointer to arguments 1636 storePtr(X86Registers::edx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args))); 1637 1638 // ArgList is passed by reference so is stackPointerRegister 1639 move(stackPointerRegister, X86Registers::ecx); 1640 1641 // edx currently points to the first argument, edx-sizeof(Register) points to 'this' 1642 loadPtr(Address(X86Registers::edx, -(int32_t)sizeof(Register)), X86Registers::edx); 1643 1644 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::esi); 1645 1646 move(callFrameRegister, X86Registers::edi); 1647 1648 call(Address(X86Registers::esi, OBJECT_OFFSETOF(JSFunction, m_data))); 1649 1650 addPtr(Imm32(sizeof(ArgList)), stackPointerRegister); 1651 #elif CPU(X86) 1652 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); 1653 1654 /* We have two structs that we use to describe the stackframe we set up for our 1655 * call to native code. NativeCallFrameStructure describes the how we set up the stack 1656 * in advance of the call. NativeFunctionCalleeSignature describes the callframe 1657 * as the native code expects it. We do this as we are using the fastcall calling 1658 * convention which results in the callee popping its arguments off the stack, but 1659 * not the rest of the callframe so we need a nice way to ensure we increment the 1660 * stack pointer by the right amount after the call. 1661 */ 1662 #if COMPILER(MSVC) || OS(LINUX) 1663 struct NativeCallFrameStructure { 1664 // CallFrame* callFrame; // passed in EDX 1665 JSObject* callee; 1666 JSValue thisValue; 1667 ArgList* argPointer; 1668 ArgList args; 1669 JSValue result; 1670 }; 1671 struct NativeFunctionCalleeSignature { 1672 JSObject* callee; 1673 JSValue thisValue; 1674 ArgList* argPointer; 1675 }; 1676 #else 1677 struct NativeCallFrameStructure { 1678 // CallFrame* callFrame; // passed in ECX 1679 // JSObject* callee; // passed in EDX 1680 JSValue thisValue; 1681 ArgList* argPointer; 1682 ArgList args; 1683 }; 1684 struct NativeFunctionCalleeSignature { 1685 JSValue thisValue; 1686 ArgList* argPointer; 1687 }; 1688 #endif 1689 const int NativeCallFrameSize = (sizeof(NativeCallFrameStructure) + 15) & ~15; 1690 // Allocate system stack frame 1691 subPtr(Imm32(NativeCallFrameSize), stackPointerRegister); 1692 1693 // Set up arguments 1694 subPtr(Imm32(1), regT0); // Don't include 'this' in argcount 1695 1696 // push argcount 1697 storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_argCount))); 1698 1699 // Calculate the start of the callframe header, and store in regT1 1700 addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int)sizeof(Register)), callFrameRegister, regT1); 1701 1702 // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT0) 1703 mul32(Imm32(sizeof(Register)), regT0, regT0); 1704 subPtr(regT0, regT1); 1705 storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, args) + OBJECT_OFFSETOF(ArgList, m_args))); 1706 1707 // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register) 1708 addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, args)), stackPointerRegister, regT0); 1709 storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, argPointer))); 1710 1711 // regT1 currently points to the first argument, regT1 - sizeof(Register) points to 'this' 1712 loadPtr(Address(regT1, -(int)sizeof(Register)), regT1); 1713 storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, thisValue))); 1714 1715 #if COMPILER(MSVC) || OS(LINUX) 1716 // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register) 1717 addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86Registers::ecx); 1718 1719 // Plant callee 1720 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::eax); 1721 storePtr(X86Registers::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee))); 1722 1723 // Plant callframe 1724 move(callFrameRegister, X86Registers::edx); 1725 1726 call(Address(X86Registers::eax, OBJECT_OFFSETOF(JSFunction, m_data))); 1727 1728 // JSValue is a non-POD type 1729 loadPtr(Address(X86Registers::eax), X86Registers::eax); 1730 #else 1731 // Plant callee 1732 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::edx); 1733 1734 // Plant callframe 1735 move(callFrameRegister, X86Registers::ecx); 1736 call(Address(X86Registers::edx, OBJECT_OFFSETOF(JSFunction, m_data))); 1737 #endif 1738 1739 // We've put a few temporaries on the stack in addition to the actual arguments 1740 // so pull them off now 1741 addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister); 1742 1743 #elif CPU(ARM) 1744 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); 1745 1746 // Allocate stack space for our arglist 1747 COMPILE_ASSERT((sizeof(ArgList) & 0x7) == 0, ArgList_should_by_8byte_aligned); 1748 subPtr(Imm32(sizeof(ArgList)), stackPointerRegister); 1749 1750 // Set up arguments 1751 subPtr(Imm32(1), regT0); // Don't include 'this' in argcount 1752 1753 // Push argcount 1754 storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount))); 1755 1756 // Calculate the start of the callframe header, and store in regT1 1757 move(callFrameRegister, regT1); 1758 sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1); 1759 1760 // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1) 1761 mul32(Imm32(sizeof(Register)), regT0, regT0); 1762 subPtr(regT0, regT1); 1763 1764 // push pointer to arguments 1765 storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args))); 1766 1767 // Setup arg3: regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this' 1768 loadPtr(Address(regT1, -(int32_t)sizeof(Register)), regT2); 1769 1770 // Setup arg2: 1771 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT1); 1772 1773 // Setup arg1: 1774 move(callFrameRegister, regT0); 1775 1776 // Setup arg4: This is a plain hack 1777 move(stackPointerRegister, ARMRegisters::r3); 1778 1779 call(Address(regT1, OBJECT_OFFSETOF(JSFunction, m_data))); 1780 1781 addPtr(Imm32(sizeof(ArgList)), stackPointerRegister); 1782 1783 #elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL) 1784 #error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform." 1785 #else 1786 breakpoint(); 1787 #endif 1788 1789 // Check for an exception 1790 loadPtr(&(globalData->exception), regT2); 1791 Jump exceptionHandler = branchTestPtr(NonZero, regT2); 1792 1793 // Grab the return address. 1794 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); 1795 1796 // Restore our caller's "r". 1797 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); 1798 1799 // Return. 1800 restoreReturnAddressBeforeReturn(regT1); 1801 ret(); 1802 1803 // Handle an exception 1804 exceptionHandler.link(this); 1805 // Grab the return address. 1806 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); 1807 move(ImmPtr(&globalData->exceptionLocation), regT2); 1808 storePtr(regT1, regT2); 1809 move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT2); 1810 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); 1811 poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); 1812 restoreReturnAddressBeforeReturn(regT2); 1813 ret(); 1814 1815 1816 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 1817 Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1); 1818 Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2); 1819 Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3); 1820 #endif 1821 1822 // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object. 1823 LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size())); 1824 1825 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 1826 patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail)); 1827 patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail)); 1828 patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail)); 1829 #endif 1830 patchBuffer.link(callArityCheck1, FunctionPtr(cti_op_call_arityCheck)); 1831 patchBuffer.link(callJSFunction1, FunctionPtr(cti_op_call_JSFunction)); 1832 #if ENABLE(JIT_OPTIMIZE_CALL) 1833 patchBuffer.link(callArityCheck2, FunctionPtr(cti_op_call_arityCheck)); 1834 patchBuffer.link(callJSFunction2, FunctionPtr(cti_op_call_JSFunction)); 1835 patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall)); 1836 #endif 1837 1838 CodeRef finalCode = patchBuffer.finalizeCode(); 1839 *executablePool = finalCode.m_executablePool; 1840 1841 trampolines->ctiVirtualCallLink = trampolineAt(finalCode, virtualCallLinkBegin); 1842 trampolines->ctiVirtualCall = trampolineAt(finalCode, virtualCallBegin); 1843 trampolines->ctiNativeCallThunk = trampolineAt(finalCode, nativeCallThunk); 1844 #if ENABLE(JIT_OPTIMIZE_MOD) 1845 trampolines->ctiSoftModulo = trampolineAt(finalCode, softModBegin); 1846 #endif 1847 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 1848 trampolines->ctiStringLengthTrampoline = trampolineAt(finalCode, stringLengthBegin); 1849 #else 1850 UNUSED_PARAM(ctiStringLengthTrampoline); 1851 #endif 1852 } 1853 1854 void JIT::emit_op_mov(Instruction* currentInstruction) 1855 { 1856 int dst = currentInstruction[1].u.operand; 1857 int src = currentInstruction[2].u.operand; 1858 1859 if (m_codeBlock->isConstantRegisterIndex(src)) { 1860 storePtr(ImmPtr(JSValue::encode(getConstantOperand(src))), Address(callFrameRegister, dst * sizeof(Register))); 1861 if (dst == m_lastResultBytecodeRegister) 1862 killLastResultRegister(); 1863 } else if ((src == m_lastResultBytecodeRegister) || (dst == m_lastResultBytecodeRegister)) { 1864 // If either the src or dst is the cached register go though 1865 // get/put registers to make sure we track this correctly. 1866 emitGetVirtualRegister(src, regT0); 1867 emitPutVirtualRegister(dst); 1868 } else { 1869 // Perform the copy via regT1; do not disturb any mapping in regT0. 1870 loadPtr(Address(callFrameRegister, src * sizeof(Register)), regT1); 1871 storePtr(regT1, Address(callFrameRegister, dst * sizeof(Register))); 1872 } 1873 } 1874 1875 void JIT::emit_op_end(Instruction* currentInstruction) 1876 { 1877 if (m_codeBlock->needsFullScopeChain()) 1878 JITStubCall(this, cti_op_end).call(); 1879 ASSERT(returnValueRegister != callFrameRegister); 1880 emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueRegister); 1881 restoreReturnAddressBeforeReturn(Address(callFrameRegister, RegisterFile::ReturnPC * static_cast<int>(sizeof(Register)))); 1882 ret(); 1883 } 1884 1885 void JIT::emit_op_jmp(Instruction* currentInstruction) 1886 { 1887 unsigned target = currentInstruction[1].u.operand; 1888 addJump(jump(), target); 1889 RECORD_JUMP_TARGET(target); 1890 } 1891 1892 void JIT::emit_op_loop_if_lesseq(Instruction* currentInstruction) 1893 { 1894 emitTimeoutCheck(); 1895 1896 unsigned op1 = currentInstruction[1].u.operand; 1897 unsigned op2 = currentInstruction[2].u.operand; 1898 unsigned target = currentInstruction[3].u.operand; 1899 if (isOperandConstantImmediateInt(op2)) { 1900 emitGetVirtualRegister(op1, regT0); 1901 emitJumpSlowCaseIfNotImmediateInteger(regT0); 1902 #if USE(JSVALUE64) 1903 int32_t op2imm = getConstantOperandImmediateInt(op2); 1904 #else 1905 int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2))); 1906 #endif 1907 addJump(branch32(LessThanOrEqual, regT0, Imm32(op2imm)), target); 1908 } else { 1909 emitGetVirtualRegisters(op1, regT0, op2, regT1); 1910 emitJumpSlowCaseIfNotImmediateInteger(regT0); 1911 emitJumpSlowCaseIfNotImmediateInteger(regT1); 1912 addJump(branch32(LessThanOrEqual, regT0, regT1), target); 1913 } 1914 } 1915 1916 void JIT::emit_op_new_object(Instruction* currentInstruction) 1917 { 1918 JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand); 1919 } 1920 1921 void JIT::emit_op_instanceof(Instruction* currentInstruction) 1922 { 1923 unsigned dst = currentInstruction[1].u.operand; 1924 unsigned value = currentInstruction[2].u.operand; 1925 unsigned baseVal = currentInstruction[3].u.operand; 1926 unsigned proto = currentInstruction[4].u.operand; 1927 1928 // Load the operands (baseVal, proto, and value respectively) into registers. 1929 // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result. 1930 emitGetVirtualRegister(value, regT2); 1931 emitGetVirtualRegister(baseVal, regT0); 1932 emitGetVirtualRegister(proto, regT1); 1933 1934 // Check that baseVal & proto are cells. 1935 emitJumpSlowCaseIfNotJSCell(regT2, value); 1936 emitJumpSlowCaseIfNotJSCell(regT0, baseVal); 1937 emitJumpSlowCaseIfNotJSCell(regT1, proto); 1938 1939 // Check that baseVal 'ImplementsDefaultHasInstance'. 1940 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); 1941 addSlowCase(branchTest32(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsDefaultHasInstance))); 1942 1943 // Optimistically load the result true, and start looping. 1944 // Initially, regT1 still contains proto and regT2 still contains value. 1945 // As we loop regT2 will be updated with its prototype, recursively walking the prototype chain. 1946 move(ImmPtr(JSValue::encode(jsBoolean(true))), regT0); 1947 Label loop(this); 1948 1949 // Load the prototype of the object in regT2. If this is equal to regT1 - WIN! 1950 // Otherwise, check if we've hit null - if we have then drop out of the loop, if not go again. 1951 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 1952 loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype)), regT2); 1953 Jump isInstance = branchPtr(Equal, regT2, regT1); 1954 emitJumpIfJSCell(regT2).linkTo(loop, this); 1955 1956 // We get here either by dropping out of the loop, or if value was not an Object. Result is false. 1957 move(ImmPtr(JSValue::encode(jsBoolean(false))), regT0); 1958 1959 // isInstance jumps right down to here, to skip setting the result to false (it has already set true). 1960 isInstance.link(this); 1961 emitPutVirtualRegister(dst); 1962 } 1963 1964 void JIT::emit_op_new_func(Instruction* currentInstruction) 1965 { 1966 JITStubCall stubCall(this, cti_op_new_func); 1967 stubCall.addArgument(ImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand))); 1968 stubCall.call(currentInstruction[1].u.operand); 1969 } 1970 1971 void JIT::emit_op_call(Instruction* currentInstruction) 1972 { 1973 compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++); 1974 } 1975 1976 void JIT::emit_op_call_eval(Instruction* currentInstruction) 1977 { 1978 compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++); 1979 } 1980 1981 void JIT::emit_op_load_varargs(Instruction* currentInstruction) 1982 { 1983 int argCountDst = currentInstruction[1].u.operand; 1984 int argsOffset = currentInstruction[2].u.operand; 1985 1986 JITStubCall stubCall(this, cti_op_load_varargs); 1987 stubCall.addArgument(Imm32(argsOffset)); 1988 stubCall.call(); 1989 // Stores a naked int32 in the register file. 1990 store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register))); 1991 } 1992 1993 void JIT::emit_op_call_varargs(Instruction* currentInstruction) 1994 { 1995 compileOpCallVarargs(currentInstruction); 1996 } 1997 1998 void JIT::emit_op_construct(Instruction* currentInstruction) 1999 { 2000 compileOpCall(op_construct, currentInstruction, m_callLinkInfoIndex++); 2001 } 2002 2003 void JIT::emit_op_get_global_var(Instruction* currentInstruction) 2004 { 2005 JSVariableObject* globalObject = static_cast<JSVariableObject*>(currentInstruction[2].u.jsCell); 2006 move(ImmPtr(globalObject), regT0); 2007 emitGetVariableObjectRegister(regT0, currentInstruction[3].u.operand, regT0); 2008 emitPutVirtualRegister(currentInstruction[1].u.operand); 2009 } 2010 2011 void JIT::emit_op_put_global_var(Instruction* currentInstruction) 2012 { 2013 emitGetVirtualRegister(currentInstruction[3].u.operand, regT1); 2014 JSVariableObject* globalObject = static_cast<JSVariableObject*>(currentInstruction[1].u.jsCell); 2015 move(ImmPtr(globalObject), regT0); 2016 emitPutVariableObjectRegister(regT1, regT0, currentInstruction[2].u.operand); 2017 } 2018 2019 void JIT::emit_op_get_scoped_var(Instruction* currentInstruction) 2020 { 2021 int skip = currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain(); 2022 2023 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT0); 2024 while (skip--) 2025 loadPtr(Address(regT0, OBJECT_OFFSETOF(ScopeChainNode, next)), regT0); 2026 2027 loadPtr(Address(regT0, OBJECT_OFFSETOF(ScopeChainNode, object)), regT0); 2028 emitGetVariableObjectRegister(regT0, currentInstruction[2].u.operand, regT0); 2029 emitPutVirtualRegister(currentInstruction[1].u.operand); 2030 } 2031 2032 void JIT::emit_op_put_scoped_var(Instruction* currentInstruction) 2033 { 2034 int skip = currentInstruction[2].u.operand + m_codeBlock->needsFullScopeChain(); 2035 2036 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1); 2037 emitGetVirtualRegister(currentInstruction[3].u.operand, regT0); 2038 while (skip--) 2039 loadPtr(Address(regT1, OBJECT_OFFSETOF(ScopeChainNode, next)), regT1); 2040 2041 loadPtr(Address(regT1, OBJECT_OFFSETOF(ScopeChainNode, object)), regT1); 2042 emitPutVariableObjectRegister(regT0, regT1, currentInstruction[1].u.operand); 2043 } 2044 2045 void JIT::emit_op_tear_off_activation(Instruction* currentInstruction) 2046 { 2047 JITStubCall stubCall(this, cti_op_tear_off_activation); 2048 stubCall.addArgument(currentInstruction[1].u.operand, regT2); 2049 stubCall.call(); 2050 } 2051 2052 void JIT::emit_op_tear_off_arguments(Instruction*) 2053 { 2054 JITStubCall(this, cti_op_tear_off_arguments).call(); 2055 } 2056 2057 void JIT::emit_op_ret(Instruction* currentInstruction) 2058 { 2059 // We could JIT generate the deref, only calling out to C when the refcount hits zero. 2060 if (m_codeBlock->needsFullScopeChain()) 2061 JITStubCall(this, cti_op_ret_scopeChain).call(); 2062 2063 ASSERT(callFrameRegister != regT1); 2064 ASSERT(regT1 != returnValueRegister); 2065 ASSERT(returnValueRegister != callFrameRegister); 2066 2067 // Return the result in %eax. 2068 emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueRegister); 2069 2070 // Grab the return address. 2071 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); 2072 2073 // Restore our caller's "r". 2074 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); 2075 2076 // Return. 2077 restoreReturnAddressBeforeReturn(regT1); 2078 ret(); 2079 } 2080 2081 void JIT::emit_op_new_array(Instruction* currentInstruction) 2082 { 2083 JITStubCall stubCall(this, cti_op_new_array); 2084 stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); 2085 stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); 2086 stubCall.call(currentInstruction[1].u.operand); 2087 } 2088 2089 void JIT::emit_op_resolve(Instruction* currentInstruction) 2090 { 2091 JITStubCall stubCall(this, cti_op_resolve); 2092 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 2093 stubCall.call(currentInstruction[1].u.operand); 2094 } 2095 2096 void JIT::emit_op_construct_verify(Instruction* currentInstruction) 2097 { 2098 emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); 2099 2100 emitJumpSlowCaseIfNotJSCell(regT0); 2101 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 2102 addSlowCase(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType))); 2103 2104 } 2105 2106 void JIT::emit_op_to_primitive(Instruction* currentInstruction) 2107 { 2108 int dst = currentInstruction[1].u.operand; 2109 int src = currentInstruction[2].u.operand; 2110 2111 emitGetVirtualRegister(src, regT0); 2112 2113 Jump isImm = emitJumpIfNotJSCell(regT0); 2114 addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr))); 2115 isImm.link(this); 2116 2117 if (dst != src) 2118 emitPutVirtualRegister(dst); 2119 2120 } 2121 2122 void JIT::emit_op_strcat(Instruction* currentInstruction) 2123 { 2124 JITStubCall stubCall(this, cti_op_strcat); 2125 stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); 2126 stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); 2127 stubCall.call(currentInstruction[1].u.operand); 2128 } 2129 2130 void JIT::emit_op_resolve_base(Instruction* currentInstruction) 2131 { 2132 JITStubCall stubCall(this, cti_op_resolve_base); 2133 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 2134 stubCall.call(currentInstruction[1].u.operand); 2135 } 2136 2137 void JIT::emit_op_resolve_skip(Instruction* currentInstruction) 2138 { 2139 JITStubCall stubCall(this, cti_op_resolve_skip); 2140 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 2141 stubCall.addArgument(Imm32(currentInstruction[3].u.operand + m_codeBlock->needsFullScopeChain())); 2142 stubCall.call(currentInstruction[1].u.operand); 2143 } 2144 2145 void JIT::emit_op_resolve_global(Instruction* currentInstruction) 2146 { 2147 // Fast case 2148 void* globalObject = currentInstruction[2].u.jsCell; 2149 Identifier* ident = &m_codeBlock->identifier(currentInstruction[3].u.operand); 2150 2151 unsigned currentIndex = m_globalResolveInfoIndex++; 2152 void* structureAddress = &(m_codeBlock->globalResolveInfo(currentIndex).structure); 2153 void* offsetAddr = &(m_codeBlock->globalResolveInfo(currentIndex).offset); 2154 2155 // Check Structure of global object 2156 move(ImmPtr(globalObject), regT0); 2157 loadPtr(structureAddress, regT1); 2158 Jump noMatch = branchPtr(NotEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure))); // Structures don't match 2159 2160 // Load cached property 2161 // Assume that the global object always uses external storage. 2162 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_externalStorage)), regT0); 2163 load32(offsetAddr, regT1); 2164 loadPtr(BaseIndex(regT0, regT1, ScalePtr), regT0); 2165 emitPutVirtualRegister(currentInstruction[1].u.operand); 2166 Jump end = jump(); 2167 2168 // Slow case 2169 noMatch.link(this); 2170 JITStubCall stubCall(this, cti_op_resolve_global); 2171 stubCall.addArgument(ImmPtr(globalObject)); 2172 stubCall.addArgument(ImmPtr(ident)); 2173 stubCall.addArgument(Imm32(currentIndex)); 2174 stubCall.call(currentInstruction[1].u.operand); 2175 end.link(this); 2176 } 2177 2178 void JIT::emit_op_not(Instruction* currentInstruction) 2179 { 2180 emitGetVirtualRegister(currentInstruction[2].u.operand, regT0); 2181 xorPtr(Imm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool)), regT0); 2182 addSlowCase(branchTestPtr(NonZero, regT0, Imm32(static_cast<int32_t>(~JSImmediate::ExtendedPayloadBitBoolValue)))); 2183 xorPtr(Imm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool | JSImmediate::ExtendedPayloadBitBoolValue)), regT0); 2184 emitPutVirtualRegister(currentInstruction[1].u.operand); 2185 } 2186 2187 void JIT::emit_op_jfalse(Instruction* currentInstruction) 2188 { 2189 unsigned target = currentInstruction[2].u.operand; 2190 emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); 2191 2192 addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0)))), target); 2193 Jump isNonZero = emitJumpIfImmediateInteger(regT0); 2194 2195 addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsBoolean(false)))), target); 2196 addSlowCase(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsBoolean(true))))); 2197 2198 isNonZero.link(this); 2199 RECORD_JUMP_TARGET(target); 2200 }; 2201 void JIT::emit_op_jeq_null(Instruction* currentInstruction) 2202 { 2203 unsigned src = currentInstruction[1].u.operand; 2204 unsigned target = currentInstruction[2].u.operand; 2205 2206 emitGetVirtualRegister(src, regT0); 2207 Jump isImmediate = emitJumpIfNotJSCell(regT0); 2208 2209 // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. 2210 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 2211 addJump(branchTest32(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target); 2212 Jump wasNotImmediate = jump(); 2213 2214 // Now handle the immediate cases - undefined & null 2215 isImmediate.link(this); 2216 andPtr(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT0); 2217 addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNull()))), target); 2218 2219 wasNotImmediate.link(this); 2220 RECORD_JUMP_TARGET(target); 2221 }; 2222 void JIT::emit_op_jneq_null(Instruction* currentInstruction) 2223 { 2224 unsigned src = currentInstruction[1].u.operand; 2225 unsigned target = currentInstruction[2].u.operand; 2226 2227 emitGetVirtualRegister(src, regT0); 2228 Jump isImmediate = emitJumpIfNotJSCell(regT0); 2229 2230 // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. 2231 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 2232 addJump(branchTest32(Zero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target); 2233 Jump wasNotImmediate = jump(); 2234 2235 // Now handle the immediate cases - undefined & null 2236 isImmediate.link(this); 2237 andPtr(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT0); 2238 addJump(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsNull()))), target); 2239 2240 wasNotImmediate.link(this); 2241 RECORD_JUMP_TARGET(target); 2242 } 2243 2244 void JIT::emit_op_jneq_ptr(Instruction* currentInstruction) 2245 { 2246 unsigned src = currentInstruction[1].u.operand; 2247 JSCell* ptr = currentInstruction[2].u.jsCell; 2248 unsigned target = currentInstruction[3].u.operand; 2249 2250 emitGetVirtualRegister(src, regT0); 2251 addJump(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue(ptr)))), target); 2252 2253 RECORD_JUMP_TARGET(target); 2254 } 2255 2256 void JIT::emit_op_jsr(Instruction* currentInstruction) 2257 { 2258 int retAddrDst = currentInstruction[1].u.operand; 2259 int target = currentInstruction[2].u.operand; 2260 DataLabelPtr storeLocation = storePtrWithPatch(ImmPtr(0), Address(callFrameRegister, sizeof(Register) * retAddrDst)); 2261 addJump(jump(), target); 2262 m_jsrSites.append(JSRInfo(storeLocation, label())); 2263 killLastResultRegister(); 2264 RECORD_JUMP_TARGET(target); 2265 } 2266 2267 void JIT::emit_op_sret(Instruction* currentInstruction) 2268 { 2269 jump(Address(callFrameRegister, sizeof(Register) * currentInstruction[1].u.operand)); 2270 killLastResultRegister(); 2271 } 2272 2273 void JIT::emit_op_eq(Instruction* currentInstruction) 2274 { 2275 emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1); 2276 emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2); 2277 set32(Equal, regT1, regT0, regT0); 2278 emitTagAsBoolImmediate(regT0); 2279 emitPutVirtualRegister(currentInstruction[1].u.operand); 2280 } 2281 2282 void JIT::emit_op_bitnot(Instruction* currentInstruction) 2283 { 2284 emitGetVirtualRegister(currentInstruction[2].u.operand, regT0); 2285 emitJumpSlowCaseIfNotImmediateInteger(regT0); 2286 #if USE(JSVALUE64) 2287 not32(regT0); 2288 emitFastArithIntToImmNoCheck(regT0, regT0); 2289 #else 2290 xorPtr(Imm32(~JSImmediate::TagTypeNumber), regT0); 2291 #endif 2292 emitPutVirtualRegister(currentInstruction[1].u.operand); 2293 } 2294 2295 void JIT::emit_op_resolve_with_base(Instruction* currentInstruction) 2296 { 2297 JITStubCall stubCall(this, cti_op_resolve_with_base); 2298 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand))); 2299 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 2300 stubCall.call(currentInstruction[2].u.operand); 2301 } 2302 2303 void JIT::emit_op_new_func_exp(Instruction* currentInstruction) 2304 { 2305 JITStubCall stubCall(this, cti_op_new_func_exp); 2306 stubCall.addArgument(ImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand))); 2307 stubCall.call(currentInstruction[1].u.operand); 2308 } 2309 2310 void JIT::emit_op_jtrue(Instruction* currentInstruction) 2311 { 2312 unsigned target = currentInstruction[2].u.operand; 2313 emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); 2314 2315 Jump isZero = branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0)))); 2316 addJump(emitJumpIfImmediateInteger(regT0), target); 2317 2318 addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsBoolean(true)))), target); 2319 addSlowCase(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsBoolean(false))))); 2320 2321 isZero.link(this); 2322 RECORD_JUMP_TARGET(target); 2323 } 2324 2325 void JIT::emit_op_neq(Instruction* currentInstruction) 2326 { 2327 emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1); 2328 emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2); 2329 set32(NotEqual, regT1, regT0, regT0); 2330 emitTagAsBoolImmediate(regT0); 2331 2332 emitPutVirtualRegister(currentInstruction[1].u.operand); 2333 2334 } 2335 2336 void JIT::emit_op_bitxor(Instruction* currentInstruction) 2337 { 2338 emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1); 2339 emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2); 2340 xorPtr(regT1, regT0); 2341 emitFastArithReTagImmediate(regT0, regT0); 2342 emitPutVirtualRegister(currentInstruction[1].u.operand); 2343 } 2344 2345 void JIT::emit_op_new_regexp(Instruction* currentInstruction) 2346 { 2347 JITStubCall stubCall(this, cti_op_new_regexp); 2348 stubCall.addArgument(ImmPtr(m_codeBlock->regexp(currentInstruction[2].u.operand))); 2349 stubCall.call(currentInstruction[1].u.operand); 2350 } 2351 2352 void JIT::emit_op_bitor(Instruction* currentInstruction) 2353 { 2354 emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1); 2355 emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2); 2356 orPtr(regT1, regT0); 2357 emitPutVirtualRegister(currentInstruction[1].u.operand); 2358 } 2359 2360 void JIT::emit_op_throw(Instruction* currentInstruction) 2361 { 2362 JITStubCall stubCall(this, cti_op_throw); 2363 stubCall.addArgument(currentInstruction[1].u.operand, regT2); 2364 stubCall.call(); 2365 ASSERT(regT0 == returnValueRegister); 2366 #ifndef NDEBUG 2367 // cti_op_throw always changes it's return address, 2368 // this point in the code should never be reached. 2369 breakpoint(); 2370 #endif 2371 } 2372 2373 void JIT::emit_op_get_pnames(Instruction* currentInstruction) 2374 { 2375 int dst = currentInstruction[1].u.operand; 2376 int base = currentInstruction[2].u.operand; 2377 int i = currentInstruction[3].u.operand; 2378 int size = currentInstruction[4].u.operand; 2379 int breakTarget = currentInstruction[5].u.operand; 2380 2381 JumpList isNotObject; 2382 2383 emitGetVirtualRegister(base, regT0); 2384 if (!m_codeBlock->isKnownNotImmediate(base)) 2385 isNotObject.append(emitJumpIfNotJSCell(regT0)); 2386 if (base != m_codeBlock->thisRegister()) { 2387 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 2388 isNotObject.append(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); 2389 } 2390 2391 // We could inline the case where you have a valid cache, but 2392 // this call doesn't seem to be hot. 2393 Label isObject(this); 2394 JITStubCall getPnamesStubCall(this, cti_op_get_pnames); 2395 getPnamesStubCall.addArgument(regT0); 2396 getPnamesStubCall.call(dst); 2397 load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3); 2398 store32(Imm32(0), addressFor(i)); 2399 store32(regT3, addressFor(size)); 2400 Jump end = jump(); 2401 2402 isNotObject.link(this); 2403 move(regT0, regT1); 2404 and32(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT1); 2405 addJump(branch32(Equal, regT1, Imm32(JSImmediate::FullTagTypeNull)), breakTarget); 2406 2407 JITStubCall toObjectStubCall(this, cti_to_object); 2408 toObjectStubCall.addArgument(regT0); 2409 toObjectStubCall.call(base); 2410 jump().linkTo(isObject, this); 2411 2412 end.link(this); 2413 } 2414 2415 void JIT::emit_op_next_pname(Instruction* currentInstruction) 2416 { 2417 int dst = currentInstruction[1].u.operand; 2418 int base = currentInstruction[2].u.operand; 2419 int i = currentInstruction[3].u.operand; 2420 int size = currentInstruction[4].u.operand; 2421 int it = currentInstruction[5].u.operand; 2422 int target = currentInstruction[6].u.operand; 2423 2424 JumpList callHasProperty; 2425 2426 Label begin(this); 2427 load32(addressFor(i), regT0); 2428 Jump end = branch32(Equal, regT0, addressFor(size)); 2429 2430 // Grab key @ i 2431 loadPtr(addressFor(it), regT1); 2432 loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2); 2433 2434 #if USE(JSVALUE64) 2435 loadPtr(BaseIndex(regT2, regT0, TimesEight), regT2); 2436 #else 2437 loadPtr(BaseIndex(regT2, regT0, TimesFour), regT2); 2438 #endif 2439 2440 emitPutVirtualRegister(dst, regT2); 2441 2442 // Increment i 2443 add32(Imm32(1), regT0); 2444 store32(regT0, addressFor(i)); 2445 2446 // Verify that i is valid: 2447 emitGetVirtualRegister(base, regT0); 2448 2449 // Test base's structure 2450 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 2451 callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))))); 2452 2453 // Test base's prototype chain 2454 loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3); 2455 loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3); 2456 addJump(branchTestPtr(Zero, Address(regT3)), target); 2457 2458 Label checkPrototype(this); 2459 loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype)), regT2); 2460 callHasProperty.append(emitJumpIfNotJSCell(regT2)); 2461 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 2462 callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3))); 2463 addPtr(Imm32(sizeof(Structure*)), regT3); 2464 branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this); 2465 2466 // Continue loop. 2467 addJump(jump(), target); 2468 2469 // Slow case: Ask the object if i is valid. 2470 callHasProperty.link(this); 2471 emitGetVirtualRegister(dst, regT1); 2472 JITStubCall stubCall(this, cti_has_property); 2473 stubCall.addArgument(regT0); 2474 stubCall.addArgument(regT1); 2475 stubCall.call(); 2476 2477 // Test for valid key. 2478 addJump(branchTest32(NonZero, regT0), target); 2479 jump().linkTo(begin, this); 2480 2481 // End of loop. 2482 end.link(this); 2483 } 2484 2485 void JIT::emit_op_push_scope(Instruction* currentInstruction) 2486 { 2487 JITStubCall stubCall(this, cti_op_push_scope); 2488 stubCall.addArgument(currentInstruction[1].u.operand, regT2); 2489 stubCall.call(currentInstruction[1].u.operand); 2490 } 2491 2492 void JIT::emit_op_pop_scope(Instruction*) 2493 { 2494 JITStubCall(this, cti_op_pop_scope).call(); 2495 } 2496 2497 void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqType type) 2498 { 2499 unsigned dst = currentInstruction[1].u.operand; 2500 unsigned src1 = currentInstruction[2].u.operand; 2501 unsigned src2 = currentInstruction[3].u.operand; 2502 2503 emitGetVirtualRegisters(src1, regT0, src2, regT1); 2504 2505 // Jump to a slow case if either operand is a number, or if both are JSCell*s. 2506 move(regT0, regT2); 2507 orPtr(regT1, regT2); 2508 addSlowCase(emitJumpIfJSCell(regT2)); 2509 addSlowCase(emitJumpIfImmediateNumber(regT2)); 2510 2511 if (type == OpStrictEq) 2512 set32(Equal, regT1, regT0, regT0); 2513 else 2514 set32(NotEqual, regT1, regT0, regT0); 2515 emitTagAsBoolImmediate(regT0); 2516 2517 emitPutVirtualRegister(dst); 2518 } 2519 2520 void JIT::emit_op_stricteq(Instruction* currentInstruction) 2521 { 2522 compileOpStrictEq(currentInstruction, OpStrictEq); 2523 } 2524 2525 void JIT::emit_op_nstricteq(Instruction* currentInstruction) 2526 { 2527 compileOpStrictEq(currentInstruction, OpNStrictEq); 2528 } 2529 2530 void JIT::emit_op_to_jsnumber(Instruction* currentInstruction) 2531 { 2532 int srcVReg = currentInstruction[2].u.operand; 2533 emitGetVirtualRegister(srcVReg, regT0); 2534 2535 Jump wasImmediate = emitJumpIfImmediateInteger(regT0); 2536 2537 emitJumpSlowCaseIfNotJSCell(regT0, srcVReg); 2538 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 2539 addSlowCase(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(NumberType))); 2540 2541 wasImmediate.link(this); 2542 2543 emitPutVirtualRegister(currentInstruction[1].u.operand); 2544 } 2545 2546 void JIT::emit_op_push_new_scope(Instruction* currentInstruction) 2547 { 2548 JITStubCall stubCall(this, cti_op_push_new_scope); 2549 stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand))); 2550 stubCall.addArgument(currentInstruction[3].u.operand, regT2); 2551 stubCall.call(currentInstruction[1].u.operand); 2552 } 2553 2554 void JIT::emit_op_catch(Instruction* currentInstruction) 2555 { 2556 killLastResultRegister(); // FIXME: Implicitly treat op_catch as a labeled statement, and remove this line of code. 2557 peek(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); 2558 emitPutVirtualRegister(currentInstruction[1].u.operand); 2559 } 2560 2561 void JIT::emit_op_jmp_scopes(Instruction* currentInstruction) 2562 { 2563 JITStubCall stubCall(this, cti_op_jmp_scopes); 2564 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 2565 stubCall.call(); 2566 addJump(jump(), currentInstruction[2].u.operand); 2567 RECORD_JUMP_TARGET(currentInstruction[2].u.operand); 2568 } 2569 2570 void JIT::emit_op_switch_imm(Instruction* currentInstruction) 2571 { 2572 unsigned tableIndex = currentInstruction[1].u.operand; 2573 unsigned defaultOffset = currentInstruction[2].u.operand; 2574 unsigned scrutinee = currentInstruction[3].u.operand; 2575 2576 // create jump table for switch destinations, track this switch statement. 2577 SimpleJumpTable* jumpTable = &m_codeBlock->immediateSwitchJumpTable(tableIndex); 2578 m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Immediate)); 2579 jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); 2580 2581 JITStubCall stubCall(this, cti_op_switch_imm); 2582 stubCall.addArgument(scrutinee, regT2); 2583 stubCall.addArgument(Imm32(tableIndex)); 2584 stubCall.call(); 2585 jump(regT0); 2586 } 2587 2588 void JIT::emit_op_switch_char(Instruction* currentInstruction) 2589 { 2590 unsigned tableIndex = currentInstruction[1].u.operand; 2591 unsigned defaultOffset = currentInstruction[2].u.operand; 2592 unsigned scrutinee = currentInstruction[3].u.operand; 2593 2594 // create jump table for switch destinations, track this switch statement. 2595 SimpleJumpTable* jumpTable = &m_codeBlock->characterSwitchJumpTable(tableIndex); 2596 m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset, SwitchRecord::Character)); 2597 jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size()); 2598 2599 JITStubCall stubCall(this, cti_op_switch_char); 2600 stubCall.addArgument(scrutinee, regT2); 2601 stubCall.addArgument(Imm32(tableIndex)); 2602 stubCall.call(); 2603 jump(regT0); 2604 } 2605 2606 void JIT::emit_op_switch_string(Instruction* currentInstruction) 2607 { 2608 unsigned tableIndex = currentInstruction[1].u.operand; 2609 unsigned defaultOffset = currentInstruction[2].u.operand; 2610 unsigned scrutinee = currentInstruction[3].u.operand; 2611 2612 // create jump table for switch destinations, track this switch statement. 2613 StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTable(tableIndex); 2614 m_switches.append(SwitchRecord(jumpTable, m_bytecodeIndex, defaultOffset)); 2615 2616 JITStubCall stubCall(this, cti_op_switch_string); 2617 stubCall.addArgument(scrutinee, regT2); 2618 stubCall.addArgument(Imm32(tableIndex)); 2619 stubCall.call(); 2620 jump(regT0); 2621 } 2622 2623 void JIT::emit_op_new_error(Instruction* currentInstruction) 2624 { 2625 JITStubCall stubCall(this, cti_op_new_error); 2626 stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); 2627 stubCall.addArgument(ImmPtr(JSValue::encode(m_codeBlock->getConstant(currentInstruction[3].u.operand)))); 2628 stubCall.addArgument(Imm32(m_bytecodeIndex)); 2629 stubCall.call(currentInstruction[1].u.operand); 2630 } 2631 2632 void JIT::emit_op_debug(Instruction* currentInstruction) 2633 { 2634 JITStubCall stubCall(this, cti_op_debug); 2635 stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); 2636 stubCall.addArgument(Imm32(currentInstruction[2].u.operand)); 2637 stubCall.addArgument(Imm32(currentInstruction[3].u.operand)); 2638 stubCall.call(); 2639 } 2640 2641 void JIT::emit_op_eq_null(Instruction* currentInstruction) 2642 { 2643 unsigned dst = currentInstruction[1].u.operand; 2644 unsigned src1 = currentInstruction[2].u.operand; 2645 2646 emitGetVirtualRegister(src1, regT0); 2647 Jump isImmediate = emitJumpIfNotJSCell(regT0); 2648 2649 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 2650 setTest32(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined), regT0); 2651 2652 Jump wasNotImmediate = jump(); 2653 2654 isImmediate.link(this); 2655 2656 andPtr(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT0); 2657 setPtr(Equal, regT0, Imm32(JSImmediate::FullTagTypeNull), regT0); 2658 2659 wasNotImmediate.link(this); 2660 2661 emitTagAsBoolImmediate(regT0); 2662 emitPutVirtualRegister(dst); 2663 2664 } 2665 2666 void JIT::emit_op_neq_null(Instruction* currentInstruction) 2667 { 2668 unsigned dst = currentInstruction[1].u.operand; 2669 unsigned src1 = currentInstruction[2].u.operand; 2670 2671 emitGetVirtualRegister(src1, regT0); 2672 Jump isImmediate = emitJumpIfNotJSCell(regT0); 2673 2674 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); 2675 setTest32(Zero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined), regT0); 2676 2677 Jump wasNotImmediate = jump(); 2678 2679 isImmediate.link(this); 2680 2681 andPtr(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT0); 2682 setPtr(NotEqual, regT0, Imm32(JSImmediate::FullTagTypeNull), regT0); 2683 2684 wasNotImmediate.link(this); 2685 2686 emitTagAsBoolImmediate(regT0); 2687 emitPutVirtualRegister(dst); 2688 2689 } 2690 2691 void JIT::emit_op_enter(Instruction*) 2692 { 2693 // Even though CTI doesn't use them, we initialize our constant 2694 // registers to zap stale pointers, to avoid unnecessarily prolonging 2695 // object lifetime and increasing GC pressure. 2696 size_t count = m_codeBlock->m_numVars; 2697 for (size_t j = 0; j < count; ++j) 2698 emitInitRegister(j); 2699 2700 } 2701 2702 void JIT::emit_op_enter_with_activation(Instruction* currentInstruction) 2703 { 2704 // Even though CTI doesn't use them, we initialize our constant 2705 // registers to zap stale pointers, to avoid unnecessarily prolonging 2706 // object lifetime and increasing GC pressure. 2707 size_t count = m_codeBlock->m_numVars; 2708 for (size_t j = 0; j < count; ++j) 2709 emitInitRegister(j); 2710 2711 JITStubCall(this, cti_op_push_activation).call(currentInstruction[1].u.operand); 2712 } 2713 2714 void JIT::emit_op_create_arguments(Instruction*) 2715 { 2716 Jump argsCreated = branchTestPtr(NonZero, Address(callFrameRegister, sizeof(Register) * RegisterFile::ArgumentsRegister)); 2717 if (m_codeBlock->m_numParameters == 1) 2718 JITStubCall(this, cti_op_create_arguments_no_params).call(); 2719 else 2720 JITStubCall(this, cti_op_create_arguments).call(); 2721 argsCreated.link(this); 2722 } 2723 2724 void JIT::emit_op_init_arguments(Instruction*) 2725 { 2726 storePtr(ImmPtr(0), Address(callFrameRegister, sizeof(Register) * RegisterFile::ArgumentsRegister)); 2727 } 2728 2729 void JIT::emit_op_convert_this(Instruction* currentInstruction) 2730 { 2731 emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); 2732 2733 emitJumpSlowCaseIfNotJSCell(regT0); 2734 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT1); 2735 addSlowCase(branchTest32(NonZero, Address(regT1, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(NeedsThisConversion))); 2736 2737 } 2738 2739 void JIT::emit_op_profile_will_call(Instruction* currentInstruction) 2740 { 2741 peek(regT1, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof (void*)); 2742 Jump noProfiler = branchTestPtr(Zero, Address(regT1)); 2743 2744 JITStubCall stubCall(this, cti_op_profile_will_call); 2745 stubCall.addArgument(currentInstruction[1].u.operand, regT1); 2746 stubCall.call(); 2747 noProfiler.link(this); 2748 2749 } 2750 2751 void JIT::emit_op_profile_did_call(Instruction* currentInstruction) 2752 { 2753 peek(regT1, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof (void*)); 2754 Jump noProfiler = branchTestPtr(Zero, Address(regT1)); 2755 2756 JITStubCall stubCall(this, cti_op_profile_did_call); 2757 stubCall.addArgument(currentInstruction[1].u.operand, regT1); 2758 stubCall.call(); 2759 noProfiler.link(this); 2760 } 2761 2762 2763 // Slow cases 2764 2765 void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2766 { 2767 linkSlowCase(iter); 2768 linkSlowCase(iter); 2769 JITStubCall stubCall(this, cti_op_convert_this); 2770 stubCall.addArgument(regT0); 2771 stubCall.call(currentInstruction[1].u.operand); 2772 } 2773 2774 void JIT::emitSlow_op_construct_verify(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2775 { 2776 linkSlowCase(iter); 2777 linkSlowCase(iter); 2778 emitGetVirtualRegister(currentInstruction[2].u.operand, regT0); 2779 emitPutVirtualRegister(currentInstruction[1].u.operand); 2780 } 2781 2782 void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2783 { 2784 linkSlowCase(iter); 2785 2786 JITStubCall stubCall(this, cti_op_to_primitive); 2787 stubCall.addArgument(regT0); 2788 stubCall.call(currentInstruction[1].u.operand); 2789 } 2790 2791 void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2792 { 2793 unsigned dst = currentInstruction[1].u.operand; 2794 unsigned base = currentInstruction[2].u.operand; 2795 unsigned property = currentInstruction[3].u.operand; 2796 2797 linkSlowCase(iter); // property int32 check 2798 linkSlowCaseIfNotJSCell(iter, base); // base cell check 2799 linkSlowCase(iter); // base array check 2800 linkSlowCase(iter); // vector length check 2801 linkSlowCase(iter); // empty value 2802 2803 JITStubCall stubCall(this, cti_op_get_by_val); 2804 stubCall.addArgument(base, regT2); 2805 stubCall.addArgument(property, regT2); 2806 stubCall.call(dst); 2807 } 2808 2809 void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2810 { 2811 unsigned op2 = currentInstruction[2].u.operand; 2812 unsigned target = currentInstruction[3].u.operand; 2813 if (isOperandConstantImmediateInt(op2)) { 2814 linkSlowCase(iter); 2815 JITStubCall stubCall(this, cti_op_loop_if_lesseq); 2816 stubCall.addArgument(regT0); 2817 stubCall.addArgument(currentInstruction[2].u.operand, regT2); 2818 stubCall.call(); 2819 emitJumpSlowToHot(branchTest32(NonZero, regT0), target); 2820 } else { 2821 linkSlowCase(iter); 2822 linkSlowCase(iter); 2823 JITStubCall stubCall(this, cti_op_loop_if_lesseq); 2824 stubCall.addArgument(regT0); 2825 stubCall.addArgument(regT1); 2826 stubCall.call(); 2827 emitJumpSlowToHot(branchTest32(NonZero, regT0), target); 2828 } 2829 } 2830 2831 void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2832 { 2833 unsigned base = currentInstruction[1].u.operand; 2834 unsigned property = currentInstruction[2].u.operand; 2835 unsigned value = currentInstruction[3].u.operand; 2836 2837 linkSlowCase(iter); // property int32 check 2838 linkSlowCaseIfNotJSCell(iter, base); // base cell check 2839 linkSlowCase(iter); // base not array check 2840 linkSlowCase(iter); // in vector check 2841 2842 JITStubCall stubPutByValCall(this, cti_op_put_by_val); 2843 stubPutByValCall.addArgument(regT0); 2844 stubPutByValCall.addArgument(property, regT2); 2845 stubPutByValCall.addArgument(value, regT2); 2846 stubPutByValCall.call(); 2847 } 2848 2849 void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2850 { 2851 linkSlowCase(iter); 2852 xorPtr(Imm32(static_cast<int32_t>(JSImmediate::FullTagTypeBool)), regT0); 2853 JITStubCall stubCall(this, cti_op_not); 2854 stubCall.addArgument(regT0); 2855 stubCall.call(currentInstruction[1].u.operand); 2856 } 2857 2858 void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2859 { 2860 linkSlowCase(iter); 2861 JITStubCall stubCall(this, cti_op_jtrue); 2862 stubCall.addArgument(regT0); 2863 stubCall.call(); 2864 emitJumpSlowToHot(branchTest32(Zero, regT0), currentInstruction[2].u.operand); // inverted! 2865 } 2866 2867 void JIT::emitSlow_op_bitnot(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2868 { 2869 linkSlowCase(iter); 2870 JITStubCall stubCall(this, cti_op_bitnot); 2871 stubCall.addArgument(regT0); 2872 stubCall.call(currentInstruction[1].u.operand); 2873 } 2874 2875 void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2876 { 2877 linkSlowCase(iter); 2878 JITStubCall stubCall(this, cti_op_jtrue); 2879 stubCall.addArgument(regT0); 2880 stubCall.call(); 2881 emitJumpSlowToHot(branchTest32(NonZero, regT0), currentInstruction[2].u.operand); 2882 } 2883 2884 void JIT::emitSlow_op_bitxor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2885 { 2886 linkSlowCase(iter); 2887 JITStubCall stubCall(this, cti_op_bitxor); 2888 stubCall.addArgument(regT0); 2889 stubCall.addArgument(regT1); 2890 stubCall.call(currentInstruction[1].u.operand); 2891 } 2892 2893 void JIT::emitSlow_op_bitor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2894 { 2895 linkSlowCase(iter); 2896 JITStubCall stubCall(this, cti_op_bitor); 2897 stubCall.addArgument(regT0); 2898 stubCall.addArgument(regT1); 2899 stubCall.call(currentInstruction[1].u.operand); 2900 } 2901 2902 void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2903 { 2904 linkSlowCase(iter); 2905 JITStubCall stubCall(this, cti_op_eq); 2906 stubCall.addArgument(regT0); 2907 stubCall.addArgument(regT1); 2908 stubCall.call(); 2909 emitTagAsBoolImmediate(regT0); 2910 emitPutVirtualRegister(currentInstruction[1].u.operand); 2911 } 2912 2913 void JIT::emitSlow_op_neq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2914 { 2915 linkSlowCase(iter); 2916 JITStubCall stubCall(this, cti_op_eq); 2917 stubCall.addArgument(regT0); 2918 stubCall.addArgument(regT1); 2919 stubCall.call(); 2920 xor32(Imm32(0x1), regT0); 2921 emitTagAsBoolImmediate(regT0); 2922 emitPutVirtualRegister(currentInstruction[1].u.operand); 2923 } 2924 2925 void JIT::emitSlow_op_stricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2926 { 2927 linkSlowCase(iter); 2928 linkSlowCase(iter); 2929 JITStubCall stubCall(this, cti_op_stricteq); 2930 stubCall.addArgument(regT0); 2931 stubCall.addArgument(regT1); 2932 stubCall.call(currentInstruction[1].u.operand); 2933 } 2934 2935 void JIT::emitSlow_op_nstricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2936 { 2937 linkSlowCase(iter); 2938 linkSlowCase(iter); 2939 JITStubCall stubCall(this, cti_op_nstricteq); 2940 stubCall.addArgument(regT0); 2941 stubCall.addArgument(regT1); 2942 stubCall.call(currentInstruction[1].u.operand); 2943 } 2944 2945 void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2946 { 2947 unsigned dst = currentInstruction[1].u.operand; 2948 unsigned value = currentInstruction[2].u.operand; 2949 unsigned baseVal = currentInstruction[3].u.operand; 2950 unsigned proto = currentInstruction[4].u.operand; 2951 2952 linkSlowCaseIfNotJSCell(iter, value); 2953 linkSlowCaseIfNotJSCell(iter, baseVal); 2954 linkSlowCaseIfNotJSCell(iter, proto); 2955 linkSlowCase(iter); 2956 JITStubCall stubCall(this, cti_op_instanceof); 2957 stubCall.addArgument(value, regT2); 2958 stubCall.addArgument(baseVal, regT2); 2959 stubCall.addArgument(proto, regT2); 2960 stubCall.call(dst); 2961 } 2962 2963 void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2964 { 2965 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call); 2966 } 2967 2968 void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2969 { 2970 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call_eval); 2971 } 2972 2973 void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2974 { 2975 compileOpCallVarargsSlowCase(currentInstruction, iter); 2976 } 2977 2978 void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2979 { 2980 compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_construct); 2981 } 2982 2983 void JIT::emitSlow_op_to_jsnumber(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 2984 { 2985 linkSlowCaseIfNotJSCell(iter, currentInstruction[2].u.operand); 2986 linkSlowCase(iter); 2987 2988 JITStubCall stubCall(this, cti_op_to_jsnumber); 2989 stubCall.addArgument(regT0); 2990 stubCall.call(currentInstruction[1].u.operand); 2991 } 2992 2993 #endif // USE(JSVALUE32_64) 2994 2995 // For both JSValue32_64 and JSValue32 2996 #if ENABLE(JIT_OPTIMIZE_MOD) 2997 #if CPU(ARM_TRADITIONAL) 2998 void JIT::softModulo() 2999 { 3000 push(regS0); 3001 push(regS1); 3002 push(regT1); 3003 push(regT3); 3004 #if USE(JSVALUE32_64) 3005 m_assembler.mov_r(regT3, regT2); 3006 m_assembler.mov_r(regT2, regT0); 3007 #else 3008 m_assembler.mov_r(regT3, m_assembler.asr(regT2, 1)); 3009 m_assembler.mov_r(regT2, m_assembler.asr(regT0, 1)); 3010 #endif 3011 m_assembler.mov_r(regT1, ARMAssembler::getOp2(0)); 3012 3013 m_assembler.teq_r(regT3, ARMAssembler::getOp2(0)); 3014 m_assembler.rsb_r(regT3, regT3, ARMAssembler::getOp2(0), ARMAssembler::MI); 3015 m_assembler.eor_r(regT1, regT1, ARMAssembler::getOp2(1), ARMAssembler::MI); 3016 3017 m_assembler.teq_r(regT2, ARMAssembler::getOp2(0)); 3018 m_assembler.rsb_r(regT2, regT2, ARMAssembler::getOp2(0), ARMAssembler::MI); 3019 m_assembler.eor_r(regT1, regT1, ARMAssembler::getOp2(2), ARMAssembler::MI); 3020 3021 Jump exitBranch = branch32(LessThan, regT2, regT3); 3022 3023 m_assembler.sub_r(regS1, regT3, ARMAssembler::getOp2(1)); 3024 m_assembler.tst_r(regS1, regT3); 3025 m_assembler.and_r(regT2, regT2, regS1, ARMAssembler::EQ); 3026 m_assembler.and_r(regT0, regS1, regT3); 3027 Jump exitBranch2 = branchTest32(Zero, regT0); 3028 3029 m_assembler.clz_r(regS1, regT2); 3030 m_assembler.clz_r(regS0, regT3); 3031 m_assembler.sub_r(regS0, regS0, regS1); 3032 3033 m_assembler.rsbs_r(regS0, regS0, ARMAssembler::getOp2(31)); 3034 3035 m_assembler.mov_r(regS0, m_assembler.lsl(regS0, 1), ARMAssembler::NE); 3036 3037 m_assembler.add_r(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(regS0, 2), ARMAssembler::NE); 3038 m_assembler.mov_r(regT0, regT0); 3039 3040 for (int i = 31; i > 0; --i) { 3041 m_assembler.cmp_r(regT2, m_assembler.lsl(regT3, i)); 3042 m_assembler.sub_r(regT2, regT2, m_assembler.lsl(regT3, i), ARMAssembler::CS); 3043 } 3044 3045 m_assembler.cmp_r(regT2, regT3); 3046 m_assembler.sub_r(regT2, regT2, regT3, ARMAssembler::CS); 3047 3048 exitBranch.link(this); 3049 exitBranch2.link(this); 3050 3051 m_assembler.teq_r(regT1, ARMAssembler::getOp2(0)); 3052 m_assembler.rsb_r(regT2, regT2, ARMAssembler::getOp2(0), ARMAssembler::GT); 3053 3054 #if USE(JSVALUE32_64) 3055 m_assembler.mov_r(regT0, regT2); 3056 #else 3057 m_assembler.mov_r(regT0, m_assembler.lsl(regT2, 1)); 3058 m_assembler.eor_r(regT0, regT0, ARMAssembler::getOp2(1)); 3059 #endif 3060 pop(regT3); 3061 pop(regT1); 3062 pop(regS1); 3063 pop(regS0); 3064 ret(); 3065 } 3066 #else 3067 #error "JIT_OPTIMIZE_MOD not yet supported on this platform." 3068 #endif // CPU(ARM_TRADITIONAL) 3069 #endif 3070 } // namespace JSC 3071 3072 #endif // ENABLE(JIT) 3073