Fixed problem where popping a handle scope after calling an accessor
authorchristian.plesner.hansen@gmail.com <christian.plesner.hansen@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 6 Nov 2009 11:35:47 +0000 (11:35 +0000)
committerchristian.plesner.hansen@gmail.com <christian.plesner.hansen@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 6 Nov 2009 11:35:47 +0000 (11:35 +0000)
would clobber the register holding the result.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3237 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/ia32/stub-cache-ia32.cc
test/cctest/test-accessors.cc

index 34d4fd5..423988c 100644 (file)
@@ -973,14 +973,18 @@ void MacroAssembler::PushHandleScope(Register scratch) {
 }
 
 
-void MacroAssembler::PopHandleScope(Register scratch) {
+void MacroAssembler::PopHandleScope(Register saved, Register scratch) {
   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);
+  // Calling a runtime function messes with registers so we save and
+  // restore any one we're asked not to change
+  if (saved.is_valid()) push(saved);
   CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
+  if (saved.is_valid()) pop(saved);
 
   bind(&write_back);
   ExternalReference limit_address =
index 18d221c..248aa77 100644 (file)
@@ -272,7 +272,10 @@ class MacroAssembler: public Assembler {
                        int result_size);
 
   void PushHandleScope(Register scratch);
-  void PopHandleScope(Register scratch);
+
+  // Pops a handle scope using the specified scratch register and
+  // ensuring that saved register, it is not no_reg, is left unchanged.
+  void PopHandleScope(Register saved, Register scratch);
 
   // Jump to a runtime routine.
   void JumpToRuntime(const ExternalReference& ext);
index 3e5fc04..1c843fd 100644 (file)
@@ -804,8 +804,9 @@ void StubCompiler::GenerateLoadCallback(JSObject* object,
   ApiGetterEntryStub stub(callback_handle, &fun);
   __ CallStub(&stub);
 
+  // We need to avoid using eax since that now holds the result.
   Register tmp = other.is(eax) ? reg : other;
-  __ PopHandleScope(tmp);
+  __ PopHandleScope(eax, tmp);
   __ LeaveInternalFrame();
 
   __ ret(0);
index b56238a..25f5c39 100644 (file)
@@ -422,3 +422,29 @@ THREADED_TEST(StackIteration) {
       "  foo();"
       "}"))->Run();
 }
+
+
+static v8::Handle<Value> AllocateHandles(Local<String> name,
+                                         const AccessorInfo& info) {
+  for (int i = 0; i < i::kHandleBlockSize + 1; i++) {
+    v8::Local<v8::Value>::New(name);
+  }
+  return v8::Integer::New(100);
+}
+
+
+THREADED_TEST(HandleScopeSegment) {
+  // Check that we can return values past popping of handle scope
+  // segments.
+  v8::HandleScope scope;
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+  obj->SetAccessor(v8_str("xxx"), AllocateHandles);
+  LocalContext env;
+  env->Global()->Set(v8_str("obj"), obj->NewInstance());
+  v8::Handle<v8::Value> result = Script::Compile(String::New(
+      "var result;"
+      "for (var i = 0; i < 4; i++)"
+      "  result = obj.xxx;"
+      "result;"))->Run();
+  CHECK_EQ(100, result->Int32Value());
+}