Flutter前端编译frontend_server
一、概述
书接上文源码解读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语法篇之集合的使用与源码解析(二)
- List
- Set
- Map
- Queue
- LinkedList
- HashMap
- Map、HashMap、LinkedHashMap、SplayTreeMap区别
- 命名构造函数from和of的区别以及使用建议
第七章 Dart语法篇之集合操作符函数与源码分析(三)
- 简述
- Iterable
- forEach
- map
- any
- every
- where
- firstWhere和singleWhere和lastWhere
- join
- take
- takeWhile
- skip
- skipWhile
- follwedBy
- expand
- reduce
- elementAt
第八章 Dart语法篇之函数的使用(四)
第九章 Dart语法篇之面向对象基础(五)
第十章 Dart语法篇之面向对象继承和Mixins(六)
第十一章 Dart语法篇之类型系统与泛型(七)
第十二章 Flutter中的widget
- Flutter页面-基础Widget
- Widget
- StatelessWidget
- State生命周期
- 基础widget
- DefaultTextStyle
- FlutterLogo
- Icon
- Iamge.asset
- CircleAvatar
- FadeInImage
- 按钮
- FlatButton
- OutlineButton
- TextFormField
后话:
现在工具的更新迭代速度之快,尤其是Android开发工程师,必须不断学习最新的工具和方法,才能够适应Android项目实战的变化,所以赶紧把flutter学习起来吧,加油!
各位小伙伴们如果有需要这份《Flutter进阶学习笔记》资料,点击下方卡片即可【免费领取】!!
Flutter前端编译frontend_server相关推荐
- LLVM Clang前端编译与调试
LLVM Clang前端编译与调试 iOS 关于编译 o 一.Objective-C 编译过程 o 为什么需要重新编译? o 编译步骤 o 二.编译步骤的详细说明 o 1.预处理 o 2.编译 o 词 ...
- Java编译分类:前端编译和后端编译
ava程序代码需要编译后才能在虚拟机中运行,编译涉及到非常多的知识层面:编译原理.语言规范.虚拟机规范.本地机器码优化等:了解编译过程有利于了解整个Java运行机制,不仅可以使得我们编写出更优秀的代码 ...
- 深入理解 Flutter 的编译原理与优化
阿里妹导读:对于开发者而言,Flutter工程和我们的Android/iOS工程有何差别?Flutter的渲染和事件传递机制如何工作?构建缓慢或出错又如何去定位,修改和生效呢?凡此种种,都需要对Flu ...
- 深入理解flutter的编译原理与优化
问题背景 对于开发者而言,什么是Flutter?它是用什么语言编写的,包含哪几部分,是如何被编译,运行到设备上的呢?Flutter如何做到Debug模式Hot Reload快速生效变更,Release ...
- java aot,Java三种编译方式: 前端编译 JIT编译 AOT编译
java程序代码需要编译后才能在虚拟机中运行,编译涉及到非常多的知识层面:编译原理.语言规范.虚拟机规范.本地机器码优化等:了解编译过程有利于了解整个Java运行机制,不仅可以使得我们编写出更优秀的代 ...
- 前端编译、JIT编译、AOT编译
一.前端编译: java设计之初就是强调跨平台,通过javac将源文件编译成于平台无关的class文件, 它定义了执行 Java 程序所需的所有信息(许多Java"语法糖",是在这 ...
- 由 Babel 理解前端编译原理
大厂技术 坚持周更 精选好文 背景 我们知道编程语言主要分为「编译型语言」和「解释型语言」,编译型语言是在代码运行前编译器将编程语言转换成机器语言,运行时不需要重新翻译,直接使用编译的结果就行了. ...
- 由Babel理解前端编译原理
背景 我们知道编程语言主要分为「编译型语言」和「解释型语言」,编译型语言是在代码运行前编译器将编程语言转换成机器语言,运行时不需要重新翻译,直接使用编译的结果就行了.而解释型语言也是需要将编程语言转换 ...
- 轻松 Flutter 入门,秒变大前端
本文作者:dickma,腾讯 IEG 前端开发工程师 本文不是Flutter的教程,只是对 Flutter 的技术特性,做了一些略全面的入门级的介绍,如果你听说过Flutter,想去了解他,但是又不想 ...
最新文章
- 11月29日云栖精选夜读:阿里传奇工程师多隆的程序世界
- angular(3)服务 --注入---自定义模块--单页面应用
- 1.3 List集合:ArrayList和LinkedList类的用法及区别
- 深入解析 Dubbo 3.0 服务端暴露全流程
- c++: internal compiler error: Killed
- python echo命令_如何用Python调用外部命令
- 求职和跳槽最好的月份要来了吗
- 感恩节(美食火鸡大餐)PNG免扣素材 总有一款你用得上
- 谷歌大脑小姐姐亲授:如何应聘成功羡煞旁人的AI工程师岗位
- LED显示驱动(六):LED显示设备显示单层图片调试(DE驱动测试)
- js中的empty()和remove()的区别
- allwinner 全志uboot git网址 及其他相关链接
- 财险产保险公司应用系统各子系统简介
- 实验一计算机基础和网络知识竞赛,第十三届计算机基础知识竞赛题库.doc
- Enterprise Architect(EA)画UML之用例图,敲详细讲解+实战举例
- 用CST进行多物理仿真,热仿真结果有误
- 浏览器缓存知识+JS实现缓存
- python绘制动漫人物图片女生可爱_绘画动漫人物图片女生唯美
- debug - UITextField 输入完跳入下一field,按钮变化
- 泛微OA自开发初始应做哪些