Remove CallEval as a subclass of the Call AST node type. We were not
differentiating between Call and CallEval except in the code generator, and the difference can be detected from a regular Call AST node at code generation time. Review URL: http://codereview.chromium.org/245042 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2984 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
6f83ad58cc
commit
928bfae405
@ -2907,11 +2907,11 @@ void CodeGenerator::VisitCall(Call* node) {
|
||||
VirtualFrame::SpilledScope spilled_scope;
|
||||
Comment cmnt(masm_, "[ Call");
|
||||
|
||||
Expression* function = node->expression();
|
||||
ZoneList<Expression*>* args = node->arguments();
|
||||
|
||||
// Standard function call.
|
||||
// Check if the function is a variable or a property.
|
||||
Expression* function = node->expression();
|
||||
Variable* var = function->AsVariableProxy()->AsVariable();
|
||||
Property* property = function->AsProperty();
|
||||
|
||||
@ -2924,7 +2924,56 @@ void CodeGenerator::VisitCall(Call* node) {
|
||||
// is resolved in cache misses (this also holds for megamorphic calls).
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (var != NULL && !var->is_this() && var->is_global()) {
|
||||
if (var != NULL && var->is_possibly_eval()) {
|
||||
// ----------------------------------
|
||||
// JavaScript example: 'eval(arg)' // eval is not known to be shadowed
|
||||
// ----------------------------------
|
||||
|
||||
// In a call to eval, we first call %ResolvePossiblyDirectEval to
|
||||
// resolve the function we need to call and the receiver of the
|
||||
// call. Then we call the resolved function using the given
|
||||
// arguments.
|
||||
// Prepare stack for call to resolved function.
|
||||
LoadAndSpill(function);
|
||||
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
frame_->EmitPush(r2); // Slot for receiver
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
LoadAndSpill(args->at(i));
|
||||
}
|
||||
|
||||
// Prepare stack for call to ResolvePossiblyDirectEval.
|
||||
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize + kPointerSize));
|
||||
frame_->EmitPush(r1);
|
||||
if (arg_count > 0) {
|
||||
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
|
||||
frame_->EmitPush(r1);
|
||||
} else {
|
||||
frame_->EmitPush(r2);
|
||||
}
|
||||
|
||||
// Resolve the call.
|
||||
frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
|
||||
|
||||
// Touch up stack with the right values for the function and the receiver.
|
||||
__ ldr(r1, FieldMemOperand(r0, FixedArray::kHeaderSize));
|
||||
__ str(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
|
||||
__ ldr(r1, FieldMemOperand(r0, FixedArray::kHeaderSize + kPointerSize));
|
||||
__ str(r1, MemOperand(sp, arg_count * kPointerSize));
|
||||
|
||||
// Call the function.
|
||||
CodeForSourcePosition(node->position());
|
||||
|
||||
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub call_function(arg_count, in_loop);
|
||||
frame_->CallStub(&call_function, arg_count + 1);
|
||||
|
||||
__ ldr(cp, frame_->Context());
|
||||
// Remove the function from the stack.
|
||||
frame_->Drop();
|
||||
frame_->EmitPush(r0);
|
||||
|
||||
} else if (var != NULL && !var->is_this() && var->is_global()) {
|
||||
// ----------------------------------
|
||||
// JavaScript example: 'foo(1, 2, 3)' // foo is global
|
||||
// ----------------------------------
|
||||
@ -3049,63 +3098,6 @@ void CodeGenerator::VisitCall(Call* node) {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::VisitCallEval(CallEval* node) {
|
||||
#ifdef DEBUG
|
||||
int original_height = frame_->height();
|
||||
#endif
|
||||
VirtualFrame::SpilledScope spilled_scope;
|
||||
Comment cmnt(masm_, "[ CallEval");
|
||||
|
||||
// In a call to eval, we first call %ResolvePossiblyDirectEval to resolve
|
||||
// the function we need to call and the receiver of the call.
|
||||
// Then we call the resolved function using the given arguments.
|
||||
|
||||
ZoneList<Expression*>* args = node->arguments();
|
||||
Expression* function = node->expression();
|
||||
|
||||
// Prepare stack for call to resolved function.
|
||||
LoadAndSpill(function);
|
||||
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
frame_->EmitPush(r2); // Slot for receiver
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
LoadAndSpill(args->at(i));
|
||||
}
|
||||
|
||||
// Prepare stack for call to ResolvePossiblyDirectEval.
|
||||
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize + kPointerSize));
|
||||
frame_->EmitPush(r1);
|
||||
if (arg_count > 0) {
|
||||
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
|
||||
frame_->EmitPush(r1);
|
||||
} else {
|
||||
frame_->EmitPush(r2);
|
||||
}
|
||||
|
||||
// Resolve the call.
|
||||
frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
|
||||
|
||||
// Touch up stack with the right values for the function and the receiver.
|
||||
__ ldr(r1, FieldMemOperand(r0, FixedArray::kHeaderSize));
|
||||
__ str(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
|
||||
__ ldr(r1, FieldMemOperand(r0, FixedArray::kHeaderSize + kPointerSize));
|
||||
__ str(r1, MemOperand(sp, arg_count * kPointerSize));
|
||||
|
||||
// Call the function.
|
||||
CodeForSourcePosition(node->position());
|
||||
|
||||
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub call_function(arg_count, in_loop);
|
||||
frame_->CallStub(&call_function, arg_count + 1);
|
||||
|
||||
__ ldr(cp, frame_->Context());
|
||||
// Remove the function from the stack.
|
||||
frame_->Drop();
|
||||
frame_->EmitPush(r0);
|
||||
ASSERT(frame_->height() == original_height + 1);
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::VisitCallNew(CallNew* node) {
|
||||
#ifdef DEBUG
|
||||
int original_height = frame_->height();
|
||||
|
@ -40,7 +40,6 @@ VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
|
||||
ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
|
||||
Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
|
||||
Call Call::sentinel_(NULL, NULL, 0);
|
||||
CallEval CallEval::sentinel_(NULL, NULL, 0);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
19
src/ast.h
19
src/ast.h
@ -85,7 +85,6 @@ namespace internal {
|
||||
V(Throw) \
|
||||
V(Property) \
|
||||
V(Call) \
|
||||
V(CallEval) \
|
||||
V(CallNew) \
|
||||
V(CallRuntime) \
|
||||
V(UnaryOperation) \
|
||||
@ -991,24 +990,6 @@ class CallNew: public Call {
|
||||
};
|
||||
|
||||
|
||||
// The CallEval class represents a call of the form 'eval(...)' where eval
|
||||
// cannot be seen to be overwritten at compile time. It is potentially a
|
||||
// direct (i.e. not aliased) eval call. The real nature of the call is
|
||||
// determined at runtime.
|
||||
class CallEval: public Call {
|
||||
public:
|
||||
CallEval(Expression* expression, ZoneList<Expression*>* arguments, int pos)
|
||||
: Call(expression, arguments, pos) { }
|
||||
|
||||
virtual void Accept(AstVisitor* v);
|
||||
|
||||
static CallEval* sentinel() { return &sentinel_; }
|
||||
|
||||
private:
|
||||
static CallEval sentinel_;
|
||||
};
|
||||
|
||||
|
||||
// The CallRuntime class does not represent any official JavaScript
|
||||
// language construct. Instead it is used to call a C or JS function
|
||||
// with a set of arguments. This is used from the builtins that are
|
||||
|
@ -398,11 +398,6 @@ void ExpressionCfgBuilder::VisitCall(Call* expr) {
|
||||
}
|
||||
|
||||
|
||||
void ExpressionCfgBuilder::VisitCallEval(CallEval* expr) {
|
||||
BAILOUT("CallEval");
|
||||
}
|
||||
|
||||
|
||||
void ExpressionCfgBuilder::VisitCallNew(CallNew* expr) {
|
||||
BAILOUT("CallNew");
|
||||
}
|
||||
|
@ -4431,10 +4431,10 @@ void CodeGenerator::VisitProperty(Property* node) {
|
||||
void CodeGenerator::VisitCall(Call* node) {
|
||||
Comment cmnt(masm_, "[ Call");
|
||||
|
||||
Expression* function = node->expression();
|
||||
ZoneList<Expression*>* args = node->arguments();
|
||||
|
||||
// Check if the function is a variable or a property.
|
||||
Expression* function = node->expression();
|
||||
Variable* var = function->AsVariableProxy()->AsVariable();
|
||||
Property* property = function->AsProperty();
|
||||
|
||||
@ -4447,7 +4447,63 @@ void CodeGenerator::VisitCall(Call* node) {
|
||||
// is resolved in cache misses (this also holds for megamorphic calls).
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (var != NULL && !var->is_this() && var->is_global()) {
|
||||
if (var != NULL && var->is_possibly_eval()) {
|
||||
// ----------------------------------
|
||||
// JavaScript example: 'eval(arg)' // eval is not known to be shadowed
|
||||
// ----------------------------------
|
||||
|
||||
// In a call to eval, we first call %ResolvePossiblyDirectEval to
|
||||
// resolve the function we need to call and the receiver of the
|
||||
// call. Then we call the resolved function using the given
|
||||
// arguments.
|
||||
|
||||
// Prepare the stack for the call to the resolved function.
|
||||
Load(function);
|
||||
|
||||
// Allocate a frame slot for the receiver.
|
||||
frame_->Push(Factory::undefined_value());
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
Load(args->at(i));
|
||||
}
|
||||
|
||||
// Prepare the stack for the call to ResolvePossiblyDirectEval.
|
||||
frame_->PushElementAt(arg_count + 1);
|
||||
if (arg_count > 0) {
|
||||
frame_->PushElementAt(arg_count);
|
||||
} else {
|
||||
frame_->Push(Factory::undefined_value());
|
||||
}
|
||||
|
||||
// Resolve the call.
|
||||
Result result =
|
||||
frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
|
||||
|
||||
// Touch up the stack with the right values for the function and the
|
||||
// receiver. Use a scratch register to avoid destroying the result.
|
||||
Result scratch = allocator_->Allocate();
|
||||
ASSERT(scratch.is_valid());
|
||||
__ mov(scratch.reg(), FieldOperand(result.reg(), FixedArray::kHeaderSize));
|
||||
frame_->SetElementAt(arg_count + 1, &scratch);
|
||||
|
||||
// We can reuse the result register now.
|
||||
frame_->Spill(result.reg());
|
||||
__ mov(result.reg(),
|
||||
FieldOperand(result.reg(), FixedArray::kHeaderSize + kPointerSize));
|
||||
frame_->SetElementAt(arg_count, &result);
|
||||
|
||||
// Call the function.
|
||||
CodeForSourcePosition(node->position());
|
||||
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub call_function(arg_count, in_loop);
|
||||
result = frame_->CallStub(&call_function, arg_count + 1);
|
||||
|
||||
// Restore the context and overwrite the function on the stack with
|
||||
// the result.
|
||||
frame_->RestoreContextRegister();
|
||||
frame_->SetElementAt(0, &result);
|
||||
|
||||
} else if (var != NULL && !var->is_this() && var->is_global()) {
|
||||
// ----------------------------------
|
||||
// JavaScript example: 'foo(1, 2, 3)' // foo is global
|
||||
// ----------------------------------
|
||||
@ -4616,64 +4672,6 @@ void CodeGenerator::VisitCallNew(CallNew* node) {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::VisitCallEval(CallEval* node) {
|
||||
Comment cmnt(masm_, "[ CallEval");
|
||||
|
||||
// In a call to eval, we first call %ResolvePossiblyDirectEval to resolve
|
||||
// the function we need to call and the receiver of the call.
|
||||
// Then we call the resolved function using the given arguments.
|
||||
|
||||
ZoneList<Expression*>* args = node->arguments();
|
||||
Expression* function = node->expression();
|
||||
|
||||
// Prepare the stack for the call to the resolved function.
|
||||
Load(function);
|
||||
|
||||
// Allocate a frame slot for the receiver.
|
||||
frame_->Push(Factory::undefined_value());
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
Load(args->at(i));
|
||||
}
|
||||
|
||||
// Prepare the stack for the call to ResolvePossiblyDirectEval.
|
||||
frame_->PushElementAt(arg_count + 1);
|
||||
if (arg_count > 0) {
|
||||
frame_->PushElementAt(arg_count);
|
||||
} else {
|
||||
frame_->Push(Factory::undefined_value());
|
||||
}
|
||||
|
||||
// Resolve the call.
|
||||
Result result =
|
||||
frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
|
||||
|
||||
// Touch up the stack with the right values for the function and the
|
||||
// receiver. Use a scratch register to avoid destroying the result.
|
||||
Result scratch = allocator_->Allocate();
|
||||
ASSERT(scratch.is_valid());
|
||||
__ mov(scratch.reg(), FieldOperand(result.reg(), FixedArray::kHeaderSize));
|
||||
frame_->SetElementAt(arg_count + 1, &scratch);
|
||||
|
||||
// We can reuse the result register now.
|
||||
frame_->Spill(result.reg());
|
||||
__ mov(result.reg(),
|
||||
FieldOperand(result.reg(), FixedArray::kHeaderSize + kPointerSize));
|
||||
frame_->SetElementAt(arg_count, &result);
|
||||
|
||||
// Call the function.
|
||||
CodeForSourcePosition(node->position());
|
||||
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub call_function(arg_count, in_loop);
|
||||
result = frame_->CallStub(&call_function, arg_count + 1);
|
||||
|
||||
// Restore the context and overwrite the function on the stack with
|
||||
// the result.
|
||||
frame_->RestoreContextRegister();
|
||||
frame_->SetElementAt(0, &result);
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
Load(args->at(0));
|
||||
|
@ -798,12 +798,6 @@ class ParserFactory BASE_EMBEDDED {
|
||||
return Call::sentinel();
|
||||
}
|
||||
|
||||
virtual Expression* NewCallEval(Expression* expression,
|
||||
ZoneList<Expression*>* arguments,
|
||||
int pos) {
|
||||
return CallEval::sentinel();
|
||||
}
|
||||
|
||||
virtual Statement* EmptyStatement() {
|
||||
return NULL;
|
||||
}
|
||||
@ -854,12 +848,6 @@ class AstBuildingParserFactory : public ParserFactory {
|
||||
return new Call(expression, arguments, pos);
|
||||
}
|
||||
|
||||
virtual Expression* NewCallEval(Expression* expression,
|
||||
ZoneList<Expression*>* arguments,
|
||||
int pos) {
|
||||
return new CallEval(expression, arguments, pos);
|
||||
}
|
||||
|
||||
virtual Statement* EmptyStatement();
|
||||
};
|
||||
|
||||
@ -3074,8 +3062,6 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
||||
// declared in the current scope chain. These calls are marked as
|
||||
// potentially direct eval calls. Whether they are actually direct calls
|
||||
// to eval is determined at run time.
|
||||
|
||||
bool is_potentially_direct_eval = false;
|
||||
if (!is_pre_parsing_) {
|
||||
VariableProxy* callee = result->AsVariableProxy();
|
||||
if (callee != NULL && callee->IsVariable(Factory::eval_symbol())) {
|
||||
@ -3083,16 +3069,10 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
||||
Variable* var = top_scope_->Lookup(name);
|
||||
if (var == NULL) {
|
||||
top_scope_->RecordEvalCall();
|
||||
is_potentially_direct_eval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_potentially_direct_eval) {
|
||||
result = factory()->NewCallEval(result, args, pos);
|
||||
} else {
|
||||
result = factory()->NewCall(result, args, pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -358,11 +358,6 @@ void PrettyPrinter::VisitCall(Call* node) {
|
||||
}
|
||||
|
||||
|
||||
void PrettyPrinter::VisitCallEval(CallEval* node) {
|
||||
VisitCall(node);
|
||||
}
|
||||
|
||||
|
||||
void PrettyPrinter::VisitCallNew(CallNew* node) {
|
||||
Print("new (");
|
||||
Visit(node->expression());
|
||||
@ -1040,11 +1035,6 @@ void AstPrinter::VisitCall(Call* node) {
|
||||
}
|
||||
|
||||
|
||||
void AstPrinter::VisitCallEval(CallEval* node) {
|
||||
VisitCall(node);
|
||||
}
|
||||
|
||||
|
||||
void AstPrinter::VisitCallNew(CallNew* node) {
|
||||
IndentedScope indent("CALL NEW");
|
||||
Visit(node->expression());
|
||||
|
@ -383,12 +383,6 @@ void AstOptimizer::VisitCall(Call* node) {
|
||||
}
|
||||
|
||||
|
||||
void AstOptimizer::VisitCallEval(CallEval* node) {
|
||||
Visit(node->expression());
|
||||
OptimizeArguments(node->arguments());
|
||||
}
|
||||
|
||||
|
||||
void AstOptimizer::VisitCallNew(CallNew* node) {
|
||||
Visit(node->expression());
|
||||
OptimizeArguments(node->arguments());
|
||||
@ -759,12 +753,6 @@ void Processor::VisitCall(Call* node) {
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitCallEval(CallEval* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Processor::VisitCallNew(CallNew* node) {
|
||||
USE(node);
|
||||
UNREACHABLE();
|
||||
|
@ -75,7 +75,6 @@ class UsageComputer: public AstVisitor {
|
||||
void VisitThrow(Throw* node);
|
||||
void VisitProperty(Property* node);
|
||||
void VisitCall(Call* node);
|
||||
void VisitCallEval(CallEval* node);
|
||||
void VisitCallNew(CallNew* node);
|
||||
void VisitCallRuntime(CallRuntime* node);
|
||||
void VisitUnaryOperation(UnaryOperation* node);
|
||||
@ -329,11 +328,6 @@ void UsageComputer::VisitCall(Call* node) {
|
||||
}
|
||||
|
||||
|
||||
void UsageComputer::VisitCallEval(CallEval* node) {
|
||||
VisitCall(node);
|
||||
}
|
||||
|
||||
|
||||
void UsageComputer::VisitCallNew(CallNew* node) {
|
||||
VisitCall(node);
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ class Variable: public ZoneObject {
|
||||
UseCount* var_uses() { return &var_uses_; }
|
||||
UseCount* obj_uses() { return &obj_uses_; }
|
||||
|
||||
bool IsVariable(Handle<String> n) {
|
||||
bool IsVariable(Handle<String> n) const {
|
||||
return !is_this() && name().is_identical_to(n);
|
||||
}
|
||||
|
||||
@ -185,6 +185,12 @@ class Variable: public ZoneObject {
|
||||
bool is_this() const { return kind_ == THIS; }
|
||||
bool is_arguments() const { return kind_ == ARGUMENTS; }
|
||||
|
||||
// True if the variable is named eval and not known to be shadowed.
|
||||
bool is_possibly_eval() const {
|
||||
return IsVariable(Factory::eval_symbol()) &&
|
||||
(mode_ == DYNAMIC || mode_ == DYNAMIC_GLOBAL);
|
||||
}
|
||||
|
||||
Variable* local_if_not_shadowed() const {
|
||||
ASSERT(mode_ == DYNAMIC_LOCAL && local_if_not_shadowed_ != NULL);
|
||||
return local_if_not_shadowed_;
|
||||
|
@ -2704,7 +2704,64 @@ void CodeGenerator::VisitCall(Call* node) {
|
||||
// is resolved in cache misses (this also holds for megamorphic calls).
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (var != NULL && !var->is_this() && var->is_global()) {
|
||||
if (var != NULL && var->is_possibly_eval()) {
|
||||
// ----------------------------------
|
||||
// JavaScript example: 'eval(arg)' // eval is not known to be shadowed
|
||||
// ----------------------------------
|
||||
|
||||
// In a call to eval, we first call %ResolvePossiblyDirectEval to
|
||||
// resolve the function we need to call and the receiver of the
|
||||
// call. Then we call the resolved function using the given
|
||||
// arguments.
|
||||
|
||||
// Prepare the stack for the call to the resolved function.
|
||||
Load(function);
|
||||
|
||||
// Allocate a frame slot for the receiver.
|
||||
frame_->Push(Factory::undefined_value());
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
Load(args->at(i));
|
||||
}
|
||||
|
||||
// Prepare the stack for the call to ResolvePossiblyDirectEval.
|
||||
frame_->PushElementAt(arg_count + 1);
|
||||
if (arg_count > 0) {
|
||||
frame_->PushElementAt(arg_count);
|
||||
} else {
|
||||
frame_->Push(Factory::undefined_value());
|
||||
}
|
||||
|
||||
// Resolve the call.
|
||||
Result result =
|
||||
frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
|
||||
|
||||
// Touch up the stack with the right values for the function and the
|
||||
// receiver. Use a scratch register to avoid destroying the result.
|
||||
Result scratch = allocator_->Allocate();
|
||||
ASSERT(scratch.is_valid());
|
||||
__ movq(scratch.reg(),
|
||||
FieldOperand(result.reg(), FixedArray::OffsetOfElementAt(0)));
|
||||
frame_->SetElementAt(arg_count + 1, &scratch);
|
||||
|
||||
// We can reuse the result register now.
|
||||
frame_->Spill(result.reg());
|
||||
__ movq(result.reg(),
|
||||
FieldOperand(result.reg(), FixedArray::OffsetOfElementAt(1)));
|
||||
frame_->SetElementAt(arg_count, &result);
|
||||
|
||||
// Call the function.
|
||||
CodeForSourcePosition(node->position());
|
||||
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub call_function(arg_count, in_loop);
|
||||
result = frame_->CallStub(&call_function, arg_count + 1);
|
||||
|
||||
// Restore the context and overwrite the function on the stack with
|
||||
// the result.
|
||||
frame_->RestoreContextRegister();
|
||||
frame_->SetElementAt(0, &result);
|
||||
|
||||
} else if (var != NULL && !var->is_this() && var->is_global()) {
|
||||
// ----------------------------------
|
||||
// JavaScript example: 'foo(1, 2, 3)' // foo is global
|
||||
// ----------------------------------
|
||||
@ -2731,6 +2788,7 @@ void CodeGenerator::VisitCall(Call* node) {
|
||||
frame_->RestoreContextRegister();
|
||||
// Replace the function on the stack with the result.
|
||||
frame_->SetElementAt(0, &result);
|
||||
|
||||
} else if (var != NULL && var->slot() != NULL &&
|
||||
var->slot()->type() == Slot::LOOKUP) {
|
||||
// ----------------------------------
|
||||
@ -2757,6 +2815,7 @@ void CodeGenerator::VisitCall(Call* node) {
|
||||
|
||||
// Call the function.
|
||||
CallWithArguments(args, node->position());
|
||||
|
||||
} else if (property != NULL) {
|
||||
// Check if the key is a literal string.
|
||||
Literal* literal = property->key()->AsLiteral();
|
||||
@ -2822,6 +2881,7 @@ void CodeGenerator::VisitCall(Call* node) {
|
||||
// Call the function.
|
||||
CallWithArguments(args, node->position());
|
||||
}
|
||||
|
||||
} else {
|
||||
// ----------------------------------
|
||||
// JavaScript example: 'foo(1, 2, 3)' // foo is not global
|
||||
@ -2839,65 +2899,6 @@ void CodeGenerator::VisitCall(Call* node) {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::VisitCallEval(CallEval* node) {
|
||||
Comment cmnt(masm_, "[ CallEval");
|
||||
|
||||
// In a call to eval, we first call %ResolvePossiblyDirectEval to resolve
|
||||
// the function we need to call and the receiver of the call.
|
||||
// Then we call the resolved function using the given arguments.
|
||||
|
||||
ZoneList<Expression*>* args = node->arguments();
|
||||
Expression* function = node->expression();
|
||||
|
||||
// Prepare the stack for the call to the resolved function.
|
||||
Load(function);
|
||||
|
||||
// Allocate a frame slot for the receiver.
|
||||
frame_->Push(Factory::undefined_value());
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
Load(args->at(i));
|
||||
}
|
||||
|
||||
// Prepare the stack for the call to ResolvePossiblyDirectEval.
|
||||
frame_->PushElementAt(arg_count + 1);
|
||||
if (arg_count > 0) {
|
||||
frame_->PushElementAt(arg_count);
|
||||
} else {
|
||||
frame_->Push(Factory::undefined_value());
|
||||
}
|
||||
|
||||
// Resolve the call.
|
||||
Result result =
|
||||
frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
|
||||
|
||||
// Touch up the stack with the right values for the function and the
|
||||
// receiver. Use a scratch register to avoid destroying the result.
|
||||
Result scratch = allocator_->Allocate();
|
||||
ASSERT(scratch.is_valid());
|
||||
__ movq(scratch.reg(),
|
||||
FieldOperand(result.reg(), FixedArray::OffsetOfElementAt(0)));
|
||||
frame_->SetElementAt(arg_count + 1, &scratch);
|
||||
|
||||
// We can reuse the result register now.
|
||||
frame_->Spill(result.reg());
|
||||
__ movq(result.reg(),
|
||||
FieldOperand(result.reg(), FixedArray::OffsetOfElementAt(1)));
|
||||
frame_->SetElementAt(arg_count, &result);
|
||||
|
||||
// Call the function.
|
||||
CodeForSourcePosition(node->position());
|
||||
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub call_function(arg_count, in_loop);
|
||||
result = frame_->CallStub(&call_function, arg_count + 1);
|
||||
|
||||
// Restore the context and overwrite the function on the stack with
|
||||
// the result.
|
||||
frame_->RestoreContextRegister();
|
||||
frame_->SetElementAt(0, &result);
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::VisitCallNew(CallNew* node) {
|
||||
Comment cmnt(masm_, "[ CallNew");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user