blob: 7ff3859b224c085407b0255c584b16212f93980e [file] [log] [blame]
Eric Holk29acb572016-04-22 09:34:41 -07001//===- subzero/runtime/wasm-runtime.cpp - Subzero WASM runtime source -----===//
Eric Holk67c7c412016-04-15 13:05:37 -07002//
3// The Subzero Code Generator
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the system calls required by the libc that is included
11// in WebAssembly programs.
12//
13//===----------------------------------------------------------------------===//
14
Eric Holk179a55d2016-05-02 10:42:27 -070015#include <algorithm>
Eric Holk4aae81a2016-04-25 12:52:49 -070016#include <cassert>
Eric Holk29acb572016-04-22 09:34:41 -070017#include <cmath>
Eric Holk179a55d2016-05-02 10:42:27 -070018#include <iostream>
19#include <vector>
20
Eric Holk87def2c2016-04-29 14:42:17 -070021#include <errno.h>
22#include <fcntl.h>
Eric Holk87def2c2016-04-29 14:42:17 -070023#include <math.h>
Eric Holk4aae81a2016-04-25 12:52:49 -070024#include <stdint.h>
Eric Holk87def2c2016-04-29 14:42:17 -070025#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <sys/ioctl.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <termios.h>
32#include <time.h>
33#include <unistd.h>
34
35#ifdef WASM_TRACE_RUNTIME
36#define TRACE_ENTRY() \
37 { std::cerr << __func__ << "(...) = "; }
38template <typename T> T trace(T x) {
39 std::cerr << x << std::endl;
40 return x;
41}
42void trace() { std::cerr << "(void)" << std::endl; }
43#else
44#define TRACE_ENTRY()
45template <typename T> T trace(T x) { return x; }
46void trace() {}
47#endif // WASM_TRACE_RUNTIME
48
49extern "C" {
Eric Holk179a55d2016-05-02 10:42:27 -070050char *WASM_MEMORY;
Eric Holk87def2c2016-04-29 14:42:17 -070051extern uint32_t WASM_DATA_SIZE;
52extern uint32_t WASM_NUM_PAGES;
53} // end of extern "C"
Eric Holk4aae81a2016-04-25 12:52:49 -070054
55namespace {
56uint32_t HeapBreak;
57
58// TODO (eholk): make all of these constexpr.
59const uint32_t PageSizeLog2 = 16;
60const uint32_t PageSize = 1 << PageSizeLog2; // 64KB
61const uint32_t StackPtrLoc = 1024; // defined by emscripten
62
63uint32_t pageNum(uint32_t Index) { return Index >> PageSizeLog2; }
64} // end of anonymous namespace
Eric Holk29acb572016-04-22 09:34:41 -070065
66namespace env {
67double floor(double X) { return std::floor(X); }
68
69float floor(float X) { return std::floor(X); }
Eric Holk4aae81a2016-04-25 12:52:49 -070070} // end of namespace env
Eric Holk29acb572016-04-22 09:34:41 -070071
72// TODO (eholk): move the C parts outside and use C++ name mangling.
Eric Holk67c7c412016-04-15 13:05:37 -070073
Eric Holk87def2c2016-04-29 14:42:17 -070074namespace {
75
76/// Some runtime functions need to return pointers. The WasmData struct is used
77/// to preallocate space for these on the heap.
78struct WasmData {
79
80 /// StrBuf is returned by functions that return strings.
81 char StrBuf[256];
82};
83
84WasmData *GlobalData = NULL;
85
86int toWasm(void *Ptr) {
87 return reinterpret_cast<int>(reinterpret_cast<char *>(Ptr) - WASM_MEMORY);
88}
89
90template <typename T> T *wasmPtr(int Index) {
91 if (pageNum(Index) < WASM_NUM_PAGES) {
92 return reinterpret_cast<T *>(WASM_MEMORY + Index);
93 }
94 abort();
95}
96
97template <typename T> class WasmPtr {
98 int Ptr;
99
100public:
101 WasmPtr(int Ptr) : Ptr(Ptr) {
102 // TODO (eholk): make this a static_assert once we have C++11
103 assert(sizeof(*this) == sizeof(int));
104 }
105
106 WasmPtr(T *Ptr) : Ptr(toWasm(Ptr)) {}
107
108 T &operator*() const { return *asPtr(); }
109
110 T *asPtr() const { return wasmPtr<T>(Ptr); }
111
112 int asInt() const { return Ptr; }
113};
114
115typedef WasmPtr<char> WasmCharPtr;
116
117template <typename T> class WasmArray {
118 int Ptr;
119
120public:
121 WasmArray(int Ptr) : Ptr(Ptr) {
122 // TODO (eholk): make this a static_assert once we have C++11.
123 assert(sizeof(*this) == sizeof(int));
124 }
125
126 T &operator[](unsigned int Index) const { return wasmPtr<T>(Ptr)[Index]; }
127};
128} // end of anonymous namespace
129
130// TODO (eholk): move the C parts outside and use C++ name mangling.
131extern "C" {
132
133void __Sz_bounds_fail() {
134 std::cerr << "Bounds check failure" << std::endl;
135 abort();
136}
137
138void __Sz_indirect_fail() {
139 std::cerr << "Invalid indirect call target" << std::endl;
140 abort();
141}
Eric Holk67c7c412016-04-15 13:05:37 -0700142
Eric Holk179a55d2016-05-02 10:42:27 -0700143extern char WASM_DATA_INIT[];
144
Eric Holk67c7c412016-04-15 13:05:37 -0700145void env$$abort() {
146 fprintf(stderr, "Aborting...\n");
147 abort();
148}
149
150void env$$_abort() { env$$abort(); }
151
Eric Holk87def2c2016-04-29 14:42:17 -0700152double env$$floor_f(float X) {
153 TRACE_ENTRY();
154 return env::floor(X);
155}
156double env$$floor_d(double X) {
157 TRACE_ENTRY();
158 return env::floor(X);
159}
Eric Holk29acb572016-04-22 09:34:41 -0700160
Eric Holk87def2c2016-04-29 14:42:17 -0700161void env$$exit(int Status) {
162 TRACE_ENTRY();
163 exit(Status);
164}
165void env$$_exit(int Status) {
166 TRACE_ENTRY();
167 env$$exit(Status);
168}
Eric Holk085bdae2016-04-18 15:08:19 -0700169
Eric Holk67c7c412016-04-15 13:05:37 -0700170#define UNIMPLEMENTED(f) \
171 void env$$##f() { \
172 fprintf(stderr, "Unimplemented: " #f "\n"); \
173 abort(); \
174 }
175
Eric Holk4aae81a2016-04-25 12:52:49 -0700176int32_t env$$sbrk(int32_t Increment) {
Eric Holk87def2c2016-04-29 14:42:17 -0700177 TRACE_ENTRY();
178 uint32_t OldBreak = HeapBreak;
Eric Holk4aae81a2016-04-25 12:52:49 -0700179 HeapBreak += Increment;
Eric Holk87def2c2016-04-29 14:42:17 -0700180 return trace(OldBreak);
Eric Holk4aae81a2016-04-25 12:52:49 -0700181}
182
Eric Holk87def2c2016-04-29 14:42:17 -0700183UNIMPLEMENTED(__addtf3)
Eric Holk085bdae2016-04-18 15:08:19 -0700184UNIMPLEMENTED(__assert_fail)
Eric Holk085bdae2016-04-18 15:08:19 -0700185UNIMPLEMENTED(__builtin_apply)
186UNIMPLEMENTED(__builtin_apply_args)
Eric Holk87def2c2016-04-29 14:42:17 -0700187UNIMPLEMENTED(__builtin_isinff)
188UNIMPLEMENTED(__builtin_isinfl)
189UNIMPLEMENTED(__builtin_malloc)
190UNIMPLEMENTED(__divtf3)
191UNIMPLEMENTED(__eqtf2)
192UNIMPLEMENTED(__extenddftf2)
193UNIMPLEMENTED(__extendsftf2)
194UNIMPLEMENTED(__fixsfti)
Eric Holk085bdae2016-04-18 15:08:19 -0700195UNIMPLEMENTED(__fixtfdi)
196UNIMPLEMENTED(__fixtfsi)
Eric Holk87def2c2016-04-29 14:42:17 -0700197UNIMPLEMENTED(__fixunstfsi)
198UNIMPLEMENTED(__floatditf)
199UNIMPLEMENTED(__floatsitf)
200UNIMPLEMENTED(__floatunsitf)
Eric Holk085bdae2016-04-18 15:08:19 -0700201UNIMPLEMENTED(__getf2)
Eric Holk87def2c2016-04-29 14:42:17 -0700202UNIMPLEMENTED(__letf2)
Eric Holk085bdae2016-04-18 15:08:19 -0700203UNIMPLEMENTED(__lttf2)
Eric Holk085bdae2016-04-18 15:08:19 -0700204UNIMPLEMENTED(__multf3)
205UNIMPLEMENTED(__multi3)
Eric Holk87def2c2016-04-29 14:42:17 -0700206UNIMPLEMENTED(__netf2)
207UNIMPLEMENTED(__subtf3)
Eric Holk29acb572016-04-22 09:34:41 -0700208UNIMPLEMENTED(__syscall140) // sys_llseek
Eric Holk87def2c2016-04-29 14:42:17 -0700209UNIMPLEMENTED(__syscall221) // sys_fcntl64
210UNIMPLEMENTED(__trunctfdf2)
211UNIMPLEMENTED(__trunctfsf2)
Eric Holk29acb572016-04-22 09:34:41 -0700212UNIMPLEMENTED(__unordtf2)
Eric Holk87def2c2016-04-29 14:42:17 -0700213UNIMPLEMENTED(longjmp)
214UNIMPLEMENTED(pthread_cleanup_pop)
215UNIMPLEMENTED(pthread_cleanup_push)
216UNIMPLEMENTED(pthread_self)
217UNIMPLEMENTED(setjmp)
Eric Holk67c7c412016-04-15 13:05:37 -0700218
Eric Holk87def2c2016-04-29 14:42:17 -0700219extern int __szwasm_main(int, WasmPtr<WasmCharPtr>);
Eric Holk67c7c412016-04-15 13:05:37 -0700220
Eric Holk87def2c2016-04-29 14:42:17 -0700221#define WASM_REF(Type, Index) (WasmPtr<Type>(Index).asPtr())
Eric Holk67c7c412016-04-15 13:05:37 -0700222#define WASM_DEREF(Type, Index) (*WASM_REF(Type, Index))
223
Eric Holk4aae81a2016-04-25 12:52:49 -0700224int main(int argc, const char **argv) {
Eric Holk179a55d2016-05-02 10:42:27 -0700225 // Create the heap.
226 std::vector<char> WasmHeap(WASM_NUM_PAGES << PageSizeLog2);
227 WASM_MEMORY = WasmHeap.data();
228 std::copy(WASM_DATA_INIT, WASM_DATA_INIT + WASM_DATA_SIZE, WasmHeap.begin());
229
Eric Holk87def2c2016-04-29 14:42:17 -0700230 // TODO (eholk): align these allocations correctly.
231
232 // Allocate space for the global data.
233 HeapBreak = WASM_DATA_SIZE;
234 GlobalData = WASM_REF(WasmData, HeapBreak);
235 HeapBreak += sizeof(WasmData);
236
237 // copy the command line arguments.
238 WasmPtr<WasmCharPtr> WasmArgV = HeapBreak;
239 WasmPtr<char> *WasmArgVPtr = WasmArgV.asPtr();
240 HeapBreak += argc * sizeof(*WasmArgVPtr);
241
242 for (int i = 0; i < argc; ++i) {
243 WasmArgVPtr[i] = HeapBreak;
244 strcpy(WASM_REF(char, HeapBreak), argv[i]);
245 HeapBreak += strlen(argv[i]) + 1;
246 }
247
Eric Holk4aae81a2016-04-25 12:52:49 -0700248 // Initialize the break to the nearest page boundary after the data segment
249 HeapBreak = (WASM_DATA_SIZE + PageSize - 1) & ~(PageSize - 1);
250
251 // Initialize the stack pointer.
252 WASM_DEREF(int32_t, StackPtrLoc) = WASM_NUM_PAGES << PageSizeLog2;
253
Eric Holk87def2c2016-04-29 14:42:17 -0700254 return __szwasm_main(argc, WasmArgV);
Eric Holk4aae81a2016-04-25 12:52:49 -0700255}
Eric Holk67c7c412016-04-15 13:05:37 -0700256
Eric Holk87def2c2016-04-29 14:42:17 -0700257int env$$abs(int a) {
258 TRACE_ENTRY();
259 return trace(abs(a));
260}
Eric Holk29acb572016-04-22 09:34:41 -0700261
Eric Holk87def2c2016-04-29 14:42:17 -0700262clock_t env$$clock() {
263 TRACE_ENTRY();
264 return trace(clock());
265}
266
267int env$$ctime(WasmPtr<time_t> Time) {
268 TRACE_ENTRY();
269 char *CTime = ctime(Time.asPtr());
270 strncpy(GlobalData->StrBuf, CTime, sizeof(GlobalData->StrBuf));
271 GlobalData->StrBuf[sizeof(GlobalData->StrBuf) - 1] = '\0';
272 return trace(WasmPtr<char>(GlobalData->StrBuf).asInt());
273}
274
275double env$$pow(double x, double y) {
276 TRACE_ENTRY();
277 return trace(pow(x, y));
278}
279
280time_t env$$time(WasmPtr<time_t> Time) {
281 TRACE_ENTRY();
282 time_t *TimePtr = WASM_REF(time_t, Time);
283 return trace(time(TimePtr));
284}
285
286// lock and unlock are no-ops in wasm.js, so we mimic that behavior.
287void env$$__lock(int32_t) {
288 TRACE_ENTRY();
289 trace();
290}
291
292void env$$__unlock(int32_t) {
293 TRACE_ENTRY();
294 trace();
295}
296
297/// sys_read
298int env$$__syscall3(int Which, WasmArray<int> VarArgs) {
299 TRACE_ENTRY();
300 int Fd = VarArgs[0];
301 int Buffer = VarArgs[1];
302 int Length = VarArgs[2];
303
304 return trace(read(Fd, WASM_REF(char *, Buffer), Length));
305}
Eric Holk29acb572016-04-22 09:34:41 -0700306
Eric Holk67c7c412016-04-15 13:05:37 -0700307/// sys_write
Eric Holk87def2c2016-04-29 14:42:17 -0700308int env$$__syscall4(int Which, WasmArray<int> VarArgs) {
309 TRACE_ENTRY();
310 int Fd = VarArgs[0];
311 int Buffer = VarArgs[1];
312 int Length = VarArgs[2];
Eric Holk67c7c412016-04-15 13:05:37 -0700313
Eric Holk87def2c2016-04-29 14:42:17 -0700314 return trace(write(Fd, WASM_REF(char *, Buffer), Length));
Eric Holk67c7c412016-04-15 13:05:37 -0700315}
316
Eric Holk085bdae2016-04-18 15:08:19 -0700317/// sys_open
Eric Holk87def2c2016-04-29 14:42:17 -0700318int env$$__syscall5(int Which, WasmArray<int> VarArgs) {
319 TRACE_ENTRY();
320 int WasmPath = VarArgs[0];
321 int Flags = VarArgs[1];
322 int Mode = VarArgs[2];
Eric Holk085bdae2016-04-18 15:08:19 -0700323 const char *Path = WASM_REF(char, WasmPath);
324
Eric Holk87def2c2016-04-29 14:42:17 -0700325 return trace(open(Path, Flags, Mode));
326}
Eric Holk085bdae2016-04-18 15:08:19 -0700327
Eric Holk87def2c2016-04-29 14:42:17 -0700328/// sys_close
329int env$$__syscall6(int Which, WasmArray<int> VarArgs) {
330 TRACE_ENTRY();
331 int Fd = VarArgs[0];
332
333 return trace(close(Fd));
334}
335
336/// sys_unlink
337int env$$__syscall10(int Which, WasmArray<int> VarArgs) {
338 TRACE_ENTRY();
339 int WasmPath = VarArgs[0];
340 const char *Path = WASM_REF(char, WasmPath);
341
342 return trace(unlink(Path));
Eric Holk085bdae2016-04-18 15:08:19 -0700343}
344
Eric Holk29acb572016-04-22 09:34:41 -0700345/// sys_getpid
Eric Holk87def2c2016-04-29 14:42:17 -0700346int env$$__syscall20(int Which, WasmArray<int> VarArgs) {
347 TRACE_ENTRY();
Eric Holk29acb572016-04-22 09:34:41 -0700348 (void)Which;
349 (void)VarArgs;
350
Eric Holk87def2c2016-04-29 14:42:17 -0700351 return trace(getpid());
352}
353
354/// sys_rmdir
355int env$$__syscall40(int Which, WasmArray<int> VarArgs) {
356 TRACE_ENTRY();
357 int WasmPath = VarArgs[0];
358 const char *Path = WASM_REF(char, WasmPath);
359
360 return trace(rmdir(Path));
Eric Holk29acb572016-04-22 09:34:41 -0700361}
362
Eric Holk67c7c412016-04-15 13:05:37 -0700363/// sys_ioctl
Eric Holk87def2c2016-04-29 14:42:17 -0700364int env$$__syscall54(int Which, WasmArray<int> VarArgs) {
365 TRACE_ENTRY();
366 int Fd = VarArgs[0];
367 int Op = VarArgs[1];
368 int ArgP = VarArgs[2];
369
370 switch (Op) {
371 case TCGETS: {
372 // struct termios has no pointers. Otherwise, we'd have to rewrite them.
373 struct termios *TermIOS = WASM_REF(struct termios, ArgP);
374 return trace(ioctl(Fd, TCGETS, TermIOS));
375 }
376 default:
377 // TODO (eholk): implement more ioctls
378 return trace(-ENOTTY);
379 }
Eric Holk67c7c412016-04-15 13:05:37 -0700380}
381
Eric Holk87def2c2016-04-29 14:42:17 -0700382struct IoVec {
383 WasmPtr<char> Ptr;
384 int Length;
385};
Eric Holk67c7c412016-04-15 13:05:37 -0700386
Eric Holk87def2c2016-04-29 14:42:17 -0700387/// sys_readv
388int env$$__syscall145(int Which, WasmArray<int> VarArgs) {
389 TRACE_ENTRY();
390 int Fd = VarArgs[0];
391 WasmArray<IoVec> Iov = VarArgs[1];
392 int Iovcnt = VarArgs[2];
Eric Holk67c7c412016-04-15 13:05:37 -0700393
Eric Holk67c7c412016-04-15 13:05:37 -0700394 int Count = 0;
395
396 for (int I = 0; I < Iovcnt; ++I) {
Eric Holk87def2c2016-04-29 14:42:17 -0700397 int Curr = read(Fd, Iov[I].Ptr.asPtr(), Iov[I].Length);
Eric Holk67c7c412016-04-15 13:05:37 -0700398
Eric Holk67c7c412016-04-15 13:05:37 -0700399 if (Curr < 0) {
Eric Holk87def2c2016-04-29 14:42:17 -0700400 return trace(-1);
Eric Holk67c7c412016-04-15 13:05:37 -0700401 }
402 Count += Curr;
403 }
Eric Holk87def2c2016-04-29 14:42:17 -0700404 return trace(Count);
405}
406
407/// sys_writev
408int env$$__syscall146(int Which, WasmArray<int> VarArgs) {
409 TRACE_ENTRY();
410 int Fd = VarArgs[0];
411 WasmArray<IoVec> Iov = VarArgs[1];
412 int Iovcnt = VarArgs[2];
413
414 int Count = 0;
415
416 for (int I = 0; I < Iovcnt; ++I) {
417 int Curr = write(Fd, Iov[I].Ptr.asPtr(), Iov[I].Length);
418
419 if (Curr < 0) {
420 return trace(-1);
421 }
422 Count += Curr;
423 }
424 return trace(Count);
Eric Holk67c7c412016-04-15 13:05:37 -0700425}
Eric Holk4aae81a2016-04-25 12:52:49 -0700426
427/// sys_mmap_pgoff
Eric Holk87def2c2016-04-29 14:42:17 -0700428int env$$__syscall192(int Which, WasmArray<int> VarArgs) {
429 TRACE_ENTRY();
Eric Holk4aae81a2016-04-25 12:52:49 -0700430 (void)Which;
431 (void)VarArgs;
432
433 // TODO (eholk): figure out how to implement this.
434
Eric Holk87def2c2016-04-29 14:42:17 -0700435 return trace(-ENOMEM);
Eric Holk4aae81a2016-04-25 12:52:49 -0700436}
Eric Holk29acb572016-04-22 09:34:41 -0700437} // end of extern "C"