mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-14 06:35:40 +00:00
Merge pull request #42 from wasmerio/fix/localtime
Fix localtime implementation
This commit is contained in:
commit
83e1a0e75c
@ -97,11 +97,6 @@ pub extern "C" fn _getgrnam(name_ptr: c_int, instance: &mut Instance) -> c_int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "C" fn _localtime_r() -> u32 {
|
|
||||||
debug!("emscripten::_localtime_r");
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub extern "C" fn _getpagesize() -> u32 {
|
pub extern "C" fn _getpagesize() -> u32 {
|
||||||
debug!("emscripten::_getpagesize");
|
debug!("emscripten::_getpagesize");
|
||||||
16384
|
16384
|
||||||
|
@ -18,7 +18,7 @@ mod time;
|
|||||||
mod utils;
|
mod utils;
|
||||||
mod varargs;
|
mod varargs;
|
||||||
|
|
||||||
pub use self::storage::{align_memory, static_alloc};
|
pub use self::storage::{align_memory};
|
||||||
pub use self::utils::{is_emscripten_module, allocate_on_stack, allocate_cstr_on_stack};
|
pub use self::utils::{is_emscripten_module, allocate_on_stack, allocate_cstr_on_stack};
|
||||||
|
|
||||||
// TODO: Magic number - how is this calculated?
|
// TODO: Magic number - how is this calculated?
|
||||||
@ -44,12 +44,6 @@ fn dynamictop_ptr(static_bump: u32) -> u32 {
|
|||||||
static_bump + DYNAMICTOP_PTR_DIFF
|
static_bump + DYNAMICTOP_PTR_DIFF
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn static_alloc(size: usize, static_top: &mut size) -> usize {
|
|
||||||
// let ret = *static_top;
|
|
||||||
// *static_top = (*static_top + size + 15) & (-16 as usize);
|
|
||||||
// ret
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn emscripten_set_up_memory(memory: &mut LinearMemory) {
|
pub fn emscripten_set_up_memory(memory: &mut LinearMemory) {
|
||||||
let dynamictop_ptr = dynamictop_ptr(STATIC_BUMP) as usize;
|
let dynamictop_ptr = dynamictop_ptr(STATIC_BUMP) as usize;
|
||||||
let dynamictop_ptr_offset = dynamictop_ptr + mem::size_of::<u32>();
|
let dynamictop_ptr_offset = dynamictop_ptr + mem::size_of::<u32>();
|
||||||
@ -383,6 +377,16 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
|
|||||||
"_clock_gettime",
|
"_clock_gettime",
|
||||||
ImportValue::Func(time::_clock_gettime as _),
|
ImportValue::Func(time::_clock_gettime as _),
|
||||||
);
|
);
|
||||||
|
import_object.set(
|
||||||
|
"env",
|
||||||
|
"_asctime",
|
||||||
|
ImportValue::Func(time::_asctime as _),
|
||||||
|
);
|
||||||
|
import_object.set(
|
||||||
|
"env",
|
||||||
|
"_asctime_r",
|
||||||
|
ImportValue::Func(time::_asctime_r as _),
|
||||||
|
);
|
||||||
import_object.set(
|
import_object.set(
|
||||||
"env",
|
"env",
|
||||||
"_localtime",
|
"_localtime",
|
||||||
@ -393,7 +397,7 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
|
|||||||
import_object.set(
|
import_object.set(
|
||||||
"env",
|
"env",
|
||||||
"_localtime_r",
|
"_localtime_r",
|
||||||
ImportValue::Func(env::_localtime_r as _),
|
ImportValue::Func(time::_localtime_r as _),
|
||||||
);
|
);
|
||||||
import_object.set(
|
import_object.set(
|
||||||
"env",
|
"env",
|
||||||
|
@ -4,22 +4,15 @@ pub fn align_memory(ptr: u32) -> u32 {
|
|||||||
(ptr + 15) & !15
|
(ptr + 15) & !15
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn static_alloc(size: u32, instance: &mut Instance) -> u32 {
|
|
||||||
// let static_top = instance.emscripten_data.static_top;
|
|
||||||
// let total_memory = instance.memories[0].maximum.unwrap_or(LinearMemory::DEFAULT_HEAP_SIZE as u32);
|
|
||||||
// instance.emscripten_data.static_top = (static_top + size + 15) & 4294967280;
|
|
||||||
// assert!(static_top < total_memory, "not enough memory for static allocation - increase total_memory!");
|
|
||||||
// static_top
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn static_alloc(size: u32, static_top: &mut u32, memory: &LinearMemory) -> u32 {
|
// pub fn static_alloc(size: u32, static_top: &mut u32, memory: &LinearMemory) -> u32 {
|
||||||
let old_static_top = *static_top;
|
// let old_static_top = *static_top;
|
||||||
let total_memory = memory.maximum_size() * LinearMemory::PAGE_SIZE;
|
// let total_memory = memory.maximum_size() * LinearMemory::PAGE_SIZE;
|
||||||
// NOTE: The `4294967280` is a u32 conversion of -16 as gotten from emscripten.
|
// // NOTE: The `4294967280` is a u32 conversion of -16 as gotten from emscripten.
|
||||||
*static_top = (*static_top + size + 15) & 4_294_967_280;
|
// *static_top = (*static_top + size + 15) & 4294967280;
|
||||||
assert!(
|
// assert!(
|
||||||
*static_top < total_memory,
|
// *static_top < total_memory,
|
||||||
"not enough memory for static allocation - increase total_memory!"
|
// "not enough memory for static allocation - increase total_memory!"
|
||||||
);
|
// );
|
||||||
old_static_top
|
// old_static_top
|
||||||
}
|
// }
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
use super::utils::copy_cstr_into_wasm;
|
use super::utils::{copy_cstr_into_wasm, write_to_buf};
|
||||||
use libc::{
|
use libc::{
|
||||||
c_int,
|
c_int,
|
||||||
c_long,
|
c_long,
|
||||||
clock_gettime as libc_clock_gettime,
|
clock_gettime as libc_clock_gettime,
|
||||||
// tm,
|
|
||||||
localtime,
|
localtime,
|
||||||
|
localtime_r,
|
||||||
|
tm,
|
||||||
time,
|
time,
|
||||||
time_t,
|
time_t,
|
||||||
timespec,
|
timespec,
|
||||||
|
c_char,
|
||||||
};
|
};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
@ -64,50 +66,163 @@ pub extern "C" fn _clock_gettime(clk_id: c_int, tp: c_int, instance: &mut Instan
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct guest_tm {
|
||||||
|
pub tm_sec: c_int, // 0
|
||||||
|
pub tm_min: c_int, // 4
|
||||||
|
pub tm_hour: c_int, // 8
|
||||||
|
pub tm_mday: c_int, // 12
|
||||||
|
pub tm_mon: c_int, // 16
|
||||||
|
pub tm_year: c_int, // 20
|
||||||
|
pub tm_wday: c_int, // 24
|
||||||
|
pub tm_yday: c_int, // 28
|
||||||
|
pub tm_isdst: c_int, // 32
|
||||||
|
pub tm_gmtoff: c_int, // 36
|
||||||
|
pub tm_zone: c_int, // 40
|
||||||
|
}
|
||||||
|
|
||||||
|
/// emscripten: _tvset
|
||||||
|
pub extern "C" fn _tvset() {
|
||||||
|
debug!("emscripten::_tvset UNIMPLEMENTED");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// formats time as a C string
|
||||||
|
unsafe extern "C" fn fmt_time(time: u32, instance: &Instance) -> *const c_char {
|
||||||
|
let date = &*(instance.memory_offset_addr(0, time as _) as *mut guest_tm);
|
||||||
|
|
||||||
|
let days = vec!["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||||
|
let months = vec!["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
||||||
|
let year = 1900 + date.tm_year;
|
||||||
|
|
||||||
|
let time_str = format!(
|
||||||
|
// NOTE: TODO: Hack! The 14 accompanying chars are needed for some reason
|
||||||
|
"{} {} {:2} {:02}:{:02}:{:02} {:4}\n\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||||
|
days[date.tm_wday as usize],
|
||||||
|
months[date.tm_mon as usize],
|
||||||
|
date.tm_mday,
|
||||||
|
date.tm_hour,
|
||||||
|
date.tm_min,
|
||||||
|
date.tm_sec,
|
||||||
|
year
|
||||||
|
);
|
||||||
|
|
||||||
|
time_str[0..26].as_ptr() as _
|
||||||
|
}
|
||||||
|
|
||||||
|
/// emscripten: _asctime
|
||||||
|
pub extern "C" fn _asctime(time: u32, instance: &mut Instance) -> u32 {
|
||||||
|
debug!("emscripten::_asctime {}", time);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let time_str_ptr = fmt_time(time, instance);
|
||||||
|
copy_cstr_into_wasm(instance, time_str_ptr)
|
||||||
|
|
||||||
|
// let c_str = instance.memory_offset_addr(0, time_str_offset as _) as *mut i8;
|
||||||
|
// use std::ffi::CStr;
|
||||||
|
// debug!("#### cstr = {:?}", CStr::from_ptr(c_str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// emscripten: _asctime_r
|
||||||
|
pub extern "C" fn _asctime_r(time: u32, buf: u32, instance: &mut Instance) -> u32 {
|
||||||
|
debug!("emscripten::_asctime_r {}", time);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// NOTE: asctime_r is specced to behave in an undefined manner if the algorithm would attempt
|
||||||
|
// to write out more than 26 bytes (including the null terminator).
|
||||||
|
// See http://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html
|
||||||
|
// Our undefined behavior is to truncate the write to at most 26 bytes, including null terminator.
|
||||||
|
let time_str_ptr = fmt_time(time, instance);
|
||||||
|
write_to_buf(time_str_ptr, buf, 26, instance)
|
||||||
|
|
||||||
|
// let c_str = instance.memory_offset_addr(0, time_str_offset as _) as *mut i8;
|
||||||
|
// use std::ffi::CStr;
|
||||||
|
// debug!("#### cstr = {:?}", CStr::from_ptr(c_str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// emscripten: _localtime
|
/// emscripten: _localtime
|
||||||
pub extern "C" fn _localtime(time_p: u32, instance: &mut Instance) -> c_int {
|
pub extern "C" fn _localtime(time_p: u32, instance: &mut Instance) -> c_int {
|
||||||
debug!("emscripten::_localtime {}", time_p);
|
debug!("emscripten::_localtime {}", time_p);
|
||||||
|
// NOTE: emscripten seems to want tzset() called in this function
|
||||||
#[repr(C)]
|
// https://stackoverflow.com/questions/19170721/real-time-awareness-of-timezone-change-in-localtime-vs-localtime-r
|
||||||
struct GuestTm {
|
|
||||||
tm_sec: i32,
|
|
||||||
tm_min: i32,
|
|
||||||
tm_hour: i32,
|
|
||||||
tm_mday: i32,
|
|
||||||
tm_mon: i32,
|
|
||||||
tm_year: i32,
|
|
||||||
tm_wday: i32,
|
|
||||||
tm_yday: i32,
|
|
||||||
tm_isdst: i32,
|
|
||||||
tm_gmtoff: c_long,
|
|
||||||
tm_zone: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let time_p_addr = instance.memory_offset_addr(0, time_p as _) as *mut i64;
|
let time_p_addr = instance.memory_offset_addr(0, time_p as _) as *mut i64;
|
||||||
let tm_struct = &*localtime(time_p_addr);
|
let result_tm = &*localtime(time_p_addr);
|
||||||
|
|
||||||
// Webassembly allocation
|
|
||||||
let tm_struct_offset = (instance.emscripten_data.as_ref().unwrap().malloc)(
|
let tm_struct_offset = (instance.emscripten_data.as_ref().unwrap().malloc)(
|
||||||
mem::size_of::<GuestTm>() as _,
|
mem::size_of::<guest_tm>() as _,
|
||||||
instance,
|
instance,
|
||||||
);
|
);
|
||||||
let tm_struct_ptr = instance.memory_offset_addr(0, tm_struct_offset as _) as *mut GuestTm;
|
|
||||||
|
|
||||||
// Initializing
|
let tm_struct_ptr = instance.memory_offset_addr(0, tm_struct_offset as _) as *mut guest_tm;
|
||||||
(*tm_struct_ptr).tm_sec = tm_struct.tm_sec;
|
// debug!(
|
||||||
(*tm_struct_ptr).tm_min = tm_struct.tm_min;
|
// ">>>>>>> time = {}, {}, {}, {}, {}, {}, {}, {}",
|
||||||
(*tm_struct_ptr).tm_hour = tm_struct.tm_hour;
|
// result_tm.tm_sec, result_tm.tm_min, result_tm.tm_hour, result_tm.tm_mday,
|
||||||
(*tm_struct_ptr).tm_mday = tm_struct.tm_mday;
|
// result_tm.tm_mon, result_tm.tm_year, result_tm.tm_wday, result_tm.tm_yday,
|
||||||
(*tm_struct_ptr).tm_mon = tm_struct.tm_mon;
|
// );
|
||||||
(*tm_struct_ptr).tm_year = tm_struct.tm_year;
|
|
||||||
(*tm_struct_ptr).tm_wday = tm_struct.tm_wday;
|
|
||||||
(*tm_struct_ptr).tm_yday = tm_struct.tm_yday;
|
|
||||||
(*tm_struct_ptr).tm_isdst = tm_struct.tm_isdst;
|
|
||||||
(*tm_struct_ptr).tm_gmtoff = tm_struct.tm_gmtoff;
|
|
||||||
(*tm_struct_ptr).tm_zone = copy_cstr_into_wasm(instance, tm_struct.tm_zone);
|
|
||||||
|
|
||||||
tm_struct_offset as c_int
|
(*tm_struct_ptr).tm_sec = result_tm.tm_sec;
|
||||||
|
(*tm_struct_ptr).tm_min = result_tm.tm_min;
|
||||||
|
(*tm_struct_ptr).tm_hour = result_tm.tm_hour;
|
||||||
|
(*tm_struct_ptr).tm_mday = result_tm.tm_mday;
|
||||||
|
(*tm_struct_ptr).tm_mon = result_tm.tm_mon;
|
||||||
|
(*tm_struct_ptr).tm_year = result_tm.tm_year;
|
||||||
|
(*tm_struct_ptr).tm_wday = result_tm.tm_wday;
|
||||||
|
(*tm_struct_ptr).tm_yday = result_tm.tm_yday;
|
||||||
|
(*tm_struct_ptr).tm_isdst = result_tm.tm_isdst;
|
||||||
|
(*tm_struct_ptr).tm_gmtoff = result_tm.tm_gmtoff as i32;
|
||||||
|
(*tm_struct_ptr).tm_zone = copy_cstr_into_wasm(instance, result_tm.tm_zone) as i32;
|
||||||
|
|
||||||
|
tm_struct_offset as _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// emscripten: _localtime_r
|
||||||
|
pub extern "C" fn _localtime_r(time_p: u32, result: u32, instance: &mut Instance) -> c_int {
|
||||||
|
debug!("emscripten::_localtime_r {}", time_p);
|
||||||
|
|
||||||
|
// NOTE: emscripten seems to want tzset() called in this function
|
||||||
|
// https://stackoverflow.com/questions/19170721/real-time-awareness-of-timezone-change-in-localtime-vs-localtime-r
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let time_p_addr = instance.memory_offset_addr(0, time_p as _) as *mut i64;
|
||||||
|
let result_addr = instance.memory_offset_addr(0, result as _) as *mut guest_tm;
|
||||||
|
|
||||||
|
let mut result_tm = tm {
|
||||||
|
tm_sec: (*result_addr).tm_sec,
|
||||||
|
tm_min: (*result_addr).tm_min,
|
||||||
|
tm_hour: (*result_addr).tm_hour,
|
||||||
|
tm_mday: (*result_addr).tm_mday,
|
||||||
|
tm_mon: (*result_addr).tm_mon,
|
||||||
|
tm_year: (*result_addr).tm_year,
|
||||||
|
tm_wday: (*result_addr).tm_wday,
|
||||||
|
tm_yday: (*result_addr).tm_yday,
|
||||||
|
tm_isdst: (*result_addr).tm_isdst,
|
||||||
|
tm_gmtoff: (*result_addr).tm_gmtoff as _,
|
||||||
|
tm_zone: instance.memory_offset_addr(0, (*result_addr).tm_zone as _) as _,
|
||||||
|
};
|
||||||
|
|
||||||
|
localtime_r(time_p_addr, &mut result_tm);
|
||||||
|
// let tm_struct = result_tm;
|
||||||
|
// debug!(
|
||||||
|
// ">>>>>>> time = {}, {}, {}, {}, {}, {}, {}, {}",
|
||||||
|
// result_tm.tm_sec, result_tm.tm_min, result_tm.tm_hour, result_tm.tm_mday,
|
||||||
|
// result_tm.tm_mon, result_tm.tm_year, result_tm.tm_wday, result_tm.tm_yday,
|
||||||
|
// );
|
||||||
|
|
||||||
|
(*result_addr).tm_sec = result_tm.tm_sec;
|
||||||
|
(*result_addr).tm_min = result_tm.tm_min;
|
||||||
|
(*result_addr).tm_hour = result_tm.tm_hour;
|
||||||
|
(*result_addr).tm_mday = result_tm.tm_mday;
|
||||||
|
(*result_addr).tm_mon = result_tm.tm_mon;
|
||||||
|
(*result_addr).tm_year = result_tm.tm_year;
|
||||||
|
(*result_addr).tm_wday = result_tm.tm_wday;
|
||||||
|
(*result_addr).tm_yday = result_tm.tm_yday;
|
||||||
|
(*result_addr).tm_isdst = result_tm.tm_isdst;
|
||||||
|
(*result_addr).tm_gmtoff = result_tm.tm_gmtoff as _;
|
||||||
|
(*result_addr).tm_zone = copy_cstr_into_wasm(instance, result_tm.tm_zone) as _;
|
||||||
|
|
||||||
|
result as _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,18 @@ pub fn is_emscripten_module(module: &Module) -> bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn write_to_buf(string: *const c_char, buf: u32, max: u32, instance: &Instance) -> u32 {
|
||||||
|
let buf_addr = instance.memory_offset_addr(0, buf as _) as *mut c_char;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
for i in 0..max {
|
||||||
|
*buf_addr.add(i as _) = *string.add(i as _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn copy_cstr_into_wasm(instance: &mut Instance, cstr: *const c_char) -> u32 {
|
pub unsafe fn copy_cstr_into_wasm(instance: &mut Instance, cstr: *const c_char) -> u32 {
|
||||||
let s = CStr::from_ptr(cstr).to_str().unwrap();
|
let s = CStr::from_ptr(cstr).to_str().unwrap();
|
||||||
let cstr_len = s.len();
|
let cstr_len = s.len();
|
||||||
@ -28,6 +40,8 @@ pub unsafe fn copy_cstr_into_wasm(instance: &mut Instance, cstr: *const c_char)
|
|||||||
*loc = byte;
|
*loc = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Appending null byte won't work, because there is CStr::from_ptr(cstr)
|
||||||
|
// at the top that crashes when there is no null byte
|
||||||
*raw_memory.add(cstr_len) = 0;
|
*raw_memory.add(cstr_len) = 0;
|
||||||
|
|
||||||
space_offset
|
space_offset
|
||||||
|
Loading…
Reference in New Issue
Block a user