1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! Symbol definitions those missing from building tensorflow without a C++
//! (or C) standard library
pub(crate) mod strlen {
cpp! {{
#include <string.h>
#include <stdint.h>
#include <limits.h>
#define ALIGN (sizeof(size_t))
#define ONES ((size_t)-1/UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX/2+1))
#define HASZERO(x) (((x)-ONES) & ~(x) & HIGHS)
}}
// A strlen implementation
pub unsafe fn strlen(string: *const cty::c_char) -> usize {
cpp! ([string as "char *"] -> usize as "size_t" {
const char *s = string;
const char *a = s;
const size_t *w;
for (; (uintptr_t)s % ALIGN; s++) if (!*s) return s-a;
for (w = (const size_t *)s; !HASZERO(*w); w++);
for (s = (const char *)w; *s; s++);
return s-a;
})
}
}
// private module
mod tensorflow {
use core::slice;
use core::str;
#[allow(clippy::empty_loop)]
#[no_mangle]
// __cxa_pure_virtual is a function, address of which compiler writes
// in the virtual table when the function is pure virtual. It may be
// called due to some unnatural pointer abuse or when trying to invoke
// pure virtual function in the destructor of the abstract base
// class. The call to this function should never happen in the normal
// application run. If it happens it means there is a bug.
pub extern "C" fn __cxa_pure_virtual() {
loop {}
}
#[allow(clippy::empty_loop)]
#[no_mangle]
// A cleanup must return control to the unwinding code by tail calling
// __cxa_end_cleanup. The routine performs whatever housekeeping is
// required and resumes the exception propagation by calling
// _Unwind_Resume. This routine does not return.
pub extern "C" fn __cxa_end_cleanup() {
loop {}
}
#[no_mangle]
pub extern "C" fn __gxx_personality_v0() {}
// Simple implementation of errno
static ERRNO: cty::c_int = 0;
#[no_mangle]
pub extern "C" fn __errno() -> *const cty::c_int {
&ERRNO
}
// Despite -fno-rtti, these symbols are still generated. Define them
// here, in a way that would likely have horrific consequences at
// runtime
cpp! {{
namespace __cxxabiv1 {
class __class_type_info {
virtual void dummy();
};
void __class_type_info::dummy() { }
};
namespace __cxxabiv1 {
class __si_class_type_info {
virtual void dummy();
};
void __si_class_type_info::dummy() { }
};
}}
// A strcmp implementation, for flatbuffers to use
cpp! {{
#include <string.h>
int strcmp(const char *l, const char *r)
{
for (; *l==*r && *l; l++, r++);
return *(unsigned char *)l - *(unsigned char *)r;
}
}}
cpp! {{
#include <string.h>
int strncmp(const char *l, const char *r, size_t n)
{
if (!n--) return 0;
for (; *l && *r && n && *l == *r ; l++, r++, n--);
return *l - *r;
}
}}
#[no_mangle]
// Repalcement for implementation in debug_log.cc
pub extern "C" fn DebugLog(s: *const cty::c_char) {
let slice = unsafe {
let len = super::strlen::strlen(s);
let ptr = s as *const u8;
slice::from_raw_parts(ptr, len as usize + 1)
};
info!("{}", str::from_utf8(slice).unwrap().trim());
}
// Underlying assert function for tensorflow to use
#[no_mangle]
pub extern "C" fn __assert_func(
_expr: *const cty::c_char,
_line: cty::c_int,
_file: *const cty::c_char,
_function: *const cty::c_char,
) {
panic!("__assert_func ASSERTED"); // __noreturn__
}
// Don't deallocate memory - tensorflow micro should be stack-based
cpp! {{
void operator delete(void * p) {}
}}
}