Revert "Implement simple effect typing for variables" and "Handle switch effects".

This reverts r15776 and r15777 due to compile failures on Chromium Mac bots.

TBR=rossberg@chromium.org

Review URL: https://codereview.chromium.org/19482016

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15786 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 24dec186
......@@ -259,7 +259,6 @@ class Statement: public AstNode {
Statement() : statement_pos_(RelocInfo::kNoPosition) {}
bool IsEmpty() { return AsEmptyStatement() != NULL; }
virtual bool IsJump() const { return false; }
void set_statement_pos(int statement_pos) { statement_pos_ = statement_pos; }
int statement_pos() const { return statement_pos_; }
......@@ -390,7 +389,7 @@ class Expression: public AstNode {
protected:
explicit Expression(Isolate* isolate)
: bounds_(Bounds::Unbounded(isolate)),
: bounds_(Type::None(), Type::Any(), isolate),
id_(GetNextId(isolate)),
test_id_(GetNextId(isolate)) {}
void set_to_boolean_types(byte types) { to_boolean_types_ = types; }
......@@ -460,11 +459,6 @@ class Block: public BreakableStatement {
ZoneList<Statement*>* statements() { return &statements_; }
bool is_initializer_block() const { return is_initializer_block_; }
virtual bool IsJump() const {
return !statements_.is_empty() && statements_.last()->IsJump()
&& labels() == NULL; // Good enough as an approximation...
}
Scope* scope() const { return scope_; }
void set_scope(Scope* scope) { scope_ = scope; }
......@@ -1015,7 +1009,6 @@ class ExpressionStatement: public Statement {
void set_expression(Expression* e) { expression_ = e; }
Expression* expression() const { return expression_; }
virtual bool IsJump() const { return expression_->IsThrow(); }
protected:
explicit ExpressionStatement(Expression* expression)
......@@ -1026,16 +1019,7 @@ class ExpressionStatement: public Statement {
};
class JumpStatement: public Statement {
public:
virtual bool IsJump() const { return true; }
protected:
JumpStatement() {}
};
class ContinueStatement: public JumpStatement {
class ContinueStatement: public Statement {
public:
DECLARE_NODE_TYPE(ContinueStatement)
......@@ -1050,7 +1034,7 @@ class ContinueStatement: public JumpStatement {
};
class BreakStatement: public JumpStatement {
class BreakStatement: public Statement {
public:
DECLARE_NODE_TYPE(BreakStatement)
......@@ -1065,7 +1049,7 @@ class BreakStatement: public JumpStatement {
};
class ReturnStatement: public JumpStatement {
class ReturnStatement: public Statement {
public:
DECLARE_NODE_TYPE(ReturnStatement)
......@@ -1184,11 +1168,6 @@ class IfStatement: public Statement {
Statement* then_statement() const { return then_statement_; }
Statement* else_statement() const { return else_statement_; }
virtual bool IsJump() const {
return HasThenStatement() && then_statement()->IsJump()
&& HasElseStatement() && else_statement()->IsJump();
}
BailoutId IfId() const { return if_id_; }
BailoutId ThenId() const { return then_id_; }
BailoutId ElseId() const { return else_id_; }
......
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_EFFECTS_H_
#define V8_EFFECTS_H_
#include "v8.h"
#include "types.h"
namespace v8 {
namespace internal {
// A simple struct to represent (write) effects. A write is represented as a
// modification of type bounds (e.g. of a variable).
//
// An effect can either be definite, if the write is known to have taken place,
// or 'possible', if it was optional. The difference is relevant when composing
// effects.
//
// There are two ways to compose effects: sequentially (they happen one after
// the other) or alternatively (either one or the other happens). A definite
// effect cancels out any previous effect upon sequencing. A possible effect
// merges into a previous effect, i.e., type bounds are merged. Alternative
// composition always merges bounds. It yields a possible effect if at least
// one was only possible.
struct Effect {
enum Modality { POSSIBLE, DEFINITE };
Modality modality;
Bounds bounds;
Effect() {}
Effect(Bounds b, Modality m = DEFINITE) : modality(m), bounds(b) {}
// The unknown effect.
static Effect Unknown(Isolate* isolate) {
return Effect(Bounds::Unbounded(isolate), POSSIBLE);
}
static Effect Forget(Isolate* isolate) {
return Effect(Bounds::Unbounded(isolate), DEFINITE);
}
// Sequential composition, as in 'e1; e2'.
static Effect Seq(Effect e1, Effect e2, Isolate* isolate) {
if (e2.modality == DEFINITE) return e2;
return Effect(Bounds::Either(e1.bounds, e2.bounds, isolate), e1.modality);
}
// Alternative composition, as in 'cond ? e1 : e2'.
static Effect Alt(Effect e1, Effect e2, Isolate* isolate) {
return Effect(
Bounds::Either(e1.bounds, e2.bounds, isolate),
e1.modality == POSSIBLE ? POSSIBLE : e2.modality);
}
};
// Classes encapsulating sets of effects on variables.
//
// Effects maps variables to effects and supports sequential and alternative
// composition.
//
// NestedEffects is an incremental representation that supports persistence
// through functional extension. It represents the map as an adjoin of a list
// of maps, whose tail can be shared.
//
// Both classes provide similar interfaces, implemented in parts through the
// EffectsMixin below (using sandwich style, to work around the style guide's
// MI restriction).
//
// We also (ab)use Effects/NestedEffects as a representation for abstract
// store typings. In that case, only definite effects are of interest.
template<class Var, class Base, class Effects>
class EffectsMixin: public Base {
public:
explicit EffectsMixin(Zone* zone) : Base(zone) {}
Effect Lookup(Var var) {
Locator locator;
return Find(var, &locator)
? locator.value() : Effect::Unknown(Base::isolate());
}
Bounds LookupBounds(Var var) {
Effect effect = Lookup(var);
return effect.modality == Effect::DEFINITE
? effect.bounds : Bounds::Unbounded(Base::isolate());
}
// Sequential composition.
void Seq(Var var, Effect effect) {
Locator locator;
if (!Insert(var, &locator)) {
effect = Effect::Seq(locator.value(), effect, Base::isolate());
}
locator.set_value(effect);
}
void Seq(Effects that) {
SeqMerger<EffectsMixin> merge = { *this };
that.ForEach(&merge);
}
// Alternative composition.
void Alt(Var var, Effect effect) {
Locator locator;
if (!Insert(var, &locator)) {
effect = Effect::Alt(locator.value(), effect, Base::isolate());
}
locator.set_value(effect);
}
void Alt(Effects that) {
AltWeakener<EffectsMixin> weaken = { *this, that };
this->ForEach(&weaken);
AltMerger<EffectsMixin> merge = { *this };
that.ForEach(&merge);
}
// Invalidation.
void Forget() {
Overrider override = {
Effect::Forget(Base::isolate()), Effects(Base::zone()) };
this->ForEach(&override);
Seq(override.effects);
}
protected:
typedef typename Base::Locator Locator;
template<class Self>
struct SeqMerger {
void Call(Var var, Effect effect) { self.Seq(var, effect); }
Self self;
};
template<class Self>
struct AltMerger {
void Call(Var var, Effect effect) { self.Alt(var, effect); }
Self self;
};
template<class Self>
struct AltWeakener {
void Call(Var var, Effect effect) {
if (effect.modality == Effect::DEFINITE && !other.Contains(var)) {
effect.modality = Effect::POSSIBLE;
Locator locator;
self.Insert(var, &locator);
locator.set_value(effect);
}
}
Self self;
Effects other;
};
struct Overrider {
void Call(Var var, Effect effect) { effects.Seq(var, new_effect); }
Effect new_effect;
Effects effects;
};
};
template<class Var, Var kNoVar> class Effects;
template<class Var, Var kNoVar> class NestedEffectsBase;
template<class Var, Var kNoVar>
class EffectsBase {
public:
explicit EffectsBase(Zone* zone) : map_(new(zone) Mapping(zone)) {}
bool IsEmpty() { return map_->is_empty(); }
protected:
friend class NestedEffectsBase<Var, kNoVar>;
friend class
EffectsMixin<Var, NestedEffectsBase<Var, kNoVar>, Effects<Var, kNoVar> >;
Zone* zone() { return map_->allocator().zone(); }
Isolate* isolate() { return zone()->isolate(); }
struct SplayTreeConfig {
typedef Var Key;
typedef Effect Value;
static const Var kNoKey = kNoVar;
static Effect NoValue() { return Effect(); }
static int Compare(int x, int y) { return y - x; }
};
typedef ZoneSplayTree<SplayTreeConfig> Mapping;
typedef typename Mapping::Locator Locator;
bool Contains(Var var) {
ASSERT(var != kNoVar);
return map_->Contains(var);
}
bool Find(Var var, Locator* locator) {
ASSERT(var != kNoVar);
return map_->Find(var, locator);
}
bool Insert(Var var, Locator* locator) {
ASSERT(var != kNoVar);
return map_->Insert(var, locator);
}
template<class Callback>
void ForEach(Callback* callback) {
return map_->ForEach(callback);
}
private:
Mapping* map_;
};
template<class Var, Var kNoVar>
const Var EffectsBase<Var, kNoVar>::SplayTreeConfig::kNoKey;
template<class Var, Var kNoVar>
class Effects: public
EffectsMixin<Var, EffectsBase<Var, kNoVar>, Effects<Var, kNoVar> > {
public:
explicit Effects(Zone* zone)
: EffectsMixin<Var, EffectsBase<Var, kNoVar>, Effects<Var, kNoVar> >(zone)
{}
};
template<class Var, Var kNoVar>
class NestedEffectsBase {
public:
explicit NestedEffectsBase(Zone* zone) : node_(new(zone) Node(zone)) {}
template<class Callback>
void ForEach(Callback* callback) {
if (node_->previous) NestedEffectsBase(node_->previous).ForEach(callback);
node_->effects.ForEach(callback);
}
Effects<Var, kNoVar> Top() { return node_->effects; }
bool IsEmpty() {
for (Node* node = node_; node != NULL; node = node->previous) {
if (!node->effects.IsEmpty()) return false;
}
return true;
}
protected:
typedef typename EffectsBase<Var, kNoVar>::Locator Locator;
Zone* zone() { return node_->zone; }
Isolate* isolate() { return zone()->isolate(); }
void push() { node_ = new(node_->zone) Node(node_->zone, node_); }
void pop() { node_ = node_->previous; }
bool is_empty() { return node_ == NULL; }
bool Contains(Var var) {
ASSERT(var != kNoVar);
for (Node* node = node_; node != NULL; node = node->previous) {
if (node->effects.Contains(var)) return true;
}
return false;
}
bool Find(Var var, Locator* locator) {
ASSERT(var != kNoVar);
for (Node* node = node_; node != NULL; node = node->previous) {
if (node->effects.Find(var, locator)) return true;
}
return false;
}
bool Insert(Var var, Locator* locator);
private:
struct Node: ZoneObject {
Zone* zone;
Effects<Var, kNoVar> effects;
Node* previous;
explicit Node(Zone* zone, Node* previous = NULL)
: zone(zone), effects(zone), previous(previous) {}
};
explicit NestedEffectsBase(Node* node) : node_(node) {}
Node* node_;
};
template<class Var, Var kNoVar>
bool NestedEffectsBase<Var, kNoVar>::Insert(Var var, Locator* locator) {
ASSERT(var != kNoVar);
if (!node_->effects.Insert(var, locator)) return false;
Locator shadowed;
for (Node* node = node_->previous; node != NULL; node = node->previous) {
if (node->effects.Find(var, &shadowed)) {
// Initialize with shadowed entry.
locator->set_value(shadowed.value());
return false;
}
}
return true;
}
template<class Var, Var kNoVar>
class NestedEffects: public
EffectsMixin<Var, NestedEffectsBase<Var, kNoVar>, Effects<Var, kNoVar> > {
public:
explicit NestedEffects(Zone* zone) :
EffectsMixin<Var, NestedEffectsBase<Var, kNoVar>, Effects<Var, kNoVar> >(
zone) {}
// Create an extension of the current effect set. The current set should not
// be modified while the extension is in use.
NestedEffects Push() {
NestedEffects result = *this;
result.push();
return result;
}
NestedEffects Pop() {
NestedEffects result = *this;
result.pop();
ASSERT(!this->is_empty());
return result;
}
};
} } // namespace v8::internal
#endif // V8_EFFECTS_H_
......@@ -90,12 +90,6 @@ bool SplayTree<Config, Allocator>::FindInternal(const Key& key) {
}
template<typename Config, class Allocator>
bool SplayTree<Config, Allocator>::Contains(const Key& key) {
return FindInternal(key);
}
template<typename Config, class Allocator>
bool SplayTree<Config, Allocator>::Find(const Key& key, Locator* locator) {
if (FindInternal(key)) {
......@@ -299,10 +293,9 @@ void SplayTree<Config, Allocator>::ForEach(Callback* callback) {
template <typename Config, class Allocator> template <class Callback>
void SplayTree<Config, Allocator>::ForEachNode(Callback* callback) {
if (root_ == NULL) return;
// Pre-allocate some space for tiny trees.
List<Node*, Allocator> nodes_to_visit(10, allocator_);
nodes_to_visit.Add(root_, allocator_);
if (root_ != NULL) nodes_to_visit.Add(root_, allocator_);
int pos = 0;
while (pos < nodes_to_visit.length()) {
Node* node = nodes_to_visit[pos++];
......
......@@ -39,9 +39,9 @@ namespace internal {
//
// typedef Key: the key type
// typedef Value: the value type
// static const Key kNoKey: the dummy key used when no key is set
// static Value kNoValue(): the dummy value used to initialize nodes
// static int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function
// static const kNoKey: the dummy key used when no key is set
// static const kNoValue: the dummy value used to initialize nodes
// int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function
//
// The tree is also parameterized by an allocation policy
// (Allocator). The policy is used for allocating lists in the C free
......@@ -74,11 +74,6 @@ class SplayTree {
UNREACHABLE();
}
AllocationPolicy allocator() { return allocator_; }
// Checks if there is a mapping for the key.
bool Contains(const Key& key);
// Inserts the given key in this tree with the given value. Returns
// true if a node was inserted, otherwise false. If found the locator
// is enabled and provides access to the mapping for the key.
......@@ -109,9 +104,6 @@ class SplayTree {
// Remove the node with the given key from the tree.
bool Remove(const Key& key);
// Remove all keys from the tree.
void Clear() { ResetRoot(); }
bool is_empty() { return root_ == NULL; }
// Perform the splay operation for the given key. Moves the node with
......
......@@ -303,11 +303,6 @@ struct Bounds {
explicit Bounds(Handle<Type> t) : lower(t), upper(t) {}
Bounds(Type* t, Isolate* isl) : lower(t, isl), upper(t, isl) {}
// Unrestricted bounds.
static Bounds Unbounded(Isolate* isl) {
return Bounds(Type::None(), Type::Any(), isl);
}
// Meet: both b1 and b2 are known to hold.
static Bounds Both(Bounds b1, Bounds b2, Isolate* isl) {
return Bounds(
......
......@@ -40,8 +40,7 @@ AstTyper::AstTyper(CompilationInfo* info)
Handle<Code>(info->closure()->shared()->code()),
Handle<Context>(info->closure()->context()->native_context()),
info->isolate(),
info->zone()),
store_(info->zone()) {
info->zone()) {
InitializeAstVisitor();
}
......@@ -80,16 +79,12 @@ void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) {
for (int i = 0; i < stmts->length(); ++i) {
Statement* stmt = stmts->at(i);
RECURSE(Visit(stmt));
if (stmt->IsJump()) break;
}
}
void AstTyper::VisitBlock(Block* stmt) {
RECURSE(VisitStatements(stmt->statements()));
if (stmt->labels() != NULL) {
store_.Forget(); // Control may transfer here via 'break l'.
}
}
......@@ -103,41 +98,30 @@ void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) {
void AstTyper::VisitIfStatement(IfStatement* stmt) {
// Collect type feedback.
RECURSE(Visit(stmt->condition()));
RECURSE(Visit(stmt->then_statement()));
RECURSE(Visit(stmt->else_statement()));
if (!stmt->condition()->ToBooleanIsTrue() &&
!stmt->condition()->ToBooleanIsFalse()) {
stmt->condition()->RecordToBooleanTypeFeedback(oracle());
}
RECURSE(Visit(stmt->condition()));
Effects then_effects = EnterEffects();
RECURSE(Visit(stmt->then_statement()));
ExitEffects();
Effects else_effects = EnterEffects();
RECURSE(Visit(stmt->else_statement()));
ExitEffects();
then_effects.Alt(else_effects);
store_.Seq(then_effects);
}
void AstTyper::VisitContinueStatement(ContinueStatement* stmt) {
// TODO(rossberg): is it worth having a non-termination effect?
}
void AstTyper::VisitBreakStatement(BreakStatement* stmt) {
// TODO(rossberg): is it worth having a non-termination effect?
}
void AstTyper::VisitReturnStatement(ReturnStatement* stmt) {
// Collect type feedback.
RECURSE(Visit(stmt->expression()));
// TODO(rossberg): we only need this for inlining into test contexts...
stmt->expression()->RecordToBooleanTypeFeedback(oracle());
RECURSE(Visit(stmt->expression()));
// TODO(rossberg): is it worth having a non-termination effect?
}
......@@ -149,18 +133,14 @@ void AstTyper::VisitWithStatement(WithStatement* stmt) {
void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) {
RECURSE(Visit(stmt->tag()));
ZoneList<CaseClause*>* clauses = stmt->cases();
SwitchStatement::SwitchType switch_type = stmt->switch_type();
Effects local_effects(zone());
bool complex_effects = false; // True for label effects or fall-through.
for (int i = 0; i < clauses->length(); ++i) {
CaseClause* clause = clauses->at(i);
Effects clause_effects = EnterEffects();
if (!clause->is_default()) {
Expression* label = clause->label();
RECURSE(Visit(label));
SwitchStatement::SwitchType label_switch_type =
label->IsSmiLiteral() ? SwitchStatement::SMI_SWITCH :
label->IsStringLiteral() ? SwitchStatement::STRING_SWITCH :
......@@ -169,32 +149,13 @@ void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) {
switch_type = label_switch_type;
else if (switch_type != label_switch_type)
switch_type = SwitchStatement::GENERIC_SWITCH;
RECURSE(Visit(label));
if (!clause_effects.IsEmpty()) complex_effects = true;
}
ZoneList<Statement*>* stmts = clause->statements();
RECURSE(VisitStatements(stmts));
ExitEffects();
if (stmts->is_empty() || stmts->last()->IsJump()) {
local_effects.Alt(clause_effects);
} else {
complex_effects = true;
}
RECURSE(VisitStatements(clause->statements()));
}
if (complex_effects) {
store_.Forget(); // Reached this in unknown state.
} else {
store_.Seq(local_effects);
}
if (switch_type == SwitchStatement::UNKNOWN_SWITCH)
switch_type = SwitchStatement::GENERIC_SWITCH;
stmt->set_switch_type(switch_type);
// Collect type feedback.
// TODO(rossberg): can we eliminate this special case and extra loop?
if (switch_type == SwitchStatement::SMI_SWITCH) {
for (int i = 0; i < clauses->length(); ++i) {
......@@ -207,31 +168,22 @@ void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) {
void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
// Collect type feedback.
RECURSE(Visit(stmt->body()));
RECURSE(Visit(stmt->cond()));
if (!stmt->cond()->ToBooleanIsTrue()) {
stmt->cond()->RecordToBooleanTypeFeedback(oracle());
}
// TODO(rossberg): refine the unconditional Forget (here and elsewhere) by
// computing the set of variables assigned in only some of the origins of the
// control transfer (such as the loop body here).
store_.Forget(); // Control may transfer here via looping or 'continue'.
RECURSE(Visit(stmt->body()));
RECURSE(Visit(stmt->cond()));
store_.Forget(); // Control may transfer here via 'break'.
}
void AstTyper::VisitWhileStatement(WhileStatement* stmt) {
// Collect type feedback.
RECURSE(Visit(stmt->cond()));
RECURSE(Visit(stmt->body()));
if (!stmt->cond()->ToBooleanIsTrue()) {
stmt->cond()->RecordToBooleanTypeFeedback(oracle());
}
store_.Forget(); // Control may transfer here via looping or 'continue'.
RECURSE(Visit(stmt->cond()));
RECURSE(Visit(stmt->body()));
store_.Forget(); // Control may transfer here via termination or 'break'.
}
......@@ -239,65 +191,45 @@ void AstTyper::VisitForStatement(ForStatement* stmt) {
if (stmt->init() != NULL) {
RECURSE(Visit(stmt->init()));
}
store_.Forget(); // Control may transfer here via looping.
if (stmt->cond() != NULL) {
// Collect type feedback.
stmt->cond()->RecordToBooleanTypeFeedback(oracle());
RECURSE(Visit(stmt->cond()));
stmt->cond()->RecordToBooleanTypeFeedback(oracle());
}
RECURSE(Visit(stmt->body()));
store_.Forget(); // Control may transfer here via 'continue'.
if (stmt->next() != NULL) {
RECURSE(Visit(stmt->next()));
}
store_.Forget(); // Control may transfer here via termination or 'break'.
}
void AstTyper::VisitForInStatement(ForInStatement* stmt) {
// Collect type feedback.
stmt->RecordTypeFeedback(oracle());
RECURSE(Visit(stmt->enumerable()));
store_.Forget(); // Control may transfer here via looping or 'continue'.
RECURSE(Visit(stmt->body()));
store_.Forget(); // Control may transfer here via 'break'.
stmt->RecordTypeFeedback(oracle());
}
void AstTyper::VisitForOfStatement(ForOfStatement* stmt) {
RECURSE(Visit(stmt->iterable()));
store_.Forget(); // Control may transfer here via looping or 'continue'.
RECURSE(Visit(stmt->body()));
store_.Forget(); // Control may transfer here via 'break'.
}
void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
Effects try_effects = EnterEffects();
RECURSE(Visit(stmt->try_block()));
ExitEffects();
Effects catch_effects = EnterEffects();
store_.Forget(); // Control may transfer here via 'throw'.
RECURSE(Visit(stmt->catch_block()));
ExitEffects();
try_effects.Alt(catch_effects);
store_.Seq(try_effects);
// At this point, only variables that were reassigned in the catch block are
// still remembered.
}
void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
RECURSE(Visit(stmt->try_block()));
store_.Forget(); // Control may transfer here via 'throw'.
RECURSE(Visit(stmt->finally_block()));
}
void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
store_.Forget(); // May do whatever.
}
......@@ -310,18 +242,11 @@ void AstTyper::VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral* expr) {
void AstTyper::VisitConditional(Conditional* expr) {
// Collect type feedback.
expr->condition()->RecordToBooleanTypeFeedback(oracle());
RECURSE(Visit(expr->condition()));
Effects then_effects = EnterEffects();
RECURSE(Visit(expr->then_expression()));
ExitEffects();
Effects else_effects = EnterEffects();
RECURSE(Visit(expr->else_expression()));
ExitEffects();
then_effects.Alt(else_effects);
store_.Seq(then_effects);
expr->condition()->RecordToBooleanTypeFeedback(oracle());
NarrowType(expr, Bounds::Either(
expr->then_expression()->bounds(),
......@@ -330,10 +255,7 @@ void AstTyper::VisitConditional(Conditional* expr) {
void AstTyper::VisitVariableProxy(VariableProxy* expr) {
Variable* var = expr->var();
if (var->IsStackAllocated()) {
NarrowType(expr, store_.LookupBounds(variable_index(var)));
}
// TODO(rossberg): typing of variables
}
......@@ -352,8 +274,8 @@ void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
for (int i = 0; i < properties->length(); ++i) {
ObjectLiteral::Property* prop = properties->at(i);
RECURSE(Visit(prop->value()));
// Collect type feedback.
if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
!CompileTimeValue::IsCompileTimeValue(prop->value())) ||
prop->kind() == ObjectLiteral::Property::COMPUTED) {
......@@ -361,8 +283,6 @@ void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
prop->RecordTypeFeedback(oracle());
}
}
RECURSE(Visit(prop->value()));
}
NarrowType(expr, Bounds(Type::Object(), isolate_));
......@@ -383,7 +303,8 @@ void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) {
void AstTyper::VisitAssignment(Assignment* expr) {
// TODO(rossberg): Can we clean this up?
if (expr->is_compound()) {
// Collect type feedback.
RECURSE(Visit(expr->binary_operation()));
Expression* target = expr->target();
Property* prop = target->AsProperty();
if (prop != NULL) {
......@@ -393,25 +314,18 @@ void AstTyper::VisitAssignment(Assignment* expr) {
}
}
RECURSE(Visit(expr->binary_operation()));
NarrowType(expr, expr->binary_operation()->bounds());
} else {
// Collect type feedback.
if (expr->target()->IsProperty()) {
expr->RecordTypeFeedback(oracle(), zone());
}
RECURSE(Visit(expr->target()));
RECURSE(Visit(expr->value()));
NarrowType(expr, expr->value()->bounds());
}
if (expr->target()->AsProperty()) {
expr->RecordTypeFeedback(oracle(), zone());
}
VariableProxy* proxy = expr->target()->AsVariableProxy();
if (proxy != NULL && proxy->var()->IsStackAllocated()) {
store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
NarrowType(expr, expr->value()->bounds());
}
// TODO(rossberg): handle target variables
}
......@@ -419,40 +333,28 @@ void AstTyper::VisitYield(Yield* expr) {
RECURSE(Visit(expr->generator_object()));
RECURSE(Visit(expr->expression()));
// We don't know anything about the result type.
// We don't know anything about the type.
}
void AstTyper::VisitThrow(Throw* expr) {
RECURSE(Visit(expr->exception()));
// TODO(rossberg): is it worth having a non-termination effect?
NarrowType(expr, Bounds(Type::None(), isolate_));
}
void AstTyper::VisitProperty(Property* expr) {
// Collect type feedback.
expr->RecordTypeFeedback(oracle(), zone());
RECURSE(Visit(expr->obj()));
RECURSE(Visit(expr->key()));
// We don't know anything about the result type.
expr->RecordTypeFeedback(oracle(), zone());
// We don't know anything about the type.
}
void AstTyper::VisitCall(Call* expr) {
// Collect type feedback.
Expression* callee = expr->expression();
Property* prop = callee->AsProperty();
if (prop != NULL) {
if (prop->key()->IsPropertyName())
expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD);
} else {
expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION);
}
RECURSE(Visit(expr->expression()));
ZoneList<Expression*>* args = expr->arguments();
for (int i = 0; i < args->length(); ++i) {
......@@ -460,19 +362,20 @@ void AstTyper::VisitCall(Call* expr) {
RECURSE(Visit(arg));
}
VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
store_.Forget(); // Eval could do whatever to local variables.
Expression* callee = expr->expression();
Property* prop = callee->AsProperty();
if (prop != NULL) {
if (prop->key()->IsPropertyName())
expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD);
} else {
expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION);
}
// We don't know anything about the result type.
// We don't know anything about the type.
}
void AstTyper::VisitCallNew(CallNew* expr) {
// Collect type feedback.
expr->RecordTypeFeedback(oracle());
RECURSE(Visit(expr->expression()));
ZoneList<Expression*>* args = expr->arguments();
for (int i = 0; i < args->length(); ++i) {
......@@ -480,7 +383,9 @@ void AstTyper::VisitCallNew(CallNew* expr) {
RECURSE(Visit(arg));
}
// We don't know anything about the result type.
expr->RecordTypeFeedback(oracle());
// We don't know anything about the type.
}
......@@ -491,11 +396,13 @@ void AstTyper::VisitCallRuntime(CallRuntime* expr) {
RECURSE(Visit(arg));
}
// We don't know anything about the result type.
// We don't know anything about the type.
}
void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
RECURSE(Visit(expr->expression()));
// Collect type feedback.
Handle<Type> op_type = oracle()->UnaryType(expr->UnaryOperationFeedbackId());
NarrowLowerType(expr->expression(), op_type);
......@@ -504,8 +411,6 @@ void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
expr->expression()->RecordToBooleanTypeFeedback(oracle());
}
RECURSE(Visit(expr->expression()));
switch (expr->op()) {
case Token::NOT:
case Token::DELETE:
......@@ -534,25 +439,22 @@ void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
void AstTyper::VisitCountOperation(CountOperation* expr) {
// Collect type feedback.
RECURSE(Visit(expr->expression()));
expr->RecordTypeFeedback(oracle(), zone());
Property* prop = expr->expression()->AsProperty();
if (prop != NULL) {
prop->RecordTypeFeedback(oracle(), zone());
}
RECURSE(Visit(expr->expression()));
NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_));
VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (proxy != NULL && proxy->var()->IsStackAllocated()) {
store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
}
}
void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
RECURSE(Visit(expr->left()));
RECURSE(Visit(expr->right()));
// Collect type feedback.
Handle<Type> type, left_type, right_type;
Maybe<int> fixed_right_arg;
......@@ -568,29 +470,15 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
switch (expr->op()) {
case Token::COMMA:
RECURSE(Visit(expr->left()));
RECURSE(Visit(expr->right()));
NarrowType(expr, expr->right()->bounds());
break;
case Token::OR:
case Token::AND: {
Effects left_effects = EnterEffects();
RECURSE(Visit(expr->left()));
ExitEffects();
Effects right_effects = EnterEffects();
RECURSE(Visit(expr->right()));
ExitEffects();
left_effects.Alt(right_effects);
store_.Seq(left_effects);
case Token::AND:
NarrowType(expr, Bounds::Either(
expr->left()->bounds(), expr->right()->bounds(), isolate_));
break;
}
case Token::BIT_OR:
case Token::BIT_AND: {
RECURSE(Visit(expr->left()));
RECURSE(Visit(expr->right()));
Type* upper = Type::Union(
expr->left()->bounds().upper, expr->right()->bounds().upper);
if (!upper->Is(Type::Signed32())) upper = Type::Signed32();
......@@ -600,18 +488,12 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
case Token::BIT_XOR:
case Token::SHL:
case Token::SAR:
RECURSE(Visit(expr->left()));
RECURSE(Visit(expr->right()));
NarrowType(expr, Bounds(Type::Smi(), Type::Signed32(), isolate_));
break;
case Token::SHR:
RECURSE(Visit(expr->left()));
RECURSE(Visit(expr->right()));
NarrowType(expr, Bounds(Type::Smi(), Type::Unsigned32(), isolate_));
break;
case Token::ADD: {
RECURSE(Visit(expr->left()));
RECURSE(Visit(expr->right()));
Bounds l = expr->left()->bounds();
Bounds r = expr->right()->bounds();
Type* lower =
......@@ -631,8 +513,6 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
case Token::MUL:
case Token::DIV:
case Token::MOD:
RECURSE(Visit(expr->left()));
RECURSE(Visit(expr->right()));
NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_));
break;
default:
......@@ -642,6 +522,9 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
void AstTyper::VisitCompareOperation(CompareOperation* expr) {
RECURSE(Visit(expr->left()));
RECURSE(Visit(expr->right()));
// Collect type feedback.
Handle<Type> left_type, right_type, combined_type;
oracle()->CompareType(expr->CompareOperationFeedbackId(),
......@@ -650,9 +533,6 @@ void AstTyper::VisitCompareOperation(CompareOperation* expr) {
NarrowLowerType(expr->right(), right_type);
expr->set_combined_type(combined_type);
RECURSE(Visit(expr->left()));
RECURSE(Visit(expr->right()));
NarrowType(expr, Bounds(Type::Boolean(), isolate_));
}
......
......@@ -35,7 +35,6 @@
#include "compiler.h"
#include "type-info.h"
#include "types.h"
#include "effects.h"
#include "zone.h"
#include "scopes.h"
......@@ -58,13 +57,8 @@ class AstTyper: public AstVisitor {
private:
explicit AstTyper(CompilationInfo* info);
static const int kNoVar = INT_MIN;
typedef v8::internal::Effects<int, kNoVar> Effects;
typedef v8::internal::NestedEffects<int, kNoVar> Store;
CompilationInfo* info_;
TypeFeedbackOracle oracle_;
Store store_;
TypeFeedbackOracle* oracle() { return &oracle_; }
Zone* zone() const { return info_->zone(); }
......@@ -76,17 +70,6 @@ class AstTyper: public AstVisitor {
e->set_bounds(Bounds::NarrowLower(e->bounds(), t, isolate_));
}
Effects EnterEffects() {
store_ = store_.Push();
return store_.Top();
}
void ExitEffects() { store_ = store_.Pop(); }
int variable_index(Variable* var) {
return var->IsStackLocal() ? var->index() :
var->IsParameter() ? -var->index() : kNoVar;
}
void VisitDeclarations(ZoneList<Declaration*>* declarations);
void VisitStatements(ZoneList<Statement*>* statements);
......
......@@ -109,12 +109,6 @@ void* ZoneList<T>::operator new(size_t size, Zone* zone) {
}
template <typename T>
void* ZoneSplayTree<T>::operator new(size_t size, Zone* zone) {
return zone->New(static_cast<int>(size));
}
} } // namespace v8::internal
#endif // V8_ZONE_INL_H_
......@@ -177,7 +177,6 @@ struct ZoneAllocationPolicy {
explicit ZoneAllocationPolicy(Zone* zone) : zone_(zone) { }
INLINE(void* New(size_t size));
INLINE(static void Delete(void *pointer)) { }
Zone* zone() { return zone_; }
private:
Zone* zone_;
......@@ -247,8 +246,6 @@ class ZoneSplayTree: public SplayTree<Config, ZoneAllocationPolicy> {
explicit ZoneSplayTree(Zone* zone)
: SplayTree<Config, ZoneAllocationPolicy>(ZoneAllocationPolicy(zone)) {}
~ZoneSplayTree();
INLINE(void* operator new(size_t size, Zone* zone));
};
......
......@@ -290,7 +290,6 @@
'../../src/double.h',
'../../src/dtoa.cc',
'../../src/dtoa.h',
'../../src/effects.h',
'../../src/elements-kind.cc',
'../../src/elements-kind.h',
'../../src/elements.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment