Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(809)

Side by Side Diff: runtime/wasm-runtime.cpp

Issue 1918213003: Subzero, Wasm: Dynamically reallocate read buffer. Runtime improvements. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Code review changes Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pydir/wasm-run-torture-tests.py ('k') | src/IceCompiler.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 //===- subzero/runtime/wasm-runtime.cpp - Subzero WASM runtime source -----===// 1 //===- subzero/runtime/wasm-runtime.cpp - Subzero WASM runtime source -----===//
2 // 2 //
3 // The Subzero Code Generator 3 // The Subzero Code Generator
4 // 4 //
5 // This file is distributed under the University of Illinois Open Source 5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details. 6 // License. See LICENSE.TXT for details.
7 // 7 //
8 //===----------------------------------------------------------------------===// 8 //===----------------------------------------------------------------------===//
9 // 9 //
10 // This file implements the system calls required by the libc that is included 10 // This file implements the system calls required by the libc that is included
11 // in WebAssembly programs. 11 // in WebAssembly programs.
12 // 12 //
13 //===----------------------------------------------------------------------===// 13 //===----------------------------------------------------------------------===//
14 14
15 #include <cassert> 15 #include <cassert>
16 #include <cmath> 16 #include <cmath>
17 // TODO (eholk): change to cstdint 17 #include <errno.h>
18 #include <fcntl.h>
19 #include <iostream>
20 #include <math.h>
18 #include <stdint.h> 21 #include <stdint.h>
22 #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__ << "(...) = "; }
35 template <typename T> T trace(T x) {
36 std::cerr << x << std::endl;
37 return x;
38 }
39 void trace() { std::cerr << "(void)" << std::endl; }
40 #else
41 #define TRACE_ENTRY()
42 template <typename T> T trace(T x) { return x; }
43 void trace() {}
44 #endif // WASM_TRACE_RUNTIME
45
46 extern "C" {
47 extern char WASM_MEMORY[];
48 extern uint32_t WASM_DATA_SIZE;
49 extern uint32_t WASM_NUM_PAGES;
50 } // end of extern "C"
19 51
20 namespace { 52 namespace {
21 uint32_t HeapBreak; 53 uint32_t HeapBreak;
22 54
23 // TODO (eholk): make all of these constexpr. 55 // TODO (eholk): make all of these constexpr.
24 const uint32_t PageSizeLog2 = 16; 56 const uint32_t PageSizeLog2 = 16;
25 const uint32_t PageSize = 1 << PageSizeLog2; // 64KB 57 const uint32_t PageSize = 1 << PageSizeLog2; // 64KB
26 const uint32_t StackPtrLoc = 1024; // defined by emscripten 58 const uint32_t StackPtrLoc = 1024; // defined by emscripten
27 59
28 uint32_t pageNum(uint32_t Index) { return Index >> PageSizeLog2; } 60 uint32_t pageNum(uint32_t Index) { return Index >> PageSizeLog2; }
29 } // end of anonymous namespace 61 } // end of anonymous namespace
30 62
31 namespace env { 63 namespace env {
32 double floor(double X) { return std::floor(X); } 64 double floor(double X) { return std::floor(X); }
33 65
34 float floor(float X) { return std::floor(X); } 66 float floor(float X) { return std::floor(X); }
35 } // end of namespace env 67 } // end of namespace env
36 68
37 // TODO (eholk): move the C parts outside and use C++ name mangling. 69 // TODO (eholk): move the C parts outside and use C++ name mangling.
70
71 namespace {
72
73 /// Some runtime functions need to return pointers. The WasmData struct is used
74 /// to preallocate space for these on the heap.
75 struct WasmData {
76
77 /// StrBuf is returned by functions that return strings.
78 char StrBuf[256];
79 };
80
81 WasmData *GlobalData = NULL;
82
83 int toWasm(void *Ptr) {
84 return reinterpret_cast<int>(reinterpret_cast<char *>(Ptr) - WASM_MEMORY);
85 }
86
87 template <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
94 template <typename T> class WasmPtr {
95 int Ptr;
96
97 public:
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
112 typedef WasmPtr<char> WasmCharPtr;
113
114 template <typename T> class WasmArray {
115 int Ptr;
116
117 public:
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.
38 extern "C" { 128 extern "C" {
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <math.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <unistd.h>
48 129
49 extern char WASM_MEMORY[]; 130 void __Sz_bounds_fail() {
50 extern uint32_t WASM_DATA_SIZE; 131 std::cerr << "Bounds check failure" << std::endl;
51 extern uint32_t WASM_NUM_PAGES; 132 abort();
133 }
134
135 void __Sz_indirect_fail() {
136 std::cerr << "Invalid indirect call target" << std::endl;
137 abort();
138 }
52 139
53 void env$$abort() { 140 void env$$abort() {
54 fprintf(stderr, "Aborting...\n"); 141 fprintf(stderr, "Aborting...\n");
55 abort(); 142 abort();
56 } 143 }
57 144
58 void env$$_abort() { env$$abort(); } 145 void env$$_abort() { env$$abort(); }
59 146
60 double env$$floor_f(float X) { return env::floor(X); } 147 double env$$floor_f(float X) {
61 double env$$floor_d(double X) { return env::floor(X); } 148 TRACE_ENTRY();
149 return env::floor(X);
150 }
151 double env$$floor_d(double X) {
152 TRACE_ENTRY();
153 return env::floor(X);
154 }
62 155
63 void env$$exit(int Status) { exit(Status); } 156 void env$$exit(int Status) {
64 void env$$_exit(int Status) { env$$exit(Status); } 157 TRACE_ENTRY();
158 exit(Status);
159 }
160 void env$$_exit(int Status) {
161 TRACE_ENTRY();
162 env$$exit(Status);
163 }
65 164
66 #define UNIMPLEMENTED(f) \ 165 #define UNIMPLEMENTED(f) \
67 void env$$##f() { \ 166 void env$$##f() { \
68 fprintf(stderr, "Unimplemented: " #f "\n"); \ 167 fprintf(stderr, "Unimplemented: " #f "\n"); \
69 abort(); \ 168 abort(); \
70 } 169 }
71 170
72 int32_t env$$sbrk(int32_t Increment) { 171 int32_t env$$sbrk(int32_t Increment) {
172 TRACE_ENTRY();
173 uint32_t OldBreak = HeapBreak;
73 HeapBreak += Increment; 174 HeapBreak += Increment;
74 return HeapBreak; 175 return trace(OldBreak);
75 } 176 }
76 177
77 UNIMPLEMENTED(setjmp) 178 UNIMPLEMENTED(__addtf3)
78 UNIMPLEMENTED(longjmp)
79 UNIMPLEMENTED(__assert_fail) 179 UNIMPLEMENTED(__assert_fail)
80 UNIMPLEMENTED(__builtin_malloc) 180 UNIMPLEMENTED(__builtin_apply)
181 UNIMPLEMENTED(__builtin_apply_args)
81 UNIMPLEMENTED(__builtin_isinff) 182 UNIMPLEMENTED(__builtin_isinff)
82 UNIMPLEMENTED(__builtin_isinfl) 183 UNIMPLEMENTED(__builtin_isinfl)
83 UNIMPLEMENTED(__builtin_apply) 184 UNIMPLEMENTED(__builtin_malloc)
84 UNIMPLEMENTED(__builtin_apply_args) 185 UNIMPLEMENTED(__divtf3)
85 UNIMPLEMENTED(pthread_cleanup_push) 186 UNIMPLEMENTED(__eqtf2)
86 UNIMPLEMENTED(pthread_cleanup_pop) 187 UNIMPLEMENTED(__extenddftf2)
87 UNIMPLEMENTED(pthread_self) 188 UNIMPLEMENTED(__extendsftf2)
189 UNIMPLEMENTED(__fixsfti)
190 UNIMPLEMENTED(__fixtfdi)
191 UNIMPLEMENTED(__fixtfsi)
192 UNIMPLEMENTED(__fixunstfsi)
88 UNIMPLEMENTED(__floatditf) 193 UNIMPLEMENTED(__floatditf)
89 UNIMPLEMENTED(__floatsitf) 194 UNIMPLEMENTED(__floatsitf)
90 UNIMPLEMENTED(__fixtfdi) 195 UNIMPLEMENTED(__floatunsitf)
91 UNIMPLEMENTED(__fixtfsi)
92 UNIMPLEMENTED(__fixsfti)
93 UNIMPLEMENTED(__netf2)
94 UNIMPLEMENTED(__getf2) 196 UNIMPLEMENTED(__getf2)
95 UNIMPLEMENTED(__eqtf2) 197 UNIMPLEMENTED(__letf2)
96 UNIMPLEMENTED(__lttf2) 198 UNIMPLEMENTED(__lttf2)
97 UNIMPLEMENTED(__addtf3)
98 UNIMPLEMENTED(__subtf3)
99 UNIMPLEMENTED(__divtf3)
100 UNIMPLEMENTED(__multf3) 199 UNIMPLEMENTED(__multf3)
101 UNIMPLEMENTED(__multi3) 200 UNIMPLEMENTED(__multi3)
102 UNIMPLEMENTED(__lock) 201 UNIMPLEMENTED(__netf2)
103 UNIMPLEMENTED(__unlock) 202 UNIMPLEMENTED(__subtf3)
104 UNIMPLEMENTED(__syscall6) // sys_close
105 UNIMPLEMENTED(__syscall140) // sys_llseek 203 UNIMPLEMENTED(__syscall140) // sys_llseek
204 UNIMPLEMENTED(__syscall221) // sys_fcntl64
205 UNIMPLEMENTED(__trunctfdf2)
206 UNIMPLEMENTED(__trunctfsf2)
106 UNIMPLEMENTED(__unordtf2) 207 UNIMPLEMENTED(__unordtf2)
107 UNIMPLEMENTED(__fixunstfsi) 208 UNIMPLEMENTED(longjmp)
108 UNIMPLEMENTED(__floatunsitf) 209 UNIMPLEMENTED(pthread_cleanup_pop)
109 UNIMPLEMENTED(__extenddftf2) 210 UNIMPLEMENTED(pthread_cleanup_push)
110 211 UNIMPLEMENTED(pthread_self)
111 void *wasmPtr(uint32_t Index) { 212 UNIMPLEMENTED(setjmp)
112 if (pageNum(Index) < WASM_NUM_PAGES) { 213
113 return WASM_MEMORY + Index; 214 extern int __szwasm_main(int, WasmPtr<WasmCharPtr>);
114 } 215
115 abort(); 216 #define WASM_REF(Type, Index) (WasmPtr<Type>(Index).asPtr())
116 }
117
118 extern int __szwasm_main(int, const char **);
119
120 #define WASM_REF(Type, Index) ((Type *)wasmPtr(Index))
121 #define WASM_DEREF(Type, Index) (*WASM_REF(Type, Index)) 217 #define WASM_DEREF(Type, Index) (*WASM_REF(Type, Index))
122 218
123 int main(int argc, const char **argv) { 219 int main(int argc, const char **argv) {
220 // 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
124 // Initialize the break to the nearest page boundary after the data segment 238 // Initialize the break to the nearest page boundary after the data segment
125 HeapBreak = (WASM_DATA_SIZE + PageSize - 1) & ~(PageSize - 1); 239 HeapBreak = (WASM_DATA_SIZE + PageSize - 1) & ~(PageSize - 1);
126 240
127 // Initialize the stack pointer. 241 // Initialize the stack pointer.
128 WASM_DEREF(int32_t, StackPtrLoc) = WASM_NUM_PAGES << PageSizeLog2; 242 WASM_DEREF(int32_t, StackPtrLoc) = WASM_NUM_PAGES << PageSizeLog2;
129 243
130 return __szwasm_main(argc, argv); 244 return __szwasm_main(argc, WasmArgV);
131 } 245 }
132 246
133 int env$$abs(int a) { return abs(a); } 247 int env$$abs(int a) {
134 248 TRACE_ENTRY();
135 double env$$pow(double x, double y) { return pow(x, y); } 249 return trace(abs(a));
250 }
251
252 clock_t env$$clock() {
253 TRACE_ENTRY();
254 return trace(clock());
255 }
256
257 int 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
265 double env$$pow(double x, double y) {
266 TRACE_ENTRY();
267 return trace(pow(x, y));
268 }
269
270 time_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.
277 void env$$__lock(int32_t) {
278 TRACE_ENTRY();
279 trace();
280 }
281
282 void env$$__unlock(int32_t) {
283 TRACE_ENTRY();
284 trace();
285 }
286
287 /// sys_read
288 int 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 }
136 296
137 /// sys_write 297 /// sys_write
138 int env$$__syscall4(int Which, int VarArgs) { 298 int env$$__syscall4(int Which, WasmArray<int> VarArgs) {
139 int Fd = WASM_DEREF(int, VarArgs + 0 * sizeof(int)); 299 TRACE_ENTRY();
140 int Buffer = WASM_DEREF(int, VarArgs + 1 * sizeof(int)); 300 int Fd = VarArgs[0];
141 int Length = WASM_DEREF(int, VarArgs + 2 * sizeof(int)); 301 int Buffer = VarArgs[1];
142 302 int Length = VarArgs[2];
143 return write(Fd, WASM_REF(char *, Buffer), Length); 303
304 return trace(write(Fd, WASM_REF(char *, Buffer), Length));
144 } 305 }
145 306
146 /// sys_open 307 /// sys_open
147 int env$$__syscall5(int Which, int VarArgs) { 308 int env$$__syscall5(int Which, WasmArray<int> VarArgs) {
148 int WasmPath = WASM_DEREF(int, VarArgs); 309 TRACE_ENTRY();
149 int Flags = WASM_DEREF(int, VarArgs + 4); 310 int WasmPath = VarArgs[0];
150 int Mode = WASM_DEREF(int, VarArgs + 8); 311 int Flags = VarArgs[1];
312 int Mode = VarArgs[2];
151 const char *Path = WASM_REF(char, WasmPath); 313 const char *Path = WASM_REF(char, WasmPath);
152 314
153 fprintf(stderr, "sys_open(%s, %d, %d)\n", Path, Flags, Mode); 315 return trace(open(Path, Flags, Mode));
154 316 }
155 return open(Path, Flags, Mode); 317
318 /// sys_close
319 int 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
327 int 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));
156 } 333 }
157 334
158 /// sys_getpid 335 /// sys_getpid
159 int env$$__syscall20(int Which, int VarArgs) { 336 int env$$__syscall20(int Which, WasmArray<int> VarArgs) {
337 TRACE_ENTRY();
160 (void)Which; 338 (void)Which;
161 (void)VarArgs; 339 (void)VarArgs;
162 340
163 return getpid(); 341 return trace(getpid());
342 }
343
344 /// sys_rmdir
345 int 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));
164 } 351 }
165 352
166 /// sys_ioctl 353 /// sys_ioctl
167 int env$$__syscall54(int A, int B) { 354 int env$$__syscall54(int Which, WasmArray<int> VarArgs) {
168 int Fd = WASM_DEREF(int, B + 0 * sizeof(int)); 355 TRACE_ENTRY();
169 int Op = WASM_DEREF(int, B + 1 * sizeof(int)); 356 int Fd = VarArgs[0];
170 int ArgP = WASM_DEREF(int, B + 2 * sizeof(int)); 357 int Op = VarArgs[1];
171 // TODO (eholk): implement sys_ioctl 358 int ArgP = VarArgs[2];
172 return -ENOTTY; 359
173 } 360 switch (Op) {
174 361 case TCGETS: {
175 /// sys_write 362 // struct termios has no pointers. Otherwise, we'd have to rewrite them.
176 int env$$__syscall146(int Which, int VarArgs) { 363 struct termios *TermIOS = WASM_REF(struct termios, ArgP);
177 364 return trace(ioctl(Fd, TCGETS, TermIOS));
178 int Fd = WASM_DEREF(int, VarArgs); 365 }
179 int Iov = WASM_DEREF(int, VarArgs + sizeof(int)); 366 default:
180 int Iovcnt = WASM_DEREF(int, VarArgs + 2 * sizeof(int)); 367 // TODO (eholk): implement more ioctls
368 return trace(-ENOTTY);
369 }
370 }
371
372 struct IoVec {
373 WasmPtr<char> Ptr;
374 int Length;
375 };
376
377 /// sys_readv
378 int 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];
181 383
182 int Count = 0; 384 int Count = 0;
183 385
184 for (int I = 0; I < Iovcnt; ++I) { 386 for (int I = 0; I < Iovcnt; ++I) {
185 void *Ptr = WASM_REF(void, WASM_DEREF(int, Iov + I * 8)); 387 int Curr = read(Fd, Iov[I].Ptr.asPtr(), Iov[I].Length);
186 int Length = WASM_DEREF(int, Iov + I * 8 + 4);
187
188 int Curr = write(Fd, Ptr, Length);
189 388
190 if (Curr < 0) { 389 if (Curr < 0) {
191 return -1; 390 return trace(-1);
192 } 391 }
193 Count += Curr; 392 Count += Curr;
194 } 393 }
195 return Count; 394 return trace(Count);
395 }
396
397 /// sys_writev
398 int 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);
196 } 415 }
197 416
198 /// sys_mmap_pgoff 417 /// sys_mmap_pgoff
199 int env$$__syscall192(int Which, int VarArgs) { 418 int env$$__syscall192(int Which, WasmArray<int> VarArgs) {
419 TRACE_ENTRY();
200 (void)Which; 420 (void)Which;
201 (void)VarArgs; 421 (void)VarArgs;
202 422
203 // TODO (eholk): figure out how to implement this. 423 // TODO (eholk): figure out how to implement this.
204 424
205 return -ENOMEM; 425 return trace(-ENOMEM);
206 } 426 }
207 } // end of extern "C" 427 } // end of extern "C"
OLDNEW
« no previous file with comments | « pydir/wasm-run-torture-tests.py ('k') | src/IceCompiler.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698