包含了dart相关的基础command tools和dart相关的基础库
...
├── pkg //dart工具包
├── runtime //dart运行时相
├── sdk //dart sdk,基础工具包以及各平台的实现
├── tools
└── utils
├── _http ... //dart http请求库,基于dart其它基础库编写(io/isolate/match等)
├── _internal ... //不同平台(移动端和desktop中vm,浏览器的js)的对dart抽象接口的实现
│ ├── js_dev_runtime ...
│ ├── js_runtime ...
│ ├── vm .. //
├── async ... // 异步函数库,基于isolate
├── collection ... //
├── convert ... //
├── core ... //
├── dev_compiler ...//
├── ffi ... // 外部函接口,通过dart调用调用`C/C++`库,通过`external`关键字将dart的函数,类型定义和c/c++的实现关联起来,并通过函数指针查找和调用c库
├── internal ... // 对dart:core中基本类型封装和扩展
├── io ... // 定义了input/ios相关接口,对native网络访问,文件存储,stream操作语法糖
├── isolate ... // dart隔离的接口定义,由dartvm创建
├── math ... // 提供对系统c库的基础match函数的调用
Native: 对于针对移动和桌面设备的应用程序,Dart包括一个具有即时(JIT)编译的Dart VM和一个用于生成机器代码的提前(AOT)编译器.
Web: 对于面向web的应用程序,Dart包括开发时编译器(dartdevc)和生产时编译器(dart2js)。两个编译器都将Dart转换为JavaScript
analyze Analyze Dart code in a directory.
compile Compile Dart to various formats.
create Create a new Dart project.
fix Apply automated fixes to Dart source code.
format Idiomatically format Dart source code.
migrate Perform null safety migration on a project.
pub Work with packages.
run Run a Dart program.
test Run tests for a project.
dart analyze --fatal-infos .
分析当前文件下是否有致命的错误
dart analyze --fatal-warnings .
分析当前文件下是否有警告, 一般使用这个
aot-snapshot 编译成Aot快照,`ahead of time`,占用内存低,启动快,无需要rumtime运行
exe 编译成可执行文件
jit-snapshot 编译成`JIT(just in time)`,可以增量运行
js 编译成js代码
kernel 编译成易于携带的内核快照
下面是采用不同方式编译执行test.dart
├── out.js
├── out.js.deps
├── out.js.map
├── test.aot //dartaotruntime test.aot
├── test.dart //dart test.dart compile + execute
├── test.dill //dart run test.dill
├── test.exe //test.exe
└── test.jit //dart run test.jit
pub常用于运行远程库,该库必须有是可以执行的main
函数入口
executables:
devtools:
上面是devtools-2.5.0
中制定的入口,devtools
为main函数所在文件
dart pub global [activate|deactivate|list|run]
如dart pub global active devtools
将package编译成exe
可执行文件,并放在$HOME/.pub-cache/bin
目录下
如dart pub global run devtools
执行package的main函数
├── _temp
├── bin //编译后的可以执行文件
├──── dcdg
└──── devtools
├── git
├── global_packages //package快信息
└── hosted //package源代码
/Users/jiodg45/.pub-cache/hosted/pub.flutter-io.cn/devtools-2.5.0
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── bin
├──── devtools.dart //main函数入口
├── build
├── devtools.iml
├── ios
├── lib
├── linux
├── macos
└── pubspec.yaml //需要申明`executables`为main函数所在文件
在dart-sdk
中可以看到很多这样的注解和external
关键字
下面Object
在dart:core
中定义
@pragma("vm:entry-point")
class Object {
@pragma("vm:recognized", "other")
const Object();
external bool operator ==(Object other);
external int get hashCode;
external String toString();
@pragma("vm:entry-point")
external dynamic noSuchMethod(Invocation invocation);
external Type get runtimeType;
}
external
定义该方法需要在外实现,对应的external函数都会有一个@patch
的注解与之对应, 如下Object
在dart for web
以及vm for dart
完成了具体的实现
lib/_internal/js_runtime/lib/core_patch.dart:
52 @patch
53: class Object {
54 @patch
lib/_internal/vm/lib/object_patch.dart:
14 @pragma("vm:entry-point")
15: class Object {
16 // The VM has its own implementation of equals.
lib/core/object.dart:
17 @pragma("vm:entry-point")
18: class Object {
19 /// Creates a new [Object] instance.
以DynamicLibrary.open
, dart:ffi
为接口抽象层,_internal/vm/lib/ffi
则是对应平台的具体实现
lib/_internal/vm/lib/ffi_dynamic_library_patch.dart:
10
11: DynamicLibrary _open(String path) native "Ffi_dl_open";
12 DynamicLibrary _processLibrary() native "Ffi_dl_processLibrary";
lib/_internal/vm/lib/ffi_dynamic_library_patch.dart:
18 @patch
19: factory DynamicLibrary.open(String path) {
20 return _open(path);
lib/ffi/dynamic_library.dart:
32 /// which are equal (`==`), but not [identical].
33: external factory DynamicLibrary.open(String path);
34
在ffi_dynamic_library_patch
中使用了native关键字Ffi_dl_open
,该函数最终会和native的函数指针绑定. 在 https://github.com/dart-lang/sdk/blob/main/runtime/lib/ffi_dynamic_library.cc
实现Native定义的方法
DEFINE_NATIVE_ENTRY(Ffi_dl_open, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(String, lib_path, arguments->NativeArgAt(0));
void* handle = LoadDynamicLibrary(lib_path.ToCString());
return DynamicLibrary::New(handle);
}
DEFINE_NATIVE_ENTRY(Ffi_dl_processLibrary, 0, 0) {
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
return DynamicLibrary::New(RTLD_DEFAULT);
#else
const Array& args = Array::Handle(Array::New(1));
args.SetAt(0,
String::Handle(String::New(
"DynamicLibrary.process is not available on this platform.")));
Exceptions::ThrowByType(Exceptions::kUnsupported, args);
#endif
}
third_party/tonic/dart_library_natives.cc:
14
15: void DartLibraryNatives::Register(std::initializer_list<Entry> entries) {
16 for (const Entry& entry : entries)
third_party/tonic/dart_library_natives.h:
class DartLibraryNatives {
public:
DartLibraryNatives();
~DartLibraryNatives();
struct Entry {
const char* symbol;
Dart_NativeFunction native_function;
int argument_count;
bool auto_setup_scope;
};
//注册native函数
void Register(std::initializer_list<Entry> entries);
//Dart_NativeFunction--> exectue --> Dart_Handle --> dart
Dart_NativeFunction GetNativeFunction(Dart_Handle name,
int argument_count,
bool* auto_setup_scope);
const uint8_t* GetSymbol(Dart_NativeFunction native_function);
private:
std::unordered_map<std::string, Entry> entries_;
std::unordered_map<Dart_NativeFunction, const char*> symbols_;
TONIC_DISALLOW_COPY_AND_ASSIGN(DartLibraryNatives);
};
}
DEFINE_NATIVE_ENTRY(Ffi_dl_lookup, 1, 2) {
GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(DynamicLibrary, dlib, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(String, argSymbolName,
arguments->NativeArgAt(1));
void* handle = dlib.GetHandle();
const uword pointer =
reinterpret_cast<uword>(ResolveSymbol(handle, argSymbolName.ToCString()));
return Pointer::New(type_arg, pointer);
}
FFi其实主要是用了2个系统函数
dl_open
(dynamic library open),打开动态库并将其装入内存中
dlsym
根据动态链接库操作句柄与符号,返回符号对应的地址,不但可以获取函数地址,也可以获取变量地址,返回符号对应的地址。当调用dart断的lookup
函数最终会调用此方法,如下代码就是通过lookup函数去查找动态库的hello_world
方法, 具体示例见https://dart.dev/guides/libraries/c-interop
final HelloWorld hello = dylib
.lookup<ffi.NativeFunction<hello_world_func>>('hello_world')
.asFunction();
2.dart:ui中也定义了许多的native函数绑定义,它是flutter framework
和engine
的桥梁,在创建DartVM
的时候会完成绑定
lib/ui/dart_ui.cc
void DartUI::InitForGlobal() {
if (!g_natives) {
g_natives = new tonic::DartLibraryNatives();
Canvas::RegisterNatives(g_natives); //画布
CanvasGradient::RegisterNatives(g_natives);
CanvasImage::RegisterNatives(g_natives);
CanvasPath::RegisterNatives(g_natives);
CanvasPathMeasure::RegisterNatives(g_natives);
Codec::RegisterNatives(g_natives);
ColorFilter::RegisterNatives(g_natives); //颜色滤镜
DartRuntimeHooks::RegisterNatives(g_natives);
EngineLayer::RegisterNatives(g_natives); //具柄,用于保留引擎层的图层
FontCollection::RegisterNatives(g_natives);
FragmentShader::RegisterNatives(g_natives); //片段着色器
ImageDescriptor::RegisterNatives(g_natives);
ImageFilter::RegisterNatives(g_natives); //图片滤镜
ImageShader::RegisterNatives(g_natives); //图片色器
ImmutableBuffer::RegisterNatives(g_natives);
IsolateNameServerNatives::RegisterNatives(g_natives);
NativeStringAttribute::RegisterNatives(g_natives);
Paragraph::RegisterNatives(g_natives); //文本布局引擎接口
ParagraphBuilder::RegisterNatives(g_natives);
Picture::RegisterNatives(g_natives); //用于后续加入到senece中 或 绘制到canvase中
PictureRecorder::RegisterNatives(g_natives); //记录一些列图形操作指令,并保存到Picture对象中,通过engine记录绘制指令并返回到flutter端,
Scene::RegisterNatives(g_natives); //提供界面场景,表示合成场景的不透明对象,它是由sceneBuilder在engine中根据picture组合生成layers合成的,可以通过`FlutterView.render`显示出来
SceneBuilder::RegisterNatives(g_natives); //根据给定的可视化内容构建场景
SemanticsUpdate::RegisterNatives(g_natives);
SemanticsUpdateBuilder::RegisterNatives(g_natives);
Vertices::RegisterNatives(g_natives);
PlatformConfiguration::RegisterNatives(g_natives); //用户处理engine和flutter framework之间的通信,拥有主窗口,PlatformConfigurationClient接口运行时控制器定义。
}
}
void DartRuntimeHooks::Install(bool is_ui_isolate,
const std::string& script_uri) {
Dart_Handle builtin = Dart_LookupLibrary(ToDart("dart:ui"));
InitDartInternal(builtin, is_ui_isolate);
InitDartCore(builtin, script_uri);
InitDartAsync(builtin, is_ui_isolate);
InitDartIO(builtin, script_uri);
}
@pragma("vm:entry-point", ...)
用于标注对应的class或方法在AOT
模式下,是否可以被dart vm
或native
访问.其作用就是避免TFA(type flow analysis)
和tree shaking
,以及obfuscation
,TFA
为深度挖掘更多的类型信息,从而决定哪些无用的代码是可以优化的.obfuscation
会混淆代码,导致名称变化. 通过vm:entry-point
注解保留的class或方法名不变,从而能通过native或vm进行访问.应用在class上
@pragma("vm:entry-point")
@pragma("vm:entry-point", true/false)
@pragma("vm:entry-point", !const bool.formEnvironment("dart.vm.product"))
class C { ... }
在上面示例中vm:entry-point", true
或vm:entry-point"
会允许vm和native code分配内存
vm:entry-point", false
则会保留类不被混淆,没有alloc的存根,不允许vm和native code创建
应用在method上
@pragma("vm:entry-point")
@pragma("vm:entry-point", true/false)
@pragma("vm:entry-point", !const bool.formEnvironment("dart.vm.product"))
@pragma("vm:entry-point", "get")
@pragma("vm:entry-point", "call")
void foo() { ... }
同上面提到的一样,当第二个参数为null
或者false
不能被dart vm
和native
执行,可以不被混淆
实用get
和call
定义的注解可以被Dart_GetField
或Dart_Invoke
访问.
@pragma("vm:entry-point")
@pragma("vm:entry-point", null) //支持 get 和 set访问
@pragma("vm:entry-point", true/false) false不支持native/vm get 和 set访问
@pragma("vm:entry-point", !const bool.formEnvironment("dart.vm.product"))
@pragma("vm:entry-point", "get"/"set") //指定支持get或set,二选一
int foo;
用于追中vm调用信息,通过制定勾子函数,来追踪vm的调用
void hook(String functionName, int entryPointId) {
// ...
}
class C<T> {
@pragma('vm:testing.unsafe.trace-entrypoints-fn', hook)
void foo(T x) {
// ...
}
}
指定返回类型,多态的类型适配
class A {}
class B extends A {}
// Reference to type via type literal
@pragma("vm:exact-result-type", B)
A foo() native "foo_impl";
// Reference to type via path
@pragma("vm:exact-result-type", "dart:core#_Smi");
int foo() native "foo_impl";
// 类型的泛型适配
@pragma("vm:exact-result-type",
[D, "result-type-uses-passed-type-arguments"])
factory D(); // returns an instance of D<T>
}
详见https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/optimization_levels.md
优化等级,
–optimization_level=
0: unoptimized (O0)
1: size optimized (Os)
2: default optimized (O2)
3: speed optimized (O3)
好处
允许对不符合当前O2理念的尺寸或速度进行新的优化
能够从O2中移除现有优化,这些优化仅对尺寸产生了不成比例的负面影响
允许引入更昂贵的分析,可以(但不保证)找到更多优化机会
为与其他用户不同的用户提供更多的控制权,使他们更喜欢大小或速度
可能会提供更多关于优化的见解,这些优化最初被认为是有风险的,但“在现场”有所帮助;也许可以找到更好的启发式方法来将这些迁移到O2
坏处
通过编译器的另外两个代码路径,增加了所有测试矩阵的大小(Dart、颤振、性能、正确性)
错误使用标志以避免花费时间寻找更好的启发式方法的风险
设置代码的优化等级在一定程度上可以提高代码的执行效率,减少程序的体积,但过度的优化可能会导致代码的执的正确性,具体还需要结合项目实际情况