一、概述

书接上文源码解读Flutter run机制的第四节 flutter build aot命令将dart源码编译成AOT产物,其主要工作为前端编译器frontend_server和机器码生成,本文先介绍前端编译器frontend_server的工作原理。

1.1 frontend_server命令

KernelCompiler.compile()过程等价于如下命令:

// 该frontend_server命令 同时适用于Android和iOS
flutter/bin/cache/dart-sdk/bin/dart                                            \flutter/bin/cache/artifacts/engine/darwin-x64/frontend_server.dart.snapshot  \--sdk-root flutter/bin/cache/artifacts/engine/common/flutter_patched_sdk/    \--strong                                                                     \--target=flutter                                                             \--aot --tfa                                                                  \-Ddart.vm.product=true                                                       \--packages .packages                                                         \--output-dill /build/app/intermediates/flutter/release/app.dill              \--depfile     /build/app/intermediates/flutter/release/kernel_compile.d      \--"package" /lib/main.dart

可见,通过dart虚拟机启动frontend_server.dart.snapshot,将dart代码转换成app.dill形式的kernel文件。frontend_server.dart.snapshot入口位于Flutter引擎中的 flutter/frontend_server/bin/starter.dart。

1.2 frontend参数表

前端编译器的可选参数:

参数 说明 默认值
aot 在AOT模式下运行编译器(启用整个程序转换) false
tfa 在AOT模式下启用全局类型流分析和相关转换 false
train 通过示例命令行运行以生成快照 false
incremental 以增量模式运行编译器 flase
link-platform 批处理模式,平台kernel文件链接到结果的内核文件 true
embed-source-text 源码加入到生成的dill文件,便于得到用于调试的堆栈信息 true
track-widget-creation 运行内核转换器来跟踪widgets创建的位置 false
strong 已过时flags true
import-dill 从已存在的dill文件中引入库 null
output-dill 将生成的dill文件输出路径 null
output-incremental-dill 将生成的增量dill文件输出路径 null
depfile 仅用于批量,输出Ninja的depfile
packages 用于编译的.packages文件 null
sdk-root SDK根目录的路径 …/…/out/android_debug/flutter_patched_sdk
target 确定哪些核心库可用,可取值vm、flutter、flutter_runner、dart_runner vm
  • 增量模式运行编译器应该能加快编译速度
  • track-widget-creation、aot、tfa参数的使用场景

1.3 frontend_server执行流程图

(1)点击查看大图

frontend_server前端编译器将dart代码转换为AST,并生成app.dill文件,其中bytecode生成过程默认是关闭的。

(2)点击查看大图

Component的成员变量:

  • uriToSource的类型为Map<Uri, Source> ,用于从源文件URI映射到行开始表和源代码。给定一个源文件URI和该文件中的偏移量,就可以转换为该文件中line:column的位置。

二、 源码解读frontend_server

BuildAotCommand.runCommandAOTSnapshotter.compileKernelKernelCompiler.compilefrontend_server命令

2.1 starter.main

[-> flutter/frontend_server/bin/starter.dart]

void main(List<String> args) async {final int exitCode = await starter(args);...
}

2.2 server.starter

[-> flutter/frontend_server/lib/server.dart]

Future<int> starter(List<String> args, {frontend.CompilerInterface compiler,Stream<List<int>> input,StringSink output,}) async {...//解析参数 [见小节2.2.1]ArgResults options = frontend.argParser.parse(args);//创建前端编译器实例对象compiler ??= new _FlutterFrontendCompiler(output,trackWidgetCreation: options['track-widget-creation'],unsafePackageSerialization: options['unsafe-package-serialization']);if (options.rest.isNotEmpty) {//解析命令行的剩余参数 [见小节2.3]return await compiler.compile(options.rest[0], options) ? 0 : 254;}...
}

该方法主要工作:

  • 解析KernelCompiler.compile()方法中传递过来的参数,参数表小节[1.2]
  • 创建前端编译器实例对象_FlutterFrontendCompiler;
  • 执行编译操作;

2.3 _FlutterFrontendCompiler.compile

[-> flutter/frontend_server/lib/server.dart]

class _FlutterFrontendCompiler implements frontend.CompilerInterface{final frontend.CompilerInterface _compiler;_FlutterFrontendCompiler(StringSink output,{bool trackWidgetCreation: false, bool unsafePackageSerialization}) ://创建编译器对象_compiler = new frontend.FrontendCompiler(output,transformer: trackWidgetCreation ? new WidgetCreatorTracker() : null,unsafePackageSerialization: unsafePackageSerialization);Future<bool> compile(String filename, ArgResults options, {IncrementalCompiler generator}) async {// filename是入口文件名 [见小节2.4]return _compiler.compile(filename, options, generator: generator);}
}

创建前端编译器实例对象_FlutterFrontendCompiler,其内部有一个重要的成员变量frontend.FrontendCompiler,该对象主要是在FrontendCompile功能的基础之上编译中添加了一个widgetCreatorTracker的内核转换器,所以核心工作都是交由FrontendCompiler来执行。

2.4 FrontendCompiler.compile

[-> third_party/dart/pkg/vm/lib/frontend_server.dart]

class FrontendCompiler implements CompilerInterface {Future<bool> compile(String entryPoint, ArgResults options, {IncrementalCompiler generator,}) async {_options = options;_fileSystem = createFrontEndFileSystem(options['filesystem-scheme'], options['filesystem-root']);//源码入口函数名,也就是lib/main.dart_mainSource = _getFileOrUri(entryPoint);_kernelBinaryFilenameFull = _options['output-dill'] ?? '$entryPoint.dill';_kernelBinaryFilenameIncremental = _options['output-incremental-dill'] ??(_options['output-dill'] != null? '${_options['output-dill']}.incremental.dill': '$entryPoint.incremental.dill');_kernelBinaryFilename = _kernelBinaryFilenameFull;_initializeFromDill = _options['initialize-from-dill'] ?? _kernelBinaryFilenameFull;final String boundaryKey = new Uuid().generateV4();_outputStream.writeln('result $boundaryKey');final Uri sdkRoot = _ensureFolderPath(options['sdk-root']);final String platformKernelDill = options['platform'] ?? 'platform_strong.dill';...Component component;if (options['incremental']) {_compilerOptions = compilerOptions;setVMEnvironmentDefines(environmentDefines, _compilerOptions);_compilerOptions.omitPlatform = false;_generator = generator ?? _createGenerator(new Uri.file(_initializeFromDill));await invalidateIfInitializingFromDill();component = await _runWithPrintRedirection(() => _generator.compile());} else {...// [见小节2.5]component = await _runWithPrintRedirection(() => compileToKernel(_mainSource, compilerOptions,aot: options['aot'],useGlobalTypeFlowAnalysis: options['tfa'],environmentDefines: environmentDefines));}if (component != null) {if (transformer != null) {transformer.transform(component);}//[见小节2.10] 写入dill文件await writeDillFile(component, _kernelBinaryFilename,filterExternal: importDill != null);await _outputDependenciesDelta(component);final String depfile = options['depfile'];if (depfile != null) {await writeDepfile(compilerOptions.fileSystem, component,_kernelBinaryFilename, depfile);}_kernelBinaryFilename = _kernelBinaryFilenameIncremental;}return errors.isEmpty;}
}

该方法主要功能:

  • 执行compileToKernel,将dart转换为kernel文件,也就是中间语言文件;
  • 再将中间数据写入app.dill文件

2.5 compileToKernel

[-> third_party/dart/pkg/vm/lib/kernel_front_end.dart]

Future<Component> compileToKernel(Uri source, CompilerOptions options,{bool aot: false,bool useGlobalTypeFlowAnalysis: false,Map<String, String> environmentDefines,bool genBytecode: false,bool emitBytecodeSourcePositions: false,bool emitBytecodeAnnotations: false,bool dropAST: false,bool useFutureBytecodeFormat: false,bool enableAsserts: false,bool enableConstantEvaluation: true,bool useProtobufTreeShaker: false}) async {//替代错误处理程序以检测是否存在编译错误final errorDetector = new ErrorDetector(previousErrorHandler: options.onDiagnostic);options.onDiagnostic = errorDetector;setVMEnvironmentDefines(environmentDefines, options);//将dart代码转换为component对象 [见小节2.6]final component = await kernelForProgram(source, options);if (aot && component != null) {// 执行全局转换器 [见小节2.7]await _runGlobalTransformations(source,options,component,useGlobalTypeFlowAnalysis,environmentDefines,enableAsserts,enableConstantEvaluation,useProtobufTreeShaker,errorDetector);}if (genBytecode && !errorDetector.hasCompilationErrors && component != null) {//生成字节码,genBytecode默认为false,不执行该操作 [见小节2.8]await runWithFrontEndCompilerContext(source, options, component, () {generateBytecode(component,emitSourcePositions: emitBytecodeSourcePositions,emitAnnotations: emitBytecodeAnnotations,useFutureBytecodeFormat: useFutureBytecodeFormat,environmentDefines: environmentDefines);});if (dropAST) {new ASTRemover(component).visitComponent(component);}}//恢复错误处理程序options.onDiagnostic = errorDetector.previousErrorHandler;return component;
}

该方法主要功能:

  • kernelForProgram:将dart代码转换为component对象;
  • _runGlobalTransformations:执行全局转换器;
  • generateBytecode:默认genBytecode为false,AST不生成kernel字节码

2.6 kernelForProgram

[-> third_party/dart/pkg/front_end/lib/src/api_prototype/kernel_generator.dart]

Future<CompilerResult> kernelForProgram(Uri source, CompilerOptions options) async {return (await kernelForProgramInternal(source, options));
}Future<CompilerResult> kernelForProgramInternal(Uri source, CompilerOptions options,{bool retainDataForTesting: false}) async {var pOptions = new ProcessedOptions(options: options, inputs: [source]);return await CompilerContext.runWithOptions(pOptions, (context) async {//生成component [见小节2.6.1]var component = (await generateKernelInternal())?.component;if (component == null) return null;// 输入source应该是包含main方法的脚步,否则将报告错误if (component.mainMethod == null) {context.options.report(messageMissingMain.withLocation(source, -1, noLength),Severity.error);return null;}return component;});
}

该方法的主要功能是将整个dart程序代码生成component对象。编译整个程序,生成程序的内核表示,该程序的主库位于给定的源码。 给定包含main方法的文件的Uri,通过该函数的import, export, part声明来发现整个程序,并将结果转换为Dart Kernel格式。 需要注意的是,当[options]中的compileSdk=true,则生成的组件将包含SDK代码。

Component的成员变量libraries,记录所有的lib库,包括app源文件、package以及三方库。每个Library对象会有Class、Field、procedure等组成。

2.6.1 generateKernelInternal

[-> third_party/dart/pkg/front_end/lib/src/kernel_generator_impl.dart]

Future<CompilerResult> generateKernelInternal({bool buildSummary: false,bool buildComponent: true,bool truncateSummary: false}) async {var options = CompilerContext.current.options;var fs = options.fileSystem;Loader sourceLoader;return withCrashReporting<CompilerResult>(() async {UriTranslator uriTranslator = await options.getUriTranslator();var dillTarget = new DillTarget(options.ticker, uriTranslator, options.target);...await dillTarget.buildOutlines();//创建KernelTargetvar kernelTarget = new KernelTarget(fs, false, dillTarget, uriTranslator);sourceLoader = kernelTarget.loader;kernelTarget.setEntryPoints(options.inputs);Component summaryComponent = await kernelTarget.buildOutlines(nameRoot: nameRoot);if (buildSummary) {...}Component component;if (buildComponent) {//[见小节2.6.2]component = await kernelTarget.buildComponent(verify: options.verify);}...return new InternalCompilerResult(summary: summary,component: component,classHierarchy:includeHierarchyAndCoreTypes ? kernelTarget.loader.hierarchy : null,coreTypes:includeHierarchyAndCoreTypes ? kernelTarget.loader.coreTypes : null,deps: new List<Uri>.from(CompilerContext.current.dependencies),kernelTargetForTesting: retainDataForTesting ? kernelTarget : null);}, () => sourceLoader?.currentUriForCrashReporting ?? options.inputs.first);
}

2.6.2 buildComponent

[-> third_party/dart/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart]

class KernelTarget extends TargetImplementation {Component component;  //成员变量--组件Future<Component> buildComponent({bool verify: false}) async {if (loader.first == null) return null;return withCrashReporting<Component>(() async {//[见小节2.6.3]await loader.buildBodies();finishClonedParameters();loader.finishDeferredLoadTearoffs();loader.finishNoSuchMethodForwarders();List<SourceClassBuilder> myClasses = collectMyClasses();loader.finishNativeMethods();loader.finishPatchMethods();finishAllConstructors(myClasses);runBuildTransformations();if (verify) this.verify();installAllComponentProblems(loader.allComponentProblems);return component;}, () => loader?.currentUriForCrashReporting);}
}

KernelTarget的component记录整个dart代码的各种信息。

2.6.3 buildBodies

[-> third_party/dart/pkg/front_end/lib/src/fasta/loader.dart]

Future<Null> buildBodies() async {for (LibraryBuilder library in builders.values) {if (library.loader == this) {currentUriForCrashReporting = library.uri;//[见小节2.6.4]await buildBody(library);}}currentUriForCrashReporting = null;logSummary(templateSourceBodySummary);
}

此处的loader为SourceLoader,是在KernelTarget对象创建过程初始化的。

2.6.4 buildBody

[-> third_party/dart/pkg/front_end/lib/src/fasta/source/source_loader.dart]

class SourceLoader extends Loader<Library> {Future<Null> buildBody(LibraryBuilder library) async {if (library is SourceLibraryBuilder) {//词法分析Token tokens = await tokenize(library, suppressLexicalErrors: true);DietListener listener = createDietListener(library);DietParser parser = new DietParser(listener);//语法分析parser.parseUnit(tokens);for (SourceLibraryBuilder part in library.parts) {if (part.partOfLibrary != library) {// part部分包含在多个库中,此处跳过continue;}Token tokens = await tokenize(part);if (tokens != null) {listener.uri = part.fileUri;listener.partDirectiveIndex = 0;parser.parseUnit(tokens);}}}}
}

该方法主要工作:

  • 词法分析tokenize:对库中dart源码,根据一定的词法规则解析成词法单元tokens;
  • 语法分析parser:对tokens根据Dart语法规则解析成抽象语法树;

说明,这个过程采用两次标记源文件,以保持较低的内存使用率。 这是第二次,第一次是在上面的[buildOutline]中,所以这抑制词法错误。

2.7 _runGlobalTransformations

[-> third_party/dart/pkg/vm/lib/kernel_front_end.dart]

Future _runGlobalTransformations(Uri source,CompilerOptions compilerOptions,Component component,bool useGlobalTypeFlowAnalysis,Map<String, String> environmentDefines,bool enableAsserts,bool enableConstantEvaluation,bool useProtobufTreeShaker,ErrorDetector errorDetector) async {if (errorDetector.hasCompilationErrors) return;final coreTypes = new CoreTypes(component);_patchVmConstants(coreTypes);//mixin应用在前端创建mixin应用时,所有后端(以及从一开始就进行的所有转换)能都受益于mixin重复数据删除。//AOT除外, JIT构建情况下,都需要运行此转换mixin_deduplication.transformComponent(component);if (enableConstantEvaluation) {await _performConstantEvaluation(source, compilerOptions, component,coreTypes, environmentDefines, enableAsserts);if (errorDetector.hasCompilationErrors) return;}if (useGlobalTypeFlowAnalysis) {globalTypeFlow.transformComponent(compilerOptions.target, coreTypes, component);} else {devirtualization.transformComponent(coreTypes, component);no_dynamic_invocations_annotator.transformComponent(component);}if (useProtobufTreeShaker) {if (!useGlobalTypeFlowAnalysis) {throw 'Protobuf tree shaker requires type flow analysis (--tfa)';}protobuf_tree_shaker.removeUnusedProtoReferences(component, coreTypes, null);globalTypeFlow.transformComponent(compilerOptions.target, coreTypes, component);}// 避免通过从平台文件读取重新计算CSAvoid ignoreAmbiguousSupertypes(cls, a, b) {}final hierarchy = new ClassHierarchy(component,onAmbiguousSupertypes: ignoreAmbiguousSupertypes);call_site_annotator.transformLibraries(component, component.libraries, coreTypes, hierarchy);// 不确定gen_snapshot是否要进行混淆处理,但是如果这样做,则需要混淆处理禁止。obfuscationProhibitions.transformComponent(component, coreTypes);
}

执行混淆等转换工作

2.8 runWithFrontEndCompilerContext

[-> third_party/dart/pkg/vm/lib/kernel_front_end.dart]

Future<T> runWithFrontEndCompilerContext<T>(Uri source,CompilerOptions compilerOptions, Component component, T action()) async {final processedOptions =new ProcessedOptions(options: compilerOptions, inputs: [source]);//在上下文中运行,则可以获取uri源的tokensreturn await CompilerContext.runWithOptions(processedOptions,(CompilerContext context) async {// 为了使fileUri / fileOffset->行/列映射,则需要预填充映射。context.uriToSource.addAll(component.uriToSource);//此处action对应的是generateBytecode()方法 [见小节2.8.1]return action();});
}
generateBytecodeBytecodeGenerator.visitLibrary(Library node)visitList(node.procedures, BytecodeGenerator);Procedure.accept(BytecodeGenerator);BytecodeGenerator.visitProcedure(Procedure);BytecodeGenerator.defaultMember(Procedure)_genxxxasm.emitPush

third_party/dart/pkg/vm/lib/bytecode/dbc.dart 中定义很多指令

2.8.1 generateBytecode

[-> third_party/dart/pkg/vm/lib/bytecode/gen_bytecode.dart]


void generateBytecode(ast.Component component, {bool emitSourcePositions: false,bool emitAnnotations: false,bool omitAssertSourcePositions: false,bool useFutureBytecodeFormat: false,Map<String, String> environmentDefines: const <String, String>{},ErrorReporter errorReporter,List<Library> libraries,
}) {final coreTypes = new CoreTypes(component);void ignoreAmbiguousSupertypes(Class cls, Supertype a, Supertype b) {}final hierarchy = new ClassHierarchy(component,onAmbiguousSupertypes: ignoreAmbiguousSupertypes);final typeEnvironment = new TypeEnvironment(coreTypes, hierarchy);final constantsBackend = new VmConstantsBackend(coreTypes);final errorReporter = new ForwardConstantEvaluationErrors();//从component获取librarieslibraries ??= component.libraries;//创建字节码生成器对象final bytecodeGenerator = new BytecodeGenerator(component,coreTypes,hierarchy,typeEnvironment,constantsBackend,environmentDefines,emitSourcePositions,emitAnnotations,omitAssertSourcePositions,useFutureBytecodeFormat,errorReporter);for (var library in libraries) {//[见小节2.8.2]bytecodeGenerator.visitLibrary(library);}
}

遍历component中的所有libraries。

2.8.2 visitLibrary

[-> third_party/dart/pkg/vm/lib/bytecode/gen_bytecode.dart]

class BytecodeGenerator extends RecursiveVisitor<Null> {visitLibrary(Library node) {if (node.isExternal) {return;}//对于class的visit会调用到下方的visitClassvisitList(node.classes, this);//初始化fieldDeclarations和functionDeclarations来记录类的字段和方法startMembers();// [见小节2.8.3]visitList(node.procedures, this);visitList(node.fields, this);endMembers(node);}visitClass(Class node) {startMembers();visitList(node.constructors, this);visitList(node.procedures, this);visitList(node.fields, this);endMembers(node);}
}

该方法主要功能:

  • 通过visitList来访问库中的classes,procedures,fields。

    • 先访问类中的构造函数constructors、方法procedures以及字段fields;
    • 再访问库中不属于任何类的一些方法和字段;
  • fieldDeclarations和functionDeclarations来记录类的字段和方法,最终保存在bytecodeComponent的成员变量members;

2.8.3 visitList

[-> third_party/dart/pkg/kernel/lib/ast.dart]

void visitList(List<Node> nodes, Visitor visitor) {for (int i = 0; i < nodes.length; ++i) {// [见小节2.8.4]nodes[i].accept(visitor);}
}

该方法说明:

  • 此处的nodes,可以是classes,constructors,procedures或者fields
  • 此处的visitor,便是BytecodeGenerator

2.8.4 accept

[-> third_party/dart/pkg/kernel/lib/ast.dart]

class Procedure extends Member {accept(MemberVisitor v) => v.visitProcedure(this);
}class Field extends Member {R accept<R>(MemberVisitor<R> v) => v.visitField(this);
}class Constructor extends Member {R accept<R>(MemberVisitor<R> v) => v.visitConstructor(this);
}

此处的v是BytecodeGenerator,而BytecodeGenerator间接继承于TreeVisitor,在TreeVisitor由大量的visitXXX()方法,最终都是调用到defaultMember(),如下所示。

class TreeVisitor<R> {// [见小节2.8.5]R visitConstructor(Constructor node) => defaultMember(node);R visitProcedure(Procedure node) => defaultMember(node);R visitField(Field node) => defaultMember(node);
}

2.8.5 defaultMember

[-> third_party/dart/pkg/vm/lib/bytecode/gen_bytecode.dart]

defaultMember(Member node) {// 当该方法表示重定向工厂构造函数,并且没有可运行的主体,则直接返回if (node is Procedure && node.isRedirectingFactoryConstructor) {return;}try {bool hasCode = false;start(node);//字段类型if (node is Field) {  if (hasInitializerCode(node)) {hasCode = true;if (node.isConst) {_genPushConstExpr(node.initializer);} else {_generateNode(node.initializer);}_genReturnTOS();}//方法类型} else if ((node is Procedure && !node.isRedirectingFactoryConstructor) ||(node is Constructor)) {if (!node.isAbstract) {hasCode = true;if (node is Constructor) {_genConstructorInitializers(node);}if (node.isExternal) {final String nativeName = getExternalName(node);if (nativeName != null) {_genNativeCall(nativeName);} else {asm.emitPushNull();}} else {_generateNode(node.function?.body);// 如果无法访问此字节码,则BytecodeAssembler会将其消除。asm.emitPushNull();}_genReturnTOS();}} else {throw 'Unexpected member ${node.runtimeType} $node';}end(node, hasCode);} on BytecodeLimitExceededException {// 不生成字节码,回滚到内核语法树ASThasErrors = true;end(node, false);}
}

该方法主要功能是 根据node类型:字段、方法或者构造方法,则生成相应的汇编指令。 这里会有很多_genXXX()方法,最终是调用asm.emitXXX()方法, 此处的asm的数据类型为BytecodeAssembler。 接下来以emitPushNull为例子,继续往下说。

2.8.6 emitPushNull

[-> third_party/dart/pkg/vm/lib/bytecode/assembler.dart]

class BytecodeAssembler {final List<int> bytecode = new List<int>();final Uint32List _encodeBufferIn;final Uint8List _encodeBufferOut;void emitPushNull() {emitWord(_encode0(Opcode.kPushNull));}void emitWord(int word) {if (isUnreachable) {return;}_encodeBufferIn[0] = word;  //opcode写入_encodeBufferInbytecode.addAll(_encodeBufferOut);}//将操作码转换整型int _encode0(Opcode opcode) => _uint8(opcode.index);...
}

可见,所有的字节码信息最终都写入到BytecodeAssembler的bytecode列表。另外,Opcode操作码位于dbc.dart,里面定义了各种操作码。

2.9 writeDillFile

[-> third_party/dart/pkg/vm/lib/frontend_server.dart]

writeDillFile(Component component, String filename,{bool filterExternal: false}) async {final IOSink sink = new File(filename).openWrite();final BinaryPrinter printer = filterExternal? new LimitedBinaryPrinter(sink, (lib) => !lib.isExternal, true /* excludeUriToSource */): printerFactory.newBinaryPrinter(sink);component.libraries.sort((Library l1, Library l2) {return "${l1.fileUri}".compareTo("${l2.fileUri}");});component.computeCanonicalNames();for (Library library in component.libraries) {library.additionalExports.sort((Reference r1, Reference r2) {return "${r1.canonicalName}".compareTo("${r2.canonicalName}");});}if (unsafePackageSerialization == true) {writePackagesToSinkAndTrimComponent(component, sink);}//[见小节2.9.1]printer.writeComponentFile(component);await sink.close();
}

再回到[小节2.4],执行完compileToKernel()后开始执行writeDillFile,该方法主要功能便是将component内容写入app.dill文件。

  • component:是指compileToKernel()方法执行后得到的,记录dart代码中类、方法、字段等所有相关信息
  • filename:是指前面传递–output-dill参数值,也就是app.dill

2.9.1 writeComponentFile

[-> third_party/dart/pkg/kernel/lib/binary/ast_to_binary.dart]

void writeComponentFile(Component component) {computeCanonicalNames(component);final componentOffset = getBufferOffset();writeUInt32(Tag.ComponentFile);writeUInt32(Tag.BinaryFormatVersion);writeListOfStrings(component.problemsAsJson);indexLinkTable(component);_collectMetadata(component);if (_metadataSubsections != null) {// 将asm.bytecode写入文件_writeNodeMetadataImpl(component, componentOffset);}libraryOffsets = <int>[];CanonicalName main = getCanonicalNameOfMember(component.mainMethod);if (main != null) {checkCanonicalName(main);}writeLibraries(component);writeUriToSource(component.uriToSource);writeLinkTable(component);_writeMetadataSection(component);writeStringTable(stringIndexer);writeConstantTable(_constantIndexer);writeComponentIndex(component, component.libraries);_flush();
}

这便完成的kernel编译以及文件生成过程。

附录

本文相关源码flutter engine

flutter/frontend_server/- bin/starter.dart- lib/server.dartthird_party/dart/pkg/- vm/lib/- frontend_server.dart- kernel_front_end.dart- bytecode/gen_bytecode.dart- bytecode/assembler.dart- front_end/lib/- src/api_prototype/kernel_generator.dart- src/kernel_generator_impl.dart- src/fasta/kernel/kernel_target.dart- src/fasta/loader.dart- src/fasta/source/source_loader.dart- kernel/lib/- ast.dart- binary/ast_to_binary.dart

链接:http://gityuan.com/2019/09/14/flutter_frontend_server/

大家在正式学习了flutter之后就能够深入体会,flutter学习并不算难,难得是需要具有一个清晰、系统的思维,为了帮助大家更好的理解flutter,我给大家准备了一份《Flutter进阶学习笔记》,相信大家能在它的帮助下快速掌握flutter的知识,有需要的朋友可以点击下方卡片自取

《Flutter进阶学习笔记》

目录

第一章 为什么 Flutter 是跨平台开发的终极之选

第二章 在Windows上搭建Flutter开发环境

第三章 编写您的第一个 Flutter App

第四章 Flutter开发环境搭建和调试

第五章 Dart语法篇之基础语法(一)

第六章 Dart语法篇之集合的使用与源码解析(二)

第七章 Dart语法篇之集合操作符函数与源码分析(三)

第八章 Dart语法篇之函数的使用(四)

第九章 Dart语法篇之面向对象基础(五)

第十章 Dart语法篇之面向对象继承和Mixins(六)

第十一章 Dart语法篇之类型系统与泛型(七)

第十二章 Flutter中的widget

后话:

现在工具的更新迭代速度之快,尤其是Android开发工程师,必须不断学习最新的工具和方法,才能够适应Android项目实战的变化,所以赶紧把flutter学习起来吧,加油!

各位小伙伴们如果有需要这份《Flutter进阶学习笔记》资料,点击下方卡片即可【免费领取】!!

Flutter前端编译frontend_server相关推荐

  1. LLVM Clang前端编译与调试

    LLVM Clang前端编译与调试 iOS 关于编译 o 一.Objective-C 编译过程 o 为什么需要重新编译? o 编译步骤 o 二.编译步骤的详细说明 o 1.预处理 o 2.编译 o 词 ...

  2. Java编译分类:前端编译和后端编译

    ava程序代码需要编译后才能在虚拟机中运行,编译涉及到非常多的知识层面:编译原理.语言规范.虚拟机规范.本地机器码优化等:了解编译过程有利于了解整个Java运行机制,不仅可以使得我们编写出更优秀的代码 ...

  3. 深入理解 Flutter 的编译原理与优化

    阿里妹导读:对于开发者而言,Flutter工程和我们的Android/iOS工程有何差别?Flutter的渲染和事件传递机制如何工作?构建缓慢或出错又如何去定位,修改和生效呢?凡此种种,都需要对Flu ...

  4. 深入理解flutter的编译原理与优化

    问题背景 对于开发者而言,什么是Flutter?它是用什么语言编写的,包含哪几部分,是如何被编译,运行到设备上的呢?Flutter如何做到Debug模式Hot Reload快速生效变更,Release ...

  5. java aot,Java三种编译方式: 前端编译 JIT编译 AOT编译

    java程序代码需要编译后才能在虚拟机中运行,编译涉及到非常多的知识层面:编译原理.语言规范.虚拟机规范.本地机器码优化等:了解编译过程有利于了解整个Java运行机制,不仅可以使得我们编写出更优秀的代 ...

  6. 前端编译、JIT编译、AOT编译

    一.前端编译: java设计之初就是强调跨平台,通过javac将源文件编译成于平台无关的class文件, 它定义了执行 Java 程序所需的所有信息(许多Java"语法糖",是在这 ...

  7. 由 Babel 理解前端编译原理

    大厂技术  坚持周更  精选好文 背景 我们知道编程语言主要分为「编译型语言」和「解释型语言」,编译型语言是在代码运行前编译器将编程语言转换成机器语言,运行时不需要重新翻译,直接使用编译的结果就行了. ...

  8. 由Babel理解前端编译原理

    背景 我们知道编程语言主要分为「编译型语言」和「解释型语言」,编译型语言是在代码运行前编译器将编程语言转换成机器语言,运行时不需要重新翻译,直接使用编译的结果就行了.而解释型语言也是需要将编程语言转换 ...

  9. 轻松 Flutter 入门,秒变大前端

    本文作者:dickma,腾讯 IEG 前端开发工程师 本文不是Flutter的教程,只是对 Flutter 的技术特性,做了一些略全面的入门级的介绍,如果你听说过Flutter,想去了解他,但是又不想 ...

最新文章

  1. 11月29日云栖精选夜读:阿里传奇工程师多隆的程序世界
  2. angular(3)服务 --注入---自定义模块--单页面应用
  3. 1.3 List集合:ArrayList和LinkedList类的用法及区别
  4. 深入解析 Dubbo 3.0 服务端暴露全流程
  5. c++: internal compiler error: Killed
  6. python echo命令_如何用Python调用外部命令
  7. 求职和跳槽最好的月份要来了吗
  8. 感恩节(美食火鸡大餐)PNG免扣素材 总有一款你用得上
  9. 谷歌大脑小姐姐亲授:如何应聘成功羡煞旁人的AI工程师岗位
  10. LED显示驱动(六):LED显示设备显示单层图片调试(DE驱动测试)
  11. js中的empty()和remove()的区别
  12. allwinner 全志uboot git网址 及其他相关链接
  13. 财险产保险公司应用系统各子系统简介
  14. 实验一计算机基础和网络知识竞赛,第十三届计算机基础知识竞赛题库.doc
  15. Enterprise Architect(EA)画UML之用例图,敲详细讲解+实战举例
  16. 用CST进行多物理仿真,热仿真结果有误
  17. 浏览器缓存知识+JS实现缓存
  18. python绘制动漫人物图片女生可爱_绘画动漫人物图片女生唯美
  19. debug - UITextField 输入完跳入下一field,按钮变化
  20. 泛微OA自开发初始应做哪些

热门文章

  1. 初始 D2 Admin
  2. d2admin 登陆 笔记
  3. 1256:献给阿尔吉侬的花束(BFS)
  4. 28.EXTI外部中断原理与配置
  5. 数据库水平扩展和垂直扩展
  6. (权限维持)端口复用原理
  7. CMD命令跳转指定目录
  8. v-if与v-for
  9. 数据结构经典算法学习之八枚银币(简单决策树)
  10. c语言打印图形B,C语言图形编程(三、绘图函数-02) B