deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / ia32 / debug-ia32.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #if V8_TARGET_ARCH_IA32
8
9 #include "src/codegen.h"
10 #include "src/debug.h"
11
12
13 namespace v8 {
14 namespace internal {
15
16
17 // Patch the code at the current PC with a call to the target address.
18 // Additional guard int3 instructions can be added if required.
19 void PatchCodeWithCall(Address pc, Address target, int guard_bytes) {
20   // Call instruction takes up 5 bytes and int3 takes up one byte.
21   static const int kCallCodeSize = 5;
22   int code_size = kCallCodeSize + guard_bytes;
23
24   // Create a code patcher.
25   CodePatcher patcher(pc, code_size);
26
27 // Add a label for checking the size of the code used for returning.
28 #ifdef DEBUG
29   Label check_codesize;
30   patcher.masm()->bind(&check_codesize);
31 #endif
32
33   // Patch the code.
34   patcher.masm()->call(target, RelocInfo::NONE32);
35
36   // Check that the size of the code generated is as expected.
37   DCHECK_EQ(kCallCodeSize,
38             patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
39
40   // Add the requested number of int3 instructions after the call.
41   DCHECK_GE(guard_bytes, 0);
42   for (int i = 0; i < guard_bytes; i++) {
43     patcher.masm()->int3();
44   }
45
46   CpuFeatures::FlushICache(pc, code_size);
47 }
48
49
50 // Patch the JS frame exit code with a debug break call. See
51 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-ia32.cc
52 // for the precise return instructions sequence.
53 void BreakLocation::SetDebugBreakAtReturn() {
54   DCHECK(Assembler::kJSReturnSequenceLength >=
55          Assembler::kCallInstructionLength);
56   PatchCodeWithCall(
57       pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
58       Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
59 }
60
61
62 void BreakLocation::SetDebugBreakAtSlot() {
63   DCHECK(IsDebugBreakSlot());
64   Isolate* isolate = debug_info_->GetIsolate();
65   PatchCodeWithCall(
66       pc(), isolate->builtins()->Slot_DebugBreak()->entry(),
67       Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
68 }
69
70
71 #define __ ACCESS_MASM(masm)
72
73 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
74                                           RegList object_regs,
75                                           RegList non_object_regs,
76                                           bool convert_call_to_jmp) {
77   // Enter an internal frame.
78   {
79     FrameScope scope(masm, StackFrame::INTERNAL);
80
81     // Load padding words on stack.
82     for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
83       __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue)));
84     }
85     __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
86
87     // Store the registers containing live values on the expression stack to
88     // make sure that these are correctly updated during GC. Non object values
89     // are stored as a smi causing it to be untouched by GC.
90     DCHECK((object_regs & ~kJSCallerSaved) == 0);
91     DCHECK((non_object_regs & ~kJSCallerSaved) == 0);
92     DCHECK((object_regs & non_object_regs) == 0);
93     for (int i = 0; i < kNumJSCallerSaved; i++) {
94       int r = JSCallerSavedCode(i);
95       Register reg = { r };
96       if ((object_regs & (1 << r)) != 0) {
97         __ push(reg);
98       }
99       if ((non_object_regs & (1 << r)) != 0) {
100         if (FLAG_debug_code) {
101           __ test(reg, Immediate(0xc0000000));
102           __ Assert(zero, kUnableToEncodeValueAsSmi);
103         }
104         __ SmiTag(reg);
105         __ push(reg);
106       }
107     }
108
109 #ifdef DEBUG
110     __ RecordComment("// Calling from debug break to runtime - come in - over");
111 #endif
112     __ Move(eax, Immediate(0));  // No arguments.
113     __ mov(ebx, Immediate(ExternalReference::debug_break(masm->isolate())));
114
115     CEntryStub ceb(masm->isolate(), 1);
116     __ CallStub(&ceb);
117
118     // Automatically find register that could be used after register restore.
119     // We need one register for padding skip instructions.
120     Register unused_reg = { -1 };
121
122     // Restore the register values containing object pointers from the
123     // expression stack.
124     for (int i = kNumJSCallerSaved; --i >= 0;) {
125       int r = JSCallerSavedCode(i);
126       Register reg = { r };
127       if (FLAG_debug_code) {
128         __ Move(reg, Immediate(kDebugZapValue));
129       }
130       bool taken = reg.code() == esi.code();
131       if ((object_regs & (1 << r)) != 0) {
132         __ pop(reg);
133         taken = true;
134       }
135       if ((non_object_regs & (1 << r)) != 0) {
136         __ pop(reg);
137         __ SmiUntag(reg);
138         taken = true;
139       }
140       if (!taken) {
141         unused_reg = reg;
142       }
143     }
144
145     DCHECK(unused_reg.code() != -1);
146
147     // Read current padding counter and skip corresponding number of words.
148     __ pop(unused_reg);
149     // We divide stored value by 2 (untagging) and multiply it by word's size.
150     STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0);
151     __ lea(esp, Operand(esp, unused_reg, times_half_pointer_size, 0));
152
153     // Get rid of the internal frame.
154   }
155
156   // If this call did not replace a call but patched other code then there will
157   // be an unwanted return address left on the stack. Here we get rid of that.
158   if (convert_call_to_jmp) {
159     __ add(esp, Immediate(kPointerSize));
160   }
161
162   // Now that the break point has been handled, resume normal execution by
163   // jumping to the target address intended by the caller and that was
164   // overwritten by the address of DebugBreakXXX.
165   ExternalReference after_break_target =
166       ExternalReference::debug_after_break_target_address(masm->isolate());
167   __ jmp(Operand::StaticVariable(after_break_target));
168 }
169
170
171 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
172   // Register state for CallICStub
173   // ----------- S t a t e -------------
174   //  -- edx    : type feedback slot (smi)
175   //  -- edi    : function
176   // -----------------------------------
177   Generate_DebugBreakCallHelper(masm, edx.bit() | edi.bit(),
178                                 0, false);
179 }
180
181
182 void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
183   // Register state for IC load call (from ic-ia32.cc).
184   Register receiver = LoadDescriptor::ReceiverRegister();
185   Register name = LoadDescriptor::NameRegister();
186   RegList regs = receiver.bit() | name.bit();
187   if (FLAG_vector_ics) {
188     regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
189   }
190   Generate_DebugBreakCallHelper(masm, regs, 0, false);
191 }
192
193
194 void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
195   // Register state for IC store call (from ic-ia32.cc).
196   Register receiver = StoreDescriptor::ReceiverRegister();
197   Register name = StoreDescriptor::NameRegister();
198   Register value = StoreDescriptor::ValueRegister();
199   Generate_DebugBreakCallHelper(
200       masm, receiver.bit() | name.bit() | value.bit(), 0, false);
201 }
202
203
204 void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
205   // Register state for keyed IC load call (from ic-ia32.cc).
206   GenerateLoadICDebugBreak(masm);
207 }
208
209
210 void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
211   // Register state for keyed IC store call (from ic-ia32.cc).
212   Register receiver = StoreDescriptor::ReceiverRegister();
213   Register name = StoreDescriptor::NameRegister();
214   Register value = StoreDescriptor::ValueRegister();
215   Generate_DebugBreakCallHelper(
216       masm, receiver.bit() | name.bit() | value.bit(), 0, false);
217 }
218
219
220 void DebugCodegen::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
221   // Register state for CompareNil IC
222   // ----------- S t a t e -------------
223   //  -- eax    : value
224   // -----------------------------------
225   Generate_DebugBreakCallHelper(masm, eax.bit(), 0, false);
226 }
227
228
229 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
230   // Register state just before return from JS function (from codegen-ia32.cc).
231   // ----------- S t a t e -------------
232   //  -- eax: return value
233   // -----------------------------------
234   Generate_DebugBreakCallHelper(masm, eax.bit(), 0, true);
235 }
236
237
238 void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
239   // Register state for CallFunctionStub (from code-stubs-ia32.cc).
240   // ----------- S t a t e -------------
241   //  -- edi: function
242   // -----------------------------------
243   Generate_DebugBreakCallHelper(masm, edi.bit(), 0, false);
244 }
245
246
247 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
248   // Register state for CallConstructStub (from code-stubs-ia32.cc).
249   // eax is the actual number of arguments not encoded as a smi see comment
250   // above IC call.
251   // ----------- S t a t e -------------
252   //  -- eax: number of arguments (not smi)
253   //  -- edi: constructor function
254   // -----------------------------------
255   // The number of arguments in eax is not smi encoded.
256   Generate_DebugBreakCallHelper(masm, edi.bit(), eax.bit(), false);
257 }
258
259
260 void DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
261     MacroAssembler* masm) {
262   // Register state for CallConstructStub (from code-stubs-ia32.cc).
263   // eax is the actual number of arguments not encoded as a smi see comment
264   // above IC call.
265   // ----------- S t a t e -------------
266   //  -- eax: number of arguments (not smi)
267   //  -- ebx: feedback array
268   //  -- edx: feedback slot (smi)
269   //  -- edi: constructor function
270   // -----------------------------------
271   // The number of arguments in eax is not smi encoded.
272   Generate_DebugBreakCallHelper(masm, ebx.bit() | edx.bit() | edi.bit(),
273                                 eax.bit(), false);
274 }
275
276
277 void DebugCodegen::GenerateSlot(MacroAssembler* masm) {
278   // Generate enough nop's to make space for a call instruction.
279   Label check_codesize;
280   __ bind(&check_codesize);
281   __ RecordDebugBreakSlot();
282   __ Nop(Assembler::kDebugBreakSlotLength);
283   DCHECK_EQ(Assembler::kDebugBreakSlotLength,
284             masm->SizeOfCodeGeneratedSince(&check_codesize));
285 }
286
287
288 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
289   // In the places where a debug break slot is inserted no registers can contain
290   // object pointers.
291   Generate_DebugBreakCallHelper(masm, 0, 0, true);
292 }
293
294
295 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
296   masm->ret(0);
297 }
298
299
300 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
301   ExternalReference restarter_frame_function_slot =
302       ExternalReference::debug_restarter_frame_function_pointer_address(
303           masm->isolate());
304   __ mov(Operand::StaticVariable(restarter_frame_function_slot), Immediate(0));
305
306   // We do not know our frame height, but set esp based on ebp.
307   __ lea(esp, Operand(ebp, -1 * kPointerSize));
308
309   __ pop(edi);  // Function.
310   __ pop(ebp);
311
312   // Load context from the function.
313   __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
314
315   // Get function code.
316   __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
317   __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
318   __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
319
320   // Re-run JSFunction, edi is function, esi is context.
321   __ jmp(edx);
322 }
323
324
325 const bool LiveEdit::kFrameDropperSupported = true;
326
327 #undef __
328
329 } }  // namespace v8::internal
330
331 #endif  // V8_TARGET_ARCH_IA32