Index: runtime/wasm-runtime.cpp |
diff --git a/runtime/wasm-runtime.cpp b/runtime/wasm-runtime.cpp |
index d867509ea51d1bf88a579f02d02232f3043b27dc..51b84b8bc0afe50a25cef35b03b4f7157b11cd20 100644 |
--- a/runtime/wasm-runtime.cpp |
+++ b/runtime/wasm-runtime.cpp |
@@ -14,8 +14,34 @@ |
#include <cassert> |
#include <cmath> |
John
2016/04/27 02:28:20
extreme nit ** 10: space between c++ and c headers
|
-// TODO (eholk): change to cstdint |
+#include <errno.h> |
+#include <fcntl.h> |
+#include <iostream> |
John
2016/04/27 02:28:20
move this to the "c++ header section?"
|
+#include <math.h> |
#include <stdint.h> |
+#include <stdio.h> |
+#include <stdlib.h> |
+#include <string.h> |
+#include <sys/ioctl.h> |
+#include <sys/types.h> |
+#include <sys/stat.h> |
+#include <termios.h> |
+#include <time.h> |
+#include <unistd.h> |
+ |
+#ifdef WASM_TRACE_RUNTIME |
+#define TRACE_ENTRY() \ |
+ { std::cerr << __func__ << "(...) = "; } |
+template <typename T> T trace(T x) { |
+ std::cerr << x << std::endl; |
+ return x; |
+} |
+void trace() { std::cerr << "(void)" << std::endl; } |
+#else |
+#define TRACE_ENTRY() |
+template <typename T> T trace(T x) { return x; } |
+void trace() {} |
+#endif // WASM_TRACE_RUNTIME |
namespace { |
uint32_t HeapBreak; |
@@ -35,16 +61,35 @@ float floor(float X) { return std::floor(X); } |
} // end of namespace env |
// TODO (eholk): move the C parts outside and use C++ name mangling. |
+ |
+typedef int32_t WasmPtr; |
+ |
+namespace { |
+ |
+/// Some runtime functions need to return pointers. The WasmData struct is used |
+/// to preallocate space for these on the heap. |
+struct WasmData { |
+ |
+ /// StrBuf is returned by functions that return strings. |
+ char StrBuf[256]; |
+}; |
+ |
+WasmData *GlobalData = NULL; |
+ |
+} // end of anonymous namespace |
+ |
+// TODO (eholk): move the C parts outside and use C++ name mangling. |
extern "C" { |
-#include <errno.h> |
-#include <fcntl.h> |
-#include <math.h> |
-#include <stdio.h> |
-#include <stdlib.h> |
-#include <string.h> |
-#include <sys/types.h> |
-#include <sys/stat.h> |
-#include <unistd.h> |
+ |
+void __sz_bounds_fail() { |
+ std::cerr << "Bounds check failure" << std::endl; |
+ abort(); |
+} |
+ |
+void __sz_indirect_fail() { |
+ std::cerr << "Invalid indirect call target" << std::endl; |
+ abort(); |
+} |
extern char WASM_MEMORY[]; |
extern uint32_t WASM_DATA_SIZE; |
@@ -57,11 +102,23 @@ void env$$abort() { |
void env$$_abort() { env$$abort(); } |
-double env$$floor_f(float X) { return env::floor(X); } |
-double env$$floor_d(double X) { return env::floor(X); } |
+double env$$floor_f(float X) { |
+ TRACE_ENTRY(); |
+ return env::floor(X); |
+} |
+double env$$floor_d(double X) { |
+ TRACE_ENTRY(); |
+ return env::floor(X); |
+} |
-void env$$exit(int Status) { exit(Status); } |
-void env$$_exit(int Status) { env$$exit(Status); } |
+void env$$exit(int Status) { |
+ TRACE_ENTRY(); |
+ exit(Status); |
+} |
+void env$$_exit(int Status) { |
+ TRACE_ENTRY(); |
+ env$$exit(Status); |
+} |
#define UNIMPLEMENTED(f) \ |
void env$$##f() { \ |
@@ -70,111 +127,248 @@ void env$$_exit(int Status) { env$$exit(Status); } |
} |
int32_t env$$sbrk(int32_t Increment) { |
+ TRACE_ENTRY(); |
+ uint32_t OldBreak = HeapBreak; |
HeapBreak += Increment; |
- return HeapBreak; |
+ return trace(OldBreak); |
} |
-UNIMPLEMENTED(setjmp) |
-UNIMPLEMENTED(longjmp) |
+UNIMPLEMENTED(__addtf3) |
UNIMPLEMENTED(__assert_fail) |
-UNIMPLEMENTED(__builtin_malloc) |
-UNIMPLEMENTED(__builtin_isinff) |
-UNIMPLEMENTED(__builtin_isinfl) |
UNIMPLEMENTED(__builtin_apply) |
UNIMPLEMENTED(__builtin_apply_args) |
-UNIMPLEMENTED(pthread_cleanup_push) |
-UNIMPLEMENTED(pthread_cleanup_pop) |
-UNIMPLEMENTED(pthread_self) |
-UNIMPLEMENTED(__floatditf) |
-UNIMPLEMENTED(__floatsitf) |
+UNIMPLEMENTED(__builtin_isinff) |
+UNIMPLEMENTED(__builtin_isinfl) |
+UNIMPLEMENTED(__builtin_malloc) |
+UNIMPLEMENTED(__divtf3) |
+UNIMPLEMENTED(__eqtf2) |
+UNIMPLEMENTED(__extenddftf2) |
+UNIMPLEMENTED(__extendsftf2) |
+UNIMPLEMENTED(__fixsfti) |
UNIMPLEMENTED(__fixtfdi) |
UNIMPLEMENTED(__fixtfsi) |
-UNIMPLEMENTED(__fixsfti) |
-UNIMPLEMENTED(__netf2) |
+UNIMPLEMENTED(__fixunstfsi) |
+UNIMPLEMENTED(__floatditf) |
+UNIMPLEMENTED(__floatsitf) |
+UNIMPLEMENTED(__floatunsitf) |
UNIMPLEMENTED(__getf2) |
-UNIMPLEMENTED(__eqtf2) |
+UNIMPLEMENTED(__letf2) |
UNIMPLEMENTED(__lttf2) |
-UNIMPLEMENTED(__addtf3) |
-UNIMPLEMENTED(__subtf3) |
-UNIMPLEMENTED(__divtf3) |
UNIMPLEMENTED(__multf3) |
UNIMPLEMENTED(__multi3) |
-UNIMPLEMENTED(__lock) |
-UNIMPLEMENTED(__unlock) |
-UNIMPLEMENTED(__syscall6) // sys_close |
+UNIMPLEMENTED(__netf2) |
+UNIMPLEMENTED(__subtf3) |
UNIMPLEMENTED(__syscall140) // sys_llseek |
+UNIMPLEMENTED(__syscall221) // sys_fcntl64 |
+UNIMPLEMENTED(__trunctfdf2) |
+UNIMPLEMENTED(__trunctfsf2) |
UNIMPLEMENTED(__unordtf2) |
-UNIMPLEMENTED(__fixunstfsi) |
-UNIMPLEMENTED(__floatunsitf) |
-UNIMPLEMENTED(__extenddftf2) |
+UNIMPLEMENTED(longjmp) |
+UNIMPLEMENTED(pthread_cleanup_pop) |
+UNIMPLEMENTED(pthread_cleanup_push) |
+UNIMPLEMENTED(pthread_self) |
+UNIMPLEMENTED(setjmp) |
-void *wasmPtr(uint32_t Index) { |
+void *wasmPtr(int Index) { |
if (pageNum(Index) < WASM_NUM_PAGES) { |
return WASM_MEMORY + Index; |
} |
abort(); |
} |
-extern int __szwasm_main(int, const char **); |
+WasmPtr toWasm(void *Ptr) { |
+ return reinterpret_cast<WasmPtr>(reinterpret_cast<char *>(Ptr) - WASM_MEMORY); |
+} |
+ |
+extern int __szwasm_main(int, WasmPtr); |
#define WASM_REF(Type, Index) ((Type *)wasmPtr(Index)) |
#define WASM_DEREF(Type, Index) (*WASM_REF(Type, Index)) |
int main(int argc, const char **argv) { |
+ // fprintf(stderr, "main(%d)\n", argc); |
+ |
+ // TODO (eholk): align these allocations correctly. |
+ |
+ // Allocate space for the global data. |
+ HeapBreak = WASM_DATA_SIZE; |
+ GlobalData = WASM_REF(WasmData, HeapBreak); |
+ HeapBreak += sizeof(WasmData); |
+ |
+ // copy the command line arguments. |
+ WasmPtr WasmArgV = HeapBreak; |
+ WasmPtr *WasmArgVPtr = WASM_REF(WasmPtr, WasmArgV); |
+ HeapBreak += argc * sizeof(WasmPtr); |
+ |
+ for (int i = 0; i < argc; ++i) { |
+ WasmArgVPtr[i] = HeapBreak; |
+ strcpy(WASM_REF(char, HeapBreak), argv[i]); |
+ HeapBreak += strlen(argv[i]) + 1; |
+ } |
+ |
// Initialize the break to the nearest page boundary after the data segment |
HeapBreak = (WASM_DATA_SIZE + PageSize - 1) & ~(PageSize - 1); |
// Initialize the stack pointer. |
WASM_DEREF(int32_t, StackPtrLoc) = WASM_NUM_PAGES << PageSizeLog2; |
- return __szwasm_main(argc, argv); |
+ return __szwasm_main(argc, WasmArgV); |
} |
-int env$$abs(int a) { return abs(a); } |
+int env$$abs(int a) { |
+ TRACE_ENTRY(); |
+ return trace(abs(a)); |
+} |
-double env$$pow(double x, double y) { return pow(x, y); } |
+clock_t env$$clock() { |
+ TRACE_ENTRY(); |
+ return trace(clock()); |
+} |
+ |
+WasmPtr env$$ctime(WasmPtr Time) { |
+ TRACE_ENTRY(); |
+ time_t *TimePtr = WASM_REF(time_t, Time); |
+ char *CTime = ctime(TimePtr); |
+ strncpy(GlobalData->StrBuf, CTime, sizeof(GlobalData->StrBuf)); |
+ GlobalData->StrBuf[sizeof(GlobalData->StrBuf) - 1] = '\0'; |
+ return trace(toWasm(GlobalData->StrBuf)); |
+} |
+ |
+double env$$pow(double x, double y) { |
+ TRACE_ENTRY(); |
+ return trace(pow(x, y)); |
+} |
+ |
+time_t env$$time(WasmPtr Time) { |
+ TRACE_ENTRY(); |
+ time_t *TimePtr = WASM_REF(time_t, Time); |
+ return trace(time(TimePtr)); |
+} |
+ |
+// lock and unlock are no-ops in wasm.js, so we mimic that behavior. |
+void env$$__lock(int32_t _) { |
+ TRACE_ENTRY(); |
+ (void)_; |
+ trace(); |
+} |
+ |
+void env$$__unlock(int32_t _) { |
+ TRACE_ENTRY(); |
+ (void)_; |
+ trace(); |
+} |
+ |
+/// sys_read |
+int env$$__syscall3(int Which, int VarArgs) { |
+ TRACE_ENTRY(); |
+ int Fd = WASM_DEREF(int, VarArgs + 0 * sizeof(int)); |
+ int Buffer = WASM_DEREF(int, VarArgs + 1 * sizeof(int)); |
+ int Length = WASM_DEREF(int, VarArgs + 2 * sizeof(int)); |
+ |
+ return trace(read(Fd, WASM_REF(char *, Buffer), Length)); |
+} |
/// sys_write |
int env$$__syscall4(int Which, int VarArgs) { |
+ TRACE_ENTRY(); |
int Fd = WASM_DEREF(int, VarArgs + 0 * sizeof(int)); |
int Buffer = WASM_DEREF(int, VarArgs + 1 * sizeof(int)); |
int Length = WASM_DEREF(int, VarArgs + 2 * sizeof(int)); |
- return write(Fd, WASM_REF(char *, Buffer), Length); |
+ return trace(write(Fd, WASM_REF(char *, Buffer), Length)); |
} |
/// sys_open |
int env$$__syscall5(int Which, int VarArgs) { |
+ TRACE_ENTRY(); |
int WasmPath = WASM_DEREF(int, VarArgs); |
int Flags = WASM_DEREF(int, VarArgs + 4); |
int Mode = WASM_DEREF(int, VarArgs + 8); |
const char *Path = WASM_REF(char, WasmPath); |
- fprintf(stderr, "sys_open(%s, %d, %d)\n", Path, Flags, Mode); |
+ return trace(open(Path, Flags, Mode)); |
+} |
- return open(Path, Flags, Mode); |
+/// sys_close |
+int env$$__syscall6(int Which, int VarArgs) { |
+ TRACE_ENTRY(); |
+ int Fd = WASM_DEREF(int, VarArgs + 0 * sizeof(int)); |
+ |
+ return trace(close(Fd)); |
+} |
+ |
+/// sys_unlink |
+int env$$__syscall10(int Which, int VarArgs) { |
+ TRACE_ENTRY(); |
+ int WasmPath = WASM_DEREF(int, VarArgs); |
+ const char *Path = WASM_REF(char, WasmPath); |
+ |
+ return trace(unlink(Path)); |
} |
/// sys_getpid |
int env$$__syscall20(int Which, int VarArgs) { |
+ TRACE_ENTRY(); |
(void)Which; |
(void)VarArgs; |
- return getpid(); |
+ return trace(getpid()); |
+} |
+ |
+/// sys_rmdir |
+int env$$__syscall40(int Which, int VarArgs) { |
+ TRACE_ENTRY(); |
+ int WasmPath = WASM_DEREF(int, VarArgs); |
+ const char *Path = WASM_REF(char, WasmPath); |
+ |
+ return trace(rmdir(Path)); |
} |
/// sys_ioctl |
int env$$__syscall54(int A, int B) { |
+ TRACE_ENTRY(); |
int Fd = WASM_DEREF(int, B + 0 * sizeof(int)); |
int Op = WASM_DEREF(int, B + 1 * sizeof(int)); |
int ArgP = WASM_DEREF(int, B + 2 * sizeof(int)); |
- // TODO (eholk): implement sys_ioctl |
- return -ENOTTY; |
+ |
+ switch (Op) { |
+ case TCGETS: { |
+ // struct termios has no pointers. Otherwise, we'd have to rewrite them. |
+ struct termios *TermIOS = WASM_REF(struct termios, ArgP); |
+ return trace(ioctl(Fd, TCGETS, TermIOS)); |
+ } |
+ default: |
+ // TODO (eholk): implement more ioctls |
+ return trace(-ENOTTY); |
+ } |
} |
-/// sys_write |
-int env$$__syscall146(int Which, int VarArgs) { |
+/// sys_readv |
+int env$$__syscall145(int Which, int VarArgs) { |
+ TRACE_ENTRY(); |
+ int Fd = WASM_DEREF(int, VarArgs); |
+ int Iov = WASM_DEREF(int, VarArgs + sizeof(int)); |
+ int Iovcnt = WASM_DEREF(int, VarArgs + 2 * sizeof(int)); |
+ |
+ int Count = 0; |
+ |
+ for (int I = 0; I < Iovcnt; ++I) { |
+ void *Ptr = WASM_REF(void, WASM_DEREF(int, Iov + I * 8)); |
+ int Length = WASM_DEREF(int, Iov + I * 8 + 4); |
+ int Curr = read(Fd, Ptr, Length); |
+ |
+ if (Curr < 0) { |
+ return trace(-1); |
+ } |
+ Count += Curr; |
+ } |
+ return trace(Count); |
+} |
+ |
+/// sys_writev |
+int env$$__syscall146(int Which, int VarArgs) { |
+ TRACE_ENTRY(); |
int Fd = WASM_DEREF(int, VarArgs); |
int Iov = WASM_DEREF(int, VarArgs + sizeof(int)); |
int Iovcnt = WASM_DEREF(int, VarArgs + 2 * sizeof(int)); |
@@ -188,20 +382,21 @@ int env$$__syscall146(int Which, int VarArgs) { |
int Curr = write(Fd, Ptr, Length); |
if (Curr < 0) { |
- return -1; |
+ return trace(-1); |
} |
Count += Curr; |
} |
- return Count; |
+ return trace(Count); |
} |
/// sys_mmap_pgoff |
int env$$__syscall192(int Which, int VarArgs) { |
+ TRACE_ENTRY(); |
(void)Which; |
(void)VarArgs; |
// TODO (eholk): figure out how to implement this. |
- return -ENOMEM; |
+ return trace(-ENOMEM); |
} |
} // end of extern "C" |