blob: 3ea82a0bace4fe926b01314ec47407603c4e4d11 [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 Holk4aae81a2016-04-25 12:52:49 -070015#include <cassert>
Eric Holk29acb572016-04-22 09:34:41 -070016#include <cmath>
Eric Holk87def2c2016-04-29 14:42:17 -070017#include <errno.h>
18#include <fcntl.h>
19#include <iostream>
20#include <math.h>
Eric Holk4aae81a2016-04-25 12:52:49 -070021#include <stdint.h>
Eric Holk87def2c2016-04-29 14:42:17 -070022#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/ioctl.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <termios.h>
29#include <time.h>
30#include <unistd.h>
31
32#ifdef WASM_TRACE_RUNTIME
33#define TRACE_ENTRY() \
34 { std::cerr << __func__ << "(...) = "; }
35template <typename T> T trace(T x) {
36 std::cerr << x << std::endl;
37 return x;
38}
39void trace() { std::cerr << "(void)" << std::endl; }
40#else
41#define TRACE_ENTRY()
42template <typename T> T trace(T x) { return x; }
43void trace() {}
44#endif // WASM_TRACE_RUNTIME
45
46extern "C" {
47extern char WASM_MEMORY[];
48extern uint32_t WASM_DATA_SIZE;
49extern uint32_t WASM_NUM_PAGES;
50} // end of extern "C"
Eric Holk4aae81a2016-04-25 12:52:49 -070051
52namespace {
53uint32_t HeapBreak;
54
55// TODO (eholk): make all of these constexpr.
56const uint32_t PageSizeLog2 = 16;
57const uint32_t PageSize = 1 << PageSizeLog2; // 64KB
58const uint32_t StackPtrLoc = 1024; // defined by emscripten
59
60uint32_t pageNum(uint32_t Index) { return Index >> PageSizeLog2; }
61} // end of anonymous namespace
Eric Holk29acb572016-04-22 09:34:41 -070062
63namespace env {
64double floor(double X) { return std::floor(X); }
65
66float floor(float X) { return std::floor(X); }
Eric Holk4aae81a2016-04-25 12:52:49 -070067} // end of namespace env
Eric Holk29acb572016-04-22 09:34:41 -070068
69// TODO (eholk): move the C parts outside and use C++ name mangling.
Eric Holk67c7c412016-04-15 13:05:37 -070070
Eric Holk87def2c2016-04-29 14:42:17 -070071namespace {
72
73/// Some runtime functions need to return pointers. The WasmData struct is used
74/// to preallocate space for these on the heap.
75struct WasmData {
76
77 /// StrBuf is returned by functions that return strings.
78 char StrBuf[256];
79};
80
81WasmData *GlobalData = NULL;
82
83int toWasm(void *Ptr) {
84 return reinterpret_cast<int>(reinterpret_cast<char *>(Ptr) - WASM_MEMORY);
85}
86
87template <typename T> T *wasmPtr(int Index) {
88 if (pageNum(Index) < WASM_NUM_PAGES) {
89 return reinterpret_cast<T *>(WASM_MEMORY + Index);
90 }
91 abort();
92}
93
94template <typename T> class WasmPtr {
95 int Ptr;
96
97public:
98 WasmPtr(int Ptr) : Ptr(Ptr) {
99 // TODO (eholk): make this a static_assert once we have C++11
100 assert(sizeof(*this) == sizeof(int));
101 }
102
103 WasmPtr(T *Ptr) : Ptr(toWasm(Ptr)) {}
104
105 T &operator*() const { return *asPtr(); }
106
107 T *asPtr() const { return wasmPtr<T>(Ptr); }
108
109 int asInt() const { return Ptr; }
110};
111
112typedef WasmPtr<char> WasmCharPtr;
113
114template <typename T> class WasmArray {
115 int Ptr;
116
117public:
118 WasmArray(int Ptr) : Ptr(Ptr) {
119 // TODO (eholk): make this a static_assert once we have C++11.
120 assert(sizeof(*this) == sizeof(int));
121 }
122
123 T &operator[](unsigned int Index) const { return wasmPtr<T>(Ptr)[Index]; }
124};
125} // end of anonymous namespace
126
127// TODO (eholk): move the C parts outside and use C++ name mangling.
128extern "C" {
129
130void __Sz_bounds_fail() {
131 std::cerr << "Bounds check failure" << std::endl;
132 abort();
133}
134
135void __Sz_indirect_fail() {
136 std::cerr << "Invalid indirect call target" << std::endl;
137 abort();
138}
Eric Holk67c7c412016-04-15 13:05:37 -0700139
140void env$$abort() {
141 fprintf(stderr, "Aborting...\n");
142 abort();
143}
144
145void env$$_abort() { env$$abort(); }
146
Eric Holk87def2c2016-04-29 14:42:17 -0700147double env$$floor_f(float X) {
148 TRACE_ENTRY();
149 return env::floor(X);
150}
151double env$$floor_d(double X) {
152 TRACE_ENTRY();
153 return env::floor(X);
154}
Eric Holk29acb572016-04-22 09:34:41 -0700155
Eric Holk87def2c2016-04-29 14:42:17 -0700156void env$$exit(int Status) {
157 TRACE_ENTRY();
158 exit(Status);
159}
160void env$$_exit(int Status) {
161 TRACE_ENTRY();
162 env$$exit(Status);
163}
Eric Holk085bdae2016-04-18 15:08:19 -0700164
Eric Holk67c7c412016-04-15 13:05:37 -0700165#define UNIMPLEMENTED(f) \
166 void env$$##f() { \
167 fprintf(stderr, "Unimplemented: " #f "\n"); \
168 abort(); \
169 }
170
Eric Holk4aae81a2016-04-25 12:52:49 -0700171int32_t env$$sbrk(int32_t Increment) {
Eric Holk87def2c2016-04-29 14:42:17 -0700172 TRACE_ENTRY();
173 uint32_t OldBreak = HeapBreak;
Eric Holk4aae81a2016-04-25 12:52:49 -0700174 HeapBreak += Increment;
Eric Holk87def2c2016-04-29 14:42:17 -0700175 return trace(OldBreak);
Eric Holk4aae81a2016-04-25 12:52:49 -0700176}
177
Eric Holk87def2c2016-04-29 14:42:17 -0700178UNIMPLEMENTED(__addtf3)
Eric Holk085bdae2016-04-18 15:08:19 -0700179UNIMPLEMENTED(__assert_fail)
Eric Holk085bdae2016-04-18 15:08:19 -0700180UNIMPLEMENTED(__builtin_apply)
181UNIMPLEMENTED(__builtin_apply_args)
Eric Holk87def2c2016-04-29 14:42:17 -0700182UNIMPLEMENTED(__builtin_isinff)
183UNIMPLEMENTED(__builtin_isinfl)
184UNIMPLEMENTED(__builtin_malloc)
185UNIMPLEMENTED(__divtf3)
186UNIMPLEMENTED(__eqtf2)
187UNIMPLEMENTED(__extenddftf2)
188UNIMPLEMENTED(__extendsftf2)
189UNIMPLEMENTED(__fixsfti)
Eric Holk085bdae2016-04-18 15:08:19 -0700190UNIMPLEMENTED(__fixtfdi)
191UNIMPLEMENTED(__fixtfsi)
Eric Holk87def2c2016-04-29 14:42:17 -0700192UNIMPLEMENTED(__fixunstfsi)
193UNIMPLEMENTED(__floatditf)
194UNIMPLEMENTED(__floatsitf)
195UNIMPLEMENTED(__floatunsitf)
Eric Holk085bdae2016-04-18 15:08:19 -0700196UNIMPLEMENTED(__getf2)
Eric Holk87def2c2016-04-29 14:42:17 -0700197UNIMPLEMENTED(__letf2)
Eric Holk085bdae2016-04-18 15:08:19 -0700198UNIMPLEMENTED(__lttf2)
Eric Holk085bdae2016-04-18 15:08:19 -0700199UNIMPLEMENTED(__multf3)
200UNIMPLEMENTED(__multi3)
Eric Holk87def2c2016-04-29 14:42:17 -0700201UNIMPLEMENTED(__netf2)
202UNIMPLEMENTED(__subtf3)
Eric Holk29acb572016-04-22 09:34:41 -0700203UNIMPLEMENTED(__syscall140) // sys_llseek
Eric Holk87def2c2016-04-29 14:42:17 -0700204UNIMPLEMENTED(__syscall221) // sys_fcntl64
205UNIMPLEMENTED(__trunctfdf2)
206UNIMPLEMENTED(__trunctfsf2)
Eric Holk29acb572016-04-22 09:34:41 -0700207UNIMPLEMENTED(__unordtf2)
Eric Holk87def2c2016-04-29 14:42:17 -0700208UNIMPLEMENTED(longjmp)
209UNIMPLEMENTED(pthread_cleanup_pop)
210UNIMPLEMENTED(pthread_cleanup_push)
211UNIMPLEMENTED(pthread_self)
212UNIMPLEMENTED(setjmp)
Eric Holk67c7c412016-04-15 13:05:37 -0700213
Eric Holk87def2c2016-04-29 14:42:17 -0700214extern int __szwasm_main(int, WasmPtr<WasmCharPtr>);
Eric Holk67c7c412016-04-15 13:05:37 -0700215
Eric Holk87def2c2016-04-29 14:42:17 -0700216#define WASM_REF(Type, Index) (WasmPtr<Type>(Index).asPtr())
Eric Holk67c7c412016-04-15 13:05:37 -0700217#define WASM_DEREF(Type, Index) (*WASM_REF(Type, Index))
218
Eric Holk4aae81a2016-04-25 12:52:49 -0700219int main(int argc, const char **argv) {
Eric Holk87def2c2016-04-29 14:42:17 -0700220 // TODO (eholk): align these allocations correctly.
221
222 // Allocate space for the global data.
223 HeapBreak = WASM_DATA_SIZE;
224 GlobalData = WASM_REF(WasmData, HeapBreak);
225 HeapBreak += sizeof(WasmData);
226
227 // copy the command line arguments.
228 WasmPtr<WasmCharPtr> WasmArgV = HeapBreak;
229 WasmPtr<char> *WasmArgVPtr = WasmArgV.asPtr();
230 HeapBreak += argc * sizeof(*WasmArgVPtr);
231
232 for (int i = 0; i < argc; ++i) {
233 WasmArgVPtr[i] = HeapBreak;
234 strcpy(WASM_REF(char, HeapBreak), argv[i]);
235 HeapBreak += strlen(argv[i]) + 1;
236 }
237
Eric Holk4aae81a2016-04-25 12:52:49 -0700238 // Initialize the break to the nearest page boundary after the data segment
239 HeapBreak = (WASM_DATA_SIZE + PageSize - 1) & ~(PageSize - 1);
240
241 // Initialize the stack pointer.
242 WASM_DEREF(int32_t, StackPtrLoc) = WASM_NUM_PAGES << PageSizeLog2;
243
Eric Holk87def2c2016-04-29 14:42:17 -0700244 return __szwasm_main(argc, WasmArgV);
Eric Holk4aae81a2016-04-25 12:52:49 -0700245}
Eric Holk67c7c412016-04-15 13:05:37 -0700246
Eric Holk87def2c2016-04-29 14:42:17 -0700247int env$$abs(int a) {
248 TRACE_ENTRY();
249 return trace(abs(a));
250}
Eric Holk29acb572016-04-22 09:34:41 -0700251
Eric Holk87def2c2016-04-29 14:42:17 -0700252clock_t env$$clock() {
253 TRACE_ENTRY();
254 return trace(clock());
255}
256
257int env$$ctime(WasmPtr<time_t> Time) {
258 TRACE_ENTRY();
259 char *CTime = ctime(Time.asPtr());
260 strncpy(GlobalData->StrBuf, CTime, sizeof(GlobalData->StrBuf));
261 GlobalData->StrBuf[sizeof(GlobalData->StrBuf) - 1] = '\0';
262 return trace(WasmPtr<char>(GlobalData->StrBuf).asInt());
263}
264
265double env$$pow(double x, double y) {
266 TRACE_ENTRY();
267 return trace(pow(x, y));
268}
269
270time_t env$$time(WasmPtr<time_t> Time) {
271 TRACE_ENTRY();
272 time_t *TimePtr = WASM_REF(time_t, Time);
273 return trace(time(TimePtr));
274}
275
276// lock and unlock are no-ops in wasm.js, so we mimic that behavior.
277void env$$__lock(int32_t) {
278 TRACE_ENTRY();
279 trace();
280}
281
282void env$$__unlock(int32_t) {
283 TRACE_ENTRY();
284 trace();
285}
286
287/// sys_read
288int env$$__syscall3(int Which, WasmArray<int> VarArgs) {
289 TRACE_ENTRY();
290 int Fd = VarArgs[0];
291 int Buffer = VarArgs[1];
292 int Length = VarArgs[2];
293
294 return trace(read(Fd, WASM_REF(char *, Buffer), Length));
295}
Eric Holk29acb572016-04-22 09:34:41 -0700296
Eric Holk67c7c412016-04-15 13:05:37 -0700297/// sys_write
Eric Holk87def2c2016-04-29 14:42:17 -0700298int env$$__syscall4(int Which, WasmArray<int> VarArgs) {
299 TRACE_ENTRY();
300 int Fd = VarArgs[0];
301 int Buffer = VarArgs[1];
302 int Length = VarArgs[2];
Eric Holk67c7c412016-04-15 13:05:37 -0700303
Eric Holk87def2c2016-04-29 14:42:17 -0700304 return trace(write(Fd, WASM_REF(char *, Buffer), Length));
Eric Holk67c7c412016-04-15 13:05:37 -0700305}
306
Eric Holk085bdae2016-04-18 15:08:19 -0700307/// sys_open
Eric Holk87def2c2016-04-29 14:42:17 -0700308int env$$__syscall5(int Which, WasmArray<int> VarArgs) {
309 TRACE_ENTRY();
310 int WasmPath = VarArgs[0];
311 int Flags = VarArgs[1];
312 int Mode = VarArgs[2];
Eric Holk085bdae2016-04-18 15:08:19 -0700313 const char *Path = WASM_REF(char, WasmPath);
314
Eric Holk87def2c2016-04-29 14:42:17 -0700315 return trace(open(Path, Flags, Mode));
316}
Eric Holk085bdae2016-04-18 15:08:19 -0700317
Eric Holk87def2c2016-04-29 14:42:17 -0700318/// sys_close
319int env$$__syscall6(int Which, WasmArray<int> VarArgs) {
320 TRACE_ENTRY();
321 int Fd = VarArgs[0];
322
323 return trace(close(Fd));
324}
325
326/// sys_unlink
327int env$$__syscall10(int Which, WasmArray<int> VarArgs) {
328 TRACE_ENTRY();
329 int WasmPath = VarArgs[0];
330 const char *Path = WASM_REF(char, WasmPath);
331
332 return trace(unlink(Path));
Eric Holk085bdae2016-04-18 15:08:19 -0700333}
334
Eric Holk29acb572016-04-22 09:34:41 -0700335/// sys_getpid
Eric Holk87def2c2016-04-29 14:42:17 -0700336int env$$__syscall20(int Which, WasmArray<int> VarArgs) {
337 TRACE_ENTRY();
Eric Holk29acb572016-04-22 09:34:41 -0700338 (void)Which;
339 (void)VarArgs;
340
Eric Holk87def2c2016-04-29 14:42:17 -0700341 return trace(getpid());
342}
343
344/// sys_rmdir
345int env$$__syscall40(int Which, WasmArray<int> VarArgs) {
346 TRACE_ENTRY();
347 int WasmPath = VarArgs[0];
348 const char *Path = WASM_REF(char, WasmPath);
349
350 return trace(rmdir(Path));
Eric Holk29acb572016-04-22 09:34:41 -0700351}
352
Eric Holk67c7c412016-04-15 13:05:37 -0700353/// sys_ioctl
Eric Holk87def2c2016-04-29 14:42:17 -0700354int env$$__syscall54(int Which, WasmArray<int> VarArgs) {
355 TRACE_ENTRY();
356 int Fd = VarArgs[0];
357 int Op = VarArgs[1];
358 int ArgP = VarArgs[2];
359
360 switch (Op) {
361 case TCGETS: {
362 // struct termios has no pointers. Otherwise, we'd have to rewrite them.
363 struct termios *TermIOS = WASM_REF(struct termios, ArgP);
364 return trace(ioctl(Fd, TCGETS, TermIOS));
365 }
366 default:
367 // TODO (eholk): implement more ioctls
368 return trace(-ENOTTY);
369 }
Eric Holk67c7c412016-04-15 13:05:37 -0700370}
371
Eric Holk87def2c2016-04-29 14:42:17 -0700372struct IoVec {
373 WasmPtr<char> Ptr;
374 int Length;
375};
Eric Holk67c7c412016-04-15 13:05:37 -0700376
Eric Holk87def2c2016-04-29 14:42:17 -0700377/// sys_readv
378int env$$__syscall145(int Which, WasmArray<int> VarArgs) {
379 TRACE_ENTRY();
380 int Fd = VarArgs[0];
381 WasmArray<IoVec> Iov = VarArgs[1];
382 int Iovcnt = VarArgs[2];
Eric Holk67c7c412016-04-15 13:05:37 -0700383
Eric Holk67c7c412016-04-15 13:05:37 -0700384 int Count = 0;
385
386 for (int I = 0; I < Iovcnt; ++I) {
Eric Holk87def2c2016-04-29 14:42:17 -0700387 int Curr = read(Fd, Iov[I].Ptr.asPtr(), Iov[I].Length);
Eric Holk67c7c412016-04-15 13:05:37 -0700388
Eric Holk67c7c412016-04-15 13:05:37 -0700389 if (Curr < 0) {
Eric Holk87def2c2016-04-29 14:42:17 -0700390 return trace(-1);
Eric Holk67c7c412016-04-15 13:05:37 -0700391 }
392 Count += Curr;
393 }
Eric Holk87def2c2016-04-29 14:42:17 -0700394 return trace(Count);
395}
396
397/// sys_writev
398int env$$__syscall146(int Which, WasmArray<int> VarArgs) {
399 TRACE_ENTRY();
400 int Fd = VarArgs[0];
401 WasmArray<IoVec> Iov = VarArgs[1];
402 int Iovcnt = VarArgs[2];
403
404 int Count = 0;
405
406 for (int I = 0; I < Iovcnt; ++I) {
407 int Curr = write(Fd, Iov[I].Ptr.asPtr(), Iov[I].Length);
408
409 if (Curr < 0) {
410 return trace(-1);
411 }
412 Count += Curr;
413 }
414 return trace(Count);
Eric Holk67c7c412016-04-15 13:05:37 -0700415}
Eric Holk4aae81a2016-04-25 12:52:49 -0700416
417/// sys_mmap_pgoff
Eric Holk87def2c2016-04-29 14:42:17 -0700418int env$$__syscall192(int Which, WasmArray<int> VarArgs) {
419 TRACE_ENTRY();
Eric Holk4aae81a2016-04-25 12:52:49 -0700420 (void)Which;
421 (void)VarArgs;
422
423 // TODO (eholk): figure out how to implement this.
424
Eric Holk87def2c2016-04-29 14:42:17 -0700425 return trace(-ENOMEM);
Eric Holk4aae81a2016-04-25 12:52:49 -0700426}
Eric Holk29acb572016-04-22 09:34:41 -0700427} // end of extern "C"