Port change (r1837) that allows call-as-function handlers to be called
authorager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 7 May 2009 07:18:33 +0000 (07:18 +0000)
committerager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 7 May 2009 07:18:33 +0000 (07:18 +0000)
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

src/arm/builtins-arm.cc
src/arm/codegen-arm.cc
test/cctest/test-api.cc

index 519c04a..9c7a42a 100644 (file)
@@ -58,6 +58,16 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
   //  -- 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();
 
@@ -169,7 +179,17 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
   __ 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);
 }
 
 
@@ -235,7 +255,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
   // Exit the JS frame and remove the parameters (except function), and return.
   // Respect ABI stack constraint.
   __ LeaveInternalFrame();
-  __ mov(pc, lr);
+  __ Jump(lr);
 
   // r0: result
 }
@@ -544,7 +564,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
   // Tear down the internal frame and remove function, receiver and args.
   __ LeaveInternalFrame();
   __ add(sp, sp, Operand(3 * kPointerSize));
-  __ mov(pc, lr);
+  __ Jump(lr);
 }
 
 
@@ -663,14 +683,14 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
 
   // Exit frame and return.
   LeaveArgumentsAdaptorFrame(masm);
-  __ mov(pc, lr);
+  __ Jump(lr);
 
 
   // -------------------------------------------
   // Dont adapt arguments.
   // -------------------------------------------
   __ bind(&dont_adapt_arguments);
-  __ mov(pc, r3);
+  __ Jump(r3);
 }
 
 
index 57e98c1..1930a7c 100644 (file)
@@ -277,7 +277,7 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
     frame_->Exit();
 
     __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));
-    __ mov(pc, lr);
+    __ Jump(lr);
   }
 
   // Code generation state must be reset.
@@ -5034,13 +5034,13 @@ void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
 
   // 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);
 }
 
 
@@ -5072,7 +5072,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   __ 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
@@ -5086,7 +5086,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   __ 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.
index a59b1d4..1b9621e 100644 (file)
@@ -4627,35 +4627,42 @@ THREADED_TEST(CallAsFunction) {
   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());
 }