Revision: 5689
Author: [email protected]
Date: Thu Oct 21 07:21:00 2010
Log: Optimizing HandleScope. Also fixed HandleScope destruction when API getter throws an exception.
Review URL: http://codereview.chromium.org/3792003
http://code.google.com/p/v8/source/detail?r=5689

Modified:
 /branches/bleeding_edge/include/v8.h
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/api.h
 /branches/bleeding_edge/src/assembler.cc
 /branches/bleeding_edge/src/assembler.h
 /branches/bleeding_edge/src/handles-inl.h
 /branches/bleeding_edge/src/handles.cc
 /branches/bleeding_edge/src/handles.h
 /branches/bleeding_edge/src/ia32/assembler-ia32.h
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/runtime.h
 /branches/bleeding_edge/src/serialize.cc
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.h
 /branches/bleeding_edge/src/x64/stub-cache-x64.cc

=======================================
--- /branches/bleeding_edge/include/v8.h        Tue Oct  5 05:01:46 2010
+++ /branches/bleeding_edge/include/v8.h        Thu Oct 21 07:21:00 2010
@@ -467,16 +467,21 @@
   // typedef in the ImplementationUtilities class.
   class V8EXPORT Data {
    public:
-    int extensions;
     internal::Object** next;
     internal::Object** limit;
+    int level;
+
     inline void Initialize() {
-      extensions = -1;
       next = limit = NULL;
+      level = 0;
     }
   };
-
-  Data previous_;
+
+  void Leave();
+
+
+  internal::Object** prev_next_;
+  internal::Object** prev_limit_;

// Allow for the active closing of HandleScopes which allows to pass a handle
   // from the HandleScope being closed to the next top most HandleScope.
=======================================
--- /branches/bleeding_edge/src/api.cc  Tue Oct  5 04:51:41 2010
+++ /branches/bleeding_edge/src/api.cc  Thu Oct 21 07:21:00 2010
@@ -457,17 +457,35 @@
 // --- H a n d l e s ---


-HandleScope::HandleScope() : is_closed_(false) {
+HandleScope::HandleScope()
+    : prev_next_(i::HandleScope::current_.next),
+      prev_limit_(i::HandleScope::current_.limit),
+      is_closed_(false) {
   API_ENTRY_CHECK("HandleScope::HandleScope");
-  i::HandleScope::Enter(&previous_);
+  i::HandleScope::current_.level++;
 }


 HandleScope::~HandleScope() {
   if (!is_closed_) {
-    i::HandleScope::Leave(&previous_);
+    Leave();
   }
 }
+
+
+void HandleScope::Leave() {
+  i::HandleScope::current_.level--;
+  ASSERT(i::HandleScope::current_.level >= 0);
+  i::HandleScope::current_.next = prev_next_;
+  if (i::HandleScope::current_.limit != prev_limit_) {
+    i::HandleScope::current_.limit = prev_limit_;
+    i::HandleScope::DeleteExtensions();
+  }
+
+#ifdef DEBUG
+  i::HandleScope::ZapRange(prev_next_, prev_limit_);
+#endif
+}


 int HandleScope::NumberOfHandles() {
@@ -553,7 +571,7 @@
     result = *value;
   }
   is_closed_ = true;
-  i::HandleScope::Leave(&previous_);
+  Leave();

   if (value == NULL) {
     return NULL;
=======================================
--- /branches/bleeding_edge/src/api.h   Mon Oct  4 08:04:16 2010
+++ /branches/bleeding_edge/src/api.h   Thu Oct 21 07:21:00 2010
@@ -353,7 +353,7 @@


   inline internal::Object** GetSpareOrNewBlock();
-  inline void DeleteExtensions(int extensions);
+  inline void DeleteExtensions(internal::Object** prev_limit);

   inline void IncrementCallDepth() {call_depth_++;}
   inline void DecrementCallDepth() {call_depth_--;}
@@ -465,25 +465,28 @@
 }


-void HandleScopeImplementer::DeleteExtensions(int extensions) {
-  if (spare_ != NULL) {
-    DeleteArray(spare_);
-    spare_ = NULL;
-  }
-  for (int i = extensions; i > 1; --i) {
-    internal::Object** block = blocks_.RemoveLast();
+void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) {
+  while (!blocks_.is_empty()) {
+    internal::Object** block_start = blocks_.last();
+    internal::Object** block_limit = block_start + kHandleBlockSize;
 #ifdef DEBUG
-    v8::ImplementationUtilities::ZapHandleRange(block,
-                                                &block[kHandleBlockSize]);
+ // NoHandleAllocation may make the prev_limit to point inside the block.
+    if (block_start <= prev_limit && prev_limit <= block_limit) break;
+#else
+    if (prev_limit == block_limit) break;
 #endif
-    DeleteArray(block);
-  }
-  spare_ = blocks_.RemoveLast();
+
+    blocks_.RemoveLast();
 #ifdef DEBUG
-  v8::ImplementationUtilities::ZapHandleRange(
-      spare_,
-      &spare_[kHandleBlockSize]);
+    v8::ImplementationUtilities::ZapHandleRange(block_start, block_limit);
 #endif
+    if (spare_ != NULL) {
+      DeleteArray(spare_);
+    }
+    spare_ = block_start;
+  }
+  ASSERT((blocks_.is_empty() && prev_limit == NULL) ||
+         (!blocks_.is_empty() && prev_limit != NULL));
 }

 } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/assembler.cc    Thu Sep 30 00:22:53 2010
