2 * Copyright (C) 2011, 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGThunks.h"
31 #include "CCallHelpers.h"
32 #include "DFGOSRExitCompiler.h"
35 #include "LinkBuffer.h"
36 #include "MacroAssembler.h"
37 #include "JSCInlines.h"
39 namespace JSC
{ namespace DFG
{
41 MacroAssemblerCodeRef
osrExitGenerationThunkGenerator(VM
* vm
)
45 size_t scratchSize
= sizeof(EncodedJSValue
) * (GPRInfo::numberOfRegisters
+ FPRInfo::numberOfRegisters
);
46 ScratchBuffer
* scratchBuffer
= vm
->scratchBufferForSize(scratchSize
);
47 EncodedJSValue
* buffer
= static_cast<EncodedJSValue
*>(scratchBuffer
->dataBuffer());
49 for (unsigned i
= 0; i
< GPRInfo::numberOfRegisters
; ++i
) {
51 jit
.store64(GPRInfo::toRegister(i
), buffer
+ i
);
53 jit
.store32(GPRInfo::toRegister(i
), buffer
+ i
);
56 for (unsigned i
= 0; i
< FPRInfo::numberOfRegisters
; ++i
) {
57 jit
.move(MacroAssembler::TrustedImmPtr(buffer
+ GPRInfo::numberOfRegisters
+ i
), GPRInfo::regT0
);
58 jit
.storeDouble(FPRInfo::toRegister(i
), MacroAssembler::Address(GPRInfo::regT0
));
61 // Tell GC mark phase how much of the scratch buffer is active during call.
62 jit
.move(MacroAssembler::TrustedImmPtr(scratchBuffer
->activeLengthPtr()), GPRInfo::regT0
);
63 jit
.storePtr(MacroAssembler::TrustedImmPtr(scratchSize
), MacroAssembler::Address(GPRInfo::regT0
));
65 // Set up one argument.
67 jit
.poke(GPRInfo::callFrameRegister
, 0);
69 jit
.move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
72 MacroAssembler::Call functionCall
= jit
.call();
74 jit
.move(MacroAssembler::TrustedImmPtr(scratchBuffer
->activeLengthPtr()), GPRInfo::regT0
);
75 jit
.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(GPRInfo::regT0
));
77 for (unsigned i
= 0; i
< FPRInfo::numberOfRegisters
; ++i
) {
78 jit
.move(MacroAssembler::TrustedImmPtr(buffer
+ GPRInfo::numberOfRegisters
+ i
), GPRInfo::regT0
);
79 jit
.loadDouble(MacroAssembler::Address(GPRInfo::regT0
), FPRInfo::toRegister(i
));
81 for (unsigned i
= 0; i
< GPRInfo::numberOfRegisters
; ++i
) {
83 jit
.load64(buffer
+ i
, GPRInfo::toRegister(i
));
85 jit
.load32(buffer
+ i
, GPRInfo::toRegister(i
));
89 jit
.jump(MacroAssembler::AbsoluteAddress(&vm
->osrExitJumpDestination
));
91 LinkBuffer
patchBuffer(*vm
, jit
, GLOBAL_THUNK_ID
);
93 patchBuffer
.link(functionCall
, compileOSRExit
);
95 return FINALIZE_CODE(patchBuffer
, ("DFG OSR exit generation thunk"));
98 MacroAssemblerCodeRef
osrEntryThunkGenerator(VM
* vm
)
102 // We get passed the address of a scratch buffer. The first 8-byte slot of the buffer
103 // is the frame size. The second 8-byte slot is the pointer to where we are supposed to
104 // jump. The remaining bytes are the new call frame header followed by the locals.
106 ptrdiff_t offsetOfFrameSize
= 0; // This is the DFG frame count.
107 ptrdiff_t offsetOfTargetPC
= offsetOfFrameSize
+ sizeof(EncodedJSValue
);
108 ptrdiff_t offsetOfPayload
= offsetOfTargetPC
+ sizeof(EncodedJSValue
);
109 ptrdiff_t offsetOfLocals
= offsetOfPayload
+ sizeof(Register
) * JSStack::CallFrameHeaderSize
;
111 jit
.move(GPRInfo::returnValueGPR2
, GPRInfo::regT0
);
112 jit
.loadPtr(MacroAssembler::Address(GPRInfo::regT0
, offsetOfFrameSize
), GPRInfo::regT1
); // Load the frame size.
113 jit
.move(GPRInfo::regT1
, GPRInfo::regT2
);
114 jit
.lshiftPtr(MacroAssembler::Imm32(3), GPRInfo::regT2
);
115 jit
.move(GPRInfo::callFrameRegister
, MacroAssembler::stackPointerRegister
);
116 jit
.subPtr(GPRInfo::regT2
, MacroAssembler::stackPointerRegister
);
118 MacroAssembler::Label loop
= jit
.label();
119 jit
.subPtr(MacroAssembler::TrustedImm32(1), GPRInfo::regT1
);
120 jit
.move(GPRInfo::regT1
, GPRInfo::regT4
);
121 jit
.negPtr(GPRInfo::regT4
);
122 jit
.load32(MacroAssembler::BaseIndex(GPRInfo::regT0
, GPRInfo::regT1
, MacroAssembler::TimesEight
, offsetOfLocals
), GPRInfo::regT2
);
123 jit
.load32(MacroAssembler::BaseIndex(GPRInfo::regT0
, GPRInfo::regT1
, MacroAssembler::TimesEight
, offsetOfLocals
+ sizeof(int32_t)), GPRInfo::regT3
);
124 jit
.store32(GPRInfo::regT2
, MacroAssembler::BaseIndex(GPRInfo::callFrameRegister
, GPRInfo::regT4
, MacroAssembler::TimesEight
, -static_cast<intptr_t>(sizeof(Register
))));
125 jit
.store32(GPRInfo::regT3
, MacroAssembler::BaseIndex(GPRInfo::callFrameRegister
, GPRInfo::regT4
, MacroAssembler::TimesEight
, -static_cast<intptr_t>(sizeof(Register
)) + static_cast<intptr_t>(sizeof(int32_t))));
126 jit
.branchPtr(MacroAssembler::NotEqual
, GPRInfo::regT1
, MacroAssembler::TrustedImmPtr(bitwise_cast
<void*>(-static_cast<intptr_t>(JSStack::CallFrameHeaderSize
)))).linkTo(loop
, &jit
);
128 jit
.loadPtr(MacroAssembler::Address(GPRInfo::regT0
, offsetOfTargetPC
), GPRInfo::regT1
);
129 MacroAssembler::Jump ok
= jit
.branchPtr(MacroAssembler::Above
, GPRInfo::regT1
, MacroAssembler::TrustedImmPtr(bitwise_cast
<void*>(static_cast<intptr_t>(1000))));
130 jit
.abortWithReason(DFGUnreasonableOSREntryJumpDestination
);
132 jit
.jump(GPRInfo::regT1
);
134 LinkBuffer
patchBuffer(*vm
, jit
, GLOBAL_THUNK_ID
);
135 return FINALIZE_CODE(patchBuffer
, ("DFG OSR entry thunk"));
138 } } // namespace JSC::DFG
140 #endif // ENABLE(DFG_JIT)