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:
parent
58c4e6ceb4
commit
ec042177d7
@ -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),
|
||||||
|
11
src/ast.h
11
src/ast.h
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()) {
|
||||||
|
@ -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_;
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user