Author: [EMAIL PROTECTED]
Date: Tue Sep 23 01:19:26 2008
New Revision: 359
Modified:
branches/bleeding_edge/src/builtins-arm.cc
branches/bleeding_edge/src/builtins-ia32.cc
branches/bleeding_edge/src/codegen-arm.cc
branches/bleeding_edge/src/codegen-ia32.cc
branches/bleeding_edge/src/frames-ia32.h
branches/bleeding_edge/src/ic-arm.cc
branches/bleeding_edge/src/ic-ia32.cc
branches/bleeding_edge/src/macro-assembler-arm.cc
branches/bleeding_edge/src/macro-assembler-arm.h
branches/bleeding_edge/src/macro-assembler-ia32.cc
branches/bleeding_edge/src/macro-assembler-ia32.h
branches/bleeding_edge/src/stub-cache-arm.cc
branches/bleeding_edge/src/stub-cache-ia32.cc
Log:
Refactored the code for entering and leaving exit frames (calls
from JavaScript to C++). Includes a few slight optimizations
like keeping argv in a callee-saved register.
Review URL: http://codereview.chromium.org/4035
Modified: branches/bleeding_edge/src/builtins-arm.cc
==============================================================================
--- branches/bleeding_edge/src/builtins-arm.cc (original)
+++ branches/bleeding_edge/src/builtins-arm.cc Tue Sep 23 01:19:26 2008
@@ -168,7 +168,7 @@
// sp[1]: constructor function
// sp[2]: number of arguments (smi-tagged)
__ ldr(r1, MemOperand(sp, 2 * kPointerSize));
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
__ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
__ add(sp, sp, Operand(kPointerSize));
__ mov(pc, Operand(lr));
@@ -240,7 +240,7 @@
// Exit the JS frame and remove the parameters (except function), and
return.
// Respect ABI stack constraint.
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
__ mov(pc, lr);
// r0: result
@@ -337,7 +337,7 @@
__ pop(r0);
__ mov(r0, Operand(r0, ASR, kSmiTagSize));
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
__ b(&patch_receiver);
// Use the global object from the called function as the receiver.
@@ -525,7 +525,7 @@
__ InvokeFunction(r1, actual, CALL_FUNCTION);
// Tear down the internal frame and remove function, receiver and args.
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
__ add(sp, sp, Operand(3 * kPointerSize));
__ mov(pc, lr);
}
Modified: branches/bleeding_edge/src/builtins-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/builtins-ia32.cc (original)
+++ branches/bleeding_edge/src/builtins-ia32.cc Tue Sep 23 01:19:26 2008
@@ -297,7 +297,7 @@
// Restore the arguments count and exit the internal frame.
__ bind(&exit);
__ mov(ebx, Operand(esp, kPointerSize)); // get arguments count
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
// Remove caller arguments from the stack and return.
ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
@@ -363,7 +363,7 @@
// Exit the JS frame. Notice that this also removes the empty
// context and the function left on the stack by the code
// invocation.
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
__ ret(1 * kPointerSize); // remove receiver
}
@@ -450,7 +450,7 @@
__ pop(eax);
__ shr(eax, kSmiTagSize);
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
__ jmp(&patch_receiver);
// Use the global object from the called function as the receiver.
@@ -613,7 +613,7 @@
__ mov(edi, Operand(ebp, 4 * kPointerSize));
__ InvokeFunction(edi, actual, CALL_FUNCTION);
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
__ ret(3 * kPointerSize); // remove this, receiver, and arguments
}
@@ -771,7 +771,7 @@
__ PopRegistersToMemory(pointer_regs);
// Get rid of the internal frame.
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
// If this call did not replace a call but patched other code then there
will
// be an unwanted return address left on the stack. Here we get rid of
that.
Modified: branches/bleeding_edge/src/codegen-arm.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-arm.cc (original)
+++ branches/bleeding_edge/src/codegen-arm.cc Tue Sep 23 01:19:26 2008
@@ -1634,6 +1634,7 @@
// r0: result parameter for PerformGC, if any
// r4: number of arguments including receiver (C callee-saved)
// r5: pointer to builtin function (C callee-saved)
+ // r6: pointer to the first argument (C callee-saved)
if (do_gc) {
// Passing r0.
@@ -1641,11 +1642,9 @@
}
// Call C built-in.
- // r0 = argc.
+ // r0 = argc, r1 = argv
__ mov(r0, Operand(r4));
- // r1 = argv.
- __ add(r1, fp, Operand(r4, LSL, kPointerSizeLog2));
- __ add(r1, r1, Operand(ExitFrameConstants::kPPDisplacement -
kPointerSize));
+ __ mov(r1, Operand(r6));
// TODO(1242173): To let the GC traverse the return address of the exit
// frames, we need to know where the return address is. Right now,
@@ -1672,11 +1671,6 @@
__ tst(r2, Operand(kFailureTagMask));
__ b(eq, &failure_returned);
- // clear top frame
- __ mov(r3, Operand(0));
- __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
- __ str(r3, MemOperand(ip));
-
// Restore the memory copy of the registers by digging them out from
// the stack.
if (do_restore) {
@@ -1692,12 +1686,7 @@
// sp: stack pointer
// fp: frame pointer
// pp: caller's parameter pointer pp (restored as C callee-saved)
-
- // Restore current context from top and clear it in debug mode.
- __ mov(r3, Operand(Top::context_address()));
- __ ldr(cp, MemOperand(r3));
- __ mov(sp, Operand(fp)); // respect ABI stack constraint
- __ ldm(ia, sp, fp.bit() | sp.bit() | pc.bit());
+ __ LeaveExitFrame();
// check if we should retry or throw exception
Label retry;
@@ -1745,28 +1734,12 @@
// this by performing a garbage collection and retrying the
// builtin once.
- // Enter C frame
- // Compute parameter pointer before making changes and save it as ip
register
- // so that it is restored as sp register on exit, thereby popping the
args.
- // ip = sp + kPointerSize*args_len;
- __ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
-
- // push in reverse order:
- // caller_fp, sp_on_exit, caller_pc
- __ stm(db_w, sp, fp.bit() | ip.bit() | lr.bit());
- __ mov(fp, Operand(sp)); // setup new frame pointer
-
- // Store the current context in top.
- __ mov(ip, Operand(ExternalReference(Top::k_context_address)));
- __ str(cp, MemOperand(ip));
-
- // remember top frame
- __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
- __ str(fp, MemOperand(ip));
-
- // Push debug marker.
- __ mov(ip, Operand(is_debug_break ? 1 : 0));
- __ push(ip);
+ StackFrame::Type frame_type = is_debug_break
+ ? StackFrame::EXIT_DEBUG
+ : StackFrame::EXIT;
+
+ // Enter the exit frame that transitions from JavaScript to C++.
+ __ EnterExitFrame(frame_type);
if (is_debug_break) {
// Save the state of all registers to the stack from the memory
location.
@@ -1774,13 +1747,6 @@
__ CopyRegistersFromMemoryToStack(sp, kJSCallerSaved);
}
- // move number of arguments (argc) into callee-saved register
- __ mov(r4, Operand(r0));
-
- // move pointer to builtin function into callee-saved register
- __ mov(r5, Operand(r1));
-
- // r0: result parameter for PerformGC, if any (setup below)
// r4: number of arguments
// r5: pointer to builtin function (C callee-saved)
Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc Tue Sep 23 01:19:26 2008
@@ -5252,6 +5252,7 @@
// ebp: frame pointer (restored after C call)
// esp: stack pointer (restored after C call)
// edi: number of arguments including receiver (C callee-saved)
+ // esi: pointer to the first argument (C callee-saved)
if (do_gc) {
__ mov(Operand(esp, 0 * kPointerSize), eax); // Result.
@@ -5259,12 +5260,8 @@
}
// Call C function.
- __ lea(eax, Operand(ebp,
- edi,
- times_4,
- StandardFrameConstants::kCallerSPOffset -
kPointerSize));
__ mov(Operand(esp, 0 * kPointerSize), edi); // argc.
- __ mov(Operand(esp, 1 * kPointerSize), eax); // argv.
+ __ mov(Operand(esp, 1 * kPointerSize), esi); // argv.
__ call(Operand(ebx));
// Result is in eax or edx:eax - do not destroy these registers!
@@ -5276,11 +5273,6 @@
__ test(ecx, Immediate(kFailureTagMask));
__ j(zero, &failure_returned, not_taken);
- // Restore number of arguments to ecx and clear top frame.
- __ mov(ecx, Operand(edi));
- ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
- __ mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
-
// Restore the memory copy of the registers by digging them out from
// the stack.
if (do_restore) {
@@ -5289,25 +5281,11 @@
const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize;
__ lea(ebx, Operand(ebp, kOffset));
- __ CopyRegistersFromStackToMemory(ebx, edi, kJSCallerSaved);
+ __ CopyRegistersFromStackToMemory(ebx, ecx, kJSCallerSaved);
}
// Exit C frame.
- __ lea(esp, Operand(ebp, -1 * kPointerSize));
- __ pop(ebx);
- __ pop(ebp);
-
- // Restore current context from top and clear it in debug mode.
- ExternalReference context_address(Top::k_context_address);
- __ mov(esi, Operand::StaticVariable(context_address));
- if (kDebug) {
- __ mov(Operand::StaticVariable(context_address), Immediate(0));
- }
-
- // Pop arguments from caller's stack and return.
- __ pop(ebx); // Ok to clobber ebx - function pointer not needed anymore.
- __ lea(esp, Operand(esp, ecx, times_4, 0));
- __ push(ebx);
+ __ LeaveExitFrame();
__ ret(0);
// Handling of Failure.
@@ -5407,25 +5385,12 @@
// this by performing a garbage collection and retrying the
// builtin once.
- // Enter C frame.
- // Here we make the following assumptions and use them when setting
- // up the top-most Frame. Adjust the code if these assumptions
- // change.
- ASSERT(ExitFrameConstants::kPPDisplacement == +2 * kPointerSize);
- ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
- ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize);
- ASSERT(ExitFrameConstants::kSPOffset == -2 * kPointerSize);
- __ push(ebp); // caller fp
- __ mov(ebp, Operand(esp)); // C entry fp
- __ push(ebx); // C function
- __ push(Immediate(0)); // saved entry sp, set before call
- __ push(Immediate(is_debug_break ? 1 : 0));
-
- // Remember top frame.
- ExternalReference c_entry_fp(Top::k_c_entry_fp_address);
- ExternalReference context_address(Top::k_context_address);
- __ mov(Operand::StaticVariable(c_entry_fp), ebp);
- __ mov(Operand::StaticVariable(context_address), esi);
+ StackFrame::Type frame_type = is_debug_break ?
+ StackFrame::EXIT_DEBUG :
+ StackFrame::EXIT;
+
+ // Enter the exit frame that transitions from JavaScript to C++.
+ __ EnterExitFrame(frame_type);
if (is_debug_break) {
// Save the state of all registers to the stack from the memory
@@ -5439,10 +5404,6 @@
// associated with this issue).
__ PushRegistersFromMemory(kJSCallerSaved);
}
-
- // Move number of arguments (argc) into callee-saved register. Note
- // that edi is only available after remembering the top frame.
- __ mov(edi, Operand(eax));
// Allocate stack space for 2 arguments (argc, argv).
GenerateReserveCParameterSpace(masm, 2);
Modified: branches/bleeding_edge/src/frames-ia32.h
==============================================================================
--- branches/bleeding_edge/src/frames-ia32.h (original)
+++ branches/bleeding_edge/src/frames-ia32.h Tue Sep 23 01:19:26 2008
@@ -81,8 +81,8 @@
class ExitFrameConstants : public AllStatic {
public:
- static const int kDebugMarkOffset = -3 * kPointerSize;
- static const int kSPOffset = -2 * kPointerSize;
+ static const int kDebugMarkOffset = -2 * kPointerSize;
+ static const int kSPOffset = -1 * kPointerSize;
// Let the parameters pointer for exit frames point just below the
// frame structure on the stack (frame pointer and return address).
Modified: branches/bleeding_edge/src/ic-arm.cc
==============================================================================
--- branches/bleeding_edge/src/ic-arm.cc (original)
+++ branches/bleeding_edge/src/ic-arm.cc Tue Sep 23 01:19:26 2008
@@ -427,7 +427,7 @@
// Move result to r1.
__ mov(r1, Operand(r0));
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
// Patch the function on the stack; 1 ~ receiver.
__ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
Modified: branches/bleeding_edge/src/ic-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ic-ia32.cc (original)
+++ branches/bleeding_edge/src/ic-ia32.cc Tue Sep 23 01:19:26 2008
@@ -528,7 +528,7 @@
// Move result to edi and exit the internal frame.
__ mov(Operand(edi), eax);
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
// Invoke the function.
ParameterCount actual(argc);
Modified: branches/bleeding_edge/src/macro-assembler-arm.cc
==============================================================================
--- branches/bleeding_edge/src/macro-assembler-arm.cc (original)
+++ branches/bleeding_edge/src/macro-assembler-arm.cc Tue Sep 23 01:19:26
2008
@@ -264,7 +264,7 @@
}
-void MacroAssembler::ExitInternalFrame() {
+void MacroAssembler::LeaveInternalFrame() {
// r0: preserved
// r1: preserved
// r2: preserved
@@ -273,6 +273,58 @@
// frame pointer and return address.
mov(sp, fp);
ldm(ia_w, sp, fp.bit() | lr.bit());
+}
+
+
+void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
+ ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG);
+ // Compute parameter pointer before making changes and save it as ip
+ // register so that it is restored as sp register on exit, thereby
+ // popping the args.
+
+ // ip = sp + kPointerSize * #args;
+ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2));
+
+ // Push in reverse order: caller_fp, sp_on_exit, and caller_pc.
+ stm(db_w, sp, fp.bit() | ip.bit() | lr.bit());
+ mov(fp, Operand(sp)); // setup new frame pointer
+
+ // Push debug marker.
+ mov(ip, Operand(type == StackFrame::EXIT_DEBUG ? 1 : 0));
+ push(ip);
+
+ // Save the frame pointer and the context in top.
+ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
+ str(fp, MemOperand(ip));
+ mov(ip, Operand(ExternalReference(Top::k_context_address)));
+ str(cp, MemOperand(ip));
+
+ // Setup argc and the builtin function in callee-saved registers.
+ mov(r4, Operand(r0));
+ mov(r5, Operand(r1));
+
+ // Compute the argv pointer and keep it in a callee-saved register.
+ add(r6, fp, Operand(r4, LSL, kPointerSizeLog2));
+ add(r6, r6, Operand(ExitFrameConstants::kPPDisplacement - kPointerSize));
+}
+
+
+void MacroAssembler::LeaveExitFrame() {
+ // Clear top frame.
+ mov(r3, Operand(0));
+ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
+ str(r3, MemOperand(ip));
+
+ // Restore current context from top and clear it in debug mode.
+ mov(ip, Operand(ExternalReference(Top::k_context_address)));
+ ldr(cp, MemOperand(ip));
+ if (kDebug) {
+ str(r3, MemOperand(ip));
+ }
+
+ // Pop the arguments, restore registers, and return.
+ mov(sp, Operand(fp)); // respect ABI stack constraint
+ ldm(ia, sp, fp.bit() | sp.bit() | pc.bit());
}
Modified: branches/bleeding_edge/src/macro-assembler-arm.h
==============================================================================
--- branches/bleeding_edge/src/macro-assembler-arm.h (original)
+++ branches/bleeding_edge/src/macro-assembler-arm.h Tue Sep 23 01:19:26
2008
@@ -99,7 +99,16 @@
// Activation frames
void EnterInternalFrame();
- void ExitInternalFrame();
+ void LeaveInternalFrame();
+
+ // Enter specific kind of exit frame; either EXIT or
+ // EXIT_DEBUG. Expects the number of arguments in register r0 and
+ // the builtin function to call in register r1. Exits with argc in
+ // r4, argv in r6, and and the builtin function to call in r5.
+ void EnterExitFrame(StackFrame::Type type);
+
+ // Leave the current exit frame. Expects the return value in r0.
+ void LeaveExitFrame();
//
---------------------------------------------------------------------------
Modified: branches/bleeding_edge/src/macro-assembler-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/macro-assembler-ia32.cc (original)
+++ branches/bleeding_edge/src/macro-assembler-ia32.cc Tue Sep 23 01:19:26
2008
@@ -325,7 +325,7 @@
}
-void MacroAssembler::ExitInternalFrame() {
+void MacroAssembler::LeaveInternalFrame() {
if (FLAG_debug_code) {
StackFrame::Type type = StackFrame::INTERNAL;
cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
@@ -333,6 +333,58 @@
Check(equal, "stack frame types must match");
}
leave();
+}
+
+
+void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
+ ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG);
+
+ // Setup the frame structure on the stack.
+ ASSERT(ExitFrameConstants::kPPDisplacement == +2 * kPointerSize);
+ ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
+ ASSERT(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize);
+ push(ebp);
+ mov(ebp, Operand(esp));
+
+ // Reserve room for entry stack pointer and push the debug marker.
+ ASSERT(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
+ push(Immediate(0)); // saved entry sp, patched before call
+ push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0));
+
+ // Save the frame pointer and the context in top.
+ ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
+ ExternalReference context_address(Top::k_context_address);
+ mov(Operand::StaticVariable(c_entry_fp_address), ebp);
+ mov(Operand::StaticVariable(context_address), esi);
+
+ // Setup argc and argv in callee-saved registers.
+ int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
+ mov(edi, Operand(eax));
+ lea(esi, Operand(ebp, eax, times_4, offset));
+}
+
+
+void MacroAssembler::LeaveExitFrame() {
+ // Get the return address from the stack and restore the frame pointer.
+ mov(ecx, Operand(ebp, 1 * kPointerSize));
+ mov(ebp, Operand(ebp, 0 * kPointerSize));
+
+ // Pop the arguments and the receiver from the caller stack.
+ lea(esp, Operand(esi, 1 * kPointerSize));
+
+ // Restore current context from top and clear it in debug mode.
+ ExternalReference context_address(Top::k_context_address);
+ mov(esi, Operand::StaticVariable(context_address));
+ if (kDebug) {
+ mov(Operand::StaticVariable(context_address), Immediate(0));
+ }
+
+ // Push the return address to get ready to return.
+ push(ecx);
+
+ // Clear the top frame.
+ ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
+ mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
}
Modified: branches/bleeding_edge/src/macro-assembler-ia32.h
==============================================================================
--- branches/bleeding_edge/src/macro-assembler-ia32.h (original)
+++ branches/bleeding_edge/src/macro-assembler-ia32.h Tue Sep 23 01:19:26
2008
@@ -86,10 +86,19 @@
//
---------------------------------------------------------------------------
// Activation frames
- // Enter or exit a stack frame of the given type. Cannot be used to
- // construct or leave JavaScript frames.
void EnterInternalFrame();
- void ExitInternalFrame();
+ void LeaveInternalFrame();
+
+ // Enter specific kind of exit frame; either EXIT or
+ // EXIT_DEBUG. Expects the number of arguments in register eax and
+ // sets up the number of arguments in register edi and the pointer
+ // to the first argument in register esi.
+ void EnterExitFrame(StackFrame::Type type);
+
+ // Leave the current exit frame. Expects the return value in
+ // register eax:edx (untouched) and the pointer to the first
+ // argument in register esi.
+ void LeaveExitFrame();
//
---------------------------------------------------------------------------
@@ -197,6 +206,10 @@
// Jump to the builtin routine.
void JumpToBuiltin(const ExternalReference& ext);
+
+
+ //
---------------------------------------------------------------------------
+ // Utilities
void Ret();
Modified: branches/bleeding_edge/src/stub-cache-arm.cc
==============================================================================
--- branches/bleeding_edge/src/stub-cache-arm.cc (original)
+++ branches/bleeding_edge/src/stub-cache-arm.cc Tue Sep 23 01:19:26 2008
@@ -178,7 +178,7 @@
__ pop(r1);
// Tear down temporary frame.
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
// Do a tail-call of the compiled function.
__ Jump(r2);
Modified: branches/bleeding_edge/src/stub-cache-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/stub-cache-ia32.cc (original)
+++ branches/bleeding_edge/src/stub-cache-ia32.cc Tue Sep 23 01:19:26 2008
@@ -476,7 +476,7 @@
__ CallRuntime(Runtime::kLazyCompile, 1);
__ pop(edi);
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
// Do a tail-call of the compiled function.
__ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
@@ -688,7 +688,7 @@
__ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
// Exit frame.
- __ ExitInternalFrame();
+ __ LeaveInternalFrame();
// Check that the function really is a function.
__ test(edi, Immediate(kSmiTagMask));
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---