Incorporate constness into inferred interfaces

(in preparation for handling imports).

R=svenpanne@chromium.org
BUG=v8:1569
TEST=

Review URL: https://chromiumcodereview.appspot.com/10698167

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12078 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
rossberg@chromium.org 2012-07-13 09:29:43 +00:00
parent 58c4e6ceb4
commit ec042177d7
8 changed files with 79 additions and 37 deletions

View File

@ -85,8 +85,8 @@ VariableProxy::VariableProxy(Isolate* isolate, Variable* var)
VariableProxy::VariableProxy(Isolate* isolate, VariableProxy::VariableProxy(Isolate* isolate,
Handle<String> name, Handle<String> name,
bool is_this, bool is_this,
int position, Interface* interface,
Interface* interface) int position)
: Expression(isolate), : Expression(isolate),
name_(name), name_(name),
var_(NULL), var_(NULL),

View File

@ -1496,8 +1496,8 @@ class VariableProxy: public Expression {
VariableProxy(Isolate* isolate, VariableProxy(Isolate* isolate,
Handle<String> name, Handle<String> name,
bool is_this, bool is_this,
int position, Interface* interface,
Interface* interface); int position);
Handle<String> name_; Handle<String> name_;
Variable* var_; // resolved variable, or NULL Variable* var_; // resolved variable, or NULL
@ -2846,11 +2846,10 @@ class AstNodeFactory BASE_EMBEDDED {
VariableProxy* NewVariableProxy(Handle<String> name, VariableProxy* NewVariableProxy(Handle<String> name,
bool is_this, bool is_this,
int position = RelocInfo::kNoPosition, Interface* interface = Interface::NewValue(),
Interface* interface = int position = RelocInfo::kNoPosition) {
Interface::NewValue()) {
VariableProxy* proxy = VariableProxy* proxy =
new(zone_) VariableProxy(isolate_, name, is_this, position, interface); new(zone_) VariableProxy(isolate_, name, is_this, interface, position);
VISIT_AND_RETURN(VariableProxy, proxy) VISIT_AND_RETURN(VariableProxy, proxy)
} }

View File

@ -124,8 +124,16 @@ void Interface::Unify(Interface* that, Zone* zone, bool* ok) {
*ok = true; *ok = true;
if (this == that) return; if (this == that) return;
if (this->IsValue()) return that->MakeValue(ok); if (this->IsValue()) {
if (that->IsValue()) return this->MakeValue(ok); that->MakeValue(ok);
if (*ok && this->IsConst()) that->MakeConst(ok);
return;
}
if (that->IsValue()) {
this->MakeValue(ok);
if (*ok && that->IsConst()) this->MakeConst(ok);
return;
}
#ifdef DEBUG #ifdef DEBUG
if (FLAG_print_interface_details) { if (FLAG_print_interface_details) {
@ -214,6 +222,8 @@ void Interface::Print(int n) {
if (IsUnknown()) { if (IsUnknown()) {
PrintF("unknown\n"); PrintF("unknown\n");
} else if (IsConst()) {
PrintF("const\n");
} else if (IsValue()) { } else if (IsValue()) {
PrintF("value\n"); PrintF("value\n");
} else if (IsModule()) { } else if (IsModule()) {

View File

@ -36,25 +36,41 @@ namespace internal {
// This class implements the following abstract grammar of interfaces // This class implements the following abstract grammar of interfaces
// (i.e. module types): // (i.e. module types):
// interface ::= UNDETERMINED | VALUE | MODULE(exports) // interface ::= UNDETERMINED | VALUE | CONST | MODULE(exports)
// exports ::= {name : interface, ...} // exports ::= {name : interface, ...}
// A frozen module type is one that is fully determined. Unification does not // A frozen type is one that is fully determined. Unification does not
// allow adding additional exports to frozen interfaces. // allow to turn non-const values into const, or adding additional exports to
// Otherwise, unifying modules merges their exports. // frozen interfaces. Otherwise, unifying modules merges their exports.
// Undetermined types are unification variables that can be unified freely. // Undetermined types are unification variables that can be unified freely.
// There is a natural subsort lattice that reflects the increase of knowledge:
//
// undetermined
// // | \\ .
// value (frozen) module
// // \\ / \ //
// const fr.value fr.module
// \\ /
// fr.const
//
// where the bold lines are the only transitions allowed.
class Interface : public ZoneObject { class Interface : public ZoneObject {
public: public:
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Factory methods. // Factory methods.
static Interface* NewUnknown(Zone* zone) {
return new(zone) Interface(NONE);
}
static Interface* NewValue() { static Interface* NewValue() {
static Interface value_interface(VALUE + FROZEN); // Cached. static Interface value_interface(VALUE + FROZEN); // Cached.
return &value_interface; return &value_interface;
} }
static Interface* NewUnknown(Zone* zone) { static Interface* NewConst() {
return new(zone) Interface(NONE); static Interface value_interface(VALUE + CONST + FROZEN); // Cached.
return &value_interface;
} }
static Interface* NewModule(Zone* zone) { static Interface* NewModule(Zone* zone) {
@ -80,6 +96,12 @@ class Interface : public ZoneObject {
if (*ok) Chase()->flags_ |= VALUE; if (*ok) Chase()->flags_ |= VALUE;
} }
// Determine this interface to be an immutable interface.
void MakeConst(bool* ok) {
*ok = !IsModule() && (IsConst() || !IsFrozen());
if (*ok) Chase()->flags_ |= VALUE + CONST;
}
// Determine this interface to be a module interface. // Determine this interface to be a module interface.
void MakeModule(bool* ok) { void MakeModule(bool* ok) {
*ok = !IsValue(); *ok = !IsValue();
@ -107,6 +129,9 @@ class Interface : public ZoneObject {
// Check whether this is a value type. // Check whether this is a value type.
bool IsValue() { return Chase()->flags_ & VALUE; } bool IsValue() { return Chase()->flags_ & VALUE; }
// Check whether this is a constant type.
bool IsConst() { return Chase()->flags_ & CONST; }
// Check whether this is a module type. // Check whether this is a module type.
bool IsModule() { return Chase()->flags_ & MODULE; } bool IsModule() { return Chase()->flags_ & MODULE; }
@ -161,8 +186,9 @@ class Interface : public ZoneObject {
enum Flags { // All flags are monotonic enum Flags { // All flags are monotonic
NONE = 0, NONE = 0,
VALUE = 1, // This type describes a value VALUE = 1, // This type describes a value
MODULE = 2, // This type describes a module CONST = 2, // This type describes a constant
FROZEN = 4 // This type is fully determined MODULE = 4, // This type describes a module
FROZEN = 8 // This type is fully determined
}; };
int flags_; int flags_;

View File

@ -1408,8 +1408,8 @@ Module* Parser::ParseModuleVariable(bool* ok) {
PrintF("# Module variable %s ", name->ToAsciiArray()); PrintF("# Module variable %s ", name->ToAsciiArray());
#endif #endif
VariableProxy* proxy = top_scope_->NewUnresolved( VariableProxy* proxy = top_scope_->NewUnresolved(
factory(), name, scanner().location().beg_pos, factory(), name, Interface::NewModule(zone()),
Interface::NewModule(zone())); scanner().location().beg_pos);
return factory()->NewModuleVariable(proxy); return factory()->NewModuleVariable(proxy);
} }
@ -1499,7 +1499,6 @@ Block* Parser::ParseImportDeclaration(bool* ok) {
Declaration* declaration = Declaration* declaration =
factory()->NewImportDeclaration(proxy, module, top_scope_); factory()->NewImportDeclaration(proxy, module, top_scope_);
Declare(declaration, true, CHECK_OK); Declare(declaration, true, CHECK_OK);
// TODO(rossberg): Add initialization statement to block.
} }
return block; return block;
@ -1740,7 +1739,7 @@ VariableProxy* Parser::NewUnresolved(
// Let/const variables in harmony mode are always added to the immediately // Let/const variables in harmony mode are always added to the immediately
// enclosing scope. // enclosing scope.
return DeclarationScope(mode)->NewUnresolved( return DeclarationScope(mode)->NewUnresolved(
factory(), name, scanner().location().beg_pos, interface); factory(), name, interface, scanner().location().beg_pos);
} }
@ -1954,7 +1953,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
// TODO(1240846): It's weird that native function declarations are // TODO(1240846): It's weird that native function declarations are
// introduced dynamically when we meet their declarations, whereas // introduced dynamically when we meet their declarations, whereas
// other functions are set up when entering the surrounding scope. // other functions are set up when entering the surrounding scope.
VariableProxy* proxy = NewUnresolved(name, VAR); VariableProxy* proxy = NewUnresolved(name, VAR, Interface::NewValue());
Declaration* declaration = Declaration* declaration =
factory()->NewVariableDeclaration(proxy, VAR, top_scope_); factory()->NewVariableDeclaration(proxy, VAR, top_scope_);
Declare(declaration, true, CHECK_OK); Declare(declaration, true, CHECK_OK);
@ -1983,7 +1982,7 @@ Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) {
// scope, we treat is as such and introduce the function with it's // scope, we treat is as such and introduce the function with it's
// initial value upon entering the corresponding scope. // initial value upon entering the corresponding scope.
VariableMode mode = is_extended_mode() ? LET : VAR; VariableMode mode = is_extended_mode() ? LET : VAR;
VariableProxy* proxy = NewUnresolved(name, mode); VariableProxy* proxy = NewUnresolved(name, mode, Interface::NewValue());
Declaration* declaration = Declaration* declaration =
factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_); factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_);
Declare(declaration, true, CHECK_OK); Declare(declaration, true, CHECK_OK);
@ -2215,7 +2214,9 @@ Block* Parser::ParseVariableDeclarations(
// For let/const declarations in harmony mode, we can also immediately // For let/const declarations in harmony mode, we can also immediately
// pre-resolve the proxy because it resides in the same scope as the // pre-resolve the proxy because it resides in the same scope as the
// declaration. // declaration.
VariableProxy* proxy = NewUnresolved(name, mode); Interface* interface =
is_const ? Interface::NewConst() : Interface::NewValue();
VariableProxy* proxy = NewUnresolved(name, mode, interface);
Declaration* declaration = Declaration* declaration =
factory()->NewVariableDeclaration(proxy, mode, top_scope_); factory()->NewVariableDeclaration(proxy, mode, top_scope_);
Declare(declaration, mode != VAR, CHECK_OK); Declare(declaration, mode != VAR, CHECK_OK);
@ -2376,7 +2377,7 @@ Block* Parser::ParseVariableDeclarations(
// if they are inside a 'with' statement - they may change a 'with' object // if they are inside a 'with' statement - they may change a 'with' object
// property). // property).
VariableProxy* proxy = VariableProxy* proxy =
initialization_scope->NewUnresolved(factory(), name); initialization_scope->NewUnresolved(factory(), name, interface);
Assignment* assignment = Assignment* assignment =
factory()->NewAssignment(init_op, proxy, value, position); factory()->NewAssignment(init_op, proxy, value, position);
block->AddStatement(factory()->NewExpressionStatement(assignment), block->AddStatement(factory()->NewExpressionStatement(assignment),
@ -2884,12 +2885,16 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
for_scope->set_start_position(scanner().location().beg_pos); for_scope->set_start_position(scanner().location().beg_pos);
if (peek() != Token::SEMICOLON) { if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || peek() == Token::CONST) { if (peek() == Token::VAR || peek() == Token::CONST) {
bool is_const = peek() == Token::CONST;
Handle<String> name; Handle<String> name;
Block* variable_statement = Block* variable_statement =
ParseVariableDeclarations(kForStatement, NULL, NULL, &name, CHECK_OK); ParseVariableDeclarations(kForStatement, NULL, NULL, &name, CHECK_OK);
if (peek() == Token::IN && !name.is_null()) { if (peek() == Token::IN && !name.is_null()) {
VariableProxy* each = top_scope_->NewUnresolved(factory(), name); Interface* interface =
is_const ? Interface::NewConst() : Interface::NewValue();
VariableProxy* each =
top_scope_->NewUnresolved(factory(), name, interface);
ForInStatement* loop = factory()->NewForInStatement(labels); ForInStatement* loop = factory()->NewForInStatement(labels);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
@ -2936,7 +2941,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
// implementing stack allocated block scoped variables. // implementing stack allocated block scoped variables.
Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name); Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name);
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
VariableProxy* each = top_scope_->NewUnresolved(factory(), name); Interface* interface = Interface::NewValue();
VariableProxy* each =
top_scope_->NewUnresolved(factory(), name, interface);
ForInStatement* loop = factory()->NewForInStatement(labels); ForInStatement* loop = factory()->NewForInStatement(labels);
Target target(&this->target_stack_, loop); Target target(&this->target_stack_, loop);
@ -3671,7 +3678,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
#endif #endif
Interface* interface = Interface::NewUnknown(zone()); Interface* interface = Interface::NewUnknown(zone());
result = top_scope_->NewUnresolved( result = top_scope_->NewUnresolved(
factory(), name, scanner().location().beg_pos, interface); factory(), name, interface, scanner().location().beg_pos);
break; break;
} }
@ -4517,7 +4524,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST; VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST;
fvar = new(zone()) Variable(top_scope_, fvar = new(zone()) Variable(top_scope_,
function_name, fvar_mode, true /* is valid LHS */, function_name, fvar_mode, true /* is valid LHS */,
Variable::NORMAL, kCreatedInitialized); Variable::NORMAL, kCreatedInitialized, Interface::NewConst());
VariableProxy* proxy = factory()->NewVariableProxy(fvar); VariableProxy* proxy = factory()->NewVariableProxy(fvar);
VariableDeclaration* fvar_declaration = VariableDeclaration* fvar_declaration =
factory()->NewVariableDeclaration(proxy, fvar_mode, top_scope_); factory()->NewVariableDeclaration(proxy, fvar_mode, top_scope_);
@ -4607,8 +4614,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
if (!is_lazily_compiled) { if (!is_lazily_compiled) {
body = new(zone()) ZoneList<Statement*>(8, zone()); body = new(zone()) ZoneList<Statement*>(8, zone());
if (fvar != NULL) { if (fvar != NULL) {
VariableProxy* fproxy = VariableProxy* fproxy = top_scope_->NewUnresolved(
top_scope_->NewUnresolved(factory(), function_name); factory(), function_name, Interface::NewConst());
fproxy->BindTo(fvar); fproxy->BindTo(fvar);
body->Add(factory()->NewExpressionStatement( body->Add(factory()->NewExpressionStatement(
factory()->NewAssignment(fvar_init_op, factory()->NewAssignment(fvar_init_op,

View File

@ -771,7 +771,7 @@ class Parser {
// Parser support // Parser support
VariableProxy* NewUnresolved(Handle<String> name, VariableProxy* NewUnresolved(Handle<String> name,
VariableMode mode, VariableMode mode,
Interface* interface = Interface::NewValue()); Interface* interface);
void Declare(Declaration* declaration, bool resolve, bool* ok); void Declare(Declaration* declaration, bool resolve, bool* ok);
bool TargetStackContainsLabel(Handle<String> label); bool TargetStackContainsLabel(Handle<String> label);

View File

@ -257,7 +257,7 @@ bool Rewriter::Rewrite(CompilationInfo* info) {
// coincides with the end of the with scope which is the position of '1'. // coincides with the end of the with scope which is the position of '1'.
int position = function->end_position(); int position = function->end_position();
VariableProxy* result_proxy = processor.factory()->NewVariableProxy( VariableProxy* result_proxy = processor.factory()->NewVariableProxy(
result->name(), false, position); result->name(), false, Interface::NewValue(), position);
result_proxy->BindTo(result); result_proxy->BindTo(result);
Statement* result_statement = Statement* result_statement =
processor.factory()->NewReturnStatement(result_proxy); processor.factory()->NewReturnStatement(result_proxy);

View File

@ -166,14 +166,14 @@ class Scope: public ZoneObject {
template<class Visitor> template<class Visitor>
VariableProxy* NewUnresolved(AstNodeFactory<Visitor>* factory, VariableProxy* NewUnresolved(AstNodeFactory<Visitor>* factory,
Handle<String> name, Handle<String> name,
int position = RelocInfo::kNoPosition, Interface* interface = Interface::NewValue(),
Interface* interface = Interface::NewValue()) { int position = RelocInfo::kNoPosition) {
// Note that we must not share the unresolved variables with // Note that we must not share the unresolved variables with
// the same name because they may be removed selectively via // the same name because they may be removed selectively via
// RemoveUnresolved(). // RemoveUnresolved().
ASSERT(!already_resolved()); ASSERT(!already_resolved());
VariableProxy* proxy = VariableProxy* proxy =
factory->NewVariableProxy(name, false, position, interface); factory->NewVariableProxy(name, false, interface, position);
unresolved_.Add(proxy, zone_); unresolved_.Add(proxy, zone_);
return proxy; return proxy;
} }