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

Side by Side Diff: src/jsregexp.cc

Issue 10793: More assertion propagation. (Closed)
Patch Set: Created 12 years 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
« no previous file with comments | « src/jsregexp.h ('k') | src/parser.h » ('j') | src/parser.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 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 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 Handle<FixedArray> cached = CompilationCache::LookupRegExp(pattern, flags); 211 Handle<FixedArray> cached = CompilationCache::LookupRegExp(pattern, flags);
212 bool in_cache = !cached.is_null(); 212 bool in_cache = !cached.is_null();
213 Handle<Object> result; 213 Handle<Object> result;
214 if (in_cache) { 214 if (in_cache) {
215 re->set_data(*cached); 215 re->set_data(*cached);
216 result = re; 216 result = re;
217 } else { 217 } else {
218 FlattenString(pattern); 218 FlattenString(pattern);
219 RegExpParseResult parse_result; 219 RegExpParseResult parse_result;
220 FlatStringReader reader(pattern); 220 FlatStringReader reader(pattern);
221 if (!ParseRegExp(&reader, &parse_result)) { 221 if (!ParseRegExp(&reader, flags.is_multiline(), &parse_result)) {
222 // Throw an exception if we fail to parse the pattern. 222 // Throw an exception if we fail to parse the pattern.
223 ThrowRegExpException(re, 223 ThrowRegExpException(re,
224 pattern, 224 pattern,
225 parse_result.error, 225 parse_result.error,
226 "malformed_regexp"); 226 "malformed_regexp");
227 return Handle<Object>(); 227 return Handle<Object>();
228 } 228 }
229 RegExpAtom* atom = parse_result.tree->AsAtom(); 229 RegExpAtom* atom = parse_result.tree->AsAtom();
230 if (atom != NULL && !flags.is_ignore_case()) { 230 if (atom != NULL && !flags.is_ignore_case()) {
231 if (parse_result.has_character_escapes) { 231 if (parse_result.has_character_escapes) {
232 Vector<const uc16> atom_pattern = atom->data(); 232 Vector<const uc16> atom_pattern = atom->data();
233 Handle<String> atom_string = 233 Handle<String> atom_string =
234 Factory::NewStringFromTwoByte(atom_pattern); 234 Factory::NewStringFromTwoByte(atom_pattern);
235 result = AtomCompile(re, pattern, flags, atom_string); 235 result = AtomCompile(re, pattern, flags, atom_string);
236 } else { 236 } else {
237 result = AtomCompile(re, pattern, flags, pattern); 237 result = AtomCompile(re, pattern, flags, pattern);
238 } 238 }
239 } else { 239 } else {
240 RegExpNode* node = NULL; 240 RegExpNode* node = NULL;
241 Handle<FixedArray> irregexp_data = 241 Handle<FixedArray> irregexp_data =
242 RegExpEngine::Compile(&parse_result, 242 RegExpEngine::Compile(&parse_result,
243 &node, 243 &node,
244 flags.is_ignore_case()); 244 flags.is_ignore_case(),
245 flags.is_multiline());
245 if (irregexp_data.is_null()) { 246 if (irregexp_data.is_null()) {
246 if (FLAG_disable_jscre) { 247 if (FLAG_disable_jscre) {
247 UNIMPLEMENTED(); 248 UNIMPLEMENTED();
248 } 249 }
249 result = JscrePrepare(re, pattern, flags); 250 result = JscrePrepare(re, pattern, flags);
250 } else { 251 } else {
251 result = IrregexpPrepare(re, pattern, flags, irregexp_data); 252 result = IrregexpPrepare(re, pattern, flags, irregexp_data);
252 } 253 }
253 } 254 }
254 Object* data = re->data(); 255 Object* data = re->data();
(...skipping 718 matching lines...) Expand 10 before | Expand all | Expand 10 after
973 array->set(RegExpImpl::kIrregexpCodeIndex, *code); 974 array->set(RegExpImpl::kIrregexpCodeIndex, *code);
974 work_list_ = NULL; 975 work_list_ = NULL;
975 return array; 976 return array;
976 } 977 }
977 978
978 979
979 bool RegExpNode::GoTo(RegExpCompiler* compiler) { 980 bool RegExpNode::GoTo(RegExpCompiler* compiler) {
980 // TODO(erikcorry): Implement support. 981 // TODO(erikcorry): Implement support.
981 if (info_.follows_word_interest || 982 if (info_.follows_word_interest ||
982 info_.follows_newline_interest || 983 info_.follows_newline_interest ||
983 info_.follows_start_interest) { 984 info_.follows_start_interest ||
985 info_.at_end) {
984 return false; 986 return false;
985 } 987 }
986 if (label_.is_bound()) { 988 if (label_.is_bound()) {
987 compiler->macro_assembler()->GoTo(&label_); 989 compiler->macro_assembler()->GoTo(&label_);
988 return true; 990 return true;
989 } else { 991 } else {
990 if (compiler->recursion_depth() > RegExpCompiler::kMaxRecursion) { 992 if (compiler->recursion_depth() > RegExpCompiler::kMaxRecursion) {
991 compiler->macro_assembler()->GoTo(&label_); 993 compiler->macro_assembler()->GoTo(&label_);
992 compiler->AddWork(this); 994 compiler->AddWork(this);
993 return true; 995 return true;
994 } else { 996 } else {
995 compiler->IncrementRecursionDepth(); 997 compiler->IncrementRecursionDepth();
996 bool how_it_went = Emit(compiler); 998 bool how_it_went = Emit(compiler);
997 compiler->DecrementRecursionDepth(); 999 compiler->DecrementRecursionDepth();
998 return how_it_went; 1000 return how_it_went;
999 } 1001 }
1000 } 1002 }
1001 } 1003 }
1002 1004
1003 1005
1004 bool EndNode::GoTo(RegExpCompiler* compiler) { 1006 bool EndNode::GoTo(RegExpCompiler* compiler) {
1005 if (info()->follows_word_interest || 1007 if (info_.follows_word_interest ||
1006 info()->follows_newline_interest || 1008 info_.follows_newline_interest ||
1007 info()->follows_start_interest) { 1009 info_.follows_start_interest ||
1010 info_.at_end) {
1008 return false; 1011 return false;
1009 } 1012 }
1010 if (!label()->is_bound()) { 1013 if (!label()->is_bound()) {
1011 Bind(compiler->macro_assembler()); 1014 Bind(compiler->macro_assembler());
1012 } 1015 }
1013 switch (action_) { 1016 switch (action_) {
1014 case ACCEPT: 1017 case ACCEPT:
1015 compiler->macro_assembler()->Succeed(); 1018 compiler->macro_assembler()->Succeed();
1016 break; 1019 break;
1017 case BACKTRACK: 1020 case BACKTRACK:
(...skipping 604 matching lines...) Expand 10 before | Expand all | Expand 10 after
1622 StringStream* stream() { return stream_; } 1625 StringStream* stream() { return stream_; }
1623 StringStream* stream_; 1626 StringStream* stream_;
1624 }; 1627 };
1625 1628
1626 1629
1627 void DotPrinter::PrintAttributes(RegExpNode* that) { 1630 void DotPrinter::PrintAttributes(RegExpNode* that) {
1628 stream()->Add(" a%p [shape=Mrecord, style=dashed, color=lightgrey, " 1631 stream()->Add(" a%p [shape=Mrecord, style=dashed, color=lightgrey, "
1629 "fontcolor=lightgrey, margin=0.1, fontsize=10, label=\"{", 1632 "fontcolor=lightgrey, margin=0.1, fontsize=10, label=\"{",
1630 that); 1633 that);
1631 NodeInfo* info = that->info(); 1634 NodeInfo* info = that->info();
1632 stream()->Add("{NI|%i}|{SI|%i}|{WI|%i}", 1635 stream()->Add("{NI|%i}|{WI|%i}|{SI|%i}",
1633 info->follows_newline_interest, 1636 info->follows_newline_interest,
1634 info->follows_start_interest, 1637 info->follows_word_interest,
1635 info->follows_word_interest); 1638 info->follows_start_interest);
1636 stream()->Add("|{DN|%i}|{DS|%i}|{DW|%i}", 1639 stream()->Add("|{DN|%i}|{DW|%i}|{DS|%i}|{AE|%i}",
1637 info->determine_newline, 1640 info->determine_newline,
1641 info->determine_word,
1638 info->determine_start, 1642 info->determine_start,
1639 info->determine_word); 1643 info->at_end);
1644 if (info->follows_newline != NodeInfo::UNKNOWN)
1645 stream()->Add("|{FN|%i}", info->follows_newline);
1646 if (info->follows_word != NodeInfo::UNKNOWN)
1647 stream()->Add("|{FW|%i}", info->follows_word);
1648 if (info->follows_start != NodeInfo::UNKNOWN)
1649 stream()->Add("|{FS|%i}", info->follows_start);
1640 Label* label = that->label(); 1650 Label* label = that->label();
1641 if (label->is_bound()) 1651 if (label->is_bound())
1642 stream()->Add("|{@|%x}", label->pos()); 1652 stream()->Add("|{@|%x}", label->pos());
1643 stream()->Add("}\"];\n"); 1653 stream()->Add("}\"];\n");
1644 stream()->Add(" a%p -> n%p [style=dashed, color=lightgrey, " 1654 stream()->Add(" a%p -> n%p [style=dashed, color=lightgrey, "
1645 "arrowhead=none];\n", that, that); 1655 "arrowhead=none];\n", that, that);
1646 } 1656 }
1647 1657
1648 1658
1649 void DotPrinter::VisitChoice(ChoiceNode* that) { 1659 void DotPrinter::VisitChoice(ChoiceNode* that) {
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
1917 switch (type()) { 1927 switch (type()) {
1918 case START_OF_LINE: 1928 case START_OF_LINE:
1919 info.follows_newline_interest = true; 1929 info.follows_newline_interest = true;
1920 break; 1930 break;
1921 case START_OF_INPUT: 1931 case START_OF_INPUT:
1922 info.follows_start_interest = true; 1932 info.follows_start_interest = true;
1923 break; 1933 break;
1924 case BOUNDARY: case NON_BOUNDARY: 1934 case BOUNDARY: case NON_BOUNDARY:
1925 info.follows_word_interest = true; 1935 info.follows_word_interest = true;
1926 break; 1936 break;
1927 case END_OF_LINE: case END_OF_INPUT: 1937 case END_OF_INPUT:
1938 info.at_end = true;
1939 break;
1940 case END_OF_LINE:
1928 // This is wrong but has the effect of making the compiler abort. 1941 // This is wrong but has the effect of making the compiler abort.
1929 info.follows_start_interest = true; 1942 info.at_end = true;
1930 } 1943 }
1931 return on_success->PropagateInterest(&info); 1944 return on_success->PropagateForward(&info);
1932 } 1945 }
1933 1946
1934 1947
1935 RegExpNode* RegExpBackReference::ToNode(RegExpCompiler* compiler, 1948 RegExpNode* RegExpBackReference::ToNode(RegExpCompiler* compiler,
1936 RegExpNode* on_success, 1949 RegExpNode* on_success,
1937 RegExpNode* on_failure) { 1950 RegExpNode* on_failure) {
1938 return new BackReferenceNode(RegExpCapture::StartRegister(index()), 1951 return new BackReferenceNode(RegExpCapture::StartRegister(index()),
1939 RegExpCapture::EndRegister(index()), 1952 RegExpCapture::EndRegister(index()),
1940 on_success, 1953 on_success,
1941 on_failure); 1954 on_failure);
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
2209 } 2222 }
2210 2223
2211 2224
2212 // ------------------------------------------------------------------- 2225 // -------------------------------------------------------------------
2213 // Interest propagation 2226 // Interest propagation
2214 2227
2215 2228
2216 RegExpNode* RegExpNode::GetSibling(NodeInfo* info) { 2229 RegExpNode* RegExpNode::GetSibling(NodeInfo* info) {
2217 for (int i = 0; i < siblings_.length(); i++) { 2230 for (int i = 0; i < siblings_.length(); i++) {
2218 RegExpNode* sibling = siblings_.Get(i); 2231 RegExpNode* sibling = siblings_.Get(i);
2219 if (sibling->info()->SameInterests(info)) 2232 if (sibling->info()->HasSameForwardInterests(info))
2220 return sibling; 2233 return sibling;
2221 } 2234 }
2222 return NULL; 2235 return NULL;
2223 } 2236 }
2224 2237
2225 2238
2226 template <class C> 2239 template <class C>
2227 static RegExpNode* PropagateToEndpoint(C* node, NodeInfo* info) { 2240 static RegExpNode* PropagateToEndpoint(C* node, NodeInfo* info) {
2228 RegExpNode* sibling = node->GetSibling(info); 2241 NodeInfo full_info(*node->info());
2242 full_info.AddFromPreceding(info);
2243 RegExpNode* sibling = node->GetSibling(&full_info);
2229 if (sibling != NULL) return sibling; 2244 if (sibling != NULL) return sibling;
2230 node->EnsureSiblings(); 2245 node->EnsureSiblings();
2231 sibling = new C(*node); 2246 sibling = new C(*node);
2232 sibling->info()->AdoptInterests(info); 2247 sibling->info()->AddFromPreceding(&full_info);
2233 node->AddSibling(sibling); 2248 node->AddSibling(sibling);
2234 return sibling; 2249 return sibling;
2235 } 2250 }
2236 2251
2237 2252
2238 RegExpNode* ActionNode::PropagateInterest(NodeInfo* info) { 2253 RegExpNode* ActionNode::PropagateForward(NodeInfo* info) {
2239 RegExpNode* sibling = GetSibling(info); 2254 NodeInfo full_info(*this->info());
2255 full_info.AddFromPreceding(info);
2256 RegExpNode* sibling = GetSibling(&full_info);
2240 if (sibling != NULL) return sibling; 2257 if (sibling != NULL) return sibling;
2241 EnsureSiblings(); 2258 EnsureSiblings();
2242 ActionNode* action = new ActionNode(*this); 2259 ActionNode* action = new ActionNode(*this);
2243 action->info()->AdoptInterests(info); 2260 action->info()->AddFromPreceding(&full_info);
2244 AddSibling(action); 2261 AddSibling(action);
2245 action->set_on_success(action->on_success()->PropagateInterest(info)); 2262 action->set_on_success(action->on_success()->PropagateForward(info));
2246 return action; 2263 return action;
2247 } 2264 }
2248 2265
2249 2266
2250 RegExpNode* ChoiceNode::PropagateInterest(NodeInfo* info) { 2267 RegExpNode* ChoiceNode::PropagateForward(NodeInfo* info) {
2251 RegExpNode* sibling = GetSibling(info); 2268 NodeInfo full_info(*this->info());
2269 full_info.AddFromPreceding(info);
2270 RegExpNode* sibling = GetSibling(&full_info);
2252 if (sibling != NULL) return sibling; 2271 if (sibling != NULL) return sibling;
2253 EnsureSiblings(); 2272 EnsureSiblings();
2254 ChoiceNode* choice = new ChoiceNode(*this); 2273 ChoiceNode* choice = new ChoiceNode(*this);
2255 choice->info()->AdoptInterests(info); 2274 choice->info()->AddFromPreceding(&full_info);
2256 AddSibling(choice); 2275 AddSibling(choice);
2257 ZoneList<GuardedAlternative>* old_alternatives = alternatives(); 2276 ZoneList<GuardedAlternative>* old_alternatives = alternatives();
2258 int count = old_alternatives->length(); 2277 int count = old_alternatives->length();
2259 choice->alternatives_ = new ZoneList<GuardedAlternative>(count); 2278 choice->alternatives_ = new ZoneList<GuardedAlternative>(count);
2260 for (int i = 0; i < count; i++) { 2279 for (int i = 0; i < count; i++) {
2261 GuardedAlternative alternative = old_alternatives->at(i); 2280 GuardedAlternative alternative = old_alternatives->at(i);
2262 alternative.set_node(alternative.node()->PropagateInterest(info)); 2281 alternative.set_node(alternative.node()->PropagateForward(info));
2263 choice->alternatives()->Add(alternative); 2282 choice->alternatives()->Add(alternative);
2264 } 2283 }
2265 return choice; 2284 return choice;
2266 } 2285 }
2267 2286
2268 2287
2269 RegExpNode* EndNode::PropagateInterest(NodeInfo* info) { 2288 RegExpNode* EndNode::PropagateForward(NodeInfo* info) {
2270 return PropagateToEndpoint(this, info); 2289 return PropagateToEndpoint(this, info);
2271 } 2290 }
2272 2291
2273 2292
2274 RegExpNode* BackReferenceNode::PropagateInterest(NodeInfo* info) { 2293 RegExpNode* BackReferenceNode::PropagateForward(NodeInfo* info) {
2275 return PropagateToEndpoint(this, info); 2294 return PropagateToEndpoint(this, info);
2276 } 2295 }
2277 2296
2278 2297
2279 RegExpNode* TextNode::PropagateInterest(NodeInfo* info) { 2298 RegExpNode* TextNode::PropagateForward(NodeInfo* info) {
2280 return PropagateToEndpoint(this, info); 2299 return PropagateToEndpoint(this, info);
2281 } 2300 }
2282 2301
2283 2302
2284 // ------------------------------------------------------------------- 2303 // -------------------------------------------------------------------
2285 // Splay tree 2304 // Splay tree
2286 2305
2287 2306
2288 OutSet* OutSet::Extend(unsigned value) { 2307 OutSet* OutSet::Extend(unsigned value) {
2289 if (Get(value)) 2308 if (Get(value))
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
2448 // nothing to do 2467 // nothing to do
2449 } 2468 }
2450 2469
2451 2470
2452 void Analysis::VisitText(TextNode* that) { 2471 void Analysis::VisitText(TextNode* that) {
2453 if (ignore_case_) { 2472 if (ignore_case_) {
2454 that->MakeCaseIndependent(); 2473 that->MakeCaseIndependent();
2455 } 2474 }
2456 EnsureAnalyzed(that->on_success()); 2475 EnsureAnalyzed(that->on_success());
2457 EnsureAnalyzed(that->on_failure()); 2476 EnsureAnalyzed(that->on_failure());
2477 NodeInfo* info = that->info();
2478 NodeInfo* next_info = that->on_success()->info();
2479 // If the following node is interested in what it follows then this
2480 // node must determine it.
2481 info->determine_newline = next_info->follows_newline_interest;
2482 info->determine_word = next_info->follows_word_interest;
2483 info->determine_start = next_info->follows_start_interest;
2458 } 2484 }
2459 2485
2460 2486
2461 void Analysis::VisitAction(ActionNode* that) { 2487 void Analysis::VisitAction(ActionNode* that) {
2462 RegExpNode* next = that->on_success(); 2488 EnsureAnalyzed(that->on_success());
2463 EnsureAnalyzed(next); 2489 // If the next node is interested in what it follows then this node
2464 that->info()->determine_newline = next->info()->prev_determine_newline(); 2490 // has to be interested too so it can pass the information on.
2465 that->info()->determine_word = next->info()->prev_determine_word(); 2491 that->info()->AddFromFollowing(that->on_success()->info());
2466 that->info()->determine_start = next->info()->prev_determine_start();
2467 } 2492 }
2468 2493
2469 2494
2470 void Analysis::VisitChoice(ChoiceNode* that) { 2495 void Analysis::VisitChoice(ChoiceNode* that) {
2471 NodeInfo* info = that->info(); 2496 NodeInfo* info = that->info();
2472 for (int i = 0; i < that->alternatives()->length(); i++) { 2497 for (int i = 0; i < that->alternatives()->length(); i++) {
2473 RegExpNode* node = that->alternatives()->at(i).node(); 2498 RegExpNode* node = that->alternatives()->at(i).node();
2474 EnsureAnalyzed(node); 2499 EnsureAnalyzed(node);
2475 info->determine_newline |= node->info()->prev_determine_newline(); 2500 // Anything the following nodes need to know has to be known by
2476 info->determine_word |= node->info()->prev_determine_word(); 2501 // this node also, so it can pass it on.
2477 info->determine_start |= node->info()->prev_determine_start(); 2502 info->AddFromFollowing(node->info());
2478 } 2503 }
2479 if (!that->table_calculated()) { 2504 if (!that->table_calculated()) {
2480 DispatchTableConstructor cons(that->table()); 2505 DispatchTableConstructor cons(that->table());
2481 cons.BuildTable(that); 2506 cons.BuildTable(that);
2482 } 2507 }
2483 EnsureAnalyzed(that->on_failure()); 2508 EnsureAnalyzed(that->on_failure());
2484 } 2509 }
2485 2510
2486 2511
2487 void Analysis::VisitBackReference(BackReferenceNode* that) { 2512 void Analysis::VisitBackReference(BackReferenceNode* that) {
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
2600 } 2625 }
2601 2626
2602 2627
2603 void DispatchTableConstructor::VisitAction(ActionNode* that) { 2628 void DispatchTableConstructor::VisitAction(ActionNode* that) {
2604 that->on_success()->Accept(this); 2629 that->on_success()->Accept(this);
2605 } 2630 }
2606 2631
2607 2632
2608 Handle<FixedArray> RegExpEngine::Compile(RegExpParseResult* input, 2633 Handle<FixedArray> RegExpEngine::Compile(RegExpParseResult* input,
2609 RegExpNode** node_return, 2634 RegExpNode** node_return,
2610 bool ignore_case) { 2635 bool ignore_case,
2636 bool is_multiline) {
2611 RegExpCompiler compiler(input->capture_count, ignore_case); 2637 RegExpCompiler compiler(input->capture_count, ignore_case);
2612 // Wrap the body of the regexp in capture #0. 2638 // Wrap the body of the regexp in capture #0.
2613 RegExpNode* captured_body = RegExpCapture::ToNode(input->tree, 2639 RegExpNode* captured_body = RegExpCapture::ToNode(input->tree,
2614 0, 2640 0,
2615 &compiler, 2641 &compiler,
2616 compiler.accept(), 2642 compiler.accept(),
2617 compiler.backtrack()); 2643 compiler.backtrack());
2618 // Add a .*? at the beginning, outside the body capture. 2644 // Add a .*? at the beginning, outside the body capture.
2619 // Note: We could choose to not add this if the regexp is anchored at 2645 // Note: We could choose to not add this if the regexp is anchored at
2620 // the start of the input but I'm not sure how best to do that and 2646 // the start of the input but I'm not sure how best to do that and
(...skipping 28 matching lines...) Expand all
2649 byte codes[1024]; 2675 byte codes[1024];
2650 IrregexpAssembler assembler(Vector<byte>(codes, 1024)); 2676 IrregexpAssembler assembler(Vector<byte>(codes, 1024));
2651 RegExpMacroAssemblerIrregexp macro_assembler(&assembler); 2677 RegExpMacroAssemblerIrregexp macro_assembler(&assembler);
2652 return compiler.Assemble(&macro_assembler, 2678 return compiler.Assemble(&macro_assembler,
2653 node, 2679 node,
2654 input->capture_count); 2680 input->capture_count);
2655 } 2681 }
2656 2682
2657 2683
2658 }} // namespace v8::internal 2684 }} // namespace v8::internal
OLDNEW
« no previous file with comments | « src/jsregexp.h ('k') | src/parser.h » ('j') | src/parser.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698