OLD | NEW |
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 Loading... |
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 |
835 // A ThisNamedPropertyAssignmentFinder finds and marks statements of the form | 970 // A ThisNamedPropertyAssignmentFinder finds and marks statements of the form |
836 // this.x = ...;, where x is a named property. It also determines whether a | 971 // this.x = ...;, where x is a named property. It also determines whether a |
837 // function contains only assignments of this type. | 972 // function contains only assignments of this type. |
838 class ThisNamedPropertyAssignmentFinder { | 973 class ThisNamedPropertyAssignmentFinder : public ParserFinder { |
839 public: | 974 public: |
840 ThisNamedPropertyAssignmentFinder(Isolate* isolate, Zone* zone) | 975 ThisNamedPropertyAssignmentFinder(Isolate* isolate, Zone* zone) |
841 : isolate_(isolate), | 976 : isolate_(isolate), |
842 only_simple_this_property_assignments_(true), | 977 only_simple_this_property_assignments_(true), |
843 names_(0, zone), | 978 names_(0, zone), |
844 assigned_arguments_(0, zone), | 979 assigned_arguments_(0, zone), |
845 assigned_constants_(0, zone), | 980 assigned_constants_(0, zone), |
846 zone_(zone) { | 981 zone_(zone) { |
847 } | 982 } |
848 | 983 |
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 | |
856 void Update(Scope* scope, Statement* stat) { | 984 void Update(Scope* scope, Statement* stat) { |
857 // Bail out if function already has property assignment that are | 985 // Bail out if function already has property assignment that are |
858 // not simple this property assignments. | 986 // not simple this property assignments. |
859 if (!only_simple_this_property_assignments_) { | 987 if (!only_simple_this_property_assignments_) { |
860 return; | 988 return; |
861 } | 989 } |
862 | 990 |
863 // Check whether this statement is of the form this.x = ...; | 991 // Check whether this statement is of the form this.x = ...; |
864 Assignment* assignment = AsAssignment(stat); | 992 Assignment* assignment = AsAssignment(stat); |
865 if (IsThisPropertyAssignment(assignment)) { | 993 if (IsThisPropertyAssignment(assignment)) { |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1011 // SourceElements :: | 1139 // SourceElements :: |
1012 // (ModuleElement)* <end_token> | 1140 // (ModuleElement)* <end_token> |
1013 | 1141 |
1014 // Allocate a target stack to use for this set of source | 1142 // Allocate a target stack to use for this set of source |
1015 // elements. This way, all scripts and functions get their own | 1143 // elements. This way, all scripts and functions get their own |
1016 // target stack thus avoiding illegal breaks and continues across | 1144 // target stack thus avoiding illegal breaks and continues across |
1017 // functions. | 1145 // functions. |
1018 TargetScope scope(&this->target_stack_); | 1146 TargetScope scope(&this->target_stack_); |
1019 | 1147 |
1020 ASSERT(processor != NULL); | 1148 ASSERT(processor != NULL); |
| 1149 InitializationBlockFinder block_finder(top_scope_, target_stack_); |
1021 ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate(), | 1150 ThisNamedPropertyAssignmentFinder this_property_assignment_finder(isolate(), |
1022 zone()); | 1151 zone()); |
1023 bool directive_prologue = true; // Parsing directive prologue. | 1152 bool directive_prologue = true; // Parsing directive prologue. |
1024 | 1153 |
1025 while (peek() != end_token) { | 1154 while (peek() != end_token) { |
1026 if (directive_prologue && peek() != Token::STRING) { | 1155 if (directive_prologue && peek() != Token::STRING) { |
1027 directive_prologue = false; | 1156 directive_prologue = false; |
1028 } | 1157 } |
1029 | 1158 |
1030 Scanner::Location token_loc = scanner().peek_location(); | 1159 Scanner::Location token_loc = scanner().peek_location(); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1065 ? EXTENDED_MODE : STRICT_MODE); | 1194 ? EXTENDED_MODE : STRICT_MODE); |
1066 // "use strict" is the only directive for now. | 1195 // "use strict" is the only directive for now. |
1067 directive_prologue = false; | 1196 directive_prologue = false; |
1068 } | 1197 } |
1069 } else { | 1198 } else { |
1070 // End of the directive prologue. | 1199 // End of the directive prologue. |
1071 directive_prologue = false; | 1200 directive_prologue = false; |
1072 } | 1201 } |
1073 } | 1202 } |
1074 | 1203 |
| 1204 block_finder.Update(stat); |
1075 // Find and mark all assignments to named properties in this (this.x =) | 1205 // Find and mark all assignments to named properties in this (this.x =) |
1076 if (top_scope_->is_function_scope()) { | 1206 if (top_scope_->is_function_scope()) { |
1077 this_property_assignment_finder.Update(top_scope_, stat); | 1207 this_property_assignment_finder.Update(top_scope_, stat); |
1078 } | 1208 } |
1079 processor->Add(stat, zone()); | 1209 processor->Add(stat, zone()); |
1080 } | 1210 } |
1081 | 1211 |
1082 // Propagate the collected information on this property assignments. | 1212 // Propagate the collected information on this property assignments. |
1083 if (top_scope_->is_function_scope()) { | 1213 if (top_scope_->is_function_scope()) { |
1084 bool only_simple_this_property_assignments = | 1214 bool only_simple_this_property_assignments = |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1217 | 1347 |
1218 Expect(Token::LBRACE, CHECK_OK); | 1348 Expect(Token::LBRACE, CHECK_OK); |
1219 scope->set_start_position(scanner().location().beg_pos); | 1349 scope->set_start_position(scanner().location().beg_pos); |
1220 scope->SetLanguageMode(EXTENDED_MODE); | 1350 scope->SetLanguageMode(EXTENDED_MODE); |
1221 | 1351 |
1222 { | 1352 { |
1223 BlockState block_state(this, scope); | 1353 BlockState block_state(this, scope); |
1224 TargetCollector collector(zone()); | 1354 TargetCollector collector(zone()); |
1225 Target target(&this->target_stack_, &collector); | 1355 Target target(&this->target_stack_, &collector); |
1226 Target target_body(&this->target_stack_, body); | 1356 Target target_body(&this->target_stack_, body); |
| 1357 InitializationBlockFinder block_finder(top_scope_, target_stack_); |
1227 | 1358 |
1228 while (peek() != Token::RBRACE) { | 1359 while (peek() != Token::RBRACE) { |
1229 Statement* stat = ParseModuleElement(NULL, CHECK_OK); | 1360 Statement* stat = ParseModuleElement(NULL, CHECK_OK); |
1230 if (stat && !stat->IsEmpty()) { | 1361 if (stat && !stat->IsEmpty()) { |
1231 body->AddStatement(stat, zone()); | 1362 body->AddStatement(stat, zone()); |
| 1363 block_finder.Update(stat); |
1232 } | 1364 } |
1233 } | 1365 } |
1234 } | 1366 } |
1235 | 1367 |
1236 Expect(Token::RBRACE, CHECK_OK); | 1368 Expect(Token::RBRACE, CHECK_OK); |
1237 scope->set_end_position(scanner().location().end_pos); | 1369 scope->set_end_position(scanner().location().end_pos); |
1238 body->set_scope(scope); | 1370 body->set_scope(scope); |
1239 | 1371 |
1240 // Check that all exports are bound. | 1372 // Check that all exports are bound. |
1241 Interface* interface = scope->interface(); | 1373 Interface* interface = scope->interface(); |
(...skipping 655 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1897 // Block :: | 2029 // Block :: |
1898 // '{' Statement* '}' | 2030 // '{' Statement* '}' |
1899 | 2031 |
1900 // Note that a Block does not introduce a new execution scope! | 2032 // Note that a Block does not introduce a new execution scope! |
1901 // (ECMA-262, 3rd, 12.2) | 2033 // (ECMA-262, 3rd, 12.2) |
1902 // | 2034 // |
1903 // Construct block expecting 16 statements. | 2035 // Construct block expecting 16 statements. |
1904 Block* result = factory()->NewBlock(labels, 16, false); | 2036 Block* result = factory()->NewBlock(labels, 16, false); |
1905 Target target(&this->target_stack_, result); | 2037 Target target(&this->target_stack_, result); |
1906 Expect(Token::LBRACE, CHECK_OK); | 2038 Expect(Token::LBRACE, CHECK_OK); |
| 2039 InitializationBlockFinder block_finder(top_scope_, target_stack_); |
1907 while (peek() != Token::RBRACE) { | 2040 while (peek() != Token::RBRACE) { |
1908 Statement* stat = ParseStatement(NULL, CHECK_OK); | 2041 Statement* stat = ParseStatement(NULL, CHECK_OK); |
1909 if (stat && !stat->IsEmpty()) { | 2042 if (stat && !stat->IsEmpty()) { |
1910 result->AddStatement(stat, zone()); | 2043 result->AddStatement(stat, zone()); |
| 2044 block_finder.Update(stat); |
1911 } | 2045 } |
1912 } | 2046 } |
1913 Expect(Token::RBRACE, CHECK_OK); | 2047 Expect(Token::RBRACE, CHECK_OK); |
1914 return result; | 2048 return result; |
1915 } | 2049 } |
1916 | 2050 |
1917 | 2051 |
1918 Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { | 2052 Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { |
1919 // The harmony mode uses block elements instead of statements. | 2053 // The harmony mode uses block elements instead of statements. |
1920 // | 2054 // |
1921 // Block :: | 2055 // Block :: |
1922 // '{' BlockElement* '}' | 2056 // '{' BlockElement* '}' |
1923 | 2057 |
1924 // Construct block expecting 16 statements. | 2058 // Construct block expecting 16 statements. |
1925 Block* body = factory()->NewBlock(labels, 16, false); | 2059 Block* body = factory()->NewBlock(labels, 16, false); |
1926 Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE); | 2060 Scope* block_scope = NewScope(top_scope_, BLOCK_SCOPE); |
1927 | 2061 |
1928 // Parse the statements and collect escaping labels. | 2062 // Parse the statements and collect escaping labels. |
1929 Expect(Token::LBRACE, CHECK_OK); | 2063 Expect(Token::LBRACE, CHECK_OK); |
1930 block_scope->set_start_position(scanner().location().beg_pos); | 2064 block_scope->set_start_position(scanner().location().beg_pos); |
1931 { BlockState block_state(this, block_scope); | 2065 { BlockState block_state(this, block_scope); |
1932 TargetCollector collector(zone()); | 2066 TargetCollector collector(zone()); |
1933 Target target(&this->target_stack_, &collector); | 2067 Target target(&this->target_stack_, &collector); |
1934 Target target_body(&this->target_stack_, body); | 2068 Target target_body(&this->target_stack_, body); |
| 2069 InitializationBlockFinder block_finder(top_scope_, target_stack_); |
1935 | 2070 |
1936 while (peek() != Token::RBRACE) { | 2071 while (peek() != Token::RBRACE) { |
1937 Statement* stat = ParseBlockElement(NULL, CHECK_OK); | 2072 Statement* stat = ParseBlockElement(NULL, CHECK_OK); |
1938 if (stat && !stat->IsEmpty()) { | 2073 if (stat && !stat->IsEmpty()) { |
1939 body->AddStatement(stat, zone()); | 2074 body->AddStatement(stat, zone()); |
| 2075 block_finder.Update(stat); |
1940 } | 2076 } |
1941 } | 2077 } |
1942 } | 2078 } |
1943 Expect(Token::RBRACE, CHECK_OK); | 2079 Expect(Token::RBRACE, CHECK_OK); |
1944 block_scope->set_end_position(scanner().location().end_pos); | 2080 block_scope->set_end_position(scanner().location().end_pos); |
1945 block_scope = block_scope->FinalizeBlockScope(); | 2081 block_scope = block_scope->FinalizeBlockScope(); |
1946 body->set_scope(block_scope); | 2082 body->set_scope(block_scope); |
1947 return body; | 2083 return body; |
1948 } | 2084 } |
1949 | 2085 |
(...skipping 4018 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5968 ASSERT(info->isolate()->has_pending_exception()); | 6104 ASSERT(info->isolate()->has_pending_exception()); |
5969 } else { | 6105 } else { |
5970 result = parser.ParseProgram(); | 6106 result = parser.ParseProgram(); |
5971 } | 6107 } |
5972 } | 6108 } |
5973 info->SetFunction(result); | 6109 info->SetFunction(result); |
5974 return (result != NULL); | 6110 return (result != NULL); |
5975 } | 6111 } |
5976 | 6112 |
5977 } } // namespace v8::internal | 6113 } } // namespace v8::internal |
OLD | NEW |