Commit 7adff828 authored by ager@chromium.org's avatar ager@chromium.org

Port change (r1837) that allows call-as-function handlers to be called

through new to ARM.  

Added simple test case of the current behavior.

For consistency, changed a number of occurences of explicit moves to
pc to use Jump instead.
Review URL: http://codereview.chromium.org/115014

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1889 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9ab31a82
...@@ -58,6 +58,16 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { ...@@ -58,6 +58,16 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// -- sp[...]: constructor arguments // -- 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. // Enter a construct frame.
__ EnterConstructFrame(); __ EnterConstructFrame();
...@@ -169,7 +179,17 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { ...@@ -169,7 +179,17 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
__ LeaveConstructFrame(); __ LeaveConstructFrame();
__ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1)); __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
__ add(sp, sp, Operand(kPointerSize)); __ 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);
} }
...@@ -235,7 +255,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, ...@@ -235,7 +255,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
// Exit the JS frame and remove the parameters (except function), and return. // Exit the JS frame and remove the parameters (except function), and return.
// Respect ABI stack constraint. // Respect ABI stack constraint.
__ LeaveInternalFrame(); __ LeaveInternalFrame();
__ mov(pc, lr); __ Jump(lr);
// r0: result // r0: result
} }
...@@ -544,7 +564,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { ...@@ -544,7 +564,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
// Tear down the internal frame and remove function, receiver and args. // Tear down the internal frame and remove function, receiver and args.
__ LeaveInternalFrame(); __ LeaveInternalFrame();
__ add(sp, sp, Operand(3 * kPointerSize)); __ add(sp, sp, Operand(3 * kPointerSize));
__ mov(pc, lr); __ Jump(lr);
} }
...@@ -663,14 +683,14 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { ...@@ -663,14 +683,14 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// Exit frame and return. // Exit frame and return.
LeaveArgumentsAdaptorFrame(masm); LeaveArgumentsAdaptorFrame(masm);
__ mov(pc, lr); __ Jump(lr);
// ------------------------------------------- // -------------------------------------------
// Dont adapt arguments. // Dont adapt arguments.
// ------------------------------------------- // -------------------------------------------
__ bind(&dont_adapt_arguments); __ bind(&dont_adapt_arguments);
__ mov(pc, r3); __ Jump(r3);
} }
......
...@@ -277,7 +277,7 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) { ...@@ -277,7 +277,7 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
frame_->Exit(); frame_->Exit();
__ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize)); __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));
__ mov(pc, lr); __ Jump(lr);
} }
// Code generation state must be reset. // Code generation state must be reset.
...@@ -5034,13 +5034,13 @@ void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) { ...@@ -5034,13 +5034,13 @@ void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
// Nothing to do: The formal number of parameters has already been // Nothing to do: The formal number of parameters has already been
// passed in register r0 by calling function. Just return it. // passed in register r0 by calling function. Just return it.
__ mov(pc, lr); __ Jump(lr);
// Arguments adaptor case: Read the arguments length from the // Arguments adaptor case: Read the arguments length from the
// adaptor frame and return it. // adaptor frame and return it.
__ bind(&adaptor); __ bind(&adaptor);
__ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ mov(pc, lr); __ Jump(lr);
} }
...@@ -5072,7 +5072,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { ...@@ -5072,7 +5072,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
__ sub(r3, r0, r1); __ sub(r3, r0, r1);
__ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); __ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
__ ldr(r0, MemOperand(r3, kDisplacement)); __ ldr(r0, MemOperand(r3, kDisplacement));
__ mov(pc, lr); __ Jump(lr);
// Arguments adaptor case: Check index against actual arguments // Arguments adaptor case: Check index against actual arguments
// limit found in the arguments adaptor frame. Use unsigned // limit found in the arguments adaptor frame. Use unsigned
...@@ -5086,7 +5086,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { ...@@ -5086,7 +5086,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
__ sub(r3, r0, r1); __ sub(r3, r0, r1);
__ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
__ ldr(r0, MemOperand(r3, kDisplacement)); __ ldr(r0, MemOperand(r3, kDisplacement));
__ mov(pc, lr); __ Jump(lr);
// Slow-case: Handle non-smi or out-of-bounds access to arguments // Slow-case: Handle non-smi or out-of-bounds access to arguments
// by calling the runtime system. // by calling the runtime system.
......
...@@ -4627,35 +4627,42 @@ THREADED_TEST(CallAsFunction) { ...@@ -4627,35 +4627,42 @@ THREADED_TEST(CallAsFunction) {
Local<Value> value; Local<Value> value;
CHECK(!try_catch.HasCaught()); CHECK(!try_catch.HasCaught());
value = Script::Compile(v8_str("obj(42)"))->Run(); value = CompileRun("obj(42)");
CHECK(!try_catch.HasCaught()); CHECK(!try_catch.HasCaught());
CHECK_EQ(42, value->Int32Value()); 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(!try_catch.HasCaught());
CHECK_EQ(49, value->Int32Value()); CHECK_EQ(49, value->Int32Value());
// test special case of call as function // 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(!try_catch.HasCaught());
CHECK_EQ(45, value->Int32Value()); CHECK_EQ(45, value->Int32Value());
value = Script::Compile(v8_str("obj.call = Function.prototype.call;" value = CompileRun("obj.call = Function.prototype.call;"
"obj.call(null, 87)"))->Run(); "obj.call(null, 87)");
CHECK(!try_catch.HasCaught()); CHECK(!try_catch.HasCaught());
CHECK_EQ(87, value->Int32Value()); CHECK_EQ(87, value->Int32Value());
// Regression tests for bug #1116356: Calling call through call/apply // Regression tests for bug #1116356: Calling call through call/apply
// must work for non-function receivers. // must work for non-function receivers.
const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; 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(!try_catch.HasCaught());
CHECK_EQ(99, value->Int32Value()); CHECK_EQ(99, value->Int32Value());
const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; 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(!try_catch.HasCaught());
CHECK_EQ(17, value->Int32Value()); 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());
} }
......
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