+++ /branches/bleeding_edge/src/assembler.cc    Thu Oct 21 07:21:00 2010
@@ -581,6 +581,12 @@
   return
ExternalReference(Redirect(FUNCTION_ADDR(V8::FillHeapNumberWithRandom)));
 }
+
+
+ExternalReference ExternalReference::delete_handle_scope_extensions() {
+  return ExternalReference(Redirect(FUNCTION_ADDR(
+                           HandleScope::DeleteExtensions)));
+}


 ExternalReference ExternalReference::random_uint32_function() {
@@ -653,8 +659,8 @@
 }


-ExternalReference ExternalReference::handle_scope_extensions_address() {
-  return ExternalReference(HandleScope::current_extensions_address());
+ExternalReference ExternalReference::handle_scope_level_address() {
+  return ExternalReference(HandleScope::current_level_address());
 }


=======================================
--- /branches/bleeding_edge/src/assembler.h     Fri Sep 24 01:25:31 2010
+++ /branches/bleeding_edge/src/assembler.h     Thu Oct 21 07:21:00 2010
@@ -482,6 +482,7 @@
   static ExternalReference fill_heap_number_with_random_function();
   static ExternalReference random_uint32_function();
   static ExternalReference transcendental_cache_array_address();
+  static ExternalReference delete_handle_scope_extensions();

   // Static data in the keyed lookup cache.
   static ExternalReference keyed_lookup_cache_keys();
@@ -519,9 +520,9 @@
   static ExternalReference double_fp_operation(Token::Value operation);
   static ExternalReference compare_doubles();

-  static ExternalReference handle_scope_extensions_address();
   static ExternalReference handle_scope_next_address();
   static ExternalReference handle_scope_limit_address();
+  static ExternalReference handle_scope_level_address();

   static ExternalReference scheduled_exception_address();

=======================================
--- /branches/bleeding_edge/src/handles-inl.h   Wed Aug 11 06:01:28 2010
+++ /branches/bleeding_edge/src/handles-inl.h   Thu Oct 21 07:21:00 2010
@@ -55,18 +55,22 @@
 inline NoHandleAllocation::NoHandleAllocation() {
   v8::ImplementationUtilities::HandleScopeData* current =
       v8::ImplementationUtilities::CurrentHandleScope();
-  extensions_ = current->extensions;
   // Shrink the current handle scope to make it impossible to do
   // handle allocations without an explicit handle scope.
   current->limit = current->next;
-  current->extensions = -1;
+
+  level_ = current->level;
+  current->level = 0;
 }


 inline NoHandleAllocation::~NoHandleAllocation() {
   // Restore state in current handle scope to re-enable handle
   // allocations.
- v8::ImplementationUtilities::CurrentHandleScope()->extensions = extensions_;
+  v8::ImplementationUtilities::HandleScopeData* current =
+      v8::ImplementationUtilities::CurrentHandleScope();
+  ASSERT_EQ(0, current->level);
+  current->level = level_;
 }
 #endif

=======================================
--- /branches/bleeding_edge/src/handles.cc      Wed Oct 20 06:19:03 2010
+++ /branches/bleeding_edge/src/handles.cc      Thu Oct 21 07:21:00 2010
@@ -44,7 +44,7 @@


 v8::ImplementationUtilities::HandleScopeData HandleScope::current_ =
-    { -1, NULL, NULL };
+    { NULL, NULL, 0 };


 int HandleScope::NumberOfHandles() {
@@ -61,7 +61,7 @@
   ASSERT(result == current_.limit);
   // Make sure there's at least one scope on the stack and that the
   // top of the scope stack isn't a barrier.
-  if (current_.extensions < 0) {
+  if (current_.level == 0) {
     Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
"Cannot create a handle without a HandleScope");
     return NULL;
@@ -73,6 +73,7 @@
     Object** limit = &impl->blocks()->last()[kHandleBlockSize];
     if (current_.limit != limit) {
       current_.limit = limit;
+      ASSERT(limit - current_.next < kHandleBlockSize);
     }
   }

@@ -84,7 +85,6 @@
     // Add the extension to the global list of blocks, but count the
     // extension as part of the current scope.
     impl->blocks()->Add(result);
-    current_.extensions++;
     current_.limit = &result[kHandleBlockSize];
   }

@@ -93,21 +93,20 @@


 void HandleScope::DeleteExtensions() {
-  ASSERT(current_.extensions != 0);
- HandleScopeImplementer::instance()->DeleteExtensions(current_.extensions);
+  HandleScopeImplementer::instance()->DeleteExtensions(current_.limit);
 }


 void HandleScope::ZapRange(Object** start, Object** end) {
-  if (start == NULL) return;
-  for (Object** p = start; p < end; p++) {
+  ASSERT(end - start <= kHandleBlockSize);
+  for (Object** p = start; p != end; p++) {
     *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue;
   }
 }


-Address HandleScope::current_extensions_address() {
-  return reinterpret_cast<Address>(&current_.extensions);
+Address HandleScope::current_level_address() {
+  return reinterpret_cast<Address>(&current_.level);
 }


=======================================
--- /branches/bleeding_edge/src/handles.h       Wed Oct 20 06:19:03 2010
+++ /branches/bleeding_edge/src/handles.h       Thu Oct 21 07:21:00 2010
@@ -107,12 +107,20 @@
 // for which the handle scope has been deleted is undefined.
 class HandleScope {
  public:
-  HandleScope() : previous_(current_) {
-    current_.extensions = 0;
+  HandleScope() : prev_next_(current_.next), prev_limit_(current_.limit) {
+    current_.level++;
   }

   ~HandleScope() {
-    Leave(&previous_);
+    current_.next = prev_next_;
+    current_.level--;
+    if (current_.limit != prev_limit_) {
+      current_.limit = prev_limit_;
+      DeleteExtensions();
+    }
+#ifdef DEBUG
+    ZapRange(prev_next_, prev_limit_);
+#endif
   }

   // Counts the number of allocated handles.
@@ -136,9 +144,9 @@
   // Deallocates any extensions used by the current scope.
   static void DeleteExtensions();

-  static Address current_extensions_address();
   static Address current_next_address();
   static Address current_limit_address();
+  static Address current_level_address();

  private:
   // Prevent heap allocation or illegal handle scopes.
@@ -148,27 +156,8 @@
   void operator delete(void* size_t);

   static v8::ImplementationUtilities::HandleScopeData current_;
-  const v8::ImplementationUtilities::HandleScopeData previous_;
-
-  // Pushes a fresh handle scope to be used when allocating new handles.
-  static void Enter(
-      v8::ImplementationUtilities::HandleScopeData* previous) {
-    *previous = current_;
-    current_.extensions = 0;
-  }
-
-  // Re-establishes the previous scope state. Should be called only
-  // once, and only for the current scope.
-  static void Leave(
-      const v8::ImplementationUtilities::HandleScopeData* previous) {
-    if (current_.extensions > 0) {
-      DeleteExtensions();
-    }
-    current_ = *previous;
-#ifdef DEBUG
-    ZapRange(current_.next, current_.limit);
-#endif
-  }
+  Object** const prev_next_;
+  Object** const prev_limit_;

   // Extend the handle scope making room for more handles.
   static internal::Object** Extend();
@@ -362,7 +351,7 @@
   inline NoHandleAllocation();
   inline ~NoHandleAllocation();
  private:
-  int extensions_;
+  int level_;
 #endif
 };

=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.h Tue Sep 28 07:56:36 2010 +++ /branches/bleeding_edge/src/ia32/assembler-ia32.h Thu Oct 21 07:21:00 2010
@@ -695,7 +695,6 @@
   void call(Label* L);
   void call(byte* entry, RelocInfo::Mode rmode);
   void call(const Operand& adr);
-  void call(const ExternalReference& target);
   void call(Handle<Code> code, RelocInfo::Mode rmode);

   // Jumps
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Tue Oct 19 04:14:03 2010 +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Thu Oct 21 07:21:00 2010
@@ -3056,76 +3056,14 @@
   STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize);
   __ ret(0);
 }
-
-
-// If true, a Handle<T> passed by value is passed and returned by
-// using the location_ field directly.  If false, it is passed and
-// returned as a pointer to a handle.
-#ifdef USING_BSD_ABI
-static const bool kPassHandlesDirectly = true;
-#else
-static const bool kPassHandlesDirectly = false;
-#endif


 void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
-  Label empty_handle;
-  Label prologue;
-  Label promote_scheduled_exception;
-  __ EnterApiExitFrame(kStackSpace, kArgc);
-  STATIC_ASSERT(kArgc == 4);
-  if (kPassHandlesDirectly) {
-    // When handles as passed directly we don't have to allocate extra
-    // space for and pass an out parameter.
-    __ mov(Operand(esp, 0 * kPointerSize), ebx);  // name.
-    __ mov(Operand(esp, 1 * kPointerSize), eax);  // arguments pointer.
-  } else {
-    // The function expects three arguments to be passed but we allocate
- // four to get space for the output cell. The argument slots are filled
-    // as follows:
-    //
-    //   3: output cell
-    //   2: arguments pointer
-    //   1: name
-    //   0: pointer to the output cell
-    //
-    // Note that this is one more "argument" than the function expects
-    // so the out cell will have to be popped explicitly after returning
-    // from the function.
-    __ mov(Operand(esp, 1 * kPointerSize), ebx);  // name.
-    __ mov(Operand(esp, 2 * kPointerSize), eax);  // arguments pointer.
-    __ mov(ebx, esp);
-    __ add(Operand(ebx), Immediate(3 * kPointerSize));
-    __ mov(Operand(esp, 0 * kPointerSize), ebx);  // output
-    __ mov(Operand(esp, 3 * kPointerSize), Immediate(0));  // out cell.
-  }
-  // Call the api function!
-  __ call(fun()->address(), RelocInfo::RUNTIME_ENTRY);
-  // Check if the function scheduled an exception.
-  ExternalReference scheduled_exception_address =
-      ExternalReference::scheduled_exception_address();
-  __ cmp(Operand::StaticVariable(scheduled_exception_address),
-         Immediate(Factory::the_hole_value()));
-  __ j(not_equal, &promote_scheduled_exception, not_taken);
-  if (!kPassHandlesDirectly) {
-    // The returned value is a pointer to the handle holding the result.
-    // Dereference this to get to the location.
-    __ mov(eax, Operand(eax, 0));
-  }
-  // Check if the result handle holds 0.
-  __ test(eax, Operand(eax));
-  __ j(zero, &empty_handle, not_taken);
-  // It was non-zero.  Dereference to get the result value.
-  __ mov(eax, Operand(eax, 0));
-  __ bind(&prologue);
-  __ LeaveExitFrame();
-  __ ret(0);
-  __ bind(&promote_scheduled_exception);
-  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
-  __ bind(&empty_handle);
-  // It was zero; the result is undefined.
-  __ mov(eax, Factory::undefined_value());
-  __ jmp(&prologue);
+  __ PrepareCallApiFunction(kStackSpace, kArgc);
+  STATIC_ASSERT(kArgc == 2);
+  __ mov(ApiParameterOperand(0), ebx);  // name.
+  __ mov(ApiParameterOperand(1), eax);  // arguments pointer.
+  __ CallApiFunctionAndReturn(fun(), kArgc);
 }


=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Thu Oct 21 06:15:12 2010 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Thu Oct 21 07:21:00 2010
@@ -1115,66 +1115,116 @@
 }


-void MacroAssembler::PushHandleScope(Register scratch) {
-  // Push the number of extensions, smi-tagged so the gc will ignore it.
-  ExternalReference extensions_address =
-      ExternalReference::handle_scope_extensions_address();
-  mov(scratch, Operand::StaticVariable(extensions_address));
-  SmiTag(scratch);
-  push(scratch);
-  mov(Operand::StaticVariable(extensions_address), Immediate(0));
-  // Push next and limit pointers which will be wordsize aligned and
-  // hence automatically smi tagged.
-  ExternalReference next_address =
-      ExternalReference::handle_scope_next_address();
-  push(Operand::StaticVariable(next_address));
-  ExternalReference limit_address =
-      ExternalReference::handle_scope_limit_address();
-  push(Operand::StaticVariable(limit_address));
+// If true, a Handle<T> passed by value is passed and returned by
+// using the location_ field directly.  If false, it is passed and
+// returned as a pointer to a handle.
+#ifdef USING_BSD_ABI
+static const bool kPassHandlesDirectly = true;
+#else
+static const bool kPassHandlesDirectly = false;
+#endif
+
+
+Operand ApiParameterOperand(int index) {
+ return Operand(esp, (index + (kPassHandlesDirectly ? 0 : 1)) * kPointerSize);
 }


-Object* MacroAssembler::PopHandleScopeHelper(Register saved,
-                                             Register scratch,
-                                             bool gc_allowed) {
-  Object* result = NULL;
-  ExternalReference extensions_address =
-        ExternalReference::handle_scope_extensions_address();
-  Label write_back;
-  mov(scratch, Operand::StaticVariable(extensions_address));
-  cmp(Operand(scratch), Immediate(0));
-  j(equal, &write_back);
-  push(saved);
-  if (gc_allowed) {
-    CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
+void MacroAssembler::PrepareCallApiFunction(int stack_space, int argc) {
+  if (kPassHandlesDirectly) {
+    EnterApiExitFrame(stack_space, argc);
+    // When handles as passed directly we don't have to allocate extra
+    // space for and pass an out parameter.
   } else {
-    result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
-    if (result->IsFailure()) return result;
-  }
-  pop(saved);
-
-  bind(&write_back);
-  ExternalReference limit_address =
-        ExternalReference::handle_scope_limit_address();
-  pop(Operand::StaticVariable(limit_address));
+    // We allocate two additional slots: return value and pointer to it.
+    EnterApiExitFrame(stack_space, argc + 2);
+  }
+}
+
+
+void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) {
+  if (!kPassHandlesDirectly) {
+    // The argument slots are filled as follows:
+    //
+    //   n + 1: output cell
+    //   n: arg n
+    //   ...
+    //   1: arg1
+    //   0: pointer to the output cell
+    //
+    // Note that this is one more "argument" than the function expects
+    // so the out cell will have to be popped explicitly after returning
+    // from the function. The out cell contains Handle.
+ lea(eax, Operand(esp, (argc + 1) * kPointerSize)); // pointer to out cell.
+    mov(Operand(esp, 0 * kPointerSize), eax);  // output.
+ mov(Operand(esp, (argc + 1) * kPointerSize), Immediate(0)); // out cell.
+  }
+
   ExternalReference next_address =
-        ExternalReference::handle_scope_next_address();
-  pop(Operand::StaticVariable(next_address));
-  pop(scratch);
-  SmiUntag(scratch);
-  mov(Operand::StaticVariable(extensions_address), scratch);
-
-  return result;
-}
-
-
-void MacroAssembler::PopHandleScope(Register saved, Register scratch) {
-  PopHandleScopeHelper(saved, scratch, true);
-}
-
-
-Object* MacroAssembler::TryPopHandleScope(Register saved, Register scratch) {
-  return PopHandleScopeHelper(saved, scratch, false);
+      ExternalReference::handle_scope_next_address();
+  ExternalReference limit_address =
+      ExternalReference::handle_scope_limit_address();
+  ExternalReference level_address =
+      ExternalReference::handle_scope_level_address();
+
+  // Allocate HandleScope in callee-save registers.
+  mov(ebx, Operand::StaticVariable(next_address));
+  mov(edi, Operand::StaticVariable(limit_address));
+  add(Operand::StaticVariable(level_address), Immediate(1));
+
+  // Call the api function!
+  call(function->address(), RelocInfo::RUNTIME_ENTRY);
+
+  if (!kPassHandlesDirectly) {
+    // The returned value is a pointer to the handle holding the result.
+    // Dereference this to get to the location.
+    mov(eax, Operand(eax, 0));
+  }
+
+  Label empty_handle;
+  Label prologue;
+  Label promote_scheduled_exception;
+  Label delete_allocated_handles;
+  Label leave_exit_frame;
+
+  // Check if the result handle holds 0.
+  test(eax, Operand(eax));
+  j(zero, &empty_handle, not_taken);
+  // It was non-zero.  Dereference to get the result value.
+  mov(eax, Operand(eax, 0));
+  bind(&prologue);
+  // No more valid handles (the result handle was the last one). Restore
+  // previous handle scope.
+  mov(Operand::StaticVariable(next_address), ebx);
+  sub(Operand::StaticVariable(level_address), Immediate(1));
+  Assert(above_equal, "Invalid HandleScope level");
+  cmp(edi, Operand::StaticVariable(limit_address));
+  j(not_equal, &delete_allocated_handles, not_taken);
+  bind(&leave_exit_frame);
+
+  // Check if the function scheduled an exception.
+  ExternalReference scheduled_exception_address =
+      ExternalReference::scheduled_exception_address();
+  cmp(Operand::StaticVariable(scheduled_exception_address),
+         Immediate(Factory::the_hole_value()));
+  j(not_equal, &promote_scheduled_exception, not_taken);
+  LeaveExitFrame();
+  ret(0);
+  bind(&promote_scheduled_exception);
+  TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
+  bind(&empty_handle);
+  // It was zero; the result is undefined.
+  mov(eax, Factory::undefined_value());
+  jmp(&prologue);
+
+  // HandleScope limit has changed. Delete allocated extensions.
+  bind(&delete_allocated_handles);
+  mov(Operand::StaticVariable(limit_address), edi);
+  mov(edi, eax);
+  mov(eax, Immediate(ExternalReference::delete_handle_scope_extensions()));
+  call(Operand(eax));
+  mov(eax, edi);
+  jmp(&leave_exit_frame);
 }


=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Thu Sep 23 02:22:45 2010 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Thu Oct 21 07:21:00 2010
@@ -480,15 +480,16 @@
   void CallCFunction(ExternalReference function, int num_arguments);
   void CallCFunction(Register function, int num_arguments);

-  void PushHandleScope(Register scratch);
-
-  // Pops a handle scope using the specified scratch register and
-  // ensuring that saved register is left unchanged.
-  void PopHandleScope(Register saved, Register scratch);
-
-  // As PopHandleScope, but does not perform a GC.  Instead, returns a
-  // retry after GC failure object if GC is necessary.
-  Object* TryPopHandleScope(Register saved, Register scratch);
+  // Prepares stack to put arguments (aligns and so on). Reserves
+ // space for return value if needed (assumes the return value is a handle). + // Uses callee-saved esi to restore stack state after call. Arguments must be
+  // stored in ApiParameterOperand(0), ApiParameterOperand(1) etc.
+  void PrepareCallApiFunction(int stack_space, int argc);
+
+  // Tail call an API function (jump). Allocates HandleScope, extracts
+  // returned value from handle and propagates exceptions.
+  // Clobbers ebx, esi, edi and caller-save registers.
+  void CallApiFunctionAndReturn(ApiFunction* function, int argc);

   // Jump to a runtime routine.
   void JumpToExternalReference(const ExternalReference& ext);
@@ -638,6 +639,9 @@
                                    int offset) {
   return Operand(object, index, scale, offset - kHeapObjectTag);
 }
