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>(¤t_.extensions);
+Address HandleScope::current_level_address() {
+ return reinterpret_cast<Address>(¤t_.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