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

Side by Side Diff: src/compiler.cc

Issue 2505933008: [compiler] Ensure code unsupported by Crankshaft goes to Ignition. (Closed)
Patch Set: Fix GetBaselineCode Created 4 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/ast/ast-numbering.cc ('k') | src/crankshaft/hydrogen.cc » ('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 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler.h" 5 #include "src/compiler.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <memory> 8 #include <memory>
9 9
10 #include "src/asmjs/asm-js.h" 10 #include "src/asmjs/asm-js.h"
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 } 298 }
299 299
300 // It's very important that recompiles do not alter the structure of the type 300 // It's very important that recompiles do not alter the structure of the type
301 // feedback vector. Verify that the structure fits the function literal. 301 // feedback vector. Verify that the structure fits the function literal.
302 CHECK(!info->shared_info()->feedback_metadata()->SpecDiffersFrom( 302 CHECK(!info->shared_info()->feedback_metadata()->SpecDiffersFrom(
303 info->literal()->feedback_vector_spec())); 303 info->literal()->feedback_vector_spec()));
304 } 304 }
305 305
306 bool UseTurboFan(Handle<SharedFunctionInfo> shared) { 306 bool UseTurboFan(Handle<SharedFunctionInfo> shared) {
307 bool optimization_disabled = shared->optimization_disabled(); 307 bool optimization_disabled = shared->optimization_disabled();
308 bool dont_crankshaft = shared->dont_crankshaft(); 308 bool must_use_ignition_turbo = shared->must_use_ignition_turbo();
309 309
310 // Check the enabling conditions for Turbofan. 310 // Check the enabling conditions for Turbofan.
311 // 1. "use asm" code. 311 // 1. "use asm" code.
312 bool is_turbofanable_asm = 312 bool is_turbofanable_asm =
313 FLAG_turbo_asm && shared->asm_function() && !optimization_disabled; 313 FLAG_turbo_asm && shared->asm_function() && !optimization_disabled;
314 314
315 // 2. Fallback for features unsupported by Crankshaft. 315 // 2. Fallback for features unsupported by Crankshaft.
316 bool is_unsupported_by_crankshaft_but_turbofanable = 316 bool is_unsupported_by_crankshaft_but_turbofanable =
317 dont_crankshaft && strcmp(FLAG_turbo_filter, "~~") == 0 && 317 must_use_ignition_turbo && strcmp(FLAG_turbo_filter, "~~") == 0 &&
318 !optimization_disabled; 318 !optimization_disabled;
319 319
320 // 3. Explicitly enabled by the command-line filter. 320 // 3. Explicitly enabled by the command-line filter.
321 bool passes_turbo_filter = shared->PassesFilter(FLAG_turbo_filter); 321 bool passes_turbo_filter = shared->PassesFilter(FLAG_turbo_filter);
322 322
323 return is_turbofanable_asm || is_unsupported_by_crankshaft_but_turbofanable || 323 return is_turbofanable_asm || is_unsupported_by_crankshaft_but_turbofanable ||
324 passes_turbo_filter; 324 passes_turbo_filter;
325 } 325 }
326 326
327 bool ShouldUseIgnition(CompilationInfo* info) { 327 bool ShouldUseIgnition(CompilationInfo* info) {
328 DCHECK(info->has_shared_info()); 328 DCHECK(info->has_shared_info());
329 Handle<SharedFunctionInfo> shared = info->shared_info();
330
331 // Code which can't be supported by the old pipeline should use Ignition.
332 if (shared->must_use_ignition_turbo()) return true;
329 333
330 // Resumable functions are not supported by {FullCodeGenerator}, suspended 334 // Resumable functions are not supported by {FullCodeGenerator}, suspended
331 // activations stored as {JSGeneratorObject} on the heap always assume the 335 // activations stored as {JSGeneratorObject} on the heap always assume the
332 // underlying code to be based on the bytecode array. 336 // underlying code to be based on the bytecode array.
333 // TODO(mstarzinger): Once we want to deprecate even more support from the 337 DCHECK(!IsResumableFunction(shared->kind()));
334 // {FullCodeGenerator}, we will compute an appropriate bit in {AstNumbering}
335 // and turn this predicate into a DCHECK instead.
336 if (IsResumableFunction(info->shared_info()->kind())) {
337 return true;
338 }
339 338
340 // Skip Ignition for asm.js functions. 339 // Skip Ignition for asm.js functions.
341 if (info->shared_info()->asm_function()) { 340 if (shared->asm_function()) return false;
341
342 // Skip Ignition for asm wasm code.
343 if (FLAG_validate_asm && shared->HasAsmWasmData()) {
342 return false; 344 return false;
343 } 345 }
344 346
345 // When requesting debug code as a replacement for existing code, we provide 347 // When requesting debug code as a replacement for existing code, we provide
346 // the same kind as the existing code (to prevent implicit tier-change). 348 // the same kind as the existing code (to prevent implicit tier-change).
347 if (info->is_debug() && info->shared_info()->is_compiled()) { 349 if (info->is_debug() && shared->is_compiled()) {
348 return !info->shared_info()->HasBaselineCode(); 350 return !shared->HasBaselineCode();
349 } 351 }
350 352
351 // Code destined for TurboFan should be compiled with Ignition first. 353 // Code destined for TurboFan should be compiled with Ignition first.
352 if (UseTurboFan(info->shared_info())) return true; 354 if (UseTurboFan(shared)) return true;
353 355
354 // Only use Ignition for any other function if FLAG_ignition is true. 356 // Only use Ignition for any other function if FLAG_ignition is true.
355 if (!FLAG_ignition) return false; 357 if (!FLAG_ignition) return false;
356 358
357 // Checks whether top level functions should be passed by the filter. 359 // Checks whether top level functions should be passed by the filter.
358 if (info->shared_info()->is_toplevel()) { 360 if (shared->is_toplevel()) {
359 Vector<const char> filter = CStrVector(FLAG_ignition_filter); 361 Vector<const char> filter = CStrVector(FLAG_ignition_filter);
360 return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*'); 362 return (filter.length() == 0) || (filter.length() == 1 && filter[0] == '*');
361 } 363 }
362 364
363 // Finally respect the filter. 365 // Finally respect the filter.
364 return info->shared_info()->PassesFilter(FLAG_ignition_filter); 366 return shared->PassesFilter(FLAG_ignition_filter);
365 } 367 }
366 368
367 CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) { 369 CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) {
368 // Function should have been parsed and analyzed before creating a compilation 370 // Function should have been parsed and analyzed before creating a compilation
369 // job. 371 // job.
370 DCHECK_NOT_NULL(info->literal()); 372 DCHECK_NOT_NULL(info->literal());
371 DCHECK_NOT_NULL(info->scope()); 373 DCHECK_NOT_NULL(info->scope());
372 374
373 EnsureFeedbackMetadata(info); 375 EnsureFeedbackMetadata(info);
374 if (ShouldUseIgnition(info)) { 376 if (ShouldUseIgnition(info)) {
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 parse_info->literal())) { 522 parse_info->literal())) {
521 return false; 523 return false;
522 } 524 }
523 Handle<SharedFunctionInfo> shared_info = parse_info->shared_info(); 525 Handle<SharedFunctionInfo> shared_info = parse_info->shared_info();
524 if (!shared_info.is_null()) { 526 if (!shared_info.is_null()) {
525 FunctionLiteral* lit = parse_info->literal(); 527 FunctionLiteral* lit = parse_info->literal();
526 shared_info->set_ast_node_count(lit->ast_node_count()); 528 shared_info->set_ast_node_count(lit->ast_node_count());
527 if (lit->dont_optimize_reason() != kNoReason) { 529 if (lit->dont_optimize_reason() != kNoReason) {
528 shared_info->DisableOptimization(lit->dont_optimize_reason()); 530 shared_info->DisableOptimization(lit->dont_optimize_reason());
529 } 531 }
530 if (lit->flags() & AstProperties::kDontCrankshaft) { 532 if (lit->flags() & AstProperties::kMustUseIgnitionTurbo) {
531 shared_info->set_dont_crankshaft(true); 533 shared_info->set_must_use_ignition_turbo(true);
532 } 534 }
533 } 535 }
534 return true; 536 return true;
535 } 537 }
536 538
537 bool GetOptimizedCodeNow(CompilationJob* job) { 539 bool GetOptimizedCodeNow(CompilationJob* job) {
538 CompilationInfo* info = job->info(); 540 CompilationInfo* info = job->info();
539 Isolate* isolate = info->isolate(); 541 Isolate* isolate = info->isolate();
540 542
541 // Parsing is not required when optimizing from existing bytecode. 543 // Parsing is not required when optimizing from existing bytecode.
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
643 function->ShortPrint(); 645 function->ShortPrint();
644 if (!osr_ast_id.IsNone()) { 646 if (!osr_ast_id.IsNone()) {
645 PrintF(" at OSR AST id %d", osr_ast_id.ToInt()); 647 PrintF(" at OSR AST id %d", osr_ast_id.ToInt());
646 } 648 }
647 PrintF("]\n"); 649 PrintF("]\n");
648 } 650 }
649 return cached_code; 651 return cached_code;
650 } 652 }
651 653
652 // Reset profiler ticks, function is no longer considered hot. 654 // Reset profiler ticks, function is no longer considered hot.
655 DCHECK(shared->is_compiled());
653 if (shared->HasBaselineCode()) { 656 if (shared->HasBaselineCode()) {
654 shared->code()->set_profiler_ticks(0); 657 shared->code()->set_profiler_ticks(0);
655 } else if (shared->HasBytecodeArray()) { 658 } else if (shared->HasBytecodeArray()) {
656 shared->set_profiler_ticks(0); 659 shared->set_profiler_ticks(0);
657 } 660 }
658 661
659 VMState<COMPILER> state(isolate); 662 VMState<COMPILER> state(isolate);
660 DCHECK(!isolate->has_pending_exception()); 663 DCHECK(!isolate->has_pending_exception());
661 PostponeInterruptsScope postpone(isolate); 664 PostponeInterruptsScope postpone(isolate);
662 bool use_turbofan = UseTurboFan(shared) || ignition_osr; 665 bool use_turbofan = UseTurboFan(shared) || ignition_osr;
(...skipping 19 matching lines...) Expand all
682 return MaybeHandle<Code>(); 685 return MaybeHandle<Code>();
683 } 686 }
684 687
685 TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate); 688 TimerEventScope<TimerEventOptimizeCode> optimize_code_timer(isolate);
686 RuntimeCallTimerScope runtimeTimer(isolate, &RuntimeCallStats::OptimizeCode); 689 RuntimeCallTimerScope runtimeTimer(isolate, &RuntimeCallStats::OptimizeCode);
687 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.OptimizeCode"); 690 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.OptimizeCode");
688 691
689 // TurboFan can optimize directly from existing bytecode. 692 // TurboFan can optimize directly from existing bytecode.
690 if (use_turbofan && ShouldUseIgnition(info)) { 693 if (use_turbofan && ShouldUseIgnition(info)) {
691 if (info->is_osr() && !ignition_osr) return MaybeHandle<Code>(); 694 if (info->is_osr() && !ignition_osr) return MaybeHandle<Code>();
692 if (!Compiler::EnsureBytecode(info)) { 695 DCHECK(shared->HasBytecodeArray());
693 if (isolate->has_pending_exception()) isolate->clear_pending_exception();
694 return MaybeHandle<Code>();
695 }
696 info->MarkAsOptimizeFromBytecode(); 696 info->MarkAsOptimizeFromBytecode();
697 } 697 }
698 698
699 // Verify that OSR compilations are delegated to the correct graph builder. 699 // Verify that OSR compilations are delegated to the correct graph builder.
700 // Depending on the underlying frame the semantics of the {BailoutId} differ 700 // Depending on the underlying frame the semantics of the {BailoutId} differ
701 // and the various graph builders hard-code a certain semantic: 701 // and the various graph builders hard-code a certain semantic:
702 // - Interpreter : The BailoutId represents a bytecode offset. 702 // - Interpreter : The BailoutId represents a bytecode offset.
703 // - FullCodegen : The BailoutId represents the id of an AST node. 703 // - FullCodegen : The BailoutId represents the id of an AST node.
704 DCHECK_IMPLIES(info->is_osr() && ignition_osr, 704 DCHECK_IMPLIES(info->is_osr() && ignition_osr,
705 info->is_optimizing_from_bytecode()); 705 info->is_optimizing_from_bytecode());
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
815 if (function->shared()->code()->kind() == Code::FUNCTION) { 815 if (function->shared()->code()->kind() == Code::FUNCTION) {
816 return Handle<Code>(function->shared()->code()); 816 return Handle<Code>(function->shared()->code());
817 } 817 }
818 818
819 // We do not switch to baseline code when the debugger might have created a 819 // We do not switch to baseline code when the debugger might have created a
820 // copy of the bytecode with break slots to be able to set break points. 820 // copy of the bytecode with break slots to be able to set break points.
821 if (function->shared()->HasDebugInfo()) { 821 if (function->shared()->HasDebugInfo()) {
822 return MaybeHandle<Code>(); 822 return MaybeHandle<Code>();
823 } 823 }
824 824
825 // TODO(4280): For now we do not switch generators or async functions to 825 // Don't generate full-codegen code for functions it can't support.
826 // baseline code because there might be suspended activations stored in 826 if (function->shared()->must_use_ignition_turbo()) {
827 // generator objects on the heap. We could eventually go directly to
828 // TurboFan in this case.
829 if (IsResumableFunction(function->shared()->kind())) {
830 return MaybeHandle<Code>(); 827 return MaybeHandle<Code>();
831 } 828 }
829 DCHECK(!IsResumableFunction(function->shared()->kind()));
832 830
833 if (FLAG_trace_opt) { 831 if (FLAG_trace_opt) {
834 OFStream os(stdout); 832 OFStream os(stdout);
835 os << "[switching method " << Brief(*function) << " to baseline code]" 833 os << "[switching method " << Brief(*function) << " to baseline code]"
836 << std::endl; 834 << std::endl;
837 } 835 }
838 836
839 // Parse and update CompilationInfo with the results. 837 // Parse and update CompilationInfo with the results.
840 if (!Parser::ParseStatic(info.parse_info())) return MaybeHandle<Code>(); 838 if (!Parser::ParseStatic(info.parse_info())) return MaybeHandle<Code>();
841 Handle<SharedFunctionInfo> shared = info.shared_info(); 839 Handle<SharedFunctionInfo> shared = info.shared_info();
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after
1187 1185
1188 // Restore the original function info list in order to remain side-effect 1186 // Restore the original function info list in order to remain side-effect
1189 // free as much as possible, since some code expects the old shared function 1187 // free as much as possible, since some code expects the old shared function
1190 // infos to stick around. 1188 // infos to stick around.
1191 script->set_shared_function_infos(*old_function_infos); 1189 script->set_shared_function_infos(*old_function_infos);
1192 1190
1193 return infos; 1191 return infos;
1194 } 1192 }
1195 1193
1196 bool Compiler::EnsureBytecode(CompilationInfo* info) { 1194 bool Compiler::EnsureBytecode(CompilationInfo* info) {
1197 if (!ShouldUseIgnition(info)) return false; 1195 if (!info->shared_info()->is_compiled()) {
1198 if (!info->shared_info()->HasBytecodeArray()) {
1199 Handle<Code> original_code(info->shared_info()->code());
1200 if (GetUnoptimizedCode(info).is_null()) return false; 1196 if (GetUnoptimizedCode(info).is_null()) return false;
1201 if (info->shared_info()->HasAsmWasmData()) return false; 1197 if (info->shared_info()->HasAsmWasmData()) return false;
1202 DCHECK(info->shared_info()->is_compiled());
1203 if (original_code->kind() == Code::FUNCTION) {
1204 // Generating bytecode will install the {InterpreterEntryTrampoline} as
1205 // shared code on the function. To avoid an implicit tier down we restore
1206 // original baseline code in case it existed beforehand.
1207 info->shared_info()->ReplaceCode(*original_code);
1208 }
1209 } 1198 }
1210 DCHECK(info->shared_info()->HasBytecodeArray()); 1199 DCHECK(info->shared_info()->is_compiled());
1211 return true; 1200 DCHECK_EQ(ShouldUseIgnition(info), info->shared_info()->HasBytecodeArray());
1201 return info->shared_info()->HasBytecodeArray();
1212 } 1202 }
1213 1203
1214 // TODO(turbofan): In the future, unoptimized code with deopt support could 1204 // TODO(turbofan): In the future, unoptimized code with deopt support could
1215 // be generated lazily once deopt is triggered. 1205 // be generated lazily once deopt is triggered.
1216 bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) { 1206 bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) {
1217 DCHECK_NOT_NULL(info->literal()); 1207 DCHECK_NOT_NULL(info->literal());
1218 DCHECK_NOT_NULL(info->scope()); 1208 DCHECK_NOT_NULL(info->scope());
1219 Handle<SharedFunctionInfo> shared = info->shared_info(); 1209 Handle<SharedFunctionInfo> shared = info->shared_info();
1220 if (!shared->has_deoptimization_support()) { 1210 if (!shared->has_deoptimization_support()) {
1221 Zone zone(info->isolate()->allocator(), ZONE_NAME); 1211 Zone zone(info->isolate()->allocator(), ZONE_NAME);
1222 CompilationInfo unoptimized(info->parse_info(), info->closure()); 1212 CompilationInfo unoptimized(info->parse_info(), info->closure());
1223 unoptimized.EnableDeoptimizationSupport(); 1213 unoptimized.EnableDeoptimizationSupport();
1224 1214
1225 // TODO(4280): For now we do not switch generators or async functions to 1215 // Don't generate full-codegen code for functions it can't support.
1226 // baseline code because there might be suspended activations stored in 1216 if (shared->must_use_ignition_turbo()) return false;
1227 // generator objects on the heap. We could eventually go directly to 1217 DCHECK(!IsResumableFunction(shared->kind()));
1228 // TurboFan in this case.
1229 if (IsResumableFunction(shared->kind())) return false;
1230 1218
1231 // When we call PrepareForSerializing below, we will change the shared 1219 // When we call PrepareForSerializing below, we will change the shared
1232 // ParseInfo. Make sure to reset it. 1220 // ParseInfo. Make sure to reset it.
1233 bool old_will_serialize_value = info->parse_info()->will_serialize(); 1221 bool old_will_serialize_value = info->parse_info()->will_serialize();
1234 1222
1235 // If the current code has reloc info for serialization, also include 1223 // If the current code has reloc info for serialization, also include
1236 // reloc info for serialization for the new code, so that deopt support 1224 // reloc info for serialization for the new code, so that deopt support
1237 // can be added without losing IC state. 1225 // can be added without losing IC state.
1238 if (shared->code()->kind() == Code::FUNCTION && 1226 if (shared->code()->kind() == Code::FUNCTION &&
1239 shared->code()->has_reloc_info_for_serialization()) { 1227 shared->code()->has_reloc_info_for_serialization()) {
1240 unoptimized.PrepareForSerializing(); 1228 unoptimized.PrepareForSerializing();
1241 } 1229 }
1242 EnsureFeedbackMetadata(&unoptimized); 1230 EnsureFeedbackMetadata(&unoptimized);
1231
1232 // Ensure we generate and install bytecode first if the function should use
1233 // Ignition to avoid implicit tier-down.
1234 if (!shared->is_compiled() && ShouldUseIgnition(info) &&
1235 !GenerateUnoptimizedCode(info)) {
1236 return false;
1237 }
1238
1243 if (!FullCodeGenerator::MakeCode(&unoptimized)) return false; 1239 if (!FullCodeGenerator::MakeCode(&unoptimized)) return false;
1244 1240
1245 info->parse_info()->set_will_serialize(old_will_serialize_value); 1241 info->parse_info()->set_will_serialize(old_will_serialize_value);
1246 1242
1247 // The scope info might not have been set if a lazily compiled 1243 // The scope info might not have been set if a lazily compiled
1248 // function is inlined before being called for the first time. 1244 // function is inlined before being called for the first time.
1249 if (shared->scope_info() == ScopeInfo::Empty(info->isolate())) { 1245 if (shared->scope_info() == ScopeInfo::Empty(info->isolate())) {
1250 InstallSharedScopeInfo(info, shared); 1246 InstallSharedScopeInfo(info, shared);
1251 } 1247 }
1252 1248
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
1707 return true; 1703 return true;
1708 } 1704 }
1709 return false; 1705 return false;
1710 } 1706 }
1711 } 1707 }
1712 1708
1713 void Compiler::PostInstantiation(Handle<JSFunction> function, 1709 void Compiler::PostInstantiation(Handle<JSFunction> function,
1714 PretenureFlag pretenure) { 1710 PretenureFlag pretenure) {
1715 Handle<SharedFunctionInfo> shared(function->shared()); 1711 Handle<SharedFunctionInfo> shared(function->shared());
1716 1712
1717 if (FLAG_always_opt && shared->allows_lazy_compilation()) { 1713 if (FLAG_always_opt && shared->allows_lazy_compilation() &&
1714 function->shared()->is_compiled()) {
1718 function->MarkForOptimization(); 1715 function->MarkForOptimization();
1719 } 1716 }
1720 1717
1721 CodeAndLiterals cached = shared->SearchOptimizedCodeMap( 1718 CodeAndLiterals cached = shared->SearchOptimizedCodeMap(
1722 function->context()->native_context(), BailoutId::None()); 1719 function->context()->native_context(), BailoutId::None());
1723 if (cached.code != nullptr) { 1720 if (cached.code != nullptr) {
1724 // Caching of optimized code enabled and optimized code found. 1721 // Caching of optimized code enabled and optimized code found.
1725 DCHECK(!cached.code->marked_for_deoptimization()); 1722 DCHECK(!cached.code->marked_for_deoptimization());
1726 DCHECK(function->shared()->is_compiled()); 1723 DCHECK(function->shared()->is_compiled());
1727 function->ReplaceCode(cached.code); 1724 function->ReplaceCode(cached.code);
1728 } 1725 }
1729 1726
1730 if (cached.literals != nullptr) { 1727 if (cached.literals != nullptr) {
1731 DCHECK(shared->is_compiled()); 1728 DCHECK(shared->is_compiled());
1732 function->set_literals(cached.literals); 1729 function->set_literals(cached.literals);
1733 } else if (shared->is_compiled()) { 1730 } else if (shared->is_compiled()) {
1734 // TODO(mvstanton): pass pretenure flag to EnsureLiterals. 1731 // TODO(mvstanton): pass pretenure flag to EnsureLiterals.
1735 JSFunction::EnsureLiterals(function); 1732 JSFunction::EnsureLiterals(function);
1736 } 1733 }
1737 } 1734 }
1738 1735
1739 } // namespace internal 1736 } // namespace internal
1740 } // namespace v8 1737 } // namespace v8
OLDNEW
« no previous file with comments | « src/ast/ast-numbering.cc ('k') | src/crankshaft/hydrogen.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698