is_this_(is_this),
inside_with_(inside_with),
is_trivial_(false),
- reaching_definitions_(NULL) {
+ reaching_definitions_(NULL),
+ is_primitive_(false) {
// names must be canonicalized for fast equality checks
ASSERT(name->IsSymbol());
}
VariableProxy::VariableProxy(bool is_this)
: is_this_(is_this),
- reaching_definitions_(NULL) {
+ reaching_definitions_(NULL),
+ is_primitive_(false) {
}
// The following expression types are not always primitive because we do not
// have enough information to conclude that they are.
-bool VariableProxy::IsPrimitive() { return false; }
bool Property::IsPrimitive() { return false; }
bool Call::IsPrimitive() { return false; }
bool CallRuntime::IsPrimitive() { return false; }
+// A variable use is not primitive unless the primitive-type analysis
+// determines otherwise.
+bool VariableProxy::IsPrimitive() {
+ ASSERT(!is_primitive_ || (var() != NULL && var()->IsStackAllocated()));
+ return is_primitive_;
+}
+
// The value of a conditional is the value of one of the alternatives. It's
// always primitive if both alternatives are always primitive.
bool Conditional::IsPrimitive() {
virtual bool IsPrimitive();
+ void SetIsPrimitive(bool value) { is_primitive_ = value; }
+
bool IsVariable(Handle<String> n) {
return !is_this() && name().is_identical_to(n);
}
bool inside_with_;
bool is_trivial_;
BitVector* reaching_definitions_;
+ bool is_primitive_;
VariableProxy(Handle<String> name, bool is_this, bool inside_with);
explicit VariableProxy(bool is_this);
builder.body_definitions(),
variable_count);
rd.Compute();
+
+ TypeAnalyzer ta(builder.postorder(),
+ builder.body_definitions(),
+ variable_count,
+ function->num_parameters());
+ ta.Compute();
}
}
FlowGraphBuilder builder(variable_count);
builder.Build(literal);
- if (!builder.HasStackOverflow()) {
- if (variable_count > 0) {
- ReachingDefinitions rd(builder.postorder(),
- builder.body_definitions(),
- variable_count);
- rd.Compute();
+ if (!builder.HasStackOverflow()) {
+ if (variable_count > 0) {
+ ReachingDefinitions rd(builder.postorder(),
+ builder.body_definitions(),
+ variable_count);
+ rd.Compute();
+
+ TypeAnalyzer ta(builder.postorder(),
+ builder.body_definitions(),
+ variable_count,
+ literal->num_parameters());
+ ta.Compute();
+ }
}
- }
#ifdef DEBUG
if (FLAG_print_graph_text && !builder.HasStackOverflow()) {
}
+bool TypeAnalyzer::IsPrimitiveDef(int def_num) {
+ if (def_num < param_count_) return false;
+ if (def_num < variable_count_) return true;
+ return body_definitions_->at(def_num - variable_count_)->IsPrimitive();
+}
+
+
+void TypeAnalyzer::Compute() {
+ bool changed;
+ int count = 0;
+
+ do {
+ changed = false;
+
+ if (FLAG_print_graph_text) {
+ PrintF("TypeAnalyzer::Compute - iteration %d\n", count++);
+ }
+
+ for (int i = postorder_->length() - 1; i >= 0; --i) {
+ Node* node = postorder_->at(i);
+ if (node->IsBlockNode()) {
+ BlockNode* block = BlockNode::cast(node);
+ for (int j = 0; j < block->instructions()->length(); j++) {
+ Expression* expr = block->instructions()->at(j)->AsExpression();
+ if (expr != NULL) {
+ // For variable uses: Compute new type from reaching definitions.
+ VariableProxy* proxy = expr->AsVariableProxy();
+ if (proxy != NULL && proxy->reaching_definitions() != NULL) {
+ BitVector* rd = proxy->reaching_definitions();
+ bool prim_type = true;
+ // TODO(fsc): A sparse set representation of reaching
+ // definitions would speed up iterating here.
+ for (int k = 0; k < rd->length(); k++) {
+ if (rd->Contains(k) && !IsPrimitiveDef(k)) {
+ prim_type = false;
+ break;
+ }
+ }
+ // Reset changed flag if new type information was computed.
+ if (prim_type != proxy->IsPrimitive()) {
+ changed = true;
+ proxy->SetIsPrimitive(prim_type);
+ }
+ }
+ }
+ }
+ }
+ }
+ } while (changed);
+}
+
+
} } // namespace v8::internal
bool is_empty() { return instructions_.is_empty(); }
+ ZoneList<AstNode*>* instructions() { return &instructions_; }
+
void AddPredecessor(Node* predecessor) {
ASSERT(predecessor_ == NULL && predecessor != NULL);
predecessor_ = predecessor;
};
+
+class TypeAnalyzer BASE_EMBEDDED {
+ public:
+ TypeAnalyzer(ZoneList<Node*>* postorder,
+ ZoneList<Expression*>* body_definitions,
+ int variable_count,
+ int param_count)
+ : postorder_(postorder),
+ body_definitions_(body_definitions),
+ variable_count_(variable_count),
+ param_count_(param_count) {}
+
+ void Compute();
+
+ private:
+ // Get the primitity of definition number i. Definitions are numbered
+ // by the flow graph builder.
+ bool IsPrimitiveDef(int def_num);
+
+ ZoneList<Node*>* postorder_;
+ ZoneList<Expression*>* body_definitions_;
+ int variable_count_;
+ int param_count_;
+};
+
} } // namespace v8::internal
Variable* var,
Handle<Object> value,
StaticType* type,
- int num) {
+ int num,
+ bool is_primitive) {
if (var == NULL) {
PrintLiteralIndented(info, value, true);
} else {
if (num != AstNode::kNoNumber) {
pos += OS::SNPrintF(buf + pos, ", num = %d", num);
}
+ pos += OS::SNPrintF(buf + pos,
+ is_primitive ? ", primitive" : ", non-primitive");
OS::SNPrintF(buf + pos, ")");
PrintLiteralIndented(buf.start(), value, true);
}
PrintLiteralWithModeIndented("VAR", scope->parameter(i),
scope->parameter(i)->name(),
scope->parameter(i)->type(),
- AstNode::kNoNumber);
+ AstNode::kNoNumber,
+ false);
}
}
}
node->proxy()->AsVariable(),
node->proxy()->name(),
node->proxy()->AsVariable()->type(),
- AstNode::kNoNumber);
+ AstNode::kNoNumber,
+ node->proxy()->IsPrimitive());
} else {
// function declarations
PrintIndented("FUNCTION ");
void AstPrinter::VisitVariableProxy(VariableProxy* node) {
PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name(),
- node->type(), node->num());
+ node->type(), node->num(), node->IsPrimitive());
Variable* var = node->var();
if (var != NULL && var->rewrite() != NULL) {
IndentedScope indent;
Variable* var,
Handle<Object> value,
StaticType* type,
- int num);
+ int num,
+ bool is_primitive);
void PrintLabelsIndented(const char* info, ZoneStringList* labels);
void inc_indent() { indent_++; }