+
+// Generates an Operand for saving parameters after PrepareCallApiFunction.
+Operand ApiParameterOperand(int index);


 #ifdef GENERATED_CODE_COVERAGE
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Oct 21 06:15:12 2010 +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Oct 21 07:21:00 2010
@@ -1035,7 +1035,6 @@
   Handle<AccessorInfo> callback_handle(callback);

   __ EnterInternalFrame();
-  __ PushHandleScope(scratch2);
   // Push the stack address where the list of arguments ends.
   __ mov(scratch2, esp);
   __ sub(Operand(scratch2), Immediate(2 * kPointerSize));
@@ -1070,17 +1069,6 @@
     *failure = Failure::cast(result);
     return false;
   }
-
-  // We need to avoid using eax since that now holds the result.
-  Register tmp = scratch2.is(eax) ? reg : scratch2;
-  // Emitting PopHandleScope may try to allocate.  Do not allow the
-  // assembler to perform a garbage collection but instead return a
-  // failure object.
-  result = masm()->TryPopHandleScope(eax, tmp);
-  if (result->IsFailure()) {
-    *failure = Failure::cast(result);
-    return false;
-  }
   __ LeaveInternalFrame();

   __ ret(0);
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Wed Oct 20 06:19:03 2010
+++ /branches/bleeding_edge/src/runtime.cc      Thu Oct 21 07:21:00 2010
@@ -9949,13 +9949,6 @@
   UNREACHABLE();
   return NULL;
 }
