Just out of interest I recently tried to take a look at the source code of some basic mathematical functions in the dart programming language (more specifically, in the dart:math
package).
Take e.g. the cosine function. It was easy enough to find its documentation
and click on the 'View source code' button in the top right corner. However, here the problems begin. In the respective file, the only related line of code is
/// 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);
with no hint whatsoever where to find the actual implementation. In fact, it seems that it is not at all contained in the sdk/lib/math
directory as one might expect.
Has anyone an idea where to find it? Thank you in advance!
I am not a developer on the Dart project so I might get all of this wrong. So see my answer here as my best guess into what is going on. :)
When running native, Dart uses the libc version of cos
. The implementation are a bit tricky to find but let's try do an attempt. The definition you have found are defined as external
which means the actual implementation are getting patched in depending on the running platform.
So for native, we need to look at:
@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);
The hint here is vm:recognized
which tells the Dart compiler that it should handle this method call special. We can in the SDK find a list of methods it should recognize for special handling. And here we find:
// (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) \
...
We can then later find trace of MathCos
in 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;
}
The name of this constant kinda gives away that we are using libc. But finding the definition of kLibcCosRuntimeEntry
is not obvious since this constant are getting generated using the following macro:
#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)
And is then used here:
DEFINE_RAW_LEAF_RUNTIME_ENTRY(
LibcCos,
1,
true /* is_float */,
reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&cos)));
Where &cos
refer to the cos
method that have been globally imported from math.h
here:
#include <math.h>