diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart index 2b0f8244dff..5b5eaa9a63c 100644 --- a/pkg/vm/bin/kernel_service.dart +++ b/pkg/vm/bin/kernel_service.dart @@ -158,26 +158,30 @@ abstract class Compiler { if (options.bytecode && errors.isEmpty) { await runWithFrontEndCompilerContext(script, options, component, () { // TODO(alexmarkov): disable source positions, local variables info, - // debugger stops and source files in VM PRODUCT mode. + // debugger stops, source files and unreachable code in VM PRODUCT + // mode. // TODO(rmacnak): disable annotations if mirrors are not enabled. generateBytecode(component, coreTypes: compilerResult.coreTypes, hierarchy: compilerResult.classHierarchy, options: new BytecodeOptions( - enableAsserts: enableAsserts, - environmentDefines: options.environmentDefines, - // Needed both for stack traces and the debugger. - emitSourcePositions: true, - // Only needed when the debugger is available. - emitLocalVarInfo: true, - // Only needed when the debugger is available. - emitDebuggerStops: true, - // Only needed when the VM service is available. - emitSourceFiles: true, - // Only needed when reload is available. - emitInstanceFieldInitializers: true, - // Only needed when mirrors are available. - emitAnnotations: true)); + enableAsserts: enableAsserts, + environmentDefines: options.environmentDefines, + // Needed both for stack traces and the debugger. + emitSourcePositions: true, + // Only needed when the debugger is available. + emitLocalVarInfo: true, + // Only needed when the debugger is available. + emitDebuggerStops: true, + // Only needed when the VM service is available. + emitSourceFiles: true, + // Only needed when reload is available. + emitInstanceFieldInitializers: true, + // Only needed when mirrors are available. + emitAnnotations: true, + // Only needed when observatory (source report) is available. + keepUnreachableCode: true, + )); component = createFreshComponentWithBytecode(component); }); } diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart index 4c38ad94c19..9401255df85 100644 --- a/pkg/vm/lib/bytecode/gen_bytecode.dart +++ b/pkg/vm/lib/bytecode/gen_bytecode.dart @@ -1290,6 +1290,9 @@ class BytecodeGenerator extends RecursiveVisitor { /// Returns value of the given expression if it is a bool constant. /// Otherwise, returns `null`. bool _constantConditionValue(Expression condition) { + if (options.keepUnreachableCode) { + return null; + } // TODO(dartbug.com/34585): use constant evaluator to evaluate // expressions in a non-constant context. if (condition is Not) { diff --git a/pkg/vm/lib/bytecode/options.dart b/pkg/vm/lib/bytecode/options.dart index 1772143a211..4546ef02670 100644 --- a/pkg/vm/lib/bytecode/options.dart +++ b/pkg/vm/lib/bytecode/options.dart @@ -13,6 +13,8 @@ class BytecodeOptions { 'show-bytecode-size-stat': 'Show bytecode size breakdown', 'source-positions': 'Emit source positions', 'instance-field-initializers': 'Emit separate instance field initializers', + 'keep-unreachable-code': + 'Do not remove unreachable code (useful if collecting code coverage)', }; bool enableAsserts; @@ -24,6 +26,7 @@ class BytecodeOptions { bool emitAnnotations; bool emitInstanceFieldInitializers; bool omitAssertSourcePositions; + bool keepUnreachableCode; bool showBytecodeSizeStatistics; Map environmentDefines; @@ -37,6 +40,7 @@ class BytecodeOptions { this.emitAnnotations = false, this.emitInstanceFieldInitializers = false, this.omitAssertSourcePositions = false, + this.keepUnreachableCode = false, this.showBytecodeSizeStatistics = false, this.environmentDefines = const {}}) { causalAsyncStacks ??= @@ -64,6 +68,9 @@ class BytecodeOptions { case 'instance-field-initializers': emitInstanceFieldInitializers = true; break; + case 'keep-unreachable-code': + keepUnreachableCode = true; + break; case 'show-bytecode-size-stat': showBytecodeSizeStatistics = true; break;