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
-~----------~----~----~----~------~----~------~--~---

Reply via email to