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

Side by Side Diff: src/parser.cc

Issue 10905308: Do not go to slow mode and back to fast in initializer blocks. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 3 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/full-codegen-ia32.cc ('k') | src/runtime.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 814 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 Handle<FixedArray> elements = factory->NewFixedArray(args.length()); 825 Handle<FixedArray> elements = factory->NewFixedArray(args.length());
826 for (int i = 0; i < args.length(); i++) { 826 for (int i = 0; i < args.length(); i++) {
827 elements->set(i, *args[i]); 827 elements->set(i, *args[i]);
828 } 828 }
829 Handle<JSArray> array = factory->NewJSArrayWithElements(elements); 829 Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
830 Handle<Object> result = factory->NewSyntaxError(type, array); 830 Handle<Object> result = factory->NewSyntaxError(type, array);
831 isolate()->Throw(*result, &location); 831 isolate()->Throw(*result, &location);
832 } 832 }
833 833
834 834
835 // Base class containing common code for the different finder classes used by
836 // the parser.
837 class ParserFinder {
838 protected:
839 ParserFinder() {}
840 static Assignment* AsAssignment(Statement* stat) {
841 if (stat == NULL) return NULL;
842 ExpressionStatement* exp_stat = stat->AsExpressionStatement();
843 if (exp_stat == NULL) return NULL;
844 return exp_stat->expression()->AsAssignment();
845 }
846 };
847
848
849 // An InitializationBlockFinder finds and marks sequences of statements of the
850 // form expr.a = ...; expr.b = ...; etc.
851 class InitializationBlockFinder : public ParserFinder {
852 public:
853 // We find and mark the initialization blocks in top level
854 // non-looping code only. This is because the optimization prevents
855 // reuse of the map transitions, so it should be used only for code
856 // that will only be run once.
857 InitializationBlockFinder(Scope* top_scope, Target* target)
858 : enabled_(top_scope->DeclarationScope()->is_global_scope() &&
859 !IsLoopTarget(target)),
860 first_in_block_(NULL),
861 last_in_block_(NULL),
862 block_size_(0) {}
863
864 ~InitializationBlockFinder() {
865 if (!enabled_) return;
866 if (InBlock()) EndBlock();
867 }
868
869 void Update(Statement* stat) {
870 if (!enabled_) return;
871 Assignment* assignment = AsAssignment(stat);
872 if (InBlock()) {
873 if (BlockContinues(assignment)) {
874 UpdateBlock(assignment);
875 } else {
876 EndBlock();
877 }
878 }
879 if (!InBlock() && (assignment != NULL) &&
880 (assignment->op() == Token::ASSIGN)) {
881 StartBlock(assignment);
882 }
883 }
884
885 private:
886 // The minimum number of contiguous assignment that will
887 // be treated as an initialization block. Benchmarks show that
888 // the overhead exceeds the savings below this limit.
889 static const int kMinInitializationBlock = 3;
890
891 static bool IsLoopTarget(Target* target) {
892 while (target != NULL) {
893 if (target->node()->AsIterationStatement() != NULL) return true;
894 target = target->previous();
895 }
896 return false;
897 }
898
899 // Returns true if the expressions appear to denote the same object.
900 // In the context of initialization blocks, we only consider expressions
901 // of the form 'expr.x' or expr["x"].
902 static bool SameObject(Expression* e1, Expression* e2) {
903 VariableProxy* v1 = e1->AsVariableProxy();
904 VariableProxy* v2 = e2->AsVariableProxy();
905 if (v1 != NULL && v2 != NULL) {
906 return v1->name()->Equals(*v2->name());
907 }
908 Property* p1 = e1->AsProperty();
909 Property* p2 = e2->AsProperty();
910 if ((p1 == NULL) || (p2 == NULL)) return false;
911 Literal* key1 = p1->key()->AsLiteral();
912 Literal* key2 = p2->key()->AsLiteral();
913 if ((key1 == NULL) || (key2 == NULL)) return false;
914 if (!key1->handle()->IsString() || !key2->handle()->IsString()) {
915 return false;
916 }
917 String* name1 = String::cast(*key1->handle());
918 String* name2 = String::cast(*key2->handle());
919 if (!name1->Equals(name2)) return false;
920 return SameObject(p1->obj(), p2->obj());
921 }
922
923 // Returns true if the expressions appear to denote different properties
924 // of the same object.
925 static bool PropertyOfSameObject(Expression* e1, Expression* e2) {
926 Property* p1 = e1->AsProperty();
927 Property* p2 = e2->AsProperty();
928 if ((p1 == NULL) || (p2 == NULL)) return false;
929 return SameObject(p1->obj(), p2->obj());
930 }
931
932 bool BlockContinues(Assignment* assignment) {
933 if ((assignment == NULL) || (first_in_block_ == NULL)) return false;
934 if (assignment->op() != Token::ASSIGN) return false;
935 return PropertyOfSameObject(first_in_block_->target(),
936 assignment->target());
937 }
938
939 void StartBlock(Assignment* assignment) {
940 first_in_block_ = assignment;
941 last_in_block_ = assignment;
942 block_size_ = 1;
943 }
944
945 void UpdateBlock(Assignment* assignment) {
946 last_in_block_ = assignment;
947 ++block_size_;
948 }
949
950 void EndBlock() {
951 if (block_size_ >= kMinInitializationBlock) {
952 first_in_block_->mark_block_start();
953 last_in_block_->mark_block_end();
954 }
955 last_in_block_ = first_in_block_ = NULL;
956 block_size_ = 0;
957 }
958
959 bool InBlock() { return first_in_block_ != NULL; }
960
961 const bool enabled_;
962 Assignment* first_in_block_;
963 Assignment* last_in_block_;
964 int block_size_;
965
966 DISALLOW_COPY_AND_ASSIGN(InitializationBlockFinder);
967 };
968
969
970 // A ThisNamedPropertyAssignmentFinder finds and marks statements of the form 835 // A ThisNamedPropertyAssignmentFinder finds and marks statements of the form
971 // this.x = ...;, where x is a named property. It also determines whether a 836 // this.x = ...;, where x is a named property. It also determines whether a
972 // function contains only assignments of this type. 837 // function contains only assignments of this type.
973 class ThisNamedPropertyAssignmentFinder : public ParserFinder { 838 class ThisNamedPropertyAssignmentFinder {
974 public: 839 public:
975 ThisNamedPropertyAssignmentFinder(Isolate* isolate, Zone* zone) 840 ThisNamedPropertyAssignmentFinder(Isolate* isolate, Zone* zone)
976 : isolate_(isolate), 841 : isolate_(isolate),
977 only_simple_this_property_assignments_(true), 842 only_simple_this_property_assignments_(true),
978 names_(0, zone), 843 names_(0, zone),
979 assigned_arguments_(0, zone), 844 assigned_arguments_(0, zone),
980 assigned_constants_(0, zone), 845 assigned_constants_(0, zone),
981 zone_(zone) { 846 zone_(zone) {
982 } 847 }
983 848
849 static Assignment* AsAssignment(Statement* stat) {
850 if (stat == NULL) return NULL;
851 ExpressionStatement* exp_stat = stat->AsExpressionStatement();
852 if (exp_stat == NULL) return NULL;
853 return exp_stat->expression()->AsAssignment();
854 }
855
984 void Update(Scope* scope, Statement* stat) { 856 void Update(Scope* scope, Statement* stat) {
985 // Bail out if function already has property assignment that are 857 // Bail out if function already has property assignment that are
986 // not simple this property assignments. 858 // not simple this property assignments.
987 if (!only_simple_this_property_assignments_) { 859 if (!only_simple_this_property_assignments_) {
988 return; 860 return;
989 } 861 }
990 862
991 // Check whether this statement is of the form this.x = ...; 863 // Check whether this statement is of the form this.x = ...;
992 Assignment* assignment = AsAssignment(stat); 864 Assignment* assignment = AsAssignment(stat);
993 if (IsThisPropertyAssignment(assignment)) { 865 if (IsThisPropertyAssignment(assignment)) {
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
1139 // SourceElements :: 1011 // SourceElements ::
1140 // (ModuleElement)* <end_token> 1012 // (ModuleElement)* <end_token>
1141 1013
1142 // Allocate a target stack to use for this set of source 1014 // Allocate a target stack to use for this set of source
1143 // elements. This way, all scripts and functions get their own 1015 // elements. This way, all scripts and functions get their own
1144 // target stack thus avoiding illegal breaks and continues across 1016 // target stack thus avoiding illegal breaks and continues across
1145 // functions. 1017 // functions.
1146 TargetScope scope(&this->target_stack_); 1018 TargetScope scope(&this->target_stack_);
1147 1019
1148 ASSERT(processor != NULL); 1020 ASSERT(processor != NULL);
1149 InitializationBlockFinder block_finder(top_scope_, target_stack_);
1150 ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate(), 1021 ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate(),
1151 zone()); 1022 zone());
1152 bool directive_prologue = true; // Parsing directive prologue. 1023 bool directive_prologue = true; // Parsing directive prologue.
1153 1024
1154 while (peek() != end_token) { 1025 while (peek() != end_token) {
1155 if (directive_prologue && peek() != Token::STRING) { 1026 if (directive_prologue && peek() != Token::STRING) {
1156 directive_prologue = false; 1027 directive_prologue = false;
1157 } 1028 }
1158 1029
1159 Scanner::Location token_loc = scanner().peek_location(); 1030 Scanner::Location token_loc = scanner().peek_location();
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1194 ? EXTENDED_MODE : STRICT_MODE); 1065 ? EXTENDED_MODE : STRICT_MODE);
1195 // "use strict" is the only directive for now. 1066 // "use strict" is the only directive for now.
1196 directive_prologue = false; 1067 directive_prologue = false;
1197 } 1068 }
1198 } else { 1069 } else {
1199 // End of the directive prologue. 1070 // End of the directive prologue.
1200 directive_prologue = false; 1071 directive_prologue = false;
1201 } 1072 }
1202 } 1073 }
1203 1074
1204 block_finder.Update(stat);
1205 // Find and mark all assignments to named properties in this (this.x =) 1075 // Find and mark all assignments to named properties in this (this.x =)
1206 if (top_scope_->is_function_scope()) { 1076 if (top_scope_->is_function_scope()) {
1207 this_property_assignment_finder.Update(top_scope_, stat); 1077 this_property_assignment_finder.Update(top_scope_, stat);
1208 } 1078 }
1209 processor->Add(stat, zone()); 1079 processor->Add(stat, zone());
1210 } 1080 }
1211 1081
1212 // Propagate the collected information on this property assignments. 1082 // Propagate the collected information on this property assignments.
1213 if (top_scope_->is_function_scope()) { 1083 if (top_scope_->is_function_scope()) {
1214 bool only_simple_this_property_assignments = 1084 bool only_simple_this_property_assignments =
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
1347 1217
1348 Expect(Token::LBRACE, CHECK_OK); 1218 Expect(Token::LBRACE, CHECK_OK);
1349 scope->set_start_position(scanner().location().beg_pos); 1219 scope->set_start_position(scanner().location().beg_pos);
1350 scope->SetLanguageMode(EXTENDED_MODE); 1220 scope->SetLanguageMode(EXTENDED_MODE);
1351 1221
1352 { 1222 {
1353 BlockState block_state(this, scope); 1223 BlockState block_state(this, scope);
1354 TargetCollector collector(zone()); 1224 TargetCollector collector(zone());
1355 Target target(&this->target_stack_, &collector); 1225 Target target(&this->target_stack_, &collector);
1356 Target target_body(&this->target_stack_, body); 1226 Target target_body(&this->target_stack_, body);
1357 InitializationBlockFinder block_finder(top_scope_, target_stack_);
1358 1227
1359 while (peek() != Token::RBRACE) { 1228 while (peek() != Token::RBRACE) {
1360 Statement* stat = ParseModuleElement(NULL, CHECK_OK); 1229 Statement* stat = ParseModuleElement(NULL, CHECK_OK);
1361 if (stat && !stat->IsEmpty()) { 1230 if (stat && !stat->IsEmpty()) {
1362 body->AddStatement(stat, zone()); 1231 body->AddStatement(stat, zone());
1363 block_finder.Update(stat);
1364 } 1232 }
1365 } 1233 }
1366 } 1234 }
1367 1235
1368 Expect(Token::RBRACE, CHECK_OK); 1236 Expect(Token::RBRACE, CHECK_OK);
1369 scope->set_end_position(scanner().location().end_pos); 1237 scope->set_end_position(scanner().location().end_pos);
1370 body->set_scope(scope); 1238 body->set_scope(scope);
1371 1239
1372 // Check that all exports are bound. 1240 // Check that all exports are bound.
1373 Interface* interface = scope->interface(); 1241 Interface* interface = scope->interface();
(...skipping 655 matching lines...) Expand 10 before | Expand all | Expand 10 after
2029 // Block :: 1897 // Block ::
2030 // '{' Statement* '}' 1898 // '{' Statement* '}'
2031 1899
2032 // Note that a Block does not introduce a new execution scope! 1900 // Note that a Block does not introduce a new execution scope!
2033 // (ECMA-262, 3rd, 12.2) 1901 // (ECMA-262, 3rd, 12.2)
2034 // 1902 //
2035 // Construct block expecting 16 statements. 1903 // Construct block expecting 16 statements.
2036 Block* result = factory()->NewBlock(labels, 16, false); 1904 Block* result = factory()->NewBlock(labels, 16, false);
2037 Target target(&this->target_stack_, result); 1905 Target target(&this->target_stack_, result);
2038 Expect(Token::LBRACE, CHECK_OK); 1906 Expect(Token::LBRACE, CHECK_OK);
2039 InitializationBlockFinder block_finder(top_scope_, target_stack_);
2040 while (peek() != Token::RBRACE) { 1907 while (peek() != Token::RBRACE) {
2041 Statement* stat = ParseStatement(NULL, CHECK_OK); 1908 Statement* stat = ParseStatement(NULL, CHECK_OK);
2042 if (stat && !stat->IsEmpty()) { 1909 if (stat && !stat->IsEmpty()) {
2043 result->AddStatement(stat, zone()); 1910 result->AddStatement(stat, zone());
2044 block_finder.Update(stat);
2045 } 1911 }
2046 } 1912 }
2047 Expect(Token::RBRACE, CHECK_OK); 1913 Expect(Token::RBRACE, CHECK_OK);
2048 return result; 1914 return result;
2049 } 1915 }
2050 1916
2051 1917
2052 Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { 1918 Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
2053 // The harmony mode uses block elements instead of statements. 1919 // The harmony mode uses block elements instead of statements.
2054 // 1920 //
2055 // Block :: 1921 // Block ::
2056 // '{' BlockElement* '}' 1922 // '{' BlockElement* '}'
2057 1923
2058 // Construct block expecting 16 statements. 1924 // Construct block expecting 16 statements.
2059 Block* body = factory()->NewBlock(labels, 16, false); 1925 Block* body = factory()->NewBlock(labels, 16, false);
2060 Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE); 1926 Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE);
2061 1927
2062 // Parse the statements and collect escaping labels. 1928 // Parse the statements and collect escaping labels.
2063 Expect(Token::LBRACE, CHECK_OK); 1929 Expect(Token::LBRACE, CHECK_OK);
2064 block_scope->set_start_position(scanner().location().beg_pos); 1930 block_scope->set_start_position(scanner().location().beg_pos);
2065 { BlockState block_state(this, block_scope); 1931 { BlockState block_state(this, block_scope);
2066 TargetCollector collector(zone()); 1932 TargetCollector collector(zone());
2067 Target target(&this->target_stack_, &collector); 1933 Target target(&this->target_stack_, &collector);
2068 Target target_body(&this->target_stack_, body); 1934 Target target_body(&this->target_stack_, body);
2069 InitializationBlockFinder block_finder(top_scope_, target_stack_);
2070 1935
2071 while (peek() != Token::RBRACE) { 1936 while (peek() != Token::RBRACE) {
2072 Statement* stat = ParseBlockElement(NULL, CHECK_OK); 1937 Statement* stat = ParseBlockElement(NULL, CHECK_OK);
2073 if (stat && !stat->IsEmpty()) { 1938 if (stat && !stat->IsEmpty()) {
2074 body->AddStatement(stat, zone()); 1939 body->AddStatement(stat, zone());
2075 block_finder.Update(stat);
2076 } 1940 }
2077 } 1941 }
2078 } 1942 }
2079 Expect(Token::RBRACE, CHECK_OK); 1943 Expect(Token::RBRACE, CHECK_OK);
2080 block_scope->set_end_position(scanner().location().end_pos); 1944 block_scope->set_end_position(scanner().location().end_pos);
2081 block_scope = block_scope->FinalizeBlockScope(); 1945 block_scope = block_scope->FinalizeBlockScope();
2082 body->set_scope(block_scope); 1946 body->set_scope(block_scope);
2083 return body; 1947 return body;
2084 } 1948 }
2085 1949
(...skipping 4018 matching lines...) Expand 10 before | Expand all | Expand 10 after
6104 ASSERT(info->isolate()->has_pending_exception()); 5968 ASSERT(info->isolate()->has_pending_exception());
6105 } else { 5969 } else {
6106 result = parser.ParseProgram(); 5970 result = parser.ParseProgram();
6107 } 5971 }
6108 } 5972 }
6109 info->SetFunction(result); 5973 info->SetFunction(result);
6110 return (result != NULL); 5974 return (result != NULL);
6111 } 5975 }
6112 5976
6113 } } // namespace v8::internal 5977 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/ia32/full-codegen-ia32.cc ('k') | src/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698