Support for function calls on an arbitrary expression that returns
authorfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Nov 2009 12:04:35 +0000 (12:04 +0000)
committerfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Nov 2009 12:04:35 +0000 (12:04 +0000)
a function in the top-level compiler.

e.g.

function f() { return (function() { return true; }) }
f()()

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

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

src/arm/fast-codegen-arm.cc
src/compiler.cc
src/ia32/fast-codegen-ia32.cc
src/x64/fast-codegen-x64.cc
test/mjsunit/compiler/function-call.js

index 99f5557..2bf2659 100644 (file)
@@ -723,8 +723,13 @@ void FastCodeGenerator::EmitCallWithStub(Call* expr) {
 
 void FastCodeGenerator::VisitCall(Call* expr) {
   Expression* fun = expr->expression();
+  Variable* var = fun->AsVariableProxy()->AsVariable();
 
-  if (fun->AsProperty() != NULL) {
+  if (var != NULL &&
+      var->is_possibly_eval()) {
+    // Call to eval.
+    UNREACHABLE();
+  } else if (fun->AsProperty() != NULL) {
     // Call on a property.
     Property* prop = fun->AsProperty();
     Literal* key = prop->key()->AsLiteral();
@@ -755,9 +760,8 @@ void FastCodeGenerator::VisitCall(Call* expr) {
       __ str(r1, MemOperand(sp));
       EmitCallWithStub(expr);
     }
-  } else if (fun->AsVariableProxy()->AsVariable() != NULL) {
+  } else if (var != NULL) {
     // Call on a global variable
-    Variable* var = fun->AsVariableProxy()->AsVariable();
     ASSERT(var != NULL && !var->is_this() && var->is_global());
     ASSERT(!var->is_possibly_eval());
     __ mov(r1, Operand(var->name()));
@@ -765,10 +769,19 @@ void FastCodeGenerator::VisitCall(Call* expr) {
     __ ldr(r0, CodeGenerator::GlobalObject());
     __ stm(db_w, sp, r1.bit() | r0.bit());
     EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT);
-  } else {
-    // Calls we cannot handle right now.
-    // Should bailout in the CodeGenSelector.
+  } else if (var != NULL && var->slot() != NULL &&
+             var->slot()->type() == Slot::LOOKUP) {
+    // Call inside a with-statement
     UNREACHABLE();
+  } else {
+    // Call with an arbitrary function expression.
+    Visit(expr->expression());
+    // Load global receiver object.
+    __ ldr(r1, CodeGenerator::GlobalObject());
+    __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
+    __ push(r1);
+    // Emit function call.
+    EmitCallWithStub(expr);
   }
 }
 
index 86bf160..2526ad7 100644 (file)
@@ -791,6 +791,9 @@ void CodeGenSelector::VisitCall(Call* expr) {
 
   // Check for supported calls
   if (var != NULL && var->is_possibly_eval()) {
+    // ----------------------------------
+    // JavaScript example: 'eval(arg)'  // eval is not known to be shadowed
+    // ----------------------------------
     BAILOUT("Call to a function named 'eval'");
   } else if (var != NULL && !var->is_this() && var->is_global()) {
     // ----------------------------------
@@ -811,8 +814,17 @@ void CodeGenSelector::VisitCall(Call* expr) {
       ProcessExpression(prop->key(), Expression::kValue);
       CHECK_BAILOUT;
     }
+  } else if (var != NULL && var->slot() != NULL &&
+             var->slot()->type() == Slot::LOOKUP) {
+    // ----------------------------------
+    // JavaScript example: 'with (obj) foo(1, 2, 3)'  // foo is in obj
+    // ----------------------------------
+    BAILOUT("Call inside a with-statement");
   } else {
-    BAILOUT("Unsupported call to a function");
+    // ----------------------------------
+    // JavaScript example: 'foo(1, 2, 3)'  // foo is any expression, not global
+    // ----------------------------------
+    ProcessExpression(fun, Expression::kValue);
   }
   // Check all arguments to the call.  (Relies on TEMP meaning STACK.)
   for (int i = 0; i < args->length(); i++) {
index 851f733..a234ae1 100644 (file)
@@ -745,8 +745,13 @@ void FastCodeGenerator::EmitCallWithStub(Call* expr) {
 
 void FastCodeGenerator::VisitCall(Call* expr) {
   Expression* fun = expr->expression();
+  Variable* var = fun->AsVariableProxy()->AsVariable();
 
-  if (fun->AsProperty() != NULL) {
+  if (var != NULL &&
+      var->is_possibly_eval()) {
+    // Call to eval.
+    UNREACHABLE();
+  } else if (fun->AsProperty() != NULL) {
     // Call on a property.
     Property* prop = fun->AsProperty();
     Literal* key = prop->key()->AsLiteral();
@@ -782,19 +787,28 @@ void FastCodeGenerator::VisitCall(Call* expr) {
       }
       EmitCallWithStub(expr);
     }
-  } else if (fun->AsVariableProxy()->AsVariable() != NULL) {
+  } else if (var != NULL) {
     // Call on a global variable
-    Variable* var = fun->AsVariableProxy()->AsVariable();
-    ASSERT(var != NULL && !var->is_this() && var->is_global());
+    ASSERT(var != NULL);
+    ASSERT(!var->is_this());
+    ASSERT(var->is_global());
     ASSERT(!var->is_possibly_eval());
     __ push(Immediate(var->name()));
     // Push global object (receiver).
     __ push(CodeGenerator::GlobalObject());
     EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT);
-  } else {
-    // Calls we cannot handle right now.
-    // Should bailout in the CodeGenSelector.
+  } else if (var != NULL && var->slot() != NULL &&
+             var->slot()->type() == Slot::LOOKUP) {
+    // Call inside a with-statement
     UNREACHABLE();
+  } else {
+    // Call with an arbitrary function expression.
+    Visit(expr->expression());
+    // Load global receiver object.
+    __ mov(ebx, CodeGenerator::GlobalObject());
+    __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
+    // Emit function call.
+    EmitCallWithStub(expr);
   }
 }
 
index 5592d08..b4c75ab 100644 (file)
@@ -760,8 +760,13 @@ void FastCodeGenerator::EmitCallWithStub(Call* expr) {
 
 void FastCodeGenerator::VisitCall(Call* expr) {
   Expression* fun = expr->expression();
+  Variable* var = fun->AsVariableProxy()->AsVariable();
 
-  if (fun->AsProperty() != NULL) {
+  if (var != NULL &&
+      var->is_possibly_eval()) {
+    // Call to eval.
+    UNREACHABLE();
+  } else if (fun->AsProperty() != NULL) {
     // Call on a property.
     Property* prop = fun->AsProperty();
     Literal* key = prop->key()->AsLiteral();
@@ -797,19 +802,26 @@ void FastCodeGenerator::VisitCall(Call* expr) {
       }
       EmitCallWithStub(expr);
     }
-  } else if (fun->AsVariableProxy()->AsVariable() != NULL) {
+  } else if (var != NULL) {
     // Call on a global variable
-    Variable* var = fun->AsVariableProxy()->AsVariable();
     ASSERT(var != NULL && !var->is_this() && var->is_global());
     ASSERT(!var->is_possibly_eval());
     __ Push(var->name());
     // Push global object (receiver).
     __ push(CodeGenerator::GlobalObject());
     EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT);
-  } else {
-    // Calls we cannot handle right now.
-    // Should bailout in the CodeGenSelector.
+  } else if (var != NULL && var->slot() != NULL &&
+             var->slot()->type() == Slot::LOOKUP) {
+    // Call inside a with-statement
     UNREACHABLE();
+  } else {
+    // Call with an arbitrary function expression.
+    Visit(expr->expression());
+    // Load global receiver object.
+    __ movq(rbx, CodeGenerator::GlobalObject());
+    __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
+    // Emit function call.
+    EmitCallWithStub(expr);
   }
 }
 
index 2bca509..b2e0702 100644 (file)
@@ -46,3 +46,7 @@ c = "x";
 a = b[c](10);
 assertEquals(10, a);
 
+// Call on a function expression
+function g() { return f; }
+a = g()(8);
+assertEquals(8, a);