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;
|
VirtualFrame::SpilledScope spilled_scope;
|
||||||
Comment cmnt(masm_, "[ Call");
|
Comment cmnt(masm_, "[ Call");
|
||||||
|
|
||||||
|
Expression* function = node->expression();
|
||||||
ZoneList<Expression*>* args = node->arguments();
|
ZoneList<Expression*>* args = node->arguments();
|
||||||
|
|
||||||
// Standard function call.
|
// Standard function call.
|
||||||
// Check if the function is a variable or a property.
|
// Check if the function is a variable or a property.
|
||||||
Expression* function = node->expression();
|
|
||||||
Variable* var = function->AsVariableProxy()->AsVariable();
|
Variable* var = function->AsVariableProxy()->AsVariable();
|
||||||
Property* property = function->AsProperty();
|
Property* property = function->AsProperty();
|
||||||
|
|
||||||
@ -2924,7 +2924,56 @@ void CodeGenerator::VisitCall(Call* node) {
|
|||||||
// is resolved in cache misses (this also holds for megamorphic calls).
|
// 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
|
// 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) {
|
void CodeGenerator::VisitCallNew(CallNew* node) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
int original_height = frame_->height();
|
int original_height = frame_->height();
|
||||||
|
@ -40,7 +40,6 @@ VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
|
|||||||
ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
|
ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
|
||||||
Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
|
Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
|
||||||
Call Call::sentinel_(NULL, 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(Throw) \
|
||||||
V(Property) \
|
V(Property) \
|
||||||
V(Call) \
|
V(Call) \
|
||||||
V(CallEval) \
|
|
||||||
V(CallNew) \
|
V(CallNew) \
|
||||||
V(CallRuntime) \
|
V(CallRuntime) \
|
||||||
V(UnaryOperation) \
|
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
|
// The CallRuntime class does not represent any official JavaScript
|
||||||
// language construct. Instead it is used to call a C or JS function
|
// 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
|
// 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) {
|
void ExpressionCfgBuilder::VisitCallNew(CallNew* expr) {
|
||||||
BAILOUT("CallNew");
|
BAILOUT("CallNew");
|
||||||
}
|
}
|
||||||
|
@ -4431,10 +4431,10 @@ void CodeGenerator::VisitProperty(Property* node) {
|
|||||||
void CodeGenerator::VisitCall(Call* node) {
|
void CodeGenerator::VisitCall(Call* node) {
|
||||||
Comment cmnt(masm_, "[ Call");
|
Comment cmnt(masm_, "[ Call");
|
||||||
|
|
||||||
|
Expression* function = node->expression();
|
||||||
ZoneList<Expression*>* args = node->arguments();
|
ZoneList<Expression*>* args = node->arguments();
|
||||||
|
|
||||||
// Check if the function is a variable or a property.
|
// Check if the function is a variable or a property.
|
||||||
Expression* function = node->expression();
|
|
||||||
Variable* var = function->AsVariableProxy()->AsVariable();
|
Variable* var = function->AsVariableProxy()->AsVariable();
|
||||||
Property* property = function->AsProperty();
|
Property* property = function->AsProperty();
|
||||||
|
|
||||||
@ -4447,7 +4447,63 @@ void CodeGenerator::VisitCall(Call* node) {
|
|||||||
// is resolved in cache misses (this also holds for megamorphic calls).
|
// 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
|
// 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) {
|
void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
|
||||||
ASSERT(args->length() == 1);
|
ASSERT(args->length() == 1);
|
||||||
Load(args->at(0));
|
Load(args->at(0));
|
||||||
|
@ -798,12 +798,6 @@ class ParserFactory BASE_EMBEDDED {
|
|||||||
return Call::sentinel();
|
return Call::sentinel();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Expression* NewCallEval(Expression* expression,
|
|
||||||
ZoneList<Expression*>* arguments,
|
|
||||||
int pos) {
|
|
||||||
return CallEval::sentinel();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Statement* EmptyStatement() {
|
virtual Statement* EmptyStatement() {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -854,12 +848,6 @@ class AstBuildingParserFactory : public ParserFactory {
|
|||||||
return new Call(expression, arguments, pos);
|
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();
|
virtual Statement* EmptyStatement();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3074,8 +3062,6 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
|||||||
// declared in the current scope chain. These calls are marked as
|
// declared in the current scope chain. These calls are marked as
|
||||||
// potentially direct eval calls. Whether they are actually direct calls
|
// potentially direct eval calls. Whether they are actually direct calls
|
||||||
// to eval is determined at run time.
|
// to eval is determined at run time.
|
||||||
|
|
||||||
bool is_potentially_direct_eval = false;
|
|
||||||
if (!is_pre_parsing_) {
|
if (!is_pre_parsing_) {
|
||||||
VariableProxy* callee = result->AsVariableProxy();
|
VariableProxy* callee = result->AsVariableProxy();
|
||||||
if (callee != NULL && callee->IsVariable(Factory::eval_symbol())) {
|
if (callee != NULL && callee->IsVariable(Factory::eval_symbol())) {
|
||||||
@ -3083,16 +3069,10 @@ Expression* Parser::ParseLeftHandSideExpression(bool* ok) {
|
|||||||
Variable* var = top_scope_->Lookup(name);
|
Variable* var = top_scope_->Lookup(name);
|
||||||
if (var == NULL) {
|
if (var == NULL) {
|
||||||
top_scope_->RecordEvalCall();
|
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);
|
result = factory()->NewCall(result, args, pos);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,11 +358,6 @@ void PrettyPrinter::VisitCall(Call* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PrettyPrinter::VisitCallEval(CallEval* node) {
|
|
||||||
VisitCall(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void PrettyPrinter::VisitCallNew(CallNew* node) {
|
void PrettyPrinter::VisitCallNew(CallNew* node) {
|
||||||
Print("new (");
|
Print("new (");
|
||||||
Visit(node->expression());
|
Visit(node->expression());
|
||||||
@ -1040,11 +1035,6 @@ void AstPrinter::VisitCall(Call* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AstPrinter::VisitCallEval(CallEval* node) {
|
|
||||||
VisitCall(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AstPrinter::VisitCallNew(CallNew* node) {
|
void AstPrinter::VisitCallNew(CallNew* node) {
|
||||||
IndentedScope indent("CALL NEW");
|
IndentedScope indent("CALL NEW");
|
||||||
Visit(node->expression());
|
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) {
|
void AstOptimizer::VisitCallNew(CallNew* node) {
|
||||||
Visit(node->expression());
|
Visit(node->expression());
|
||||||
OptimizeArguments(node->arguments());
|
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) {
|
void Processor::VisitCallNew(CallNew* node) {
|
||||||
USE(node);
|
USE(node);
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -75,7 +75,6 @@ class UsageComputer: public AstVisitor {
|
|||||||
void VisitThrow(Throw* node);
|
void VisitThrow(Throw* node);
|
||||||
void VisitProperty(Property* node);
|
void VisitProperty(Property* node);
|
||||||
void VisitCall(Call* node);
|
void VisitCall(Call* node);
|
||||||
void VisitCallEval(CallEval* node);
|
|
||||||
void VisitCallNew(CallNew* node);
|
void VisitCallNew(CallNew* node);
|
||||||
void VisitCallRuntime(CallRuntime* node);
|
void VisitCallRuntime(CallRuntime* node);
|
||||||
void VisitUnaryOperation(UnaryOperation* 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) {
|
void UsageComputer::VisitCallNew(CallNew* node) {
|
||||||
VisitCall(node);
|
VisitCall(node);
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ class Variable: public ZoneObject {
|
|||||||
UseCount* var_uses() { return &var_uses_; }
|
UseCount* var_uses() { return &var_uses_; }
|
||||||
UseCount* obj_uses() { return &obj_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);
|
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_this() const { return kind_ == THIS; }
|
||||||
bool is_arguments() const { return kind_ == ARGUMENTS; }
|
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 {
|
Variable* local_if_not_shadowed() const {
|
||||||
ASSERT(mode_ == DYNAMIC_LOCAL && local_if_not_shadowed_ != NULL);
|
ASSERT(mode_ == DYNAMIC_LOCAL && local_if_not_shadowed_ != NULL);
|
||||||
return local_if_not_shadowed_;
|
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).
|
// 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
|
// JavaScript example: 'foo(1, 2, 3)' // foo is global
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
@ -2731,6 +2788,7 @@ void CodeGenerator::VisitCall(Call* node) {
|
|||||||
frame_->RestoreContextRegister();
|
frame_->RestoreContextRegister();
|
||||||
// Replace the function on the stack with the result.
|
// Replace the function on the stack with the result.
|
||||||
frame_->SetElementAt(0, &result);
|
frame_->SetElementAt(0, &result);
|
||||||
|
|
||||||
} else if (var != NULL && var->slot() != NULL &&
|
} else if (var != NULL && var->slot() != NULL &&
|
||||||
var->slot()->type() == Slot::LOOKUP) {
|
var->slot()->type() == Slot::LOOKUP) {
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
@ -2757,6 +2815,7 @@ void CodeGenerator::VisitCall(Call* node) {
|
|||||||
|
|
||||||
// Call the function.
|
// Call the function.
|
||||||
CallWithArguments(args, node->position());
|
CallWithArguments(args, node->position());
|
||||||
|
|
||||||
} else if (property != NULL) {
|
} else if (property != NULL) {
|
||||||
// Check if the key is a literal string.
|
// Check if the key is a literal string.
|
||||||
Literal* literal = property->key()->AsLiteral();
|
Literal* literal = property->key()->AsLiteral();
|
||||||
@ -2822,6 +2881,7 @@ void CodeGenerator::VisitCall(Call* node) {
|
|||||||
// Call the function.
|
// Call the function.
|
||||||
CallWithArguments(args, node->position());
|
CallWithArguments(args, node->position());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// JavaScript example: 'foo(1, 2, 3)' // foo is not global
|
// 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) {
|
void CodeGenerator::VisitCallNew(CallNew* node) {
|
||||||
Comment cmnt(masm_, "[ CallNew");
|
Comment cmnt(masm_, "[ CallNew");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user