// -- sp[...]: constructor arguments
// -----------------------------------
+ Label non_function_call;
+ // Check that the function is not a smi.
+ __ tst(r1, Operand(kSmiTagMask));
+ __ b(eq, &non_function_call);
+ // Check that the function is a JSFunction.
+ __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+ __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+ __ cmp(r2, Operand(JS_FUNCTION_TYPE));
+ __ b(ne, &non_function_call);
+
// Enter a construct frame.
__ EnterConstructFrame();
__ LeaveConstructFrame();
__ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
__ add(sp, sp, Operand(kPointerSize));
- __ mov(pc, Operand(lr));
+ __ Jump(lr);
+
+ // r0: number of arguments
+ // r1: called object
+ __ bind(&non_function_call);
+
+ // Set expected number of arguments to zero (not changing r0).
+ __ mov(r2, Operand(0));
+ __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
+ __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+ RelocInfo::CODE_TARGET);
}
// Exit the JS frame and remove the parameters (except function), and return.
// Respect ABI stack constraint.
__ LeaveInternalFrame();
- __ mov(pc, lr);
+ __ Jump(lr);
// r0: result
}
// Tear down the internal frame and remove function, receiver and args.
__ LeaveInternalFrame();
__ add(sp, sp, Operand(3 * kPointerSize));
- __ mov(pc, lr);
+ __ Jump(lr);
}
// Exit frame and return.
LeaveArgumentsAdaptorFrame(masm);
- __ mov(pc, lr);
+ __ Jump(lr);
// -------------------------------------------
// Dont adapt arguments.
// -------------------------------------------
__ bind(&dont_adapt_arguments);
- __ mov(pc, r3);
+ __ Jump(r3);
}
frame_->Exit();
__ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));
- __ mov(pc, lr);
+ __ Jump(lr);
}
// Code generation state must be reset.
// Nothing to do: The formal number of parameters has already been
// passed in register r0 by calling function. Just return it.
- __ mov(pc, lr);
+ __ Jump(lr);
// Arguments adaptor case: Read the arguments length from the
// adaptor frame and return it.
__ bind(&adaptor);
__ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
- __ mov(pc, lr);
+ __ Jump(lr);
}
__ sub(r3, r0, r1);
__ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
__ ldr(r0, MemOperand(r3, kDisplacement));
- __ mov(pc, lr);
+ __ Jump(lr);
// Arguments adaptor case: Check index against actual arguments
// limit found in the arguments adaptor frame. Use unsigned
__ sub(r3, r0, r1);
__ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
__ ldr(r0, MemOperand(r3, kDisplacement));
- __ mov(pc, lr);
+ __ Jump(lr);
// Slow-case: Handle non-smi or out-of-bounds access to arguments
// by calling the runtime system.
Local<Value> value;
CHECK(!try_catch.HasCaught());
- value = Script::Compile(v8_str("obj(42)"))->Run();
+ value = CompileRun("obj(42)");
CHECK(!try_catch.HasCaught());
CHECK_EQ(42, value->Int32Value());
- value = Script::Compile(v8_str("(function(o){return o(49)})(obj)"))->Run();
+ value = CompileRun("(function(o){return o(49)})(obj)");
CHECK(!try_catch.HasCaught());
CHECK_EQ(49, value->Int32Value());
// test special case of call as function
- value = Script::Compile(v8_str("[obj]['0'](45)"))->Run();
+ value = CompileRun("[obj]['0'](45)");
CHECK(!try_catch.HasCaught());
CHECK_EQ(45, value->Int32Value());
- value = Script::Compile(v8_str("obj.call = Function.prototype.call;"
- "obj.call(null, 87)"))->Run();
+ value = CompileRun("obj.call = Function.prototype.call;"
+ "obj.call(null, 87)");
CHECK(!try_catch.HasCaught());
CHECK_EQ(87, value->Int32Value());
// Regression tests for bug #1116356: Calling call through call/apply
// must work for non-function receivers.
const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
- value = Script::Compile(v8_str(apply_99))->Run();
+ value = CompileRun(apply_99);
CHECK(!try_catch.HasCaught());
CHECK_EQ(99, value->Int32Value());
const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
- value = Script::Compile(v8_str(call_17))->Run();
+ value = CompileRun(call_17);
CHECK(!try_catch.HasCaught());
CHECK_EQ(17, value->Int32Value());
+
+ // Check that the call-as-function handler can be called through
+ // new. Currently, there is no way to check in the call-as-function
+ // handler if it has been called through new or not.
+ value = CompileRun("new obj(42)");
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(42, value->Int32Value());
}