-
-
-static Object* Runtime_DeleteHandleScopeExtensions(Arguments args) {
-  ASSERT(args.length() == 0);
-  HandleScope::DeleteExtensions();
-  return Heap::undefined_value();
-}


static Object* CacheMiss(FixedArray* cache_obj, int index, Object* key_obj) {
=======================================
--- /branches/bleeding_edge/src/runtime.h       Tue Oct 19 04:14:03 2010
+++ /branches/bleeding_edge/src/runtime.h       Thu Oct 21 07:21:00 2010
@@ -297,8 +297,6 @@
   F(Log, 2, 1) \
   /* ES5 */ \
   F(LocalKeys, 1, 1) \
-  /* Handle scopes */ \
-  F(DeleteHandleScopeExtensions, 0, 1) \
   /* Cache suport */ \
   F(GetFromCache, 2, 1) \
   \
=======================================
--- /branches/bleeding_edge/src/serialize.cc    Mon Oct 18 07:59:03 2010
+++ /branches/bleeding_edge/src/serialize.cc    Thu Oct 21 07:21:00 2010
@@ -337,6 +337,11 @@
       3,
       "V8::Random");

+  Add(ExternalReference::delete_handle_scope_extensions().address(),
+      RUNTIME_ENTRY,
+      3,
+      "HandleScope::DeleteExtensions");
+
   // Miscellaneous
   Add(ExternalReference::the_hole_value_location().address(),
       UNCLASSIFIED,
@@ -457,6 +462,18 @@
       UNCLASSIFIED,
       29,
       "TranscendentalCache::caches()");
+  Add(ExternalReference::handle_scope_next_address().address(),
+      UNCLASSIFIED,
+      30,
+      "HandleScope::next");
+  Add(ExternalReference::handle_scope_limit_address().address(),
+      UNCLASSIFIED,
+      31,
+      "HandleScope::limit");
+  Add(ExternalReference::handle_scope_level_address().address(),
+      UNCLASSIFIED,
+      32,
+      "HandleScope::level");
 }


=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Tue Oct 19 04:14:03 2010 +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Thu Oct 21 07:21:00 2010
@@ -2484,11 +2484,7 @@


 void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
-  Label empty_result;
-  Label prologue;
-  Label promote_scheduled_exception;
-  __ EnterApiExitFrame(kStackSpace, 0);
-  ASSERT_EQ(kArgc, 4);
+  __ PrepareCallApiFunction(kStackSpace);
 #ifdef _WIN64
   // All the parameters should be set up by a caller.
 #else
@@ -2497,35 +2493,7 @@
// Second parameter register rdi should be set with pointer to AccessorInfo
   // by a caller.
 #endif
-  // Call the api function!
-  __ movq(rax,
-          reinterpret_cast<int64_t>(fun()->address()),
-          RelocInfo::RUNTIME_ENTRY);
-  __ call(rax);
-  // Check if the function scheduled an exception.
-  ExternalReference scheduled_exception_address =
-      ExternalReference::scheduled_exception_address();
-  __ movq(rsi, scheduled_exception_address);
-  __ Cmp(Operand(rsi, 0), Factory::the_hole_value());
-  __ j(not_equal, &promote_scheduled_exception);
-#ifdef _WIN64
-  // rax keeps a pointer to v8::Handle, unpack it.
-  __ movq(rax, Operand(rax, 0));
-#endif
-  // Check if the result handle holds 0.
-  __ testq(rax, rax);
-  __ j(zero, &empty_result);
-  // It was non-zero.  Dereference to get the result value.
-  __ movq(rax, Operand(rax, 0));
-  __ bind(&prologue);
-  __ LeaveExitFrame();
-  __ ret(0);
-  __ bind(&promote_scheduled_exception);
-  __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
-  __ bind(&empty_result);
-  // It was zero; the result is undefined.
-  __ Move(rax, Factory::undefined_value());
-  __ jmp(&prologue);
+  __ CallApiFunctionAndReturn(fun());
 }


=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Thu Oct 21 06:15:12 2010 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Thu Oct 21 07:21:00 2010
@@ -469,76 +469,89 @@
 }


-void MacroAssembler::PushHandleScope(Register scratch) {
-  ExternalReference extensions_address =
-      ExternalReference::handle_scope_extensions_address();
-  const int kExtensionsOffset = 0;
-  const int kNextOffset = Offset(
-      ExternalReference::handle_scope_next_address(),
-      extensions_address);
-  const int kLimitOffset = Offset(
-      ExternalReference::handle_scope_limit_address(),
-      extensions_address);
-
-  // Push the number of extensions, smi-tagged so the gc will ignore it.
-  movq(kScratchRegister, extensions_address);
-  movq(scratch, Operand(kScratchRegister, kExtensionsOffset));
-  movq(Operand(kScratchRegister, kExtensionsOffset), Immediate(0));
-  Integer32ToSmi(scratch, scratch);
-  push(scratch);
-  // Push next and limit pointers which will be wordsize aligned and
-  // hence automatically smi tagged.
-  push(Operand(kScratchRegister, kNextOffset));
-  push(Operand(kScratchRegister, kLimitOffset));
+void MacroAssembler::PrepareCallApiFunction(int stack_space) {
+  EnterApiExitFrame(stack_space, 0);
 }


-Object* MacroAssembler::PopHandleScopeHelper(Register saved,
-                                             Register scratch,
-                                             bool gc_allowed) {
-  ExternalReference extensions_address =
-      ExternalReference::handle_scope_extensions_address();
-  const int kExtensionsOffset = 0;
-  const int kNextOffset = Offset(
-      ExternalReference::handle_scope_next_address(),
-      extensions_address);
+void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function) {
+  Label empty_result;
+  Label prologue;
+  Label promote_scheduled_exception;
+  Label delete_allocated_handles;
+  Label leave_exit_frame;
+  Label write_back;
+
+  ExternalReference next_address =
+      ExternalReference::handle_scope_next_address();
+  const int kNextOffset = 0;
   const int kLimitOffset = Offset(
       ExternalReference::handle_scope_limit_address(),
-      extensions_address);
-
-  Object* result = NULL;
-  Label write_back;
-  movq(kScratchRegister, extensions_address);
-  cmpq(Operand(kScratchRegister, kExtensionsOffset), Immediate(0));
-  j(equal, &write_back);
-  push(saved);
-  if (gc_allowed) {
-    CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
-  } else {
-    result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
-    if (result->IsFailure()) return result;
-  }
-  pop(saved);
-  movq(kScratchRegister, extensions_address);
-
-  bind(&write_back);
-  pop(Operand(kScratchRegister, kLimitOffset));
-  pop(Operand(kScratchRegister, kNextOffset));
-  pop(scratch);
-  SmiToInteger32(scratch, scratch);
-  movq(Operand(kScratchRegister, kExtensionsOffset), scratch);
-
-  return result;
-}
-
-
-void MacroAssembler::PopHandleScope(Register saved, Register scratch) {
-  PopHandleScopeHelper(saved, scratch, true);
-}
-
-
-Object* MacroAssembler::TryPopHandleScope(Register saved, Register scratch) {
-  return PopHandleScopeHelper(saved, scratch, false);
+      next_address);
+  const int kLevelOffset = Offset(
+      ExternalReference::handle_scope_level_address(),
+      next_address);
+  ExternalReference scheduled_exception_address =
+      ExternalReference::scheduled_exception_address();
+
+  // Allocate HandleScope in callee-save registers.
+  Register prev_next_address_reg = r14;
+  Register prev_limit_reg = rbx;
+  Register base_reg = kSmiConstantRegister;
+  movq(base_reg, next_address);
+  movq(prev_next_address_reg, Operand(base_reg, kNextOffset));
+  movq(prev_limit_reg, Operand(base_reg, kLimitOffset));
+  addl(Operand(base_reg, kLevelOffset), Immediate(1));
+  // Call the api function!
+  movq(rax,
+       reinterpret_cast<int64_t>(function->address()),
+       RelocInfo::RUNTIME_ENTRY);
+  call(rax);
+
+#ifdef _WIN64
+  // rax keeps a pointer to v8::Handle, unpack it.
+  movq(rax, Operand(rax, 0));
+#endif
+  // Check if the result handle holds 0.
+  testq(rax, rax);
+  j(zero, &empty_result);
+  // It was non-zero.  Dereference to get the result value.
+  movq(rax, Operand(rax, 0));
+  bind(&prologue);
+
+  // No more valid handles (the result handle was the last one). Restore
+  // previous handle scope.
+  subl(Operand(base_reg, kLevelOffset), Immediate(1));
+  movq(Operand(base_reg, kNextOffset), prev_next_address_reg);
+  cmpq(prev_limit_reg, Operand(base_reg, kLimitOffset));
+  j(not_equal, &delete_allocated_handles);
+  bind(&leave_exit_frame);
+  InitializeSmiConstantRegister();
+
+  // Check if the function scheduled an exception.
+  movq(rsi, scheduled_exception_address);
+  Cmp(Operand(rsi, 0), Factory::the_hole_value());
+  j(not_equal, &promote_scheduled_exception);
+
+  LeaveExitFrame();
+  ret(0);
+
+  bind(&promote_scheduled_exception);
+  TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
+
+  bind(&empty_result);
+  // It was zero; the result is undefined.
+  Move(rax, Factory::undefined_value());
+  jmp(&prologue);
+
+  // HandleScope limit has changed. Delete allocated extensions.
+  bind(&delete_allocated_handles);
+  movq(Operand(base_reg, kLimitOffset), prev_limit_reg);
+  movq(prev_limit_reg, rax);
+  movq(rax, ExternalReference::delete_handle_scope_extensions());
+  call(rax);
+  movq(rax, prev_limit_reg);
+  jmp(&leave_exit_frame);
 }


=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Wed Oct 20 01:52:46 2010 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Thu Oct 21 07:21:00 2010
@@ -816,19 +816,18 @@
                        int num_arguments,
                        int result_size);

-  void PushHandleScope(Register scratch);
-
-  // Pops a handle scope using the specified scratch register and
-  // ensuring that saved register is left unchanged.
-  void PopHandleScope(Register saved, Register scratch);
-
-  // As PopHandleScope, but does not perform a GC.  Instead, returns a
-  // retry after GC failure object if GC is necessary.
-  Object* TryPopHandleScope(Register saved, Register scratch);
-
   // Jump to a runtime routine.
void JumpToExternalReference(const ExternalReference& ext, int result_size);

+  // Prepares stack to put arguments (aligns and so on).
+  // Uses calle-saved esi to restore stack state after call.
+  void PrepareCallApiFunction(int stack_space);
+
+  // Tail call an API function (jump). Allocates HandleScope, extracts
+  // returned value from handle and propogates exceptions.
+  // Clobbers ebx, edi and caller-save registers.
+  void CallApiFunctionAndReturn(ApiFunction* function);
+
// Before calling a C-function from generated code, align arguments on stack.
   // After aligning the frame, arguments must be stored in esp[0], esp[4],
// etc., not pushed. The argument count assumes all arguments are word sized.
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Thu Oct 21 06:15:12 2010 +++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Thu Oct 21 07:21:00 2010
@@ -2547,7 +2547,6 @@
   Handle<AccessorInfo> callback_handle(callback);

   __ EnterInternalFrame();
-  __ PushHandleScope(scratch2);
   // Push the stack address where the list of arguments ends.
   __ movq(scratch2, rsp);
   __ subq(scratch2, Immediate(2 * kPointerSize));
@@ -2601,17 +2600,6 @@
   // Discard allocated slot.
   __ addq(rsp, Immediate(kPointerSize));
 #endif
-
-  // We need to avoid using rax since that now holds the result.
-  Register tmp = scratch2.is(rax) ? reg : scratch2;
-  // Emitting PopHandleScope may try to allocate.  Do not allow the
-  // assembler to perform a garbage collection but instead return a
-  // failure object.
-  result = masm()->TryPopHandleScope(rax, tmp);
-  if (result->IsFailure()) {
-    *failure = Failure::cast(result);
-    return false;
-  }
   __ LeaveInternalFrame();

   __ ret(0);

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to