Commit 0ea6c1e0 authored by serya@chromium.org's avatar serya@chromium.org

Optimizing HandleScope. Also fixed HandleScope destruction when API getter throws an exception.

Review URL: http://codereview.chromium.org/3792003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5689 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 15892383
...@@ -467,16 +467,21 @@ class V8EXPORT HandleScope { ...@@ -467,16 +467,21 @@ class V8EXPORT HandleScope {
// typedef in the ImplementationUtilities class. // typedef in the ImplementationUtilities class.
class V8EXPORT Data { class V8EXPORT Data {
public: public:
int extensions;
internal::Object** next; internal::Object** next;
internal::Object** limit; internal::Object** limit;
int level;
inline void Initialize() { inline void Initialize() {
extensions = -1;
next = limit = NULL; next = limit = NULL;
level = 0;
} }
}; };
void Leave();
Data previous_;
internal::Object** prev_next_;
internal::Object** prev_limit_;
// Allow for the active closing of HandleScopes which allows to pass a handle // Allow for the active closing of HandleScopes which allows to pass a handle
// from the HandleScope being closed to the next top most HandleScope. // from the HandleScope being closed to the next top most HandleScope.
......
...@@ -457,19 +457,37 @@ void V8::DisposeGlobal(i::Object** obj) { ...@@ -457,19 +457,37 @@ void V8::DisposeGlobal(i::Object** obj) {
// --- H a n d l e s --- // --- 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"); API_ENTRY_CHECK("HandleScope::HandleScope");
i::HandleScope::Enter(&previous_); i::HandleScope::current_.level++;
} }
HandleScope::~HandleScope() { HandleScope::~HandleScope() {
if (!is_closed_) { 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() { int HandleScope::NumberOfHandles() {
return i::HandleScope::NumberOfHandles(); return i::HandleScope::NumberOfHandles();
} }
...@@ -553,7 +571,7 @@ i::Object** v8::HandleScope::RawClose(i::Object** value) { ...@@ -553,7 +571,7 @@ i::Object** v8::HandleScope::RawClose(i::Object** value) {
result = *value; result = *value;
} }
is_closed_ = true; is_closed_ = true;
i::HandleScope::Leave(&previous_); Leave();
if (value == NULL) { if (value == NULL) {
return NULL; return NULL;
......
...@@ -353,7 +353,7 @@ class HandleScopeImplementer { ...@@ -353,7 +353,7 @@ class HandleScopeImplementer {
inline internal::Object** GetSpareOrNewBlock(); inline internal::Object** GetSpareOrNewBlock();
inline void DeleteExtensions(int extensions); inline void DeleteExtensions(internal::Object** prev_limit);
inline void IncrementCallDepth() {call_depth_++;} inline void IncrementCallDepth() {call_depth_++;}
inline void DecrementCallDepth() {call_depth_--;} inline void DecrementCallDepth() {call_depth_--;}
...@@ -465,25 +465,28 @@ internal::Object** HandleScopeImplementer::GetSpareOrNewBlock() { ...@@ -465,25 +465,28 @@ internal::Object** HandleScopeImplementer::GetSpareOrNewBlock() {
} }
void HandleScopeImplementer::DeleteExtensions(int extensions) { void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) {
if (spare_ != NULL) { while (!blocks_.is_empty()) {
DeleteArray(spare_); internal::Object** block_start = blocks_.last();
spare_ = NULL; internal::Object** block_limit = block_start + kHandleBlockSize;
}
for (int i = extensions; i > 1; --i) {
internal::Object** block = blocks_.RemoveLast();
#ifdef DEBUG #ifdef DEBUG
v8::ImplementationUtilities::ZapHandleRange(block, // NoHandleAllocation may make the prev_limit to point inside the block.
&block[kHandleBlockSize]); if (block_start <= prev_limit && prev_limit <= block_limit) break;
#else
if (prev_limit == block_limit) break;
#endif #endif
DeleteArray(block);
} blocks_.RemoveLast();
spare_ = blocks_.RemoveLast();
#ifdef DEBUG #ifdef DEBUG
v8::ImplementationUtilities::ZapHandleRange( v8::ImplementationUtilities::ZapHandleRange(block_start, block_limit);
spare_,
&spare_[kHandleBlockSize]);
#endif #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 } } // namespace v8::internal
......
...@@ -583,6 +583,12 @@ ExternalReference ExternalReference::fill_heap_number_with_random_function() { ...@@ -583,6 +583,12 @@ ExternalReference ExternalReference::fill_heap_number_with_random_function() {
} }
ExternalReference ExternalReference::delete_handle_scope_extensions() {
return ExternalReference(Redirect(FUNCTION_ADDR(
HandleScope::DeleteExtensions)));
}
ExternalReference ExternalReference::random_uint32_function() { ExternalReference ExternalReference::random_uint32_function() {
return ExternalReference(Redirect(FUNCTION_ADDR(V8::Random))); return ExternalReference(Redirect(FUNCTION_ADDR(V8::Random)));
} }
...@@ -653,8 +659,8 @@ ExternalReference ExternalReference::new_space_allocation_limit_address() { ...@@ -653,8 +659,8 @@ ExternalReference ExternalReference::new_space_allocation_limit_address() {
} }
ExternalReference ExternalReference::handle_scope_extensions_address() { ExternalReference ExternalReference::handle_scope_level_address() {
return ExternalReference(HandleScope::current_extensions_address()); return ExternalReference(HandleScope::current_level_address());
} }
......
...@@ -482,6 +482,7 @@ class ExternalReference BASE_EMBEDDED { ...@@ -482,6 +482,7 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference fill_heap_number_with_random_function(); static ExternalReference fill_heap_number_with_random_function();
static ExternalReference random_uint32_function(); static ExternalReference random_uint32_function();
static ExternalReference transcendental_cache_array_address(); static ExternalReference transcendental_cache_array_address();
static ExternalReference delete_handle_scope_extensions();
// Static data in the keyed lookup cache. // Static data in the keyed lookup cache.
static ExternalReference keyed_lookup_cache_keys(); static ExternalReference keyed_lookup_cache_keys();
...@@ -519,9 +520,9 @@ class ExternalReference BASE_EMBEDDED { ...@@ -519,9 +520,9 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference double_fp_operation(Token::Value operation); static ExternalReference double_fp_operation(Token::Value operation);
static ExternalReference compare_doubles(); static ExternalReference compare_doubles();
static ExternalReference handle_scope_extensions_address();
static ExternalReference handle_scope_next_address(); static ExternalReference handle_scope_next_address();
static ExternalReference handle_scope_limit_address(); static ExternalReference handle_scope_limit_address();
static ExternalReference handle_scope_level_address();
static ExternalReference scheduled_exception_address(); static ExternalReference scheduled_exception_address();
......
...@@ -55,18 +55,22 @@ inline T* Handle<T>::operator*() const { ...@@ -55,18 +55,22 @@ inline T* Handle<T>::operator*() const {
inline NoHandleAllocation::NoHandleAllocation() { inline NoHandleAllocation::NoHandleAllocation() {
v8::ImplementationUtilities::HandleScopeData* current = v8::ImplementationUtilities::HandleScopeData* current =
v8::ImplementationUtilities::CurrentHandleScope(); v8::ImplementationUtilities::CurrentHandleScope();
extensions_ = current->extensions;
// Shrink the current handle scope to make it impossible to do // Shrink the current handle scope to make it impossible to do
// handle allocations without an explicit handle scope. // handle allocations without an explicit handle scope.
current->limit = current->next; current->limit = current->next;
current->extensions = -1;
level_ = current->level;
current->level = 0;
} }
inline NoHandleAllocation::~NoHandleAllocation() { inline NoHandleAllocation::~NoHandleAllocation() {
// Restore state in current handle scope to re-enable handle // Restore state in current handle scope to re-enable handle
// allocations. // allocations.
v8::ImplementationUtilities::CurrentHandleScope()->extensions = extensions_; v8::ImplementationUtilities::HandleScopeData* current =
v8::ImplementationUtilities::CurrentHandleScope();
ASSERT_EQ(0, current->level);
current->level = level_;
} }
#endif #endif
......
...@@ -44,7 +44,7 @@ namespace internal { ...@@ -44,7 +44,7 @@ namespace internal {
v8::ImplementationUtilities::HandleScopeData HandleScope::current_ = v8::ImplementationUtilities::HandleScopeData HandleScope::current_ =
{ -1, NULL, NULL }; { NULL, NULL, 0 };
int HandleScope::NumberOfHandles() { int HandleScope::NumberOfHandles() {
...@@ -61,7 +61,7 @@ Object** HandleScope::Extend() { ...@@ -61,7 +61,7 @@ Object** HandleScope::Extend() {
ASSERT(result == current_.limit); ASSERT(result == current_.limit);
// Make sure there's at least one scope on the stack and that the // Make sure there's at least one scope on the stack and that the
// top of the scope stack isn't a barrier. // top of the scope stack isn't a barrier.
if (current_.extensions < 0) { if (current_.level == 0) {
Utils::ReportApiFailure("v8::HandleScope::CreateHandle()", Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
"Cannot create a handle without a HandleScope"); "Cannot create a handle without a HandleScope");
return NULL; return NULL;
...@@ -73,6 +73,7 @@ Object** HandleScope::Extend() { ...@@ -73,6 +73,7 @@ Object** HandleScope::Extend() {
Object** limit = &impl->blocks()->last()[kHandleBlockSize]; Object** limit = &impl->blocks()->last()[kHandleBlockSize];
if (current_.limit != limit) { if (current_.limit != limit) {
current_.limit = limit; current_.limit = limit;
ASSERT(limit - current_.next < kHandleBlockSize);
} }
} }
...@@ -84,7 +85,6 @@ Object** HandleScope::Extend() { ...@@ -84,7 +85,6 @@ Object** HandleScope::Extend() {
// Add the extension to the global list of blocks, but count the // Add the extension to the global list of blocks, but count the
// extension as part of the current scope. // extension as part of the current scope.
impl->blocks()->Add(result); impl->blocks()->Add(result);
current_.extensions++;
current_.limit = &result[kHandleBlockSize]; current_.limit = &result[kHandleBlockSize];
} }
...@@ -93,21 +93,20 @@ Object** HandleScope::Extend() { ...@@ -93,21 +93,20 @@ Object** HandleScope::Extend() {
void HandleScope::DeleteExtensions() { void HandleScope::DeleteExtensions() {
ASSERT(current_.extensions != 0); HandleScopeImplementer::instance()->DeleteExtensions(current_.limit);
HandleScopeImplementer::instance()->DeleteExtensions(current_.extensions);
} }
void HandleScope::ZapRange(Object** start, Object** end) { void HandleScope::ZapRange(Object** start, Object** end) {
if (start == NULL) return; ASSERT(end - start <= kHandleBlockSize);
for (Object** p = start; p < end; p++) { for (Object** p = start; p != end; p++) {
*reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue; *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue;
} }
} }
Address HandleScope::current_extensions_address() { Address HandleScope::current_level_address() {
return reinterpret_cast<Address>(&current_.extensions); return reinterpret_cast<Address>(&current_.level);
} }
......
...@@ -107,12 +107,20 @@ class Handle { ...@@ -107,12 +107,20 @@ class Handle {
// for which the handle scope has been deleted is undefined. // for which the handle scope has been deleted is undefined.
class HandleScope { class HandleScope {
public: public:
HandleScope() : previous_(current_) { HandleScope() : prev_next_(current_.next), prev_limit_(current_.limit) {
current_.extensions = 0; current_.level++;
} }
~HandleScope() { ~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. // Counts the number of allocated handles.
...@@ -136,9 +144,9 @@ class HandleScope { ...@@ -136,9 +144,9 @@ class HandleScope {
// Deallocates any extensions used by the current scope. // Deallocates any extensions used by the current scope.
static void DeleteExtensions(); static void DeleteExtensions();
static Address current_extensions_address();
static Address current_next_address(); static Address current_next_address();
static Address current_limit_address(); static Address current_limit_address();
static Address current_level_address();
private: private:
// Prevent heap allocation or illegal handle scopes. // Prevent heap allocation or illegal handle scopes.
...@@ -148,27 +156,8 @@ class HandleScope { ...@@ -148,27 +156,8 @@ class HandleScope {
void operator delete(void* size_t); void operator delete(void* size_t);
static v8::ImplementationUtilities::HandleScopeData current_; static v8::ImplementationUtilities::HandleScopeData current_;
const v8::ImplementationUtilities::HandleScopeData previous_; Object** const prev_next_;
Object** const prev_limit_;
// 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
}
// Extend the handle scope making room for more handles. // Extend the handle scope making room for more handles.
static internal::Object** Extend(); static internal::Object** Extend();
...@@ -362,7 +351,7 @@ class NoHandleAllocation BASE_EMBEDDED { ...@@ -362,7 +351,7 @@ class NoHandleAllocation BASE_EMBEDDED {
inline NoHandleAllocation(); inline NoHandleAllocation();
inline ~NoHandleAllocation(); inline ~NoHandleAllocation();
private: private:
int extensions_; int level_;
#endif #endif
}; };
......
...@@ -695,7 +695,6 @@ class Assembler : public Malloced { ...@@ -695,7 +695,6 @@ class Assembler : public Malloced {
void call(Label* L); void call(Label* L);
void call(byte* entry, RelocInfo::Mode rmode); void call(byte* entry, RelocInfo::Mode rmode);
void call(const Operand& adr); void call(const Operand& adr);
void call(const ExternalReference& target);
void call(Handle<Code> code, RelocInfo::Mode rmode); void call(Handle<Code> code, RelocInfo::Mode rmode);
// Jumps // Jumps
......
...@@ -3058,74 +3058,12 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { ...@@ -3058,74 +3058,12 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
} }
// 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) { void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
Label empty_handle; __ PrepareCallApiFunction(kStackSpace, kArgc);
Label prologue; STATIC_ASSERT(kArgc == 2);
Label promote_scheduled_exception; __ mov(ApiParameterOperand(0), ebx); // name.
__ EnterApiExitFrame(kStackSpace, kArgc); __ mov(ApiParameterOperand(1), eax); // arguments pointer.
STATIC_ASSERT(kArgc == 4); __ CallApiFunctionAndReturn(fun(), kArgc);
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);
} }
......
...@@ -1115,66 +1115,116 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, ...@@ -1115,66 +1115,116 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
} }
void MacroAssembler::PushHandleScope(Register scratch) { // If true, a Handle<T> passed by value is passed and returned by
// Push the number of extensions, smi-tagged so the gc will ignore it. // using the location_ field directly. If false, it is passed and
ExternalReference extensions_address = // returned as a pointer to a handle.
ExternalReference::handle_scope_extensions_address(); #ifdef USING_BSD_ABI
mov(scratch, Operand::StaticVariable(extensions_address)); static const bool kPassHandlesDirectly = true;
SmiTag(scratch); #else
push(scratch); static const bool kPassHandlesDirectly = false;
mov(Operand::StaticVariable(extensions_address), Immediate(0)); #endif
// Push next and limit pointers which will be wordsize aligned and
// hence automatically smi tagged.
ExternalReference next_address = Operand ApiParameterOperand(int index) {
ExternalReference::handle_scope_next_address(); return Operand(esp, (index + (kPassHandlesDirectly ? 0 : 1)) * kPointerSize);
push(Operand::StaticVariable(next_address));
ExternalReference limit_address =
ExternalReference::handle_scope_limit_address();
push(Operand::StaticVariable(limit_address));
} }
Object* MacroAssembler::PopHandleScopeHelper(Register saved, void MacroAssembler::PrepareCallApiFunction(int stack_space, int argc) {
Register scratch, if (kPassHandlesDirectly) {
bool gc_allowed) { EnterApiExitFrame(stack_space, argc);
Object* result = NULL; // When handles as passed directly we don't have to allocate extra
ExternalReference extensions_address = // space for and pass an out parameter.
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);
} else { } else {
result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0); // We allocate two additional slots: return value and pointer to it.
if (result->IsFailure()) return result; EnterApiExitFrame(stack_space, argc + 2);
} }
pop(saved); }
bind(&write_back);
ExternalReference limit_address =
ExternalReference::handle_scope_limit_address();
pop(Operand::StaticVariable(limit_address));
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::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();
ExternalReference limit_address =
ExternalReference::handle_scope_limit_address();
ExternalReference level_address =
ExternalReference::handle_scope_level_address();
void MacroAssembler::PopHandleScope(Register saved, Register scratch) { // Allocate HandleScope in callee-save registers.
PopHandleScopeHelper(saved, scratch, true); 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);
Object* MacroAssembler::TryPopHandleScope(Register saved, Register scratch) { if (!kPassHandlesDirectly) {
return PopHandleScopeHelper(saved, scratch, false); // 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);
} }
......
...@@ -480,15 +480,16 @@ class MacroAssembler: public Assembler { ...@@ -480,15 +480,16 @@ class MacroAssembler: public Assembler {
void CallCFunction(ExternalReference function, int num_arguments); void CallCFunction(ExternalReference function, int num_arguments);
void CallCFunction(Register function, int num_arguments); void CallCFunction(Register function, int num_arguments);
void PushHandleScope(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);
// Pops a handle scope using the specified scratch register and // Tail call an API function (jump). Allocates HandleScope, extracts
// ensuring that saved register is left unchanged. // returned value from handle and propagates exceptions.
void PopHandleScope(Register saved, Register scratch); // Clobbers ebx, esi, edi and caller-save registers.
void CallApiFunctionAndReturn(ApiFunction* function, int argc);
// 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. // Jump to a runtime routine.
void JumpToExternalReference(const ExternalReference& ext); void JumpToExternalReference(const ExternalReference& ext);
...@@ -639,6 +640,9 @@ static inline Operand FieldOperand(Register object, ...@@ -639,6 +640,9 @@ static inline Operand FieldOperand(Register object,
return Operand(object, index, scale, offset - kHeapObjectTag); return Operand(object, index, scale, offset - kHeapObjectTag);
} }
// Generates an Operand for saving parameters after PrepareCallApiFunction.
Operand ApiParameterOperand(int index);
#ifdef GENERATED_CODE_COVERAGE #ifdef GENERATED_CODE_COVERAGE
extern void LogGeneratedCodeCoverage(const char* file_line); extern void LogGeneratedCodeCoverage(const char* file_line);
......
...@@ -1035,7 +1035,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, ...@@ -1035,7 +1035,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
Handle<AccessorInfo> callback_handle(callback); Handle<AccessorInfo> callback_handle(callback);
__ EnterInternalFrame(); __ EnterInternalFrame();
__ PushHandleScope(scratch2);
// Push the stack address where the list of arguments ends. // Push the stack address where the list of arguments ends.
__ mov(scratch2, esp); __ mov(scratch2, esp);
__ sub(Operand(scratch2), Immediate(2 * kPointerSize)); __ sub(Operand(scratch2), Immediate(2 * kPointerSize));
...@@ -1070,17 +1069,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, ...@@ -1070,17 +1069,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
*failure = Failure::cast(result); *failure = Failure::cast(result);
return false; 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(); __ LeaveInternalFrame();
__ ret(0); __ ret(0);
......
...@@ -9951,13 +9951,6 @@ static Object* Runtime_Abort(Arguments args) { ...@@ -9951,13 +9951,6 @@ static Object* Runtime_Abort(Arguments args) {
} }
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) { static Object* CacheMiss(FixedArray* cache_obj, int index, Object* key_obj) {
ASSERT(index % 2 == 0); // index of the key ASSERT(index % 2 == 0); // index of the key
ASSERT(index >= JSFunctionResultCache::kEntriesIndex); ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
......
...@@ -297,8 +297,6 @@ namespace internal { ...@@ -297,8 +297,6 @@ namespace internal {
F(Log, 2, 1) \ F(Log, 2, 1) \
/* ES5 */ \ /* ES5 */ \
F(LocalKeys, 1, 1) \ F(LocalKeys, 1, 1) \
/* Handle scopes */ \
F(DeleteHandleScopeExtensions, 0, 1) \
/* Cache suport */ \ /* Cache suport */ \
F(GetFromCache, 2, 1) \ F(GetFromCache, 2, 1) \
\ \
......
...@@ -337,6 +337,11 @@ void ExternalReferenceTable::PopulateTable() { ...@@ -337,6 +337,11 @@ void ExternalReferenceTable::PopulateTable() {
3, 3,
"V8::Random"); "V8::Random");
Add(ExternalReference::delete_handle_scope_extensions().address(),
RUNTIME_ENTRY,
3,
"HandleScope::DeleteExtensions");
// Miscellaneous // Miscellaneous
Add(ExternalReference::the_hole_value_location().address(), Add(ExternalReference::the_hole_value_location().address(),
UNCLASSIFIED, UNCLASSIFIED,
...@@ -457,6 +462,18 @@ void ExternalReferenceTable::PopulateTable() { ...@@ -457,6 +462,18 @@ void ExternalReferenceTable::PopulateTable() {
UNCLASSIFIED, UNCLASSIFIED,
29, 29,
"TranscendentalCache::caches()"); "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");
} }
......
...@@ -2484,11 +2484,7 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { ...@@ -2484,11 +2484,7 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
void ApiGetterEntryStub::Generate(MacroAssembler* masm) { void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
Label empty_result; __ PrepareCallApiFunction(kStackSpace);
Label prologue;
Label promote_scheduled_exception;
__ EnterApiExitFrame(kStackSpace, 0);
ASSERT_EQ(kArgc, 4);
#ifdef _WIN64 #ifdef _WIN64
// All the parameters should be set up by a caller. // All the parameters should be set up by a caller.
#else #else
...@@ -2497,35 +2493,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) { ...@@ -2497,35 +2493,7 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
// Second parameter register rdi should be set with pointer to AccessorInfo // Second parameter register rdi should be set with pointer to AccessorInfo
// by a caller. // by a caller.
#endif #endif
// Call the api function! __ CallApiFunctionAndReturn(fun());
__ 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);
} }
......
...@@ -469,76 +469,89 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) { ...@@ -469,76 +469,89 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) {
} }
void MacroAssembler::PushHandleScope(Register scratch) { void MacroAssembler::PrepareCallApiFunction(int stack_space) {
ExternalReference extensions_address = EnterApiExitFrame(stack_space, 0);
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));
} }
Object* MacroAssembler::PopHandleScopeHelper(Register saved, void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function) {
Register scratch, Label empty_result;
bool gc_allowed) { Label prologue;
ExternalReference extensions_address = Label promote_scheduled_exception;
ExternalReference::handle_scope_extensions_address(); Label delete_allocated_handles;
const int kExtensionsOffset = 0; Label leave_exit_frame;
const int kNextOffset = Offset(
ExternalReference::handle_scope_next_address(),
extensions_address);
const int kLimitOffset = Offset(
ExternalReference::handle_scope_limit_address(),
extensions_address);
Object* result = NULL;
Label write_back; 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; ExternalReference next_address =
} ExternalReference::handle_scope_next_address();
const int kNextOffset = 0;
const int kLimitOffset = Offset(
void MacroAssembler::PopHandleScope(Register saved, Register scratch) { ExternalReference::handle_scope_limit_address(),
PopHandleScopeHelper(saved, scratch, true); 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);
Object* MacroAssembler::TryPopHandleScope(Register saved, Register scratch) { bind(&promote_scheduled_exception);
return PopHandleScopeHelper(saved, scratch, false); 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);
} }
......
...@@ -816,19 +816,18 @@ class MacroAssembler: public Assembler { ...@@ -816,19 +816,18 @@ class MacroAssembler: public Assembler {
int num_arguments, int num_arguments,
int result_size); 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. // Jump to a runtime routine.
void JumpToExternalReference(const ExternalReference& ext, int result_size); 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. // 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], // 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. // etc., not pushed. The argument count assumes all arguments are word sized.
......
...@@ -2547,7 +2547,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, ...@@ -2547,7 +2547,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
Handle<AccessorInfo> callback_handle(callback); Handle<AccessorInfo> callback_handle(callback);
__ EnterInternalFrame(); __ EnterInternalFrame();
__ PushHandleScope(scratch2);
// Push the stack address where the list of arguments ends. // Push the stack address where the list of arguments ends.
__ movq(scratch2, rsp); __ movq(scratch2, rsp);
__ subq(scratch2, Immediate(2 * kPointerSize)); __ subq(scratch2, Immediate(2 * kPointerSize));
...@@ -2601,17 +2600,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, ...@@ -2601,17 +2600,6 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
// Discard allocated slot. // Discard allocated slot.
__ addq(rsp, Immediate(kPointerSize)); __ addq(rsp, Immediate(kPointerSize));
#endif #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(); __ LeaveInternalFrame();
__ ret(0); __ ret(0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment