Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(931)

Unified Diff: src/parser.cc

Issue 172088: Analyze functions for assignment to this properties (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects-inl.h ('k') | src/runtime.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/parser.cc
===================================================================
--- src/parser.cc (revision 2708)
+++ src/parser.cc (working copy)
@@ -678,6 +678,25 @@
void set_contains_array_literal() { contains_array_literal_ = true; }
bool contains_array_literal() { return contains_array_literal_; }
+ void SetThisPropertyAssignmentInfo(
+ bool only_this_property_assignments,
+ bool only_simple_this_property_assignments,
+ Handle<FixedArray> this_property_assignments) {
+ only_this_property_assignments_ = only_this_property_assignments;
+ only_simple_this_property_assignments_ =
+ only_simple_this_property_assignments;
+ this_property_assignments_ = this_property_assignments;
+ }
+ bool only_this_property_assignments() {
+ return only_this_property_assignments_;
+ }
+ bool only_simple_this_property_assignments() {
+ return only_simple_this_property_assignments_;
+ }
+ Handle<FixedArray> this_property_assignments() {
+ return this_property_assignments_;
+ }
+
void AddProperty() { expected_property_count_++; }
int expected_property_count() { return expected_property_count_; }
private:
@@ -695,6 +714,10 @@
// Properties count estimation.
int expected_property_count_;
+ bool only_this_property_assignments_;
+ bool only_simple_this_property_assignments_;
+ Handle<FixedArray> this_property_assignments_;
+
// Bookkeeping
Parser* parser_;
TemporaryScope* parent_;
@@ -707,6 +730,9 @@
: materialized_literal_count_(0),
contains_array_literal_(false),
expected_property_count_(0),
+ only_this_property_assignments_(false),
+ only_simple_this_property_assignments_(false),
+ this_property_assignments_(Factory::empty_fixed_array()),
parser_(parser),
parent_(parser->temp_scope_) {
parser->temp_scope_ = this;
@@ -1218,12 +1244,20 @@
bool ok = true;
ParseSourceElements(&body, Token::EOS, &ok);
if (ok) {
- result = NEW(FunctionLiteral(no_name, top_scope_,
- body.elements(),
- temp_scope.materialized_literal_count(),
- temp_scope.contains_array_literal(),
- temp_scope.expected_property_count(),
- 0, 0, source->length(), false));
+ result = NEW(FunctionLiteral(
+ no_name,
+ top_scope_,
+ body.elements(),
+ temp_scope.materialized_literal_count(),
+ temp_scope.contains_array_literal(),
+ temp_scope.expected_property_count(),
+ temp_scope.only_this_property_assignments(),
+ temp_scope.only_simple_this_property_assignments(),
+ temp_scope.this_property_assignments(),
+ 0,
+ 0,
+ source->length(),
+ false));
} else if (scanner().stack_overflow()) {
Top::StackOverflow();
}
@@ -1314,9 +1348,23 @@
}
+// Base class containing common code for the different finder classes used by
+// the parser.
+class ParserFinder {
+ protected:
+ ParserFinder() {}
+ static Assignment* AsAssignment(Statement* stat) {
+ if (stat == NULL) return NULL;
+ ExpressionStatement* exp_stat = stat->AsExpressionStatement();
+ if (exp_stat == NULL) return NULL;
+ return exp_stat->expression()->AsAssignment();
+ }
+};
+
+
// An InitializationBlockFinder finds and marks sequences of statements of the
// form x.y.z.a = ...; x.y.z.b = ...; etc.
-class InitializationBlockFinder {
+class InitializationBlockFinder : public ParserFinder {
public:
InitializationBlockFinder()
: first_in_block_(NULL), last_in_block_(NULL), block_size_(0) {}
@@ -1341,13 +1389,6 @@
}
private:
- static Assignment* AsAssignment(Statement* stat) {
- if (stat == NULL) return NULL;
- ExpressionStatement* exp_stat = stat->AsExpressionStatement();
- if (exp_stat == NULL) return NULL;
- return exp_stat->expression()->AsAssignment();
- }
-
// Returns true if the expressions appear to denote the same object.
// In the context of initialization blocks, we only consider expressions
// of the form 'x.y.z'.
@@ -1418,6 +1459,161 @@
};
+// A ThisNamedPropertyAssigmentFinder finds and marks statements of the form
+// this.x = ...;, where x is a named property. It also determines whether a
+// function contains only assignments of this type.
+class ThisNamedPropertyAssigmentFinder : public ParserFinder {
+ public:
+ ThisNamedPropertyAssigmentFinder()
+ : only_this_property_assignments_(true),
+ only_simple_this_property_assignments_(true),
+ names_(NULL),
+ assigned_arguments_(NULL),
+ assigned_constants_(NULL) {}
+
+ void Update(Scope* scope, Statement* stat) {
+ // Bail out if function already has non this property assignment
+ // statements.
+ if (!only_this_property_assignments_) {
+ return;
+ }
+
+ // Check whether this statement is of the form this.x = ...;
+ Assignment* assignment = AsAssignment(stat);
+ if (IsThisPropertyAssignment(assignment)) {
+ HandleThisPropertyAssignment(scope, assignment);
+ } else {
+ only_this_property_assignments_ = false;
+ only_simple_this_property_assignments_ = false;
+ }
+ }
+
+ // Returns whether only statements of the form this.x = ...; was encountered.
+ bool only_this_property_assignments() {
+ return only_this_property_assignments_;
+ }
+
+ // Returns whether only statements of the form this.x = y; where y is either a
+ // constant or a function argument was encountered.
+ bool only_simple_this_property_assignments() {
+ return only_simple_this_property_assignments_;
+ }
+
+ // Returns a fixed array containing three elements for each assignment of the
+ // form this.x = y;
+ Handle<FixedArray> GetThisPropertyAssignments() {
+ if (names_ == NULL) {
+ return Factory::empty_fixed_array();
+ }
+ ASSERT(names_ != NULL);
+ ASSERT(assigned_arguments_ != NULL);
+ ASSERT_EQ(names_->length(), assigned_arguments_->length());
+ ASSERT_EQ(names_->length(), assigned_constants_->length());
+ Handle<FixedArray> assignments =
+ Factory::NewFixedArray(names_->length() * 3);
+ for (int i = 0; i < names_->length(); i++) {
+ assignments->set(i * 3, *names_->at(i));
+ assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_->at(i)));
+ assignments->set(i * 3 + 2, *assigned_constants_->at(i));
+ }
+ return assignments;
+ }
+
+ private:
+ bool IsThisPropertyAssignment(Assignment* assignment) {
+ if (assignment != NULL) {
+ Property* property = assignment->target()->AsProperty();
+ return assignment->op() == Token::ASSIGN
+ && property != NULL
+ && property->obj()->AsVariableProxy() != NULL
+ && property->obj()->AsVariableProxy()->is_this();
+ }
+ return false;
+ }
+
+ void HandleThisPropertyAssignment(Scope* scope, Assignment* assignment) {
+ // Check that the property assigned to is a named property.
+ Property* property = assignment->target()->AsProperty();
+ ASSERT(property != NULL);
+ Literal* literal = property->key()->AsLiteral();
+ uint32_t dummy;
+ if (literal != NULL &&
+ literal->handle()->IsString() &&
+ !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
+ Handle<String> key = Handle<String>::cast(literal->handle());
+
+ // Check whether the value assigned is either a constant or matches the
+ // name of one of the arguments to the function.
+ if (assignment->value()->AsLiteral() != NULL) {
+ // Constant assigned.
+ Literal* literal = assignment->value()->AsLiteral();
+ AssignmentFromConstant(key, literal->handle());
+ } else if (assignment->value()->AsVariableProxy() != NULL) {
+ // Variable assigned.
+ Handle<String> name =
+ assignment->value()->AsVariableProxy()->name();
+ // Check whether the variable assigned matches an argument name.
+ int index = -1;
+ for (int i = 0; i < scope->num_parameters(); i++) {
+ if (*scope->parameter(i)->name() == *name) {
+ // Assigned from function argument.
+ index = i;
+ break;
+ }
+ }
+ if (index != -1) {
+ AssignmentFromParameter(key, index);
+ } else {
+ AssignmentFromSomethingElse(key);
+ }
+ } else {
+ AssignmentFromSomethingElse(key);
+ }
+ }
+ }
+
+ void AssignmentFromParameter(Handle<String> name, int index) {
+ EnsureAllocation();
+ names_->Add(name);
+ assigned_arguments_->Add(index);
+ assigned_constants_->Add(Factory::undefined_value());
+ }
+
+ void AssignmentFromConstant(Handle<String> name, Handle<Object> value) {
+ EnsureAllocation();
+ names_->Add(name);
+ assigned_arguments_->Add(-1);
+ assigned_constants_->Add(value);
+ }
+
+ void AssignmentFromSomethingElse(Handle<String> name) {
+ EnsureAllocation();
+ names_->Add(name);
+ assigned_arguments_->Add(-1);
+ assigned_constants_->Add(Factory::undefined_value());
+
+ // The this assignment is not a simple one.
+ only_simple_this_property_assignments_ = false;
+ }
+
+ void EnsureAllocation() {
+ if (names_ == NULL) {
+ ASSERT(assigned_arguments_ == NULL);
+ ASSERT(assigned_constants_ == NULL);
+ names_ = new ZoneStringList(4);
+ assigned_arguments_ = new ZoneList<int>(4);
+ assigned_constants_ = new ZoneObjectList(4);
+ }
+ }
+
+ bool only_this_property_assignments_;
+ bool only_simple_this_property_assignments_;
+ ZoneStringList* names_;
+ ZoneList<int>* assigned_arguments_;
+ ZoneObjectList* assigned_constants_;
+};
+
+
void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor,
int end_token,
bool* ok) {
@@ -1432,15 +1628,33 @@
ASSERT(processor != NULL);
InitializationBlockFinder block_finder;
+ ThisNamedPropertyAssigmentFinder this_property_assignment_finder;
while (peek() != end_token) {
Statement* stat = ParseStatement(NULL, CHECK_OK);
if (stat == NULL || stat->IsEmpty()) continue;
// We find and mark the initialization blocks on top level code only.
// This is because the optimization prevents reuse of the map transitions,
// so it should be used only for code that will only be run once.
- if (top_scope_->is_global_scope()) block_finder.Update(stat);
+ if (top_scope_->is_global_scope()) {
+ block_finder.Update(stat);
+ }
+ // Find and mark all assignments to named properties in this (this.x =)
+ if (top_scope_->is_function_scope()) {
+ this_property_assignment_finder.Update(top_scope_, stat);
+ }
processor->Add(stat);
}
+
+ // Propagate the collected information on this property assignments.
+ if (top_scope_->is_function_scope()) {
+ if (this_property_assignment_finder.only_this_property_assignments()) {
+ temp_scope_->SetThisPropertyAssignmentInfo(
+ this_property_assignment_finder.only_this_property_assignments(),
+ this_property_assignment_finder.
+ only_simple_this_property_assignments(),
+ this_property_assignment_finder.GetThisPropertyAssignments());
+ }
+ }
return 0;
}
@@ -3507,6 +3721,9 @@
int materialized_literal_count;
int expected_property_count;
bool contains_array_literal;
+ bool only_this_property_assignments;
+ bool only_simple_this_property_assignments;
+ Handle<FixedArray> this_property_assignments;
if (is_lazily_compiled && pre_data() != NULL) {
FunctionEntry entry = pre_data()->GetFunctionEnd(start_pos);
int end_pos = entry.end_pos();
@@ -3514,12 +3731,20 @@
scanner_.SeekForward(end_pos);
materialized_literal_count = entry.literal_count();
expected_property_count = entry.property_count();
+ only_this_property_assignments = false;
+ only_simple_this_property_assignments = false;
+ this_property_assignments = Factory::empty_fixed_array();
contains_array_literal = entry.contains_array_literal();
} else {
ParseSourceElements(&body, Token::RBRACE, CHECK_OK);
materialized_literal_count = temp_scope.materialized_literal_count();
expected_property_count = temp_scope.expected_property_count();
contains_array_literal = temp_scope.contains_array_literal();
+ only_this_property_assignments =
+ temp_scope.only_this_property_assignments();
+ only_simple_this_property_assignments =
+ temp_scope.only_simple_this_property_assignments();
+ this_property_assignments = temp_scope.this_property_assignments();
}
Expect(Token::RBRACE, CHECK_OK);
@@ -3534,10 +3759,18 @@
}
FunctionLiteral* function_literal =
- NEW(FunctionLiteral(name, top_scope_,
- body.elements(), materialized_literal_count,
- contains_array_literal, expected_property_count,
- num_parameters, start_pos, end_pos,
+ NEW(FunctionLiteral(name,
+ top_scope_,
+ body.elements(),
+ materialized_literal_count,
+ contains_array_literal,
+ expected_property_count,
+ only_this_property_assignments,
+ only_simple_this_property_assignments,
+ this_property_assignments,
+ num_parameters,
+ start_pos,
+ end_pos,
function_name->length() > 0));
if (!is_pre_parsing_) {
function_literal->set_function_token_position(function_token_position);
« no previous file with comments | « src/objects-inl.h ('k') | src/runtime.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698