Disallow garbage collection at another site in the LoadCallback ICs.
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Sun, 20 Dec 2009 08:40:13 +0000 (08:40 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Sun, 20 Dec 2009 08:40:13 +0000 (08:40 +0000)
MacroAssembler::PopHandleScope emits a runtime call (through a stub),
which should not be allowed to perform a GC but return a failure
instead.

BUG=30790
TEST=none

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

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

src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/ia32/stub-cache-ia32.cc

index ac2895e..fb34925 100644 (file)
@@ -1072,6 +1072,12 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) {
 }
 
 
+Object* MacroAssembler::TryCallRuntime(Runtime::FunctionId id,
+                                       int num_arguments) {
+  return TryCallRuntime(Runtime::FunctionForId(id), num_arguments);
+}
+
+
 void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
   // If the expected number of arguments of the runtime function is
   // constant, we check that the actual number of arguments match the
@@ -1088,6 +1094,22 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
 }
 
 
+Object* MacroAssembler::TryCallRuntime(Runtime::Function* f,
+                                       int num_arguments) {
+  if (f->nargs >= 0 && f->nargs != num_arguments) {
+    IllegalOperation(num_arguments);
+    // Since we did not call the stub, there was no allocation failure.
+    // Return some non-failure object.
+    return Heap::undefined_value();
+  }
+
+  Runtime::FunctionId function_id =
+      static_cast<Runtime::FunctionId>(f->stub_id);
+  RuntimeStub stub(function_id, num_arguments);
+  return TryCallStub(&stub);
+}
+
+
 void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
                                      int num_arguments,
                                      int result_size) {
@@ -1120,7 +1142,10 @@ void MacroAssembler::PushHandleScope(Register scratch) {
 }
 
 
-void MacroAssembler::PopHandleScope(Register saved, Register scratch) {
+Object* MacroAssembler::PopHandleScopeHelper(Register saved,
+                                             Register scratch,
+                                             bool gc_allowed) {
+  Object* result = NULL;
   ExternalReference extensions_address =
         ExternalReference::handle_scope_extensions_address();
   Label write_back;
@@ -1130,7 +1155,12 @@ void MacroAssembler::PopHandleScope(Register saved, Register scratch) {
   // 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 (gc_allowed) {
+    CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
+  } else {
+    result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0);
+    if (result->IsFailure()) return result;
+  }
   if (saved.is_valid()) pop(saved);
 
   bind(&write_back);
@@ -1143,6 +1173,18 @@ void MacroAssembler::PopHandleScope(Register saved, Register scratch) {
   pop(scratch);
   shr(scratch, kSmiTagSize);
   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);
 }
 
 
index 50fe73a..a7c1754 100644 (file)
@@ -319,9 +319,17 @@ class MacroAssembler: public Assembler {
   // Eventually this should be used for all C calls.
   void CallRuntime(Runtime::Function* f, int num_arguments);
 
+  // Call a runtime function, returning the RuntimeStub object called.
+  // Try to generate the stub code if necessary.  Do not perform a GC
+  // but instead return a retry after GC failure.
+  Object* TryCallRuntime(Runtime::Function* f, int num_arguments);
+
   // Convenience function: Same as above, but takes the fid instead.
   void CallRuntime(Runtime::FunctionId id, int num_arguments);
 
+  // Convenience function: Same as above, but takes the fid instead.
+  Object* TryCallRuntime(Runtime::FunctionId id, int num_arguments);
+
   // Tail call of a runtime routine (jump).
   // Like JumpToRuntime, but also takes care of passing the number
   // of arguments.
@@ -335,6 +343,10 @@ class MacroAssembler: public Assembler {
   // ensuring that saved register, it is not no_reg, 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 JumpToRuntime(const ExternalReference& ext);
 
@@ -427,6 +439,13 @@ class MacroAssembler: public Assembler {
                                Register scratch,
                                AllocationFlags flags);
   void UpdateAllocationTopHelper(Register result_end, Register scratch);
+
+  // Helper for PopHandleScope.  Allowed to perform a GC and returns
+  // NULL if gc_allowed.  Does not perform a GC if !gc_allowed, and
+  // possibly returns a failure object indicating an allocation failure.
+  Object* PopHandleScopeHelper(Register saved,
+                               Register scratch,
+                               bool gc_allowed);
 };
 
 
index 1dd5d95..a8ac6ab 100644 (file)
@@ -802,9 +802,10 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
   Address getter_address = v8::ToCData<Address>(callback->getter());
   ApiFunction fun(getter_address);
   ApiGetterEntryStub stub(callback_handle, &fun);
-  // Calling the stub may try to allocate (if the code is not already
-  // generated).  Do not allow the call to perform a garbage
-  // collection but instead return the allocation failure object.
+  // Emitting a stub call may try to allocate (if the code is not
+  // already generated).  Do not allow the assembler to perform a
+  // garbage collection but instead return the allocation failure
+  // object.
   Object* result = masm()->TryCallStub(&stub);
   if (result->IsFailure()) {
     *failure = Failure::cast(result);
@@ -813,7 +814,14 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
 
   // We need to avoid using eax since that now holds the result.
   Register tmp = other.is(eax) ? reg : other;
-  __ PopHandleScope(eax, tmp);
+  // 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);