}
+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
}
+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) {
}
-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;
// 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);
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);
}
// 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.
// 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);
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);
};
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);
// 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);