Revision: 3196
Author: [email protected]
Date: Mon Nov 2 04:04:35 2009
Log: Support for function calls on an arbitrary expression that returns
a function in the top-level compiler.
e.g.
function f() { return (function() { return true; }) }
f()()
Review URL: http://codereview.chromium.org/346029
http://code.google.com/p/v8/source/detail?r=3196
Modified:
/branches/bleeding_edge/src/arm/fast-codegen-arm.cc
/branches/bleeding_edge/src/compiler.cc
/branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc
/branches/bleeding_edge/src/x64/fast-codegen-x64.cc
/branches/bleeding_edge/test/mjsunit/compiler/function-call.js
=======================================
--- /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Mon Nov 2 03:01:47
2009
+++ /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Mon Nov 2 04:04:35
2009
@@ -723,8 +723,13 @@
void FastCodeGenerator::VisitCall(Call* expr) {
Expression* fun = expr->expression();
-
- if (fun->AsProperty() != NULL) {
+ Variable* var = fun->AsVariableProxy()->AsVariable();
+
+ 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 @@
__ 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 @@
__ 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);
}
}
=======================================
--- /branches/bleeding_edge/src/compiler.cc Mon Nov 2 03:01:47 2009
+++ /branches/bleeding_edge/src/compiler.cc Mon Nov 2 04:04:35 2009
@@ -791,6 +791,9 @@
// 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 @@
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++) {
=======================================
--- /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Mon Nov 2
03:01:47 2009
+++ /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Mon Nov 2
04:04:35 2009
@@ -745,8 +745,13 @@
void FastCodeGenerator::VisitCall(Call* expr) {
Expression* fun = expr->expression();
-
- if (fun->AsProperty() != NULL) {
+ Variable* var = fun->AsVariableProxy()->AsVariable();
+
+ 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 @@
}
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);
}
}
=======================================
--- /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Mon Nov 2 03:01:47
2009
+++ /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Mon Nov 2 04:04:35
2009
@@ -760,8 +760,13 @@
void FastCodeGenerator::VisitCall(Call* expr) {
Expression* fun = expr->expression();
-
- if (fun->AsProperty() != NULL) {
+ Variable* var = fun->AsVariableProxy()->AsVariable();
+
+ 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 @@
}
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);
}
}
=======================================
--- /branches/bleeding_edge/test/mjsunit/compiler/function-call.js Fri Oct
30 03:22:31 2009
+++ /branches/bleeding_edge/test/mjsunit/compiler/function-call.js Mon Nov
2 04:04:35 2009
@@ -46,3 +46,7 @@
a = b[c](10);
assertEquals(10, a);
+// Call on a function expression
+function g() { return f; }
+a = g()(8);
+assertEquals(8, a);
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---