1 /* 2 * Copyright (C) 2008 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 #ifndef JIT_h 27 #define JIT_h 28 29 #include <wtf/Platform.h> 30 31 #if ENABLE(JIT) 32 33 // We've run into some problems where changing the size of the class JIT leads to 34 // performance fluctuations. Try forcing alignment in an attempt to stabalize this. 35 #if COMPILER(GCC) 36 #define JIT_CLASS_ALIGNMENT __attribute__ ((aligned (32))) 37 #else 38 #define JIT_CLASS_ALIGNMENT 39 #endif 40 41 #include "CodeBlock.h" 42 #include "Interpreter.h" 43 #include "JITCode.h" 44 #include "JITStubs.h" 45 #include "Opcode.h" 46 #include "RegisterFile.h" 47 #include "MacroAssembler.h" 48 #include "Profiler.h" 49 #include <bytecode/SamplingTool.h> 50 #include <wtf/AlwaysInline.h> 51 #include <wtf/Vector.h> 52 53 namespace JSC { 54 55 class CodeBlock; 56 class JIT; 57 class JSPropertyNameIterator; 58 class Interpreter; 59 class Register; 60 class RegisterFile; 61 class ScopeChainNode; 62 class StructureChain; 63 64 struct CallLinkInfo; 65 struct Instruction; 66 struct OperandTypes; 67 struct PolymorphicAccessStructureList; 68 struct SimpleJumpTable; 69 struct StringJumpTable; 70 struct StructureStubInfo; 71 72 struct CallRecord { 73 MacroAssembler::Call from; 74 unsigned bytecodeIndex; 75 void* to; 76 CallRecordCallRecord77 CallRecord() 78 { 79 } 80 81 CallRecord(MacroAssembler::Call from, unsigned bytecodeIndex, void* to = 0) fromCallRecord82 : from(from) 83 , bytecodeIndex(bytecodeIndex) 84 , to(to) 85 { 86 } 87 }; 88 89 struct JumpTable { 90 MacroAssembler::Jump from; 91 unsigned toBytecodeIndex; 92 JumpTableJumpTable93 JumpTable(MacroAssembler::Jump f, unsigned t) 94 : from(f) 95 , toBytecodeIndex(t) 96 { 97 } 98 }; 99 100 struct SlowCaseEntry { 101 MacroAssembler::Jump from; 102 unsigned to; 103 unsigned hint; 104 105 SlowCaseEntry(MacroAssembler::Jump f, unsigned t, unsigned h = 0) fromSlowCaseEntry106 : from(f) 107 , to(t) 108 , hint(h) 109 { 110 } 111 }; 112 113 struct SwitchRecord { 114 enum Type { 115 Immediate, 116 Character, 117 String 118 }; 119 120 Type type; 121 122 union { 123 SimpleJumpTable* simpleJumpTable; 124 StringJumpTable* stringJumpTable; 125 } jumpTable; 126 127 unsigned bytecodeIndex; 128 unsigned defaultOffset; 129 SwitchRecordSwitchRecord130 SwitchRecord(SimpleJumpTable* jumpTable, unsigned bytecodeIndex, unsigned defaultOffset, Type type) 131 : type(type) 132 , bytecodeIndex(bytecodeIndex) 133 , defaultOffset(defaultOffset) 134 { 135 this->jumpTable.simpleJumpTable = jumpTable; 136 } 137 SwitchRecordSwitchRecord138 SwitchRecord(StringJumpTable* jumpTable, unsigned bytecodeIndex, unsigned defaultOffset) 139 : type(String) 140 , bytecodeIndex(bytecodeIndex) 141 , defaultOffset(defaultOffset) 142 { 143 this->jumpTable.stringJumpTable = jumpTable; 144 } 145 }; 146 147 struct PropertyStubCompilationInfo { 148 MacroAssembler::Call callReturnLocation; 149 MacroAssembler::Label hotPathBegin; 150 }; 151 152 struct StructureStubCompilationInfo { 153 MacroAssembler::DataLabelPtr hotPathBegin; 154 MacroAssembler::Call hotPathOther; 155 MacroAssembler::Call callReturnLocation; 156 }; 157 158 struct MethodCallCompilationInfo { MethodCallCompilationInfoMethodCallCompilationInfo159 MethodCallCompilationInfo(unsigned propertyAccessIndex) 160 : propertyAccessIndex(propertyAccessIndex) 161 { 162 } 163 164 MacroAssembler::DataLabelPtr structureToCompare; 165 unsigned propertyAccessIndex; 166 }; 167 168 // Near calls can only be patched to other JIT code, regular calls can be patched to JIT code or relinked to stub functions. 169 void ctiPatchNearCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction); 170 void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction); 171 void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, FunctionPtr newCalleeFunction); 172 173 class JIT : private MacroAssembler { 174 friend class JITStubCall; 175 176 using MacroAssembler::Jump; 177 using MacroAssembler::JumpList; 178 using MacroAssembler::Label; 179 180 // NOTES: 181 // 182 // regT0 has two special meanings. The return value from a stub 183 // call will always be in regT0, and by default (unless 184 // a register is specified) emitPutVirtualRegister() will store 185 // the value from regT0. 186 // 187 // regT3 is required to be callee-preserved. 188 // 189 // tempRegister2 is has no such dependencies. It is important that 190 // on x86/x86-64 it is ecx for performance reasons, since the 191 // MacroAssembler will need to plant register swaps if it is not - 192 // however the code will still function correctly. 193 #if PLATFORM(X86_64) 194 static const RegisterID returnValueRegister = X86::eax; 195 static const RegisterID cachedResultRegister = X86::eax; 196 static const RegisterID firstArgumentRegister = X86::edi; 197 198 static const RegisterID timeoutCheckRegister = X86::r12; 199 static const RegisterID callFrameRegister = X86::r13; 200 static const RegisterID tagTypeNumberRegister = X86::r14; 201 static const RegisterID tagMaskRegister = X86::r15; 202 203 static const RegisterID regT0 = X86::eax; 204 static const RegisterID regT1 = X86::edx; 205 static const RegisterID regT2 = X86::ecx; 206 static const RegisterID regT3 = X86::ebx; 207 208 static const FPRegisterID fpRegT0 = X86::xmm0; 209 static const FPRegisterID fpRegT1 = X86::xmm1; 210 static const FPRegisterID fpRegT2 = X86::xmm2; 211 #elif PLATFORM(X86) 212 static const RegisterID returnValueRegister = X86::eax; 213 static const RegisterID cachedResultRegister = X86::eax; 214 // On x86 we always use fastcall conventions = but on 215 // OS X if might make more sense to just use regparm. 216 static const RegisterID firstArgumentRegister = X86::ecx; 217 218 static const RegisterID timeoutCheckRegister = X86::esi; 219 static const RegisterID callFrameRegister = X86::edi; 220 221 static const RegisterID regT0 = X86::eax; 222 static const RegisterID regT1 = X86::edx; 223 static const RegisterID regT2 = X86::ecx; 224 static const RegisterID regT3 = X86::ebx; 225 226 static const FPRegisterID fpRegT0 = X86::xmm0; 227 static const FPRegisterID fpRegT1 = X86::xmm1; 228 static const FPRegisterID fpRegT2 = X86::xmm2; 229 #elif PLATFORM_ARM_ARCH(7) 230 static const RegisterID returnValueRegister = ARM::r0; 231 static const RegisterID cachedResultRegister = ARM::r0; 232 static const RegisterID firstArgumentRegister = ARM::r0; 233 234 static const RegisterID regT0 = ARM::r0; 235 static const RegisterID regT1 = ARM::r1; 236 static const RegisterID regT2 = ARM::r2; 237 static const RegisterID regT3 = ARM::r4; 238 239 static const RegisterID callFrameRegister = ARM::r5; 240 static const RegisterID timeoutCheckRegister = ARM::r6; 241 242 static const FPRegisterID fpRegT0 = ARM::d0; 243 static const FPRegisterID fpRegT1 = ARM::d1; 244 static const FPRegisterID fpRegT2 = ARM::d2; 245 #elif PLATFORM(ARM) 246 static const RegisterID returnValueRegister = ARM::r0; 247 static const RegisterID cachedResultRegister = ARM::r0; 248 static const RegisterID firstArgumentRegister = ARM::r0; 249 250 static const RegisterID timeoutCheckRegister = ARM::r5; 251 static const RegisterID callFrameRegister = ARM::r4; 252 static const RegisterID ctiReturnRegister = ARM::r6; 253 254 static const RegisterID regT0 = ARM::r0; 255 static const RegisterID regT1 = ARM::r1; 256 static const RegisterID regT2 = ARM::r2; 257 // Callee preserved 258 static const RegisterID regT3 = ARM::r7; 259 260 static const RegisterID regS0 = ARM::S0; 261 // Callee preserved 262 static const RegisterID regS1 = ARM::S1; 263 264 static const RegisterID regStackPtr = ARM::sp; 265 static const RegisterID regLink = ARM::lr; 266 267 static const FPRegisterID fpRegT0 = ARM::d0; 268 static const FPRegisterID fpRegT1 = ARM::d1; 269 static const FPRegisterID fpRegT2 = ARM::d2; 270 #else 271 #error "JIT not supported on this platform." 272 #endif 273 274 static const int patchGetByIdDefaultStructure = -1; 275 // Magic number - initial offset cannot be representable as a signed 8bit value, or the X86Assembler 276 // will compress the displacement, and we may not be able to fit a patched offset. 277 static const int patchGetByIdDefaultOffset = 256; 278 279 public: compile(JSGlobalData * globalData,CodeBlock * codeBlock)280 static void compile(JSGlobalData* globalData, CodeBlock* codeBlock) 281 { 282 JIT jit(globalData, codeBlock); 283 jit.privateCompile(); 284 } 285 compileGetByIdProto(JSGlobalData * globalData,CallFrame * callFrame,CodeBlock * codeBlock,StructureStubInfo * stubInfo,Structure * structure,Structure * prototypeStructure,size_t cachedOffset,ReturnAddressPtr returnAddress)286 static void compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, ReturnAddressPtr returnAddress) 287 { 288 JIT jit(globalData, codeBlock); 289 jit.privateCompileGetByIdProto(stubInfo, structure, prototypeStructure, cachedOffset, returnAddress, callFrame); 290 } 291 compileGetByIdSelfList(JSGlobalData * globalData,CodeBlock * codeBlock,StructureStubInfo * stubInfo,PolymorphicAccessStructureList * polymorphicStructures,int currentIndex,Structure * structure,size_t cachedOffset)292 static void compileGetByIdSelfList(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, size_t cachedOffset) 293 { 294 JIT jit(globalData, codeBlock); 295 jit.privateCompileGetByIdSelfList(stubInfo, polymorphicStructures, currentIndex, structure, cachedOffset); 296 } compileGetByIdProtoList(JSGlobalData * globalData,CallFrame * callFrame,CodeBlock * codeBlock,StructureStubInfo * stubInfo,PolymorphicAccessStructureList * prototypeStructureList,int currentIndex,Structure * structure,Structure * prototypeStructure,size_t cachedOffset)297 static void compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, Structure* prototypeStructure, size_t cachedOffset) 298 { 299 JIT jit(globalData, codeBlock); 300 jit.privateCompileGetByIdProtoList(stubInfo, prototypeStructureList, currentIndex, structure, prototypeStructure, cachedOffset, callFrame); 301 } compileGetByIdChainList(JSGlobalData * globalData,CallFrame * callFrame,CodeBlock * codeBlock,StructureStubInfo * stubInfo,PolymorphicAccessStructureList * prototypeStructureList,int currentIndex,Structure * structure,StructureChain * chain,size_t count,size_t cachedOffset)302 static void compileGetByIdChainList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset) 303 { 304 JIT jit(globalData, codeBlock); 305 jit.privateCompileGetByIdChainList(stubInfo, prototypeStructureList, currentIndex, structure, chain, count, cachedOffset, callFrame); 306 } 307 compileGetByIdChain(JSGlobalData * globalData,CallFrame * callFrame,CodeBlock * codeBlock,StructureStubInfo * stubInfo,Structure * structure,StructureChain * chain,size_t count,size_t cachedOffset,ReturnAddressPtr returnAddress)308 static void compileGetByIdChain(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, ReturnAddressPtr returnAddress) 309 { 310 JIT jit(globalData, codeBlock); 311 jit.privateCompileGetByIdChain(stubInfo, structure, chain, count, cachedOffset, returnAddress, callFrame); 312 } 313 compilePutByIdTransition(JSGlobalData * globalData,CodeBlock * codeBlock,StructureStubInfo * stubInfo,Structure * oldStructure,Structure * newStructure,size_t cachedOffset,StructureChain * chain,ReturnAddressPtr returnAddress)314 static void compilePutByIdTransition(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress) 315 { 316 JIT jit(globalData, codeBlock); 317 jit.privateCompilePutByIdTransition(stubInfo, oldStructure, newStructure, cachedOffset, chain, returnAddress); 318 } 319 compileCTIMachineTrampolines(JSGlobalData * globalData,RefPtr<ExecutablePool> * executablePool,CodePtr * ctiStringLengthTrampoline,CodePtr * ctiVirtualCallLink,CodePtr * ctiVirtualCall,CodePtr * ctiNativeCallThunk)320 static void compileCTIMachineTrampolines(JSGlobalData* globalData, RefPtr<ExecutablePool>* executablePool, CodePtr* ctiStringLengthTrampoline, CodePtr* ctiVirtualCallLink, CodePtr* ctiVirtualCall, CodePtr* ctiNativeCallThunk) 321 { 322 JIT jit(globalData); 323 jit.privateCompileCTIMachineTrampolines(executablePool, globalData, ctiStringLengthTrampoline, ctiVirtualCallLink, ctiVirtualCall, ctiNativeCallThunk); 324 } 325 326 static void patchGetByIdSelf(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress); 327 static void patchPutByIdReplace(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress); 328 static void patchMethodCallProto(CodeBlock* codeblock, MethodCallLinkInfo&, JSFunction*, Structure*, JSObject*, ReturnAddressPtr); 329 compilePatchGetArrayLength(JSGlobalData * globalData,CodeBlock * codeBlock,ReturnAddressPtr returnAddress)330 static void compilePatchGetArrayLength(JSGlobalData* globalData, CodeBlock* codeBlock, ReturnAddressPtr returnAddress) 331 { 332 JIT jit(globalData, codeBlock); 333 return jit.privateCompilePatchGetArrayLength(returnAddress); 334 } 335 336 static void linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode&, CallLinkInfo*, int callerArgCount, JSGlobalData*); 337 static void unlinkCall(CallLinkInfo*); 338 339 private: 340 struct JSRInfo { 341 DataLabelPtr storeLocation; 342 Label target; 343 JSRInfoJSRInfo344 JSRInfo(DataLabelPtr storeLocation, Label targetLocation) 345 : storeLocation(storeLocation) 346 , target(targetLocation) 347 { 348 } 349 }; 350 351 JIT(JSGlobalData*, CodeBlock* = 0); 352 353 void privateCompileMainPass(); 354 void privateCompileLinkPass(); 355 void privateCompileSlowCases(); 356 void privateCompile(); 357 void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame); 358 void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, size_t cachedOffset); 359 void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, size_t cachedOffset, CallFrame* callFrame); 360 void privateCompileGetByIdChainList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, StructureChain* chain, size_t count, size_t cachedOffset, CallFrame* callFrame); 361 void privateCompileGetByIdChain(StructureStubInfo*, Structure*, StructureChain*, size_t count, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame); 362 void privateCompilePutByIdTransition(StructureStubInfo*, Structure*, Structure*, size_t cachedOffset, StructureChain*, ReturnAddressPtr returnAddress); 363 364 void privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* data, CodePtr* ctiStringLengthTrampoline, CodePtr* ctiVirtualCallLink, CodePtr* ctiVirtualCall, CodePtr* ctiNativeCallThunk); 365 void privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress); 366 367 void addSlowCase(Jump); 368 void addSlowCase(JumpList); 369 void addJump(Jump, int); 370 void emitJumpSlowToHot(Jump, int); 371 372 void compileOpCall(OpcodeID, Instruction* instruction, unsigned callLinkInfoIndex); 373 void compileOpCallVarargs(Instruction* instruction); 374 void compileOpCallInitializeCallFrame(); 375 void compileOpCallSetupArgs(Instruction*); 376 void compileOpCallVarargsSetupArgs(Instruction*); 377 void compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID); 378 void compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter); 379 void compileOpConstructSetupArgs(Instruction*); 380 381 enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq }; 382 void compileOpStrictEq(Instruction* instruction, CompileOpStrictEqType type); 383 384 #if USE(JSVALUE32_64) 385 Address tagFor(unsigned index, RegisterID base = callFrameRegister); 386 Address payloadFor(unsigned index, RegisterID base = callFrameRegister); 387 Address addressFor(unsigned index, RegisterID base = callFrameRegister); 388 389 bool getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant); 390 bool isOperandConstantImmediateDouble(unsigned src); 391 392 void emitLoadTag(unsigned index, RegisterID tag); 393 void emitLoadPayload(unsigned index, RegisterID payload); 394 395 void emitLoad(const JSValue& v, RegisterID tag, RegisterID payload); 396 void emitLoad(unsigned index, RegisterID tag, RegisterID payload, RegisterID base = callFrameRegister); 397 void emitLoad2(unsigned index1, RegisterID tag1, RegisterID payload1, unsigned index2, RegisterID tag2, RegisterID payload2); 398 void emitLoadDouble(unsigned index, FPRegisterID value); 399 void emitLoadInt32ToDouble(unsigned index, FPRegisterID value); 400 401 void emitStore(unsigned index, RegisterID tag, RegisterID payload, RegisterID base = callFrameRegister); 402 void emitStore(unsigned index, const JSValue constant, RegisterID base = callFrameRegister); 403 void emitStoreInt32(unsigned index, RegisterID payload, bool indexIsInt32 = false); 404 void emitStoreInt32(unsigned index, Imm32 payload, bool indexIsInt32 = false); 405 void emitStoreCell(unsigned index, RegisterID payload, bool indexIsCell = false); 406 void emitStoreBool(unsigned index, RegisterID tag, bool indexIsBool = false); 407 void emitStoreDouble(unsigned index, FPRegisterID value); 408 409 bool isLabeled(unsigned bytecodeIndex); 410 void map(unsigned bytecodeIndex, unsigned virtualRegisterIndex, RegisterID tag, RegisterID payload); 411 void unmap(RegisterID); 412 void unmap(); 413 bool isMapped(unsigned virtualRegisterIndex); 414 bool getMappedPayload(unsigned virtualRegisterIndex, RegisterID& payload); 415 bool getMappedTag(unsigned virtualRegisterIndex, RegisterID& tag); 416 417 void emitJumpSlowCaseIfNotJSCell(unsigned virtualRegisterIndex); 418 void emitJumpSlowCaseIfNotJSCell(unsigned virtualRegisterIndex, RegisterID tag); 419 void linkSlowCaseIfNotJSCell(Vector<SlowCaseEntry>::iterator&, unsigned virtualRegisterIndex); 420 421 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 422 void compileGetByIdHotPath(); 423 void compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, bool isMethodCheck = false); 424 #endif 425 void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, Structure* structure, size_t cachedOffset); 426 void compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset); 427 void compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, Structure* structure, size_t cachedOffset); 428 429 // Arithmetic opcode helpers 430 void emitAdd32Constant(unsigned dst, unsigned op, int32_t constant, ResultType opType); 431 void emitSub32Constant(unsigned dst, unsigned op, int32_t constant, ResultType opType); 432 void emitBinaryDoubleOp(OpcodeID, unsigned dst, unsigned op1, unsigned op2, OperandTypes, JumpList& notInt32Op1, JumpList& notInt32Op2, bool op1IsInRegisters = true, bool op2IsInRegisters = true); 433 434 #if PLATFORM(X86) 435 // These architecture specific value are used to enable patching - see comment on op_put_by_id. 436 static const int patchOffsetPutByIdStructure = 7; 437 static const int patchOffsetPutByIdExternalLoad = 13; 438 static const int patchLengthPutByIdExternalLoad = 3; 439 static const int patchOffsetPutByIdPropertyMapOffset1 = 22; 440 static const int patchOffsetPutByIdPropertyMapOffset2 = 28; 441 // These architecture specific value are used to enable patching - see comment on op_get_by_id. 442 static const int patchOffsetGetByIdStructure = 7; 443 static const int patchOffsetGetByIdBranchToSlowCase = 13; 444 static const int patchOffsetGetByIdExternalLoad = 13; 445 static const int patchLengthGetByIdExternalLoad = 3; 446 static const int patchOffsetGetByIdPropertyMapOffset1 = 22; 447 static const int patchOffsetGetByIdPropertyMapOffset2 = 28; 448 static const int patchOffsetGetByIdPutResult = 28; 449 #if ENABLE(OPCODE_SAMPLING) && USE(JIT_STUB_ARGUMENT_VA_LIST) 450 static const int patchOffsetGetByIdSlowCaseCall = 35; 451 #elif ENABLE(OPCODE_SAMPLING) 452 static const int patchOffsetGetByIdSlowCaseCall = 37; 453 #elif USE(JIT_STUB_ARGUMENT_VA_LIST) 454 static const int patchOffsetGetByIdSlowCaseCall = 25; 455 #else 456 static const int patchOffsetGetByIdSlowCaseCall = 27; 457 #endif 458 static const int patchOffsetOpCallCompareToJump = 6; 459 460 static const int patchOffsetMethodCheckProtoObj = 11; 461 static const int patchOffsetMethodCheckProtoStruct = 18; 462 static const int patchOffsetMethodCheckPutFunction = 29; 463 #else 464 #error "JSVALUE32_64 not supported on this platform." 465 #endif 466 467 #else // USE(JSVALUE32_64) 468 void emitGetVirtualRegister(int src, RegisterID dst); 469 void emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2); 470 void emitPutVirtualRegister(unsigned dst, RegisterID from = regT0); 471 472 int32_t getConstantOperandImmediateInt(unsigned src); 473 474 void emitGetVariableObjectRegister(RegisterID variableObject, int index, RegisterID dst); 475 void emitPutVariableObjectRegister(RegisterID src, RegisterID variableObject, int index); 476 477 void killLastResultRegister(); 478 479 Jump emitJumpIfJSCell(RegisterID); 480 Jump emitJumpIfBothJSCells(RegisterID, RegisterID, RegisterID); 481 void emitJumpSlowCaseIfJSCell(RegisterID); 482 Jump emitJumpIfNotJSCell(RegisterID); 483 void emitJumpSlowCaseIfNotJSCell(RegisterID); 484 void emitJumpSlowCaseIfNotJSCell(RegisterID, int VReg); 485 #if USE(JSVALUE64) 486 JIT::Jump emitJumpIfImmediateNumber(RegisterID); 487 JIT::Jump emitJumpIfNotImmediateNumber(RegisterID); 488 #else emitJumpIfImmediateNumber(RegisterID reg)489 JIT::Jump emitJumpIfImmediateNumber(RegisterID reg) 490 { 491 return emitJumpIfImmediateInteger(reg); 492 } 493 emitJumpIfNotImmediateNumber(RegisterID reg)494 JIT::Jump emitJumpIfNotImmediateNumber(RegisterID reg) 495 { 496 return emitJumpIfNotImmediateInteger(reg); 497 } 498 #endif 499 JIT::Jump emitJumpIfImmediateInteger(RegisterID); 500 JIT::Jump emitJumpIfNotImmediateInteger(RegisterID); 501 JIT::Jump emitJumpIfNotImmediateIntegers(RegisterID, RegisterID, RegisterID); 502 void emitJumpSlowCaseIfNotImmediateInteger(RegisterID); 503 void emitJumpSlowCaseIfNotImmediateIntegers(RegisterID, RegisterID, RegisterID); 504 505 #if !USE(JSVALUE64) 506 void emitFastArithDeTagImmediate(RegisterID); 507 Jump emitFastArithDeTagImmediateJumpIfZero(RegisterID); 508 #endif 509 void emitFastArithReTagImmediate(RegisterID src, RegisterID dest); 510 void emitFastArithImmToInt(RegisterID); 511 void emitFastArithIntToImmNoCheck(RegisterID src, RegisterID dest); 512 513 void emitTagAsBoolImmediate(RegisterID reg); 514 void compileBinaryArithOp(OpcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi); 515 void compileBinaryArithOpSlowCase(OpcodeID, Vector<SlowCaseEntry>::iterator&, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi); 516 517 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) 518 void compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier* ident, unsigned propertyAccessInstructionIndex); 519 void compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, bool isMethodCheck = false); 520 #endif 521 void compileGetDirectOffset(RegisterID base, RegisterID result, Structure* structure, size_t cachedOffset); 522 void compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID result, size_t cachedOffset); 523 void compilePutDirectOffset(RegisterID base, RegisterID value, Structure* structure, size_t cachedOffset); 524 525 #if PLATFORM(X86_64) 526 // These architecture specific value are used to enable patching - see comment on op_put_by_id. 527 static const int patchOffsetPutByIdStructure = 10; 528 static const int patchOffsetPutByIdExternalLoad = 20; 529 static const int patchLengthPutByIdExternalLoad = 4; 530 static const int patchOffsetPutByIdPropertyMapOffset = 31; 531 // These architecture specific value are used to enable patching - see comment on op_get_by_id. 532 static const int patchOffsetGetByIdStructure = 10; 533 static const int patchOffsetGetByIdBranchToSlowCase = 20; 534 static const int patchOffsetGetByIdExternalLoad = 20; 535 static const int patchLengthGetByIdExternalLoad = 4; 536 static const int patchOffsetGetByIdPropertyMapOffset = 31; 537 static const int patchOffsetGetByIdPutResult = 31; 538 #if ENABLE(OPCODE_SAMPLING) 539 static const int patchOffsetGetByIdSlowCaseCall = 63; 540 #else 541 static const int patchOffsetGetByIdSlowCaseCall = 41; 542 #endif 543 static const int patchOffsetOpCallCompareToJump = 9; 544 545 static const int patchOffsetMethodCheckProtoObj = 20; 546 static const int patchOffsetMethodCheckProtoStruct = 30; 547 static const int patchOffsetMethodCheckPutFunction = 50; 548 #elif PLATFORM(X86) 549 // These architecture specific value are used to enable patching - see comment on op_put_by_id. 550 static const int patchOffsetPutByIdStructure = 7; 551 static const int patchOffsetPutByIdExternalLoad = 13; 552 static const int patchLengthPutByIdExternalLoad = 3; 553 static const int patchOffsetPutByIdPropertyMapOffset = 22; 554 // These architecture specific value are used to enable patching - see comment on op_get_by_id. 555 static const int patchOffsetGetByIdStructure = 7; 556 static const int patchOffsetGetByIdBranchToSlowCase = 13; 557 static const int patchOffsetGetByIdExternalLoad = 13; 558 static const int patchLengthGetByIdExternalLoad = 3; 559 static const int patchOffsetGetByIdPropertyMapOffset = 22; 560 static const int patchOffsetGetByIdPutResult = 22; 561 #if ENABLE(OPCODE_SAMPLING) && USE(JIT_STUB_ARGUMENT_VA_LIST) 562 static const int patchOffsetGetByIdSlowCaseCall = 31; 563 #elif ENABLE(OPCODE_SAMPLING) 564 static const int patchOffsetGetByIdSlowCaseCall = 33; 565 #elif USE(JIT_STUB_ARGUMENT_VA_LIST) 566 static const int patchOffsetGetByIdSlowCaseCall = 21; 567 #else 568 static const int patchOffsetGetByIdSlowCaseCall = 23; 569 #endif 570 static const int patchOffsetOpCallCompareToJump = 6; 571 572 static const int patchOffsetMethodCheckProtoObj = 11; 573 static const int patchOffsetMethodCheckProtoStruct = 18; 574 static const int patchOffsetMethodCheckPutFunction = 29; 575 #elif PLATFORM_ARM_ARCH(7) 576 // These architecture specific value are used to enable patching - see comment on op_put_by_id. 577 static const int patchOffsetPutByIdStructure = 10; 578 static const int patchOffsetPutByIdExternalLoad = 20; 579 static const int patchLengthPutByIdExternalLoad = 12; 580 static const int patchOffsetPutByIdPropertyMapOffset = 40; 581 // These architecture specific value are used to enable patching - see comment on op_get_by_id. 582 static const int patchOffsetGetByIdStructure = 10; 583 static const int patchOffsetGetByIdBranchToSlowCase = 20; 584 static const int patchOffsetGetByIdExternalLoad = 20; 585 static const int patchLengthGetByIdExternalLoad = 12; 586 static const int patchOffsetGetByIdPropertyMapOffset = 40; 587 static const int patchOffsetGetByIdPutResult = 44; 588 #if ENABLE(OPCODE_SAMPLING) 589 static const int patchOffsetGetByIdSlowCaseCall = 0; // FIMXE 590 #else 591 static const int patchOffsetGetByIdSlowCaseCall = 28; 592 #endif 593 static const int patchOffsetOpCallCompareToJump = 10; 594 595 static const int patchOffsetMethodCheckProtoObj = 18; 596 static const int patchOffsetMethodCheckProtoStruct = 28; 597 static const int patchOffsetMethodCheckPutFunction = 46; 598 #endif 599 #endif // USE(JSVALUE32_64) 600 601 void emit_op_add(Instruction*); 602 void emit_op_bitand(Instruction*); 603 void emit_op_bitnot(Instruction*); 604 void emit_op_bitor(Instruction*); 605 void emit_op_bitxor(Instruction*); 606 void emit_op_call(Instruction*); 607 void emit_op_call_eval(Instruction*); 608 void emit_op_call_varargs(Instruction*); 609 void emit_op_catch(Instruction*); 610 void emit_op_construct(Instruction*); 611 void emit_op_construct_verify(Instruction*); 612 void emit_op_convert_this(Instruction*); 613 void emit_op_create_arguments(Instruction*); 614 void emit_op_debug(Instruction*); 615 void emit_op_del_by_id(Instruction*); 616 void emit_op_div(Instruction*); 617 void emit_op_end(Instruction*); 618 void emit_op_enter(Instruction*); 619 void emit_op_enter_with_activation(Instruction*); 620 void emit_op_eq(Instruction*); 621 void emit_op_eq_null(Instruction*); 622 void emit_op_get_by_id(Instruction*); 623 void emit_op_get_by_val(Instruction*); 624 void emit_op_get_global_var(Instruction*); 625 void emit_op_get_scoped_var(Instruction*); 626 void emit_op_init_arguments(Instruction*); 627 void emit_op_instanceof(Instruction*); 628 void emit_op_jeq_null(Instruction*); 629 void emit_op_jfalse(Instruction*); 630 void emit_op_jmp(Instruction*); 631 void emit_op_jmp_scopes(Instruction*); 632 void emit_op_jneq_null(Instruction*); 633 void emit_op_jneq_ptr(Instruction*); 634 void emit_op_jnless(Instruction*); 635 void emit_op_jnlesseq(Instruction*); 636 void emit_op_jsr(Instruction*); 637 void emit_op_jtrue(Instruction*); 638 void emit_op_load_varargs(Instruction*); 639 void emit_op_loop(Instruction*); 640 void emit_op_loop_if_less(Instruction*); 641 void emit_op_loop_if_lesseq(Instruction*); 642 void emit_op_loop_if_true(Instruction*); 643 void emit_op_lshift(Instruction*); 644 void emit_op_method_check(Instruction*); 645 void emit_op_mod(Instruction*); 646 void emit_op_mov(Instruction*); 647 void emit_op_mul(Instruction*); 648 void emit_op_negate(Instruction*); 649 void emit_op_neq(Instruction*); 650 void emit_op_neq_null(Instruction*); 651 void emit_op_new_array(Instruction*); 652 void emit_op_new_error(Instruction*); 653 void emit_op_new_func(Instruction*); 654 void emit_op_new_func_exp(Instruction*); 655 void emit_op_new_object(Instruction*); 656 void emit_op_new_regexp(Instruction*); 657 void emit_op_next_pname(Instruction*); 658 void emit_op_not(Instruction*); 659 void emit_op_nstricteq(Instruction*); 660 void emit_op_pop_scope(Instruction*); 661 void emit_op_post_dec(Instruction*); 662 void emit_op_post_inc(Instruction*); 663 void emit_op_pre_dec(Instruction*); 664 void emit_op_pre_inc(Instruction*); 665 void emit_op_profile_did_call(Instruction*); 666 void emit_op_profile_will_call(Instruction*); 667 void emit_op_push_new_scope(Instruction*); 668 void emit_op_push_scope(Instruction*); 669 void emit_op_put_by_id(Instruction*); 670 void emit_op_put_by_index(Instruction*); 671 void emit_op_put_by_val(Instruction*); 672 void emit_op_put_getter(Instruction*); 673 void emit_op_put_global_var(Instruction*); 674 void emit_op_put_scoped_var(Instruction*); 675 void emit_op_put_setter(Instruction*); 676 void emit_op_resolve(Instruction*); 677 void emit_op_resolve_base(Instruction*); 678 void emit_op_resolve_global(Instruction*); 679 void emit_op_resolve_skip(Instruction*); 680 void emit_op_resolve_with_base(Instruction*); 681 void emit_op_ret(Instruction*); 682 void emit_op_rshift(Instruction*); 683 void emit_op_sret(Instruction*); 684 void emit_op_strcat(Instruction*); 685 void emit_op_stricteq(Instruction*); 686 void emit_op_sub(Instruction*); 687 void emit_op_switch_char(Instruction*); 688 void emit_op_switch_imm(Instruction*); 689 void emit_op_switch_string(Instruction*); 690 void emit_op_tear_off_activation(Instruction*); 691 void emit_op_tear_off_arguments(Instruction*); 692 void emit_op_throw(Instruction*); 693 void emit_op_to_jsnumber(Instruction*); 694 void emit_op_to_primitive(Instruction*); 695 void emit_op_unexpected_load(Instruction*); 696 697 void emitSlow_op_add(Instruction*, Vector<SlowCaseEntry>::iterator&); 698 void emitSlow_op_bitand(Instruction*, Vector<SlowCaseEntry>::iterator&); 699 void emitSlow_op_bitnot(Instruction*, Vector<SlowCaseEntry>::iterator&); 700 void emitSlow_op_bitor(Instruction*, Vector<SlowCaseEntry>::iterator&); 701 void emitSlow_op_bitxor(Instruction*, Vector<SlowCaseEntry>::iterator&); 702 void emitSlow_op_call(Instruction*, Vector<SlowCaseEntry>::iterator&); 703 void emitSlow_op_call_eval(Instruction*, Vector<SlowCaseEntry>::iterator&); 704 void emitSlow_op_call_varargs(Instruction*, Vector<SlowCaseEntry>::iterator&); 705 void emitSlow_op_construct(Instruction*, Vector<SlowCaseEntry>::iterator&); 706 void emitSlow_op_construct_verify(Instruction*, Vector<SlowCaseEntry>::iterator&); 707 void emitSlow_op_convert_this(Instruction*, Vector<SlowCaseEntry>::iterator&); 708 void emitSlow_op_div(Instruction*, Vector<SlowCaseEntry>::iterator&); 709 void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&); 710 void emitSlow_op_get_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&); 711 void emitSlow_op_get_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&); 712 void emitSlow_op_instanceof(Instruction*, Vector<SlowCaseEntry>::iterator&); 713 void emitSlow_op_jfalse(Instruction*, Vector<SlowCaseEntry>::iterator&); 714 void emitSlow_op_jnless(Instruction*, Vector<SlowCaseEntry>::iterator&); 715 void emitSlow_op_jnlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&); 716 void emitSlow_op_jtrue(Instruction*, Vector<SlowCaseEntry>::iterator&); 717 void emitSlow_op_loop_if_less(Instruction*, Vector<SlowCaseEntry>::iterator&); 718 void emitSlow_op_loop_if_lesseq(Instruction*, Vector<SlowCaseEntry>::iterator&); 719 void emitSlow_op_loop_if_true(Instruction*, Vector<SlowCaseEntry>::iterator&); 720 void emitSlow_op_lshift(Instruction*, Vector<SlowCaseEntry>::iterator&); 721 void emitSlow_op_method_check(Instruction*, Vector<SlowCaseEntry>::iterator&); 722 void emitSlow_op_mod(Instruction*, Vector<SlowCaseEntry>::iterator&); 723 void emitSlow_op_mul(Instruction*, Vector<SlowCaseEntry>::iterator&); 724 void emitSlow_op_negate(Instruction*, Vector<SlowCaseEntry>::iterator&); 725 void emitSlow_op_neq(Instruction*, Vector<SlowCaseEntry>::iterator&); 726 void emitSlow_op_not(Instruction*, Vector<SlowCaseEntry>::iterator&); 727 void emitSlow_op_nstricteq(Instruction*, Vector<SlowCaseEntry>::iterator&); 728 void emitSlow_op_post_dec(Instruction*, Vector<SlowCaseEntry>::iterator&); 729 void emitSlow_op_post_inc(Instruction*, Vector<SlowCaseEntry>::iterator&); 730 void emitSlow_op_pre_dec(Instruction*, Vector<SlowCaseEntry>::iterator&); 731 void emitSlow_op_pre_inc(Instruction*, Vector<SlowCaseEntry>::iterator&); 732 void emitSlow_op_put_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&); 733 void emitSlow_op_put_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&); 734 void emitSlow_op_resolve_global(Instruction*, Vector<SlowCaseEntry>::iterator&); 735 void emitSlow_op_rshift(Instruction*, Vector<SlowCaseEntry>::iterator&); 736 void emitSlow_op_stricteq(Instruction*, Vector<SlowCaseEntry>::iterator&); 737 void emitSlow_op_sub(Instruction*, Vector<SlowCaseEntry>::iterator&); 738 void emitSlow_op_to_jsnumber(Instruction*, Vector<SlowCaseEntry>::iterator&); 739 void emitSlow_op_to_primitive(Instruction*, Vector<SlowCaseEntry>::iterator&); 740 741 /* These functions are deprecated: Please use JITStubCall instead. */ 742 void emitPutJITStubArg(RegisterID src, unsigned argumentNumber); 743 #if USE(JSVALUE32_64) 744 void emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch1, RegisterID scratch2); 745 #else 746 void emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch); 747 #endif 748 void emitPutJITStubArgConstant(unsigned value, unsigned argumentNumber); 749 void emitPutJITStubArgConstant(void* value, unsigned argumentNumber); 750 void emitGetJITStubArg(unsigned argumentNumber, RegisterID dst); 751 752 void emitInitRegister(unsigned dst); 753 754 void emitPutToCallFrameHeader(RegisterID from, RegisterFile::CallFrameHeaderEntry entry); 755 void emitPutImmediateToCallFrameHeader(void* value, RegisterFile::CallFrameHeaderEntry entry); 756 void emitGetFromCallFrameHeaderPtr(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from = callFrameRegister); 757 void emitGetFromCallFrameHeader32(RegisterFile::CallFrameHeaderEntry entry, RegisterID to, RegisterID from = callFrameRegister); 758 759 JSValue getConstantOperand(unsigned src); 760 bool isOperandConstantImmediateInt(unsigned src); 761 getSlowCase(Vector<SlowCaseEntry>::iterator & iter)762 Jump getSlowCase(Vector<SlowCaseEntry>::iterator& iter) 763 { 764 return iter++->from; 765 } linkSlowCase(Vector<SlowCaseEntry>::iterator & iter)766 void linkSlowCase(Vector<SlowCaseEntry>::iterator& iter) 767 { 768 iter->from.link(this); 769 ++iter; 770 } 771 void linkSlowCaseIfNotJSCell(Vector<SlowCaseEntry>::iterator&, int vReg); 772 773 Jump checkStructure(RegisterID reg, Structure* structure); 774 775 void restoreArgumentReference(); 776 void restoreArgumentReferenceForTrampoline(); 777 778 Call emitNakedCall(CodePtr function = CodePtr()); 779 780 void preserveReturnAddressAfterCall(RegisterID); 781 void restoreReturnAddressBeforeReturn(RegisterID); 782 void restoreReturnAddressBeforeReturn(Address); 783 784 void emitTimeoutCheck(); 785 #ifndef NDEBUG 786 void printBytecodeOperandTypes(unsigned src1, unsigned src2); 787 #endif 788 789 #if ENABLE(SAMPLING_FLAGS) 790 void setSamplingFlag(int32_t); 791 void clearSamplingFlag(int32_t); 792 #endif 793 794 #if ENABLE(SAMPLING_COUNTERS) 795 void emitCount(AbstractSamplingCounter&, uint32_t = 1); 796 #endif 797 798 #if ENABLE(OPCODE_SAMPLING) 799 void sampleInstruction(Instruction*, bool = false); 800 #endif 801 802 #if ENABLE(CODEBLOCK_SAMPLING) 803 void sampleCodeBlock(CodeBlock*); 804 #else sampleCodeBlock(CodeBlock *)805 void sampleCodeBlock(CodeBlock*) {} 806 #endif 807 808 Interpreter* m_interpreter; 809 JSGlobalData* m_globalData; 810 CodeBlock* m_codeBlock; 811 812 Vector<CallRecord> m_calls; 813 Vector<Label> m_labels; 814 Vector<PropertyStubCompilationInfo> m_propertyAccessCompilationInfo; 815 Vector<StructureStubCompilationInfo> m_callStructureStubCompilationInfo; 816 Vector<MethodCallCompilationInfo> m_methodCallCompilationInfo; 817 Vector<JumpTable> m_jmpTable; 818 819 unsigned m_bytecodeIndex; 820 Vector<JSRInfo> m_jsrSites; 821 Vector<SlowCaseEntry> m_slowCases; 822 Vector<SwitchRecord> m_switches; 823 824 unsigned m_propertyAccessInstructionIndex; 825 unsigned m_globalResolveInfoIndex; 826 unsigned m_callLinkInfoIndex; 827 828 #if USE(JSVALUE32_64) 829 unsigned m_jumpTargetIndex; 830 unsigned m_mappedBytecodeIndex; 831 unsigned m_mappedVirtualRegisterIndex; 832 RegisterID m_mappedTag; 833 RegisterID m_mappedPayload; 834 #else 835 int m_lastResultBytecodeRegister; 836 unsigned m_jumpTargetsPosition; 837 #endif 838 } JIT_CLASS_ALIGNMENT; 839 } // namespace JSC 840 841 #endif // ENABLE(JIT) 842 843 #endif // JIT_h 844