| 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 | |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |