From e38cd233c39211c7dbe7044e180e7997b5a8dc6d Mon Sep 17 00:00:00 2001 From: "fschneider@chromium.org" Date: Mon, 2 Nov 2009 12:04:35 +0000 Subject: [PATCH] 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 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3196 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/fast-codegen-arm.cc | 25 +++++++++++++++++++------ src/compiler.cc | 14 +++++++++++++- src/ia32/fast-codegen-ia32.cc | 28 +++++++++++++++++++++------- src/x64/fast-codegen-x64.cc | 24 ++++++++++++++++++------ test/mjsunit/compiler/function-call.js | 4 ++++ 5 files changed, 75 insertions(+), 20 deletions(-) diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc index 99f5557..2bf2659 100644 --- a/src/arm/fast-codegen-arm.cc +++ b/src/arm/fast-codegen-arm.cc @@ -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); } } diff --git a/src/compiler.cc b/src/compiler.cc index 86bf160..2526ad7 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -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++) { diff --git a/src/ia32/fast-codegen-ia32.cc b/src/ia32/fast-codegen-ia32.cc index 851f733..a234ae1 100644 --- a/src/ia32/fast-codegen-ia32.cc +++ b/src/ia32/fast-codegen-ia32.cc @@ -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); } } diff --git a/src/x64/fast-codegen-x64.cc b/src/x64/fast-codegen-x64.cc index 5592d08..b4c75ab 100644 --- a/src/x64/fast-codegen-x64.cc +++ b/src/x64/fast-codegen-x64.cc @@ -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); } } diff --git a/test/mjsunit/compiler/function-call.js b/test/mjsunit/compiler/function-call.js index 2bca509..b2e0702 100644 --- a/test/mjsunit/compiler/function-call.js +++ b/test/mjsunit/compiler/function-call.js @@ -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); -- 2.7.4