出于兴趣,我最近尝试查看 dart 编程语言中一些基本数学函数的源代码(更具体地说,在
dart:math
包中)。
以余弦函数。很容易找到它的文档
然后单击右上角的“查看源代码”按钮。然而,问题就从这里开始了。在相应的文件中,唯一相关的代码行是
/// Converts [radians] to a [double] and returns the cosine of the value.
///
/// If [radians] is not a finite number, the result is NaN.
external double cos(num radians);
没有任何提示在哪里可以找到实际的实现。事实上,它似乎根本没有像人们想象的那样包含在
sdk/lib/math
目录中。
有人知道在哪里可以找到它吗?预先感谢您!
我不是 Dart 项目的开发人员,所以我可能会弄错所有这些。因此,请将此我的答案视为我对正在发生的事情的最佳猜测。 :)
原生运行时,Dart 使用
cos
的 libc 版本。实现有点难找到,但让我们尝试一下。您找到的定义被定义为 external
,这意味着实际的实现正在根据运行平台进行修补。
所以对于本地人来说,我们需要看:
@pragma("vm:exact-result-type", "dart:core#_Double")
@pragma("vm:prefer-inline")
double cos(num radians) => _cos(radians.toDouble());
...
@pragma("vm:recognized", "other")
@pragma("vm:prefer-inline")
external double _cos(double x);
这里的提示是
vm:recognized
,它告诉 Dart 编译器应该特殊处理这个方法调用。我们可以在 SDK 中找到它应该识别以进行特殊处理的方法列表。在这里我们发现:
// (class-name, function-name, recognized enum, fingerprint).
// When adding a new function, add a 0 as the fingerprint and run the build in
// debug mode to get the correct fingerprint from the mismatch error.
...
V(::, _sin, MathSin, 0x17cc3e23) \
V(::, _cos, MathCos, 0xf485f165) \
V(::, _tan, MathTan, 0xeb0bc957) \
V(::, _asin, MathAsin, 0x29d649be) \
V(::, _acos, MathAcos, 0x1ffc14fb) \
V(::, _atan, MathAtan, 0x10ebd512) \
V(::, _atan2, MathAtan2, 0x58c66573) \
V(::, _sqrt, MathSqrt, 0x0309a7b0) \
V(::, _exp, MathExp, 0x00e673f0) \
V(::, _log, MathLog, 0x099ff882) \
...
我们稍后可以在
MathCos
中找到 il.cc
的踪迹:
const RuntimeEntry& InvokeMathCFunctionInstr::TargetFunction() const {
switch (recognized_kind_) {
case MethodRecognizer::kDoubleTruncateToDouble:
return kLibcTruncRuntimeEntry;
case MethodRecognizer::kDoubleRoundToDouble:
return kLibcRoundRuntimeEntry;
case MethodRecognizer::kDoubleFloorToDouble:
return kLibcFloorRuntimeEntry;
case MethodRecognizer::kDoubleCeilToDouble:
return kLibcCeilRuntimeEntry;
case MethodRecognizer::kMathDoublePow:
return kLibcPowRuntimeEntry;
case MethodRecognizer::kDoubleMod:
return kDartModuloRuntimeEntry;
case MethodRecognizer::kMathTan:
return kLibcTanRuntimeEntry;
case MethodRecognizer::kMathAsin:
return kLibcAsinRuntimeEntry;
case MethodRecognizer::kMathSin:
return kLibcSinRuntimeEntry;
case MethodRecognizer::kMathCos:
return kLibcCosRuntimeEntry;
case MethodRecognizer::kMathAcos:
return kLibcAcosRuntimeEntry;
case MethodRecognizer::kMathAtan:
return kLibcAtanRuntimeEntry;
case MethodRecognizer::kMathAtan2:
return kLibcAtan2RuntimeEntry;
case MethodRecognizer::kMathExp:
return kLibcExpRuntimeEntry;
case MethodRecognizer::kMathLog:
return kLibcLogRuntimeEntry;
default:
UNREACHABLE();
}
return kLibcPowRuntimeEntry;
}
这个常量的名称有点泄露了我们正在使用 libc。但是找到
kLibcCosRuntimeEntry
的定义并不明显,因为这个常量是使用以下宏生成的:
#define DEFINE_RAW_LEAF_RUNTIME_ENTRY(name, argument_count, is_float, func) \
extern const RuntimeEntry k##name##RuntimeEntry( \
"DFLRT_" #name, func, argument_count, true, is_float, \
/*can_lazy_deopt=*/false)
然后在这里使用:
DEFINE_RAW_LEAF_RUNTIME_ENTRY(
LibcCos,
1,
true /* is_float */,
reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&cos)));
其中
&cos
指的是从cos
全局导入的math.h
方法:
#include <math.h>