In the toplevel compiler, shift the responsibility of assigning a
location to an Expression AST node from the node's parent to the node itself. This allows an inherited code generation context from a parent node to be passed arbitrarily far down the tree (eg, the subexpression of a unary not is in the same context as the unary expression itself, the then and else subexpressions of the ternary operator are in the same context as the whole expression, and so forth). We do not yet take advantage of this in the backend (eg, the right subexpression of short-circuited OR is still compiled by using the parent's destination location, rather than the subexpression's itself). Review URL: http://codereview.chromium.org/340005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3163 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
6768703d24
commit
6a83cb0ced
@ -275,13 +275,10 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
|
|
||||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
for (int i = 0; i < expr->properties()->length(); i++) {
|
||||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
ObjectLiteral::Property* property = expr->properties()->at(i);
|
||||||
|
if (property->IsCompileTimeValue()) continue;
|
||||||
|
|
||||||
Literal* key = property->key();
|
Literal* key = property->key();
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
if (property->kind() == ObjectLiteral::Property::CONSTANT) continue;
|
|
||||||
if (property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
|
|
||||||
CompileTimeValue::IsCompileTimeValue(value)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!result_saved) {
|
if (!result_saved) {
|
||||||
__ push(r0); // Save result on stack
|
__ push(r0); // Save result on stack
|
||||||
result_saved = true;
|
result_saved = true;
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "v8.h"
|
#include "v8.h"
|
||||||
|
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
|
#include "parser.h"
|
||||||
#include "scopes.h"
|
#include "scopes.h"
|
||||||
#include "string-stream.h"
|
#include "string-stream.h"
|
||||||
|
|
||||||
@ -138,6 +139,13 @@ ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ObjectLiteral::Property::IsCompileTimeValue() {
|
||||||
|
return kind_ == CONSTANT ||
|
||||||
|
(kind_ == MATERIALIZED_LITERAL &&
|
||||||
|
CompileTimeValue::IsCompileTimeValue(value_));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ObjectLiteral::IsValidJSON() {
|
bool ObjectLiteral::IsValidJSON() {
|
||||||
int length = properties()->length();
|
int length = properties()->length();
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
|
@ -747,6 +747,8 @@ class ObjectLiteral: public MaterializedLiteral {
|
|||||||
Expression* value() { return value_; }
|
Expression* value() { return value_; }
|
||||||
Kind kind() { return kind_; }
|
Kind kind() { return kind_; }
|
||||||
|
|
||||||
|
bool IsCompileTimeValue();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Literal* key_;
|
Literal* key_;
|
||||||
Expression* value_;
|
Expression* value_;
|
||||||
|
149
src/compiler.cc
149
src/compiler.cc
@ -46,7 +46,10 @@ class CodeGenSelector: public AstVisitor {
|
|||||||
public:
|
public:
|
||||||
enum CodeGenTag { NORMAL, FAST };
|
enum CodeGenTag { NORMAL, FAST };
|
||||||
|
|
||||||
CodeGenSelector() : has_supported_syntax_(true) {}
|
CodeGenSelector()
|
||||||
|
: has_supported_syntax_(true),
|
||||||
|
location_(Location::Nowhere()) {
|
||||||
|
}
|
||||||
|
|
||||||
CodeGenTag Select(FunctionLiteral* fun);
|
CodeGenTag Select(FunctionLiteral* fun);
|
||||||
|
|
||||||
@ -54,6 +57,14 @@ class CodeGenSelector: public AstVisitor {
|
|||||||
void VisitDeclarations(ZoneList<Declaration*>* decls);
|
void VisitDeclarations(ZoneList<Declaration*>* decls);
|
||||||
void VisitStatements(ZoneList<Statement*>* stmts);
|
void VisitStatements(ZoneList<Statement*>* stmts);
|
||||||
|
|
||||||
|
// Visit an expression in effect context with a desired location of
|
||||||
|
// nowhere.
|
||||||
|
void VisitAsEffect(Expression* expr);
|
||||||
|
|
||||||
|
// Visit an expression in value context with a desired location of
|
||||||
|
// temporary.
|
||||||
|
void VisitAsValue(Expression* expr);
|
||||||
|
|
||||||
// AST node visit functions.
|
// AST node visit functions.
|
||||||
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
|
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
|
||||||
AST_NODE_LIST(DECLARE_VISIT)
|
AST_NODE_LIST(DECLARE_VISIT)
|
||||||
@ -61,6 +72,9 @@ class CodeGenSelector: public AstVisitor {
|
|||||||
|
|
||||||
bool has_supported_syntax_;
|
bool has_supported_syntax_;
|
||||||
|
|
||||||
|
// The desired location of the currently visited expression.
|
||||||
|
Location location_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(CodeGenSelector);
|
DISALLOW_COPY_AND_ASSIGN(CodeGenSelector);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -499,6 +513,30 @@ void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CodeGenSelector::VisitAsEffect(Expression* expr) {
|
||||||
|
if (location_.is_nowhere()) {
|
||||||
|
Visit(expr);
|
||||||
|
} else {
|
||||||
|
Location saved = location_;
|
||||||
|
location_ = Location::Nowhere();
|
||||||
|
Visit(expr);
|
||||||
|
location_ = saved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CodeGenSelector::VisitAsValue(Expression* expr) {
|
||||||
|
if (location_.is_temporary()) {
|
||||||
|
Visit(expr);
|
||||||
|
} else {
|
||||||
|
Location saved = location_;
|
||||||
|
location_ = Location::Temporary();
|
||||||
|
Visit(expr);
|
||||||
|
location_ = saved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenSelector::VisitDeclaration(Declaration* decl) {
|
void CodeGenSelector::VisitDeclaration(Declaration* decl) {
|
||||||
Variable* var = decl->proxy()->var();
|
Variable* var = decl->proxy()->var();
|
||||||
if (!var->is_global() || var->mode() == Variable::CONST) {
|
if (!var->is_global() || var->mode() == Variable::CONST) {
|
||||||
@ -513,10 +551,7 @@ void CodeGenSelector::VisitBlock(Block* stmt) {
|
|||||||
|
|
||||||
|
|
||||||
void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) {
|
void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) {
|
||||||
Expression* expr = stmt->expression();
|
VisitAsEffect(stmt->expression());
|
||||||
Visit(expr);
|
|
||||||
CHECK_BAILOUT;
|
|
||||||
expr->set_location(Location::Nowhere());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -541,7 +576,7 @@ void CodeGenSelector::VisitBreakStatement(BreakStatement* stmt) {
|
|||||||
|
|
||||||
|
|
||||||
void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) {
|
void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) {
|
||||||
Visit(stmt->expression());
|
VisitAsValue(stmt->expression());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -599,6 +634,7 @@ void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) {
|
|||||||
if (!expr->AllowsLazyCompilation()) {
|
if (!expr->AllowsLazyCompilation()) {
|
||||||
BAILOUT("FunctionLiteral does not allow lazy compilation");
|
BAILOUT("FunctionLiteral does not allow lazy compilation");
|
||||||
}
|
}
|
||||||
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -614,37 +650,75 @@ void CodeGenSelector::VisitConditional(Conditional* expr) {
|
|||||||
|
|
||||||
|
|
||||||
void CodeGenSelector::VisitSlot(Slot* expr) {
|
void CodeGenSelector::VisitSlot(Slot* expr) {
|
||||||
Slot::Type type = expr->type();
|
UNREACHABLE();
|
||||||
if (type != Slot::PARAMETER && type != Slot::LOCAL) {
|
|
||||||
BAILOUT("non-parameter/non-local slot reference");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
|
void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
|
||||||
Expression* rewrite = expr->var()->rewrite();
|
Expression* rewrite = expr->var()->rewrite();
|
||||||
if (rewrite != NULL) Visit(rewrite);
|
// A rewrite of NULL indicates a global variable.
|
||||||
|
if (rewrite != NULL) {
|
||||||
|
// Non-global.
|
||||||
|
Slot* slot = rewrite->AsSlot();
|
||||||
|
if (slot == NULL) {
|
||||||
|
// This is a variable rewritten to an explicit property access
|
||||||
|
// on the arguments object.
|
||||||
|
BAILOUT("non-global/non-slot variable reference");
|
||||||
|
}
|
||||||
|
|
||||||
|
Slot::Type type = slot->type();
|
||||||
|
if (type != Slot::PARAMETER && type != Slot::LOCAL) {
|
||||||
|
BAILOUT("non-parameter/non-local slot reference");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenSelector::VisitLiteral(Literal* expr) {
|
void CodeGenSelector::VisitLiteral(Literal* expr) {
|
||||||
// Literals are supported.
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) {
|
void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) {
|
||||||
// RegexpLiterals are supported.
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) {
|
void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
|
||||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
|
||||||
Visit(property->key());
|
for (int i = 0, len = properties->length(); i < len; i++) {
|
||||||
CHECK_BAILOUT;
|
ObjectLiteral::Property* property = properties->at(i);
|
||||||
Visit(property->value());
|
if (property->IsCompileTimeValue()) continue;
|
||||||
|
|
||||||
|
switch (property->kind()) {
|
||||||
|
case ObjectLiteral::Property::CONSTANT:
|
||||||
|
UNREACHABLE();
|
||||||
|
|
||||||
|
// For (non-compile-time) materialized literals and computed
|
||||||
|
// properties with symbolic keys we will use an IC and therefore not
|
||||||
|
// generate code for the key.
|
||||||
|
case ObjectLiteral::Property::COMPUTED: // Fall through.
|
||||||
|
case ObjectLiteral::Property::MATERIALIZED_LITERAL:
|
||||||
|
if (property->key()->handle()->IsSymbol()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Fall through.
|
||||||
|
|
||||||
|
// In all other cases we need the key's value on the stack
|
||||||
|
// for a runtime call. (Relies on TEMP meaning STACK.)
|
||||||
|
case ObjectLiteral::Property::GETTER: // Fall through.
|
||||||
|
case ObjectLiteral::Property::SETTER: // Fall through.
|
||||||
|
case ObjectLiteral::Property::PROTOTYPE:
|
||||||
|
VisitAsValue(property->key());
|
||||||
|
CHECK_BAILOUT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
VisitAsValue(property->value());
|
||||||
CHECK_BAILOUT;
|
CHECK_BAILOUT;
|
||||||
}
|
}
|
||||||
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -654,9 +728,10 @@ void CodeGenSelector::VisitArrayLiteral(ArrayLiteral* expr) {
|
|||||||
Expression* subexpr = subexprs->at(i);
|
Expression* subexpr = subexprs->at(i);
|
||||||
if (subexpr->AsLiteral() != NULL) continue;
|
if (subexpr->AsLiteral() != NULL) continue;
|
||||||
if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
|
if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
|
||||||
Visit(subexpr);
|
VisitAsValue(subexpr);
|
||||||
CHECK_BAILOUT;
|
CHECK_BAILOUT;
|
||||||
}
|
}
|
||||||
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -668,7 +743,10 @@ void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) {
|
|||||||
void CodeGenSelector::VisitAssignment(Assignment* expr) {
|
void CodeGenSelector::VisitAssignment(Assignment* expr) {
|
||||||
// We support plain non-compound assignments to parameters and
|
// We support plain non-compound assignments to parameters and
|
||||||
// non-context (stack-allocated) locals.
|
// non-context (stack-allocated) locals.
|
||||||
if (expr->starts_initialization_block()) BAILOUT("initialization block");
|
if (expr->starts_initialization_block() ||
|
||||||
|
expr->ends_initialization_block()) {
|
||||||
|
BAILOUT("initialization block start");
|
||||||
|
}
|
||||||
|
|
||||||
Token::Value op = expr->op();
|
Token::Value op = expr->op();
|
||||||
if (op == Token::INIT_CONST) BAILOUT("initialize constant");
|
if (op == Token::INIT_CONST) BAILOUT("initialize constant");
|
||||||
@ -687,7 +765,8 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Visit(expr->value());
|
VisitAsValue(expr->value());
|
||||||
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -697,9 +776,10 @@ void CodeGenSelector::VisitThrow(Throw* expr) {
|
|||||||
|
|
||||||
|
|
||||||
void CodeGenSelector::VisitProperty(Property* expr) {
|
void CodeGenSelector::VisitProperty(Property* expr) {
|
||||||
Visit(expr->obj());
|
VisitAsValue(expr->obj());
|
||||||
CHECK_BAILOUT;
|
CHECK_BAILOUT;
|
||||||
Visit(expr->key());
|
VisitAsValue(expr->key());
|
||||||
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -718,38 +798,42 @@ void CodeGenSelector::VisitCall(Call* expr) {
|
|||||||
} else {
|
} else {
|
||||||
BAILOUT("Call to a non-global function");
|
BAILOUT("Call to a non-global function");
|
||||||
}
|
}
|
||||||
// Check all arguments to the call
|
// Check all arguments to the call. (Relies on TEMP meaning STACK.)
|
||||||
for (int i = 0; i < args->length(); i++) {
|
for (int i = 0; i < args->length(); i++) {
|
||||||
Visit(args->at(i));
|
VisitAsValue(args->at(i));
|
||||||
CHECK_BAILOUT;
|
CHECK_BAILOUT;
|
||||||
}
|
}
|
||||||
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenSelector::VisitCallNew(CallNew* expr) {
|
void CodeGenSelector::VisitCallNew(CallNew* expr) {
|
||||||
Visit(expr->expression());
|
VisitAsValue(expr->expression());
|
||||||
CHECK_BAILOUT;
|
CHECK_BAILOUT;
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
// Check all arguments to the call
|
// Check all arguments to the call
|
||||||
for (int i = 0; i < args->length(); i++) {
|
for (int i = 0; i < args->length(); i++) {
|
||||||
Visit(args->at(i));
|
VisitAsValue(args->at(i));
|
||||||
CHECK_BAILOUT;
|
CHECK_BAILOUT;
|
||||||
}
|
}
|
||||||
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) {
|
void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) {
|
||||||
// In case of JS runtime function bail out.
|
// In case of JS runtime function bail out.
|
||||||
if (expr->function() == NULL) BAILOUT("CallRuntime");
|
if (expr->function() == NULL) BAILOUT("call JS runtime function");
|
||||||
// Check for inline runtime call
|
// Check for inline runtime call
|
||||||
if (expr->name()->Get(0) == '_' &&
|
if (expr->name()->Get(0) == '_' &&
|
||||||
CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
|
CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
|
||||||
BAILOUT("InlineRuntimeCall");
|
BAILOUT("inlined runtime call");
|
||||||
}
|
}
|
||||||
|
// Check all arguments to the call. (Relies on TEMP meaning STACK.)
|
||||||
for (int i = 0; i < expr->arguments()->length(); i++) {
|
for (int i = 0; i < expr->arguments()->length(); i++) {
|
||||||
Visit(expr->arguments()->at(i));
|
VisitAsValue(expr->arguments()->at(i));
|
||||||
CHECK_BAILOUT;
|
CHECK_BAILOUT;
|
||||||
}
|
}
|
||||||
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -766,14 +850,17 @@ void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
|
|||||||
void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
|
void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
|
||||||
switch (expr->op()) {
|
switch (expr->op()) {
|
||||||
case Token::OR:
|
case Token::OR:
|
||||||
Visit(expr->left());
|
VisitAsValue(expr->left());
|
||||||
CHECK_BAILOUT;
|
CHECK_BAILOUT;
|
||||||
|
// The location for the right subexpression is the same as for the
|
||||||
|
// whole expression so we call Visit directly.
|
||||||
Visit(expr->right());
|
Visit(expr->right());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BAILOUT("Unsupported binary operation");
|
BAILOUT("Unsupported binary operation");
|
||||||
}
|
}
|
||||||
|
expr->set_location(location_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -270,13 +270,10 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
|
|
||||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
for (int i = 0; i < expr->properties()->length(); i++) {
|
||||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
ObjectLiteral::Property* property = expr->properties()->at(i);
|
||||||
|
if (property->IsCompileTimeValue()) continue;
|
||||||
|
|
||||||
Literal* key = property->key();
|
Literal* key = property->key();
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
if (property->kind() == ObjectLiteral::Property::CONSTANT) continue;
|
|
||||||
if (property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
|
|
||||||
CompileTimeValue::IsCompileTimeValue(value)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!result_saved) {
|
if (!result_saved) {
|
||||||
__ push(eax); // Save result on the stack
|
__ push(eax); // Save result on the stack
|
||||||
result_saved = true;
|
result_saved = true;
|
||||||
|
@ -281,13 +281,10 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
|||||||
|
|
||||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
for (int i = 0; i < expr->properties()->length(); i++) {
|
||||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
ObjectLiteral::Property* property = expr->properties()->at(i);
|
||||||
|
if (property->IsCompileTimeValue()) continue;
|
||||||
|
|
||||||
Literal* key = property->key();
|
Literal* key = property->key();
|
||||||
Expression* value = property->value();
|
Expression* value = property->value();
|
||||||
if (property->kind() == ObjectLiteral::Property::CONSTANT) continue;
|
|
||||||
if (property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
|
|
||||||
CompileTimeValue::IsCompileTimeValue(value)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!result_saved) {
|
if (!result_saved) {
|
||||||
__ push(rax); // Save result on the stack
|
__ push(rax); // Save result on the stack
|
||||||
result_saved = true;
|
result_saved = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user