blob: c47bfccf13034c61062f844628a6cb25e896c604 [file] [log] [blame]
ager@chromium.org5ec48922009-05-05 07:25:34 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
kasperl@chromium.org71affb52009-05-26 05:44:31 +000028#include "v8.h"
29
30#include "bootstrapper.h"
31#include "codegen-inl.h"
ager@chromium.orgeadaf222009-06-16 09:43:10 +000032#include "assembler-x64.h"
ager@chromium.orge2902be2009-06-08 12:21:35 +000033#include "macro-assembler-x64.h"
ager@chromium.orgeadaf222009-06-16 09:43:10 +000034#include "debug.h"
kasperl@chromium.org71affb52009-05-26 05:44:31 +000035
36namespace v8 {
37namespace internal {
38
39MacroAssembler::MacroAssembler(void* buffer, int size)
40 : Assembler(buffer, size),
41 unresolved_(0),
42 generating_stub_(false),
43 allow_stub_calls_(true),
44 code_object_(Heap::undefined_value()) {
45}
46
ager@chromium.orge2902be2009-06-08 12:21:35 +000047
ager@chromium.orgeadaf222009-06-16 09:43:10 +000048void MacroAssembler::Assert(Condition cc, const char* msg) {
49 if (FLAG_debug_code) Check(cc, msg);
50}
51
52
53void MacroAssembler::Check(Condition cc, const char* msg) {
54 Label L;
55 j(cc, &L);
56 Abort(msg);
57 // will not return here
58 bind(&L);
59}
60
61
62void MacroAssembler::ConstructAndTestJSFunction() {
63 const int initial_buffer_size = 4 * KB;
64 char* buffer = new char[initial_buffer_size];
65 MacroAssembler masm(buffer, initial_buffer_size);
66
67 const uint64_t secret = V8_INT64_C(0xdeadbeefcafebabe);
68 Handle<String> constant =
69 Factory::NewStringFromAscii(Vector<const char>("451", 3), TENURED);
70#define __ ACCESS_MASM((&masm))
71 // Construct a simple JSfunction here, using Assembler and MacroAssembler
72 // commands.
73 __ movq(rax, constant, RelocInfo::EMBEDDED_OBJECT);
74 __ push(rax);
75 __ CallRuntime(Runtime::kStringParseFloat, 1);
76 __ movq(kScratchRegister, secret, RelocInfo::NONE);
77 __ addq(rax, kScratchRegister);
78 __ ret(0);
79#undef __
80 CodeDesc desc;
81 masm.GetCode(&desc);
82 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
83 Object* code = Heap::CreateCode(desc, NULL, flags, Handle<Object>::null());
84 if (!code->IsFailure()) {
85 Handle<Code> code_handle(Code::cast(code));
86 Handle<String> name =
87 Factory::NewStringFromAscii(Vector<const char>("foo", 3), NOT_TENURED);
88 Handle<JSFunction> function =
89 Factory::NewFunction(name,
90 JS_FUNCTION_TYPE,
91 JSObject::kHeaderSize,
92 code_handle,
93 true);
94 bool pending_exceptions;
95 Handle<Object> result =
96 Execution::Call(function,
97 Handle<Object>::cast(function),
98 0,
99 NULL,
100 &pending_exceptions);
101 CHECK(result->IsSmi());
102 CHECK(secret + (451 << kSmiTagSize) == reinterpret_cast<uint64_t>(*result));
103 }
104}
105
106
107void MacroAssembler::Abort(const char* msg) {
108 // We want to pass the msg string like a smi to avoid GC
109 // problems, however msg is not guaranteed to be aligned
110 // properly. Instead, we pass an aligned pointer that is
111 // a proper v8 smi, but also pass the alignment difference
112 // from the real pointer as a smi.
113 intptr_t p1 = reinterpret_cast<intptr_t>(msg);
114 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
115 // Note: p0 might not be a valid Smi *value*, but it has a valid Smi tag.
116 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
117#ifdef DEBUG
118 if (msg != NULL) {
119 RecordComment("Abort message: ");
120 RecordComment(msg);
121 }
122#endif
123 push(rax);
124 movq(kScratchRegister, p0, RelocInfo::NONE);
125 push(kScratchRegister);
126 movq(kScratchRegister,
127 reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0)),
128 RelocInfo::NONE);
129 push(kScratchRegister);
130 CallRuntime(Runtime::kAbort, 2);
131 // will not return here
132}
133
134
135void MacroAssembler::CallStub(CodeStub* stub) {
136 ASSERT(allow_stub_calls()); // calls are not allowed in some stubs
137 movq(kScratchRegister, stub->GetCode(), RelocInfo::CODE_TARGET);
138 call(kScratchRegister);
139}
140
141
142void MacroAssembler::StubReturn(int argc) {
143 ASSERT(argc >= 1 && generating_stub());
144 ret((argc - 1) * kPointerSize);
145}
146
147
148void MacroAssembler::IllegalOperation(int num_arguments) {
149 if (num_arguments > 0) {
150 addq(rsp, Immediate(num_arguments * kPointerSize));
151 }
152 movq(rax, Factory::undefined_value(), RelocInfo::EMBEDDED_OBJECT);
153}
154
155
156void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
157 CallRuntime(Runtime::FunctionForId(id), num_arguments);
158}
159
160
161void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
162 // If the expected number of arguments of the runtime function is
163 // constant, we check that the actual number of arguments match the
164 // expectation.
165 if (f->nargs >= 0 && f->nargs != num_arguments) {
166 IllegalOperation(num_arguments);
167 return;
168 }
169
170 Runtime::FunctionId function_id =
171 static_cast<Runtime::FunctionId>(f->stub_id);
172 RuntimeStub stub(function_id, num_arguments);
173 CallStub(&stub);
174}
175
176
177void MacroAssembler::TailCallRuntime(ExternalReference const& ext,
178 int num_arguments) {
179 // TODO(1236192): Most runtime routines don't need the number of
180 // arguments passed in because it is constant. At some point we
181 // should remove this need and make the runtime routine entry code
182 // smarter.
183 movq(rax, Immediate(num_arguments));
184 JumpToBuiltin(ext);
185}
186
187
188void MacroAssembler::JumpToBuiltin(const ExternalReference& ext) {
189 // Set the entry point and jump to the C entry runtime stub.
190 movq(rbx, ext);
191 CEntryStub ces;
192 movq(kScratchRegister, ces.GetCode(), RelocInfo::CODE_TARGET);
193 jmp(kScratchRegister);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000194}
195
ager@chromium.orge2902be2009-06-08 12:21:35 +0000196
197void MacroAssembler::Set(Register dst, int64_t x) {
198 if (is_int32(x)) {
199 movq(dst, Immediate(x));
200 } else if (is_uint32(x)) {
201 movl(dst, Immediate(x));
202 } else {
203 movq(dst, x, RelocInfo::NONE);
204 }
205}
206
207
208void MacroAssembler::Set(const Operand& dst, int64_t x) {
209 if (is_int32(x)) {
210 movq(kScratchRegister, Immediate(x));
211 } else if (is_uint32(x)) {
212 movl(kScratchRegister, Immediate(x));
213 } else {
214 movq(kScratchRegister, x, RelocInfo::NONE);
215 }
216 movq(dst, kScratchRegister);
217}
218
219
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000220void MacroAssembler::Jump(ExternalReference ext) {
221 movq(kScratchRegister, ext);
222 jmp(kScratchRegister);
223}
224
225
226void MacroAssembler::Jump(Address destination, RelocInfo::Mode rmode) {
227 movq(kScratchRegister, destination, rmode);
228 jmp(kScratchRegister);
229}
230
231
232void MacroAssembler::Call(ExternalReference ext) {
233 movq(kScratchRegister, ext);
234 call(kScratchRegister);
235}
236
237
238void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) {
239 movq(kScratchRegister, destination, rmode);
240 call(kScratchRegister);
241}
242
243
ager@chromium.orge2902be2009-06-08 12:21:35 +0000244void MacroAssembler::PushTryHandler(CodeLocation try_location,
245 HandlerType type) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000246 // Adjust this code if not the case.
247 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
248
249 // The pc (return address) is already on TOS. This code pushes state,
250 // frame pointer and current handler. Check that they are expected
251 // next on the stack, in that order.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000252 ASSERT_EQ(StackHandlerConstants::kStateOffset,
253 StackHandlerConstants::kPCOffset - kPointerSize);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000254 ASSERT_EQ(StackHandlerConstants::kFPOffset,
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000255 StackHandlerConstants::kStateOffset - kPointerSize);
256 ASSERT_EQ(StackHandlerConstants::kNextOffset,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000257 StackHandlerConstants::kFPOffset - kPointerSize);
258
259 if (try_location == IN_JAVASCRIPT) {
260 if (type == TRY_CATCH_HANDLER) {
261 push(Immediate(StackHandler::TRY_CATCH));
262 } else {
263 push(Immediate(StackHandler::TRY_FINALLY));
264 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000265 push(rbp);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000266 } else {
267 ASSERT(try_location == IN_JS_ENTRY);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000268 // The frame pointer does not point to a JS frame so we save NULL
269 // for rbp. We expect the code throwing an exception to check rbp
270 // before dereferencing it to restore the context.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000271 push(Immediate(StackHandler::ENTRY));
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000272 push(Immediate(0)); // NULL frame pointer.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000273 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000274 // Save the current handler.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000275 movq(kScratchRegister, ExternalReference(Top::k_handler_address));
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000276 push(Operand(kScratchRegister, 0));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000277 // Link this handler.
278 movq(Operand(kScratchRegister, 0), rsp);
279}
280
281
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000282void MacroAssembler::Ret() {
283 ret(0);
284}
285
286
287void MacroAssembler::CmpObjectType(Register heap_object,
288 InstanceType type,
289 Register map) {
290 movq(map, FieldOperand(heap_object, HeapObject::kMapOffset));
291 CmpInstanceType(map, type);
292}
293
294
295void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
296 cmpb(FieldOperand(map, Map::kInstanceTypeOffset),
297 Immediate(static_cast<int8_t>(type)));
298}
299
300
301
302void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
303 if (FLAG_native_code_counters && counter->Enabled()) {
304 movq(kScratchRegister, ExternalReference(counter));
305 movl(Operand(kScratchRegister, 0), Immediate(value));
306 }
307}
308
309
310void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
311 ASSERT(value > 0);
312 if (FLAG_native_code_counters && counter->Enabled()) {
313 movq(kScratchRegister, ExternalReference(counter));
314 Operand operand(kScratchRegister, 0);
315 if (value == 1) {
316 incl(operand);
317 } else {
318 addl(operand, Immediate(value));
319 }
320 }
321}
322
323
324void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
325 ASSERT(value > 0);
326 if (FLAG_native_code_counters && counter->Enabled()) {
327 movq(kScratchRegister, ExternalReference(counter));
328 Operand operand(kScratchRegister, 0);
329 if (value == 1) {
330 decl(operand);
331 } else {
332 subl(operand, Immediate(value));
333 }
334 }
335}
336
337
338#ifdef ENABLE_DEBUGGER_SUPPORT
339
340void MacroAssembler::PushRegistersFromMemory(RegList regs) {
341 ASSERT((regs & ~kJSCallerSaved) == 0);
342 // Push the content of the memory location to the stack.
343 for (int i = 0; i < kNumJSCallerSaved; i++) {
344 int r = JSCallerSavedCode(i);
345 if ((regs & (1 << r)) != 0) {
346 ExternalReference reg_addr =
347 ExternalReference(Debug_Address::Register(i));
348 movq(kScratchRegister, reg_addr);
349 push(Operand(kScratchRegister, 0));
350 }
351 }
352}
353
354void MacroAssembler::SaveRegistersToMemory(RegList regs) {
355 ASSERT((regs & ~kJSCallerSaved) == 0);
356 // Copy the content of registers to memory location.
357 for (int i = 0; i < kNumJSCallerSaved; i++) {
358 int r = JSCallerSavedCode(i);
359 if ((regs & (1 << r)) != 0) {
360 Register reg = { r };
361 ExternalReference reg_addr =
362 ExternalReference(Debug_Address::Register(i));
363 movq(kScratchRegister, reg_addr);
364 movq(Operand(kScratchRegister, 0), reg);
365 }
366 }
367}
368
369
370void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
371 ASSERT((regs & ~kJSCallerSaved) == 0);
372 // Copy the content of memory location to registers.
373 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
374 int r = JSCallerSavedCode(i);
375 if ((regs & (1 << r)) != 0) {
376 Register reg = { r };
377 ExternalReference reg_addr =
378 ExternalReference(Debug_Address::Register(i));
379 movq(kScratchRegister, reg_addr);
380 movq(reg, Operand(kScratchRegister, 0));
381 }
382 }
383}
384
385
386void MacroAssembler::PopRegistersToMemory(RegList regs) {
387 ASSERT((regs & ~kJSCallerSaved) == 0);
388 // Pop the content from the stack to the memory location.
389 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
390 int r = JSCallerSavedCode(i);
391 if ((regs & (1 << r)) != 0) {
392 ExternalReference reg_addr =
393 ExternalReference(Debug_Address::Register(i));
394 movq(kScratchRegister, reg_addr);
395 pop(Operand(kScratchRegister, 0));
396 }
397 }
398}
399
400
401void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
402 Register scratch,
403 RegList regs) {
404 ASSERT(!scratch.is(kScratchRegister));
405 ASSERT(!base.is(kScratchRegister));
406 ASSERT(!base.is(scratch));
407 ASSERT((regs & ~kJSCallerSaved) == 0);
408 // Copy the content of the stack to the memory location and adjust base.
409 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
410 int r = JSCallerSavedCode(i);
411 if ((regs & (1 << r)) != 0) {
412 movq(scratch, Operand(base, 0));
413 ExternalReference reg_addr =
414 ExternalReference(Debug_Address::Register(i));
415 movq(kScratchRegister, reg_addr);
416 movq(Operand(kScratchRegister, 0), scratch);
417 lea(base, Operand(base, kPointerSize));
418 }
419 }
420}
421
422#endif // ENABLE_DEBUGGER_SUPPORT
423
424
425void MacroAssembler::InvokePrologue(const ParameterCount& expected,
426 const ParameterCount& actual,
427 Handle<Code> code_constant,
428 Register code_register,
429 Label* done,
430 InvokeFlag flag) {
431 bool definitely_matches = false;
432 Label invoke;
433 if (expected.is_immediate()) {
434 ASSERT(actual.is_immediate());
435 if (expected.immediate() == actual.immediate()) {
436 definitely_matches = true;
437 } else {
438 movq(rax, Immediate(actual.immediate()));
439 if (expected.immediate() ==
440 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
441 // Don't worry about adapting arguments for built-ins that
442 // don't want that done. Skip adaption code by making it look
443 // like we have a match between expected and actual number of
444 // arguments.
445 definitely_matches = true;
446 } else {
447 movq(rbx, Immediate(expected.immediate()));
448 }
449 }
450 } else {
451 if (actual.is_immediate()) {
452 // Expected is in register, actual is immediate. This is the
453 // case when we invoke function values without going through the
454 // IC mechanism.
455 cmpq(expected.reg(), Immediate(actual.immediate()));
456 j(equal, &invoke);
457 ASSERT(expected.reg().is(rbx));
458 movq(rax, Immediate(actual.immediate()));
459 } else if (!expected.reg().is(actual.reg())) {
460 // Both expected and actual are in (different) registers. This
461 // is the case when we invoke functions using call and apply.
462 cmpq(expected.reg(), actual.reg());
463 j(equal, &invoke);
464 ASSERT(actual.reg().is(rax));
465 ASSERT(expected.reg().is(rbx));
466 }
467 }
468
469 if (!definitely_matches) {
470 Handle<Code> adaptor =
471 Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
472 if (!code_constant.is_null()) {
473 movq(rdx, code_constant, RelocInfo::EMBEDDED_OBJECT);
474 addq(rdx, Immediate(Code::kHeaderSize - kHeapObjectTag));
475 } else if (!code_register.is(rdx)) {
476 movq(rdx, code_register);
477 }
478
479 movq(kScratchRegister, adaptor, RelocInfo::CODE_TARGET);
480 if (flag == CALL_FUNCTION) {
481 call(kScratchRegister);
482 jmp(done);
483 } else {
484 jmp(kScratchRegister);
485 }
486 bind(&invoke);
487 }
488}
489
490
491
492
493void MacroAssembler::InvokeCode(Register code,
494 const ParameterCount& expected,
495 const ParameterCount& actual,
496 InvokeFlag flag) {
497 Label done;
498 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
499 if (flag == CALL_FUNCTION) {
500 call(code);
501 } else {
502 ASSERT(flag == JUMP_FUNCTION);
503 jmp(code);
504 }
505 bind(&done);
506}
507
508
509void MacroAssembler::InvokeCode(Handle<Code> code,
510 const ParameterCount& expected,
511 const ParameterCount& actual,
512 RelocInfo::Mode rmode,
513 InvokeFlag flag) {
514 Label done;
515 Register dummy = rax;
516 InvokePrologue(expected, actual, code, dummy, &done, flag);
517 movq(kScratchRegister, code, rmode);
518 if (flag == CALL_FUNCTION) {
519 call(kScratchRegister);
520 } else {
521 ASSERT(flag == JUMP_FUNCTION);
522 jmp(kScratchRegister);
523 }
524 bind(&done);
525}
526
527
528void MacroAssembler::InvokeFunction(Register function,
529 const ParameterCount& actual,
530 InvokeFlag flag) {
531 ASSERT(function.is(rdi));
532 movq(rdx, FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
533 movq(rsi, FieldOperand(function, JSFunction::kContextOffset));
534 movl(rbx, FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
535 movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
536 // Advances rdx to the end of the Code object headers, to the start of
537 // the executable code.
538 lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
539
540 ParameterCount expected(rbx);
541 InvokeCode(rdx, expected, actual, flag);
542}
543
544
545void MacroAssembler::EnterFrame(StackFrame::Type type) {
546 push(rbp);
547 movq(rbp, rsp);
548 push(rsi); // Context.
549 push(Immediate(Smi::FromInt(type)));
550 movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT);
551 push(kScratchRegister);
552 if (FLAG_debug_code) {
553 movq(kScratchRegister,
554 Factory::undefined_value(),
555 RelocInfo::EMBEDDED_OBJECT);
556 cmpq(Operand(rsp, 0), kScratchRegister);
557 Check(not_equal, "code object not properly patched");
558 }
559}
560
561
562void MacroAssembler::LeaveFrame(StackFrame::Type type) {
563 if (FLAG_debug_code) {
564 movq(kScratchRegister, Immediate(Smi::FromInt(type)));
565 cmpq(Operand(rbp, StandardFrameConstants::kMarkerOffset), kScratchRegister);
566 Check(equal, "stack frame types must match");
567 }
568 movq(rsp, rbp);
569 pop(rbp);
570}
571
572
573
574void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
575 ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG);
576
577 // Setup the frame structure on the stack.
578 ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
579 ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
580 ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize);
581 push(rbp);
582 movq(rbp, rsp);
583
584 // Reserve room for entry stack pointer and push the debug marker.
585 ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
586 push(Immediate(0)); // saved entry sp, patched before call
587 push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0));
588
589 // Save the frame pointer and the context in top.
590 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
591 ExternalReference context_address(Top::k_context_address);
592 movq(rdi, rax); // Backup rax before we use it.
593
594 movq(rax, rbp);
595 store_rax(c_entry_fp_address);
596 movq(rax, rsi);
597 store_rax(context_address);
598
599 // Setup argv in callee-saved register r15. It is reused in LeaveExitFrame,
600 // so it must be retained across the C-call.
601 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
602 lea(r15, Operand(rbp, rdi, kTimesPointerSize, offset));
603
604#ifdef ENABLE_DEBUGGER_SUPPORT
605 // Save the state of all registers to the stack from the memory
606 // location. This is needed to allow nested break points.
607 if (type == StackFrame::EXIT_DEBUG) {
608 // TODO(1243899): This should be symmetric to
609 // CopyRegistersFromStackToMemory() but it isn't! esp is assumed
610 // correct here, but computed for the other call. Very error
611 // prone! FIX THIS. Actually there are deeper problems with
612 // register saving than this asymmetry (see the bug report
613 // associated with this issue).
614 PushRegistersFromMemory(kJSCallerSaved);
615 }
616#endif
617
618 // Reserve space for two arguments: argc and argv
619 subq(rsp, Immediate(2 * kPointerSize));
620
621 // Get the required frame alignment for the OS.
622 static const int kFrameAlignment = OS::ActivationFrameAlignment();
623 if (kFrameAlignment > 0) {
624 ASSERT(IsPowerOf2(kFrameAlignment));
625 movq(kScratchRegister, Immediate(-kFrameAlignment));
626 and_(rsp, kScratchRegister);
627 }
628
629 // Patch the saved entry sp.
630 movq(Operand(rbp, ExitFrameConstants::kSPOffset), rsp);
631}
632
633
634void MacroAssembler::LeaveExitFrame(StackFrame::Type type) {
635 // Registers:
636 // r15 : argv
637#ifdef ENABLE_DEBUGGER_SUPPORT
638 // Restore the memory copy of the registers by digging them out from
639 // the stack. This is needed to allow nested break points.
640 if (type == StackFrame::EXIT_DEBUG) {
641 // It's okay to clobber register ebx below because we don't need
642 // the function pointer after this.
643 const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
644 int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize;
645 lea(rbx, Operand(rbp, kOffset));
646 CopyRegistersFromStackToMemory(rbx, rcx, kJSCallerSaved);
647 }
648#endif
649
650 // Get the return address from the stack and restore the frame pointer.
651 movq(rcx, Operand(rbp, 1 * kPointerSize));
652 movq(rbp, Operand(rbp, 0 * kPointerSize));
653
654 // Pop the arguments and the receiver from the caller stack.
655 lea(rsp, Operand(r15, 1 * kPointerSize));
656
657 // Restore current context from top and clear it in debug mode.
658 ExternalReference context_address(Top::k_context_address);
659 movq(kScratchRegister, context_address);
660 movq(rsi, Operand(kScratchRegister, 0));
661#ifdef DEBUG
662 movq(Operand(kScratchRegister, 0), Immediate(0));
663#endif
664
665 // Push the return address to get ready to return.
666 push(rcx);
667
668 // Clear the top frame.
669 ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
670 movq(kScratchRegister, c_entry_fp_address);
671 movq(Operand(kScratchRegister, 0), Immediate(0));
672}
673
674
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000675} } // namespace v8::internal