>> Mark Marron: So I think we’re ready to get started here, so it’s my pleasure to introduce John Vilk today. I think a lot of you know him; he’s kind of becoming a regular here, done internships the last two summers now, so it’s good. He—you know—he’s also a PhD student at UMass Amherst with Emery Berger, where he’s done the work that he’s gonna be talking about today. It was presented at PLDI last year; it was a SIGPLAN Highlight Award there. So it’s really exciting; I think it’s pretty cool; and I’ll just give it to John to tell you exactly what it is. >> John Vilk: Thanks Mark. So this work is joint work with Emery, so let’s just get right to it. So as many of you are aware, there are a number of programming languages out there. So for example, we have Java, Python, and Ruby. And it turns out that there are actually a lot of useful programs and libraries that are already written in these languages, but unfortunately, there’s only one language that runs across all of the browsers, and that’s JavaScript. Wouldn’t it be nice if we could just take our existing, well-tested programs and libraries and run them in the browser with no modifications? So to motivate this problem, I’ll be discussing a nonexistent text chat client written in Java, as it illustrates the challenges of bringing conventional languages and their programs into the browser. So our theoretical, nonexistent chat client lets you connect to multiple chat servers at once; it logs your chats as text files; and encapsulates each server connection in its own thread. What we would like to do is take this Java chat client and run it in the browser with no modifications whatsoever. How might we go about doing this? Now, you might reasonably expect that you could simply take the Java source code of the client and just recompile it somehow into JavaScript, but unfortunately, this turns out to be infeasible for a number of reasons. So for the first part of my talk, I’m going to discuss why this is the case. The first problem has to do with the nature of Java itself. Java is a dynamic language; performing aheadof-time compilation on Java code will rule out dynamic class-loading and many parts of the Java reflection API. The second problem is a bit more fundamental. Our chat client uses multiple threads, all inhabiting the same address space, but JavaScript does not support threads; instead, it supports workers. These workers do not inhabit the same address space, and they can’t share memory with each other. So instead, they communicate by sending messages. So we can’t simply map threads directly to workers, which poses a challenge to bringing our chat client to the web. Our chat client uses TCP sockets to communicate with the chat servers. The browser doesn’t have support for TCP sockets; instead, it supports WebSockets, which is a protocol implemented on top of TCP. As a result, our chat client will not be able to communicate with the chat servers, which expect a regular TCP connection. To log chats, the chat client writes text files into the file system, as you would expect, but the browser doesn’t have a file system. Instead, it has a variety of other mechanisms for storing data, which are unevenly supported across all the different browsers, and they also have a variety of restrictions. One of these does use a file system abstraction, but it is asynchronous and does not support blocking operations, and I’ll explain the importance of this little detail in a little bit. Unbeknownst to our chat program, under the covers, the Java chat… Java class library—which has things like the string class and all the other things that Java clients… Java programs take advantage of—it performs a number of unsafe operations using explicit memory allocation, requiring an unmanaged heap, but the browser doesn’t offer a mechanism for explicit memory allocation. And I want to note here, carefully, that I’m not complaining about this; this is actually good, but I’m just stating a fact: it’s not there and it’s… something needs to be there. So the chat client requires all these components in order to function properly. So if we want to run our chat client in the browser, we need to somehow emulate all of these resources in the browser. But there’s another challenge to doing this, and that’s browser diversity. We’re not just trying to bring our chat client into one browser—such as Google Chrome, or Opera, or something like that—we’re actually trying to bring it into multiple browsers, which unevenly implement the various web standards we need to use in order to implement all of these missing abstractions. But there also isn’t just one version of every browser out there; there’s actually multiple major versions in use at any given time. And there are additional differences, too—there’s differences between desktop, tablet, mobile, et cetera—and this becomes a major obstacle to bringing the resources that the chat client needs into the browser, and I can illustrate this with an example. Also, I want to pause for a second: if anyone has any questions along the way, feel free to interrupt me and let me know, ‘cause I’ll be happy to answer them. So let’s ignore the version differences to simplify this discussion a bit, and we’ll focus on the latest version of each browser. As I mentioned earlier, our chat client needs to write log files into a… some sort of file system, but… and there are a few persistent storage mechanisms available in the browser that we could use to emulate the file system. First, all browsers implement a simple key-value store that gives programs a paltry five megabytes of storage. Safari allows web pages to store larger amounts of data into a SQL database. Chrome and Opera offer the same functionality, but they do not persist a database; it is temporary storage. Firefox and Internet Explorer allow web pages to persist data in an object database. And once again, Chrome and Opera, they put it into temporary storage; they don’t persist it; and Internet Explorer’s version is not fully spec-compliant. And then finally, we have the HTML5 file system, which is primarily used in WebKit browsers, so only Chrome and Opera support this interface. And so the takeaway is this: if our chat client wants to persist more than five megabytes of logs in the browser and cares about browser compatibility, then it needs to support three completely different storage interfaces. SQL database, an object database… Yep? >>: So I thought index.db… is persistent among all browsers now, right? >> John Vilk: So it’s in, like, temporary storage, so it’s shared between… there’s like a pool of storage that’s shared among all, like, web pages, and then if you exceed… if that, like, pool fills up, it’ll just knock out the last thing in the storage. So it’s not totally persistent. >>: That’s horrible. >> John Vilk: Yep? >>: Safari’s not WebKit-based. >> John Vilk: Oh, sorry, I meant to say Blink-based, yeah. For some reason, even though it’s in the WebKit sources, Safari didn’t have it. It may have it now, but I haven’t checked recently, but I suspect it has the same restrictions as the other ones. Okay. So yeah, this is painful, ‘cause these are all completely different interfaces. So that’s one challenge; another challenge is the event-driven runtime model in JavaScript, so this results in pervasive asynchrony in all JavaScript code. So in particular, JavaScript I/O requires callbacks, which proves to be painful to bringing conventional languages into the browser. Let’s walk through an example, just to make this very clear. So our chat client needs to periodically send a ping command to the chat server to ensure its connection is alive, and waits for a pong response. We’ll walk through the code in Java, and then we’ll try to directly translate it to JavaScript. Let’s say that somewhere in our main method, the chat client fires off of a… fires off a ping. So the sendPing function might look something like this, but I want to note that I’m simplifying this for presentation purposes; I realize this is not totally valid code. On the first line, the chat client writes the ping command on the socket to the server, then it issues a blocking read to wait for a response. Finally, once the pong comes back, it returns the data that it read off the wire, and our chat client continues on its merry way. We’ll try to do this… oh, yep? >>: A question on your Java code: the way you present it makes it read like it’s completely synchronous and will block until the response arrives. >> John Vilk: Yes. >>: Is that what your client does, or is there another subtlety linked to the presence of a UI thread running in parallel or something? >> John Vilk: So this is what, like, this theoretical nonexistent chat client does, and this is actually what a lot of Java programs do; they do completely synchronous operations on sockets. What was your other question? >>: So the Java client, if it blocks—like if the network is stuck or something—that means the UI—the user interface—is going to be frozen for the duration of the read call on the socket, right? >> John Vilk: In JavaScript, if you were to naïvely map it into JavaScript, that is the case; the way that we deal with it in Doppio means that that does not happen. I’ll describe how that works in a little bit, but the way that it works in Doppio is that we’re able to have the same effect as a synchronous call from… in the… from the Java perspective. But from the JavaScript perspective, that call is actually asynchronous and causes things to wind down, so the GUI does have a chance to repaint, and everything stays responsive. And that… but you raise a good point. That’s actually the key issue I’m trying to hammer home here, ‘cause a lot of people aren’t familiar with JavaScript or the browser, and they might be very surprised to see that some synchronous I/O would actually block the GUI and cause things not to render properly. So let’s see if we can translate this into JavaScript somehow. So like before, the main function fires off a call to sendPing, and sendPing sends a ping command on the WebSocket like before. But then we need to assign a callback function on the socket object, which the browser will call once it receives data from the chat server, but here, we have a problem. The main function expects that sendPing will return the response from the server, but sendPing does not have the response yet. It needs to wait for the browser to call the callback we just registered. What do we have to do here to return the value that main expects? JavaScript doesn’t have a sleep function that we can use to suspend execution and persist the activation records on the call stack for sendPing and main. If we try to busy-wait, and the server does send the WebSocket message to the browser, it will end up in the browser event queue, which the program has no access to. This is also where mouse clicks, timer fires, and other events queue up, including repainting the browser window while JavaScript is executing. In addition, if we try to busy-wait, the browser will try to kill our script, because we are blocking progress in the browser event queue. One result of this is that JavaScript programs have no choice but to execute in some sort of continuation-passing style, where they periodically yield to the browser event queue by scheduling the next phase of the program to occur as a new event. In any case, the only way to unblock the browser event queue and receive the WebSocket message that is queued up in there is to empty the JavaScript call stack, which means we have to return from sendPing, and then we have to return from main. Now the JavaScript call stack is empty, and the browser will fire its next event, which triggers our callback. But now, we have completely disrupted the program, and we have no way to get this data back to main. If we wanted to port the Java code to JavaScript, the program would need to be completely restructured into continuation-passing style to allow for breaks in execution for callbacks to execute. This is not what… this is just a fundamental requirement here. So I’ve discussed these challenges, and I want to describe how the Doppio runtime system overcomes them. Yes? >>: I have a question about the file system. Why… another alternative would be to use a file system in the cloud, and just have a local cache. Why don’t you want to explore that possibility? >> John Vilk: Oh, I’m not limiting to that, in fact, when I describe it later, our file system does support Dropbox cloud storage, but in that case, it’s still going to be asynchronous, so it’s doesn’t… isn’t going to support blocking operations. >>: Oh yeah, I just mean instead of having to support the three different… you could just use the heap. >> John Vilk: It’s true. Yeah, you could do that. But the thing is you also have limited local caching, because you have to cache to something local in the browser, and so then you’re back… you’re stuck back to the original problem. You have those four different interfaces, one of which is supported everywhere, but only gives you five megabytes of cache and… >>: Assume you’re caching on disk and not memory. >>: Right. You could cache the memory and… >> John Vilk: Yeah, you can cache and memory, but if want to persist it… if you’re a web application— right—and you want to a make sure that the caching persists across reloads—if you have, like, a large amount of data, and you want to cache—you don’t want to grab it off the wire every time, then you have these very limited storage options that are everywhere and then these better ones that support large files that are completely separate; I need to support all of them to have full coverage. So that’s like a huge issue there. Yep? Sure. >>: So the limits are for storage. If you do the cloud-based option, and then you just load in the data as JavaScript files, you could presumably exceed those limits. >> John Vilk: Yes, but what I was saying is that if you wanted to cache them, so you avoid… yeah >>: I’m saying you can cache them that way. >> John Vilk: Right and wrong. >>: So when you… the next time you load the app, it loads a big-ass JavaScript file with all of the stuff that you wanted cached. JavaScript gets cached over the five… that five megabit limit… or megabyte limit. >> John Vilk: That’s true, but you don’t control the semantics of that, so you don’t really know when the cache will be empty and such like that. But you’re right in that you can piggyback on the browser’s existing caching mechanism—which works for scripts, images, et cetera—to cache your assets. You’re correct there, but you also don’t exactly control the semantics of that, so you don’t know when that will be emptied and stuff like that. But I suspect in a lot of cases that might be good. >>: I don’t you ever fully control it, ‘cause the user can empty their web history at any time. >> John Vilk: That’s true. Yep? >>: Just this comment, I guess; I mean, if you are mapping from a model that’s synchronous and that’s—you know—I mean, pretty much what you described [indiscernible] and so on and so forth— right—so you have a fundamental mismatch, as opposed to having something that’s a promise-based and… I mean, could still be Java—right—it’s just so talk about the programing style and frameworks one uses. So any thoughts on that, I mean as far as the… of closing the gap, if you will, in terms of the programming paradigm? >> John Vilk: So it sounds like what you’re suggesting would eliminate the ability to run existing programs that are already written in, like, the blocking style. Is that correct? >>: Yeah, it would. >> John Vilk: Yeah. So if you wanted to go that route, there’s already things like Google Web Toolkit and things like that that work for things that you write programs in JavaScript style, where you write things with callbacks, and you write things so that they carefully manage how long they execute so that they don’t block the browser. But if you have existing code, then you have no… you’d have to rewrite all of it, essentially, to get it to run in the browser. And so our… that’s our pain point here that we’re trying to address. We don’t want people to have to port gigantic applications like javac or things like that to get them to work in the browser. Okay, so I guess I’ll continue, and again, feel free to interrupt me in the future if you have any further questions. So now… I’ve discussed these challenges, and now I’m going to talk about how the Doppio runtime system overcomes them. So first off, Doppio is a one hundred percent JavaScript runtime library for bringing conventional languages to the web. There’s no applets; there’s no native escape hatch; it’s complete JavaScript. We implement threads on top of the JavaScript event-driven runtime model, and language implementations use these threads to keep programs responsive, support synchronous I/O, and to run multi-threaded programs. We also expose a TCP socket interface on top of WebSockets, a file system interface on top of the various storage mechanisms available to the browser, and we emulate an unmanaged heap. These three services handle the challenges of browser diversity that I’ve discussed previously, and they let programs running in Doppio to function across all of the major browsers. And using this infrastructure in Doppio, we built DoppioJVM, which is a proof-ofconcept Java Virtual Machine interpreter, written in a hundred percent JavaScript that can run unmodified programs straight from their JAR files. And DoppioJVM contains all of the features required to bring our chat client to the web. So I’ve discussed all those components; now, let’s talk about each of them. First, let’s talk about Doppio’s threads. So as discussed previously, the chat client encapsulates each individual server connection in its own thread, and this is problematic in the browser, because JavaScript only has one thread. How might we map multiple language-level threads on to one hardware thread? So first off, Doppio threads require language implementations to explicitly manage their stack state, and this allows Doppio threads to suspend execution by saving the stack information into a JavaScript object and resume later, using the same stack. And then on top of this basic mechanism, we build a time-sliced, priority-based thread scheduler that adjusts its quanta dynamically for responsiveness. And using this scheduler, not only are we able to support multi-threaded programs, but—and with a preemptive semantics from the language level—we also run… we also allow long-running threads to execute over multiple quanta, and that prevents them from freezing the webpage and keeps the application responsive to I/O, such as mouse clicks, et cetera. But wait, there’s actually more. So using this mechanism, we can support the synchronous blocking I/O by simply suspending threads when they use JavaScript’s asynchronous I/O, and then resuming them once the needed information comes back. So now we can actually directly hook up JVM threads to Doppio threads and that lets our chat clients spawn and run across multiple threads without needing to be modified at all. So that… yep? >>: The cost here is: maintain your own stack, right? >> John Vilk: Yep. >>: That’s a… that might… that’s a big thing. You really… >> John Vilk: It’s true, yes. It does have an impact on performance, but the thing is there’s actually… there’s a lot—a large class—of applications out there, that aren’t computationally intensive, that run just fine with this overhead. And if you think about the web platform right now, most applications on there are not computationally intensive; they’re just frontends to something—stuff like that—and so they run just fine—they operate fine—in this environment with the overhead. >>: Have you thought also about… there was this other project; in there, they generated code—little bit more special when they mapped to JavaScript—such that they could—at yield points—they could kind of recover the stack when you needed to save it from whatever the JavaScript was in. So it became more like trampoline style. >> John Vilk: Yeah. Was that the Racket-based Whalesong work or something else? >>: No, I think this is, like, the Tesla work. >> John Vilk: The Tesla? >>: You mean the Volta? >>: Volta, right. >> John Vilk: Oh, was that the MSR work? First… >>: It was the Microsoft, mostly, work which… >> John Vilk: Yeah, I looked into that. They never actually implemented that. I looked at their code, and then… if they discussed it, it’s not part of the actual project that they dumped onto GitHub, and I couldn’t find any information on that. >>: Right, right. >> John Vilk: Yep? >>: Isn’t OCaml JS already doing this kind of thing for dealing with tier recursion? >>: JS OCaml is doing trampoline, but not for mutually recursive functions, I think. >> John Vilk: Yeah, not that I know of. The only work that I’m aware of right now that does something similar for threads is Whalesong—which is for Racket—but they don’t deal with multi-threaded programs; they don’t deal with operating system things; they just deal with, like, single-threaded programs. >>: So when you say, “Explicitly manage your stack,” are you saying it’s CPS’d? >> John Vilk: In a way, so right now, the one language that we fully support—the JVM—it just has an explicit thread object that manages its state, but that’s not a requirement for Doppio threads. All Doppio threads require is that at a suspend point, you can suspend by somehow recovering your stack, either through explicitly managing it during execution or by dynamically recovering it at a point where… when you need to. >>: So that’s up to the application program to figure out how it wants your…? >> John Vilk: No. It’s up to the language porter, not to the application developer. The language itself supports it, so the application has no idea it’s happening at all. >>: So you could try another strategy. >> John Vilk: Yep. Oh yeah, you could. It’s not a limitation of our framework whatsoever. >>: Because now, it’s like if you can use the JavaScript stack as most as possible, you can take advantage of all the optimizations people do for JavaScript engines, right? If you maintain your own stack, now you’re—you know—you’re pushing on this stack array… >> John Vilk: Yeah, but the JavaScript stack, there’s only… you introspect on local variables or state like that, so you would need to basically have custom logic in every function or something that would persist that data somehow… >>: Yes, right. >> John Vilk: … and that would be another expense. In addition, if you do something like trampolining with exceptions, the JavaScript JIT engines are very sensitive to where you place throws and catches, and so it might degrade performance. >>: Right, right. Yeah. No, I agree, it’s a difficult question. >> John Vilk: It is. It’s a very interesting space to explore, but I haven’t fully explored it in this work. I just laid down all the requirements, and I’ve chosen one just for the proof-of-concept. >>: Right. No, yeah, great, yeah. >> John Vilk: Yeah. Another question? Yeah? >>: Yeah, two questions. The first one is: you have to have a precise understanding of where you insert calls to your custom yield function, right? >> John Vilk: Yeah. >>: Okay. >> John Vilk: So the yield function only comes into play during methods that need to be written directly in JavaScript—so like native methods. So in the JVM, there are native methods: things like socket.read and write. They eventually map down to a method that’s normally written in C that interacts with the operating system environment. So within those, the person who creates the language and rewrites these native methods needs to be aware of how the threads work and needs to say, “Hey, I’m gonna do an asynchronous operation. You can schedule another thread now.” And then the thread schedule will go ahead and pick another thread to schedule while it’s waiting for whatever to come back. There’s also… we also dynamically… so using method call counts right now as a proxy for program runtime, we use that to determine when to suspend after, like, a certain number, and we measure… we also dynamically adjust that count, depending on how long it took to get to the count in the first place, using a moving average. And so we try to stay responsive regardless of what the program is doing. So if it stays within Java code for a very long time—it doesn’t hit a native method that says, “I need you to pause for a bit and then come back”—it will eventually decide on its own: “I think it’s time to pause and let the GUI repaint and not freeze the page.” >>: And my other question was: what you describe is actually pretty similar to the ES7—I think—yield generators… >> John Vilk: Yeah, so… >>: …that do exactly what [indiscernible] yield keyword that suspends the thread, and then you just need to have an outer function that says… >> John Vilk: I agree. So James Mickens here actually implemented some sort of, like, threading mechanism on top of those, and they’re very slow right now, and they’re not very well optimized. >>: So yeah, you can… at a high level—yeah—the yield keyword allows you to implement some of the ideas that were discussed back here—about the idea of trying to leverage the native JavaScript stack to remember activation records. Now, the time that we wrote this maybe, like, a year ago, yields were super unoptimized… >> John Vilk: They were interpreted entirely in most browsers… >>: They were interpreted the whole way… >> John Vilk: …and they weren’t well-supported across browsers at all, so it only worked in Firefox, and then Chrome eventually got it. >>: Yeah. Now recently, they’ve hit sort of like the first-level slow JIT in a lot of the browsers, so I think they improved by like an order of magnitude or something like that. We can talk about that more offline, but you’re definitely right the yield will allow you to do… to leverage some of the automatic JavaScript stack. >> John Vilk: Yeah, and that’s another thing you can explore with the Doppio framework if you want to. I didn’t explore it at the time the paper was written, because it was just too slow. And before I get to another audience question I actually have one here on the screen here. It asks, “How do we switch threads when their quantum has expired?” I kind of answered that a little bit. So there’s two situations or three situations—I guess—in which a thread will be switched. One is if the program’s been running for a long time, and we use method call counts as a proxy for prog… measuring program runtime… oh, okay, they got an answer; never mind. Okay, so next audience question? >>: The issue of timeouts—right—browser timeouts, and predicting how long something might run in order to avoid those, what’s your overall thinking on that? I didn’t quite… >> John Vilk: Oh, yeah, so… >>: Do you have an answer to that? >> John Vilk: Yeah, so we… so what we do is we just do the method call counts to figure out how… to estimate kind of how long it’s been running. And we assume that the method durations, they fall like a nice distribution, and so they’re not going to take forever to… between method calls. Now right now, in our proof-of-concept, if you have a, like, long-running loop that does not make a method call, it can freeze the browser GUI, but we could fix that by augmenting our metric to incorporate loopback edges. But right now, we haven’t encountered a program that has actually done that. >>: Mmhmm. >> John Vilk: Yeah. I realize it’s imprecise, but I haven’t encountered much that has, like, taken down the browser yet. >>: Alright. ‘Cause it’s kind of a… somewhat of a terrible possibility, right? >> John Vilk: It is. >>: That, like, it can just terminate the current event loop and then just proceed. >> John Vilk: Yeah. It is, yeah. And in the future, you can use web workers, which would completely eliminate that possibility of taking down the browser, ‘cause the web worker is completely separate from the GUI context. >>: Mmhmm. >> John Vilk: But the issue is: you still have to occasionally suspend, because it gets messages from the main context—from the GUI, like mouse clicks, et cetera—in its own event queue, and it will not receive those until it winds down. So you still have to periodically suspend to be responsive to user input, but in a web worker context, you would not be able to take down the GUI if our proxy for program runtime turned out to be inaccurate in some case, and it took a long time to suspend. Anything else? Okay, I’ll continue with the next bit then. So that’s the Doppio threads, and next, I’m just gonna discuss the file system. So our text chat client that I discussed earlier, it writes files into the file system for log files, and that’s normally implemented in the UNIX file system class in Java when you’re on UNIX-based systems. And the Doppio file system which I… it’s actually called Browser FS, it exposes a POSIX file system interface in JavaScript. And this file system supports many backends, including most of the persistent storage mechanisms mentioned earlier—Dropbox cloud storage, ZIP files, in-memory storage, et cetera—all through the same interface. And then, you can actually mount these into arbitrary locations in the Doppio file system, which lets you… it gives you great flexibility in where the chat client writes its log files, and lets you… it lets you determine dynamically which one you want to use in case, for some reason, you don’t have access to some of the better storage mechanisms at the time. And so these are actually… some of these are synchronous; some of these are asynchronous, depending on the interface. Now, that’s not a problem for the Java programs, because I… as I mentioned before, our threading implementation lets you map the synchronous I/O to the asynchronous I/O—it’s not a problem at all. So that was the overview of the file system. And next, I’ll discuss network sockets, unless someone wants to know more about that. So our chat client expects to connect to the chat server through a TCP connection, but there’s a problem to porting the setup to the browser that I‘ve sort of inferred earlier. The browser does not give you raw access to TCP at all, and instead, you must use WebSockets, the WebSo… and WebSockets are… is a protocol on top of TCP. The server has no idea how to handle these WebSocket connections. So using Doppio threads, we can implement the JVM synchronous socket abstraction on top of asynchronous JavaScript WebSockets. But the server still has no idea what a WebSocket connection even is. But we can fix that with a pre-existing Python program called WebSockify. So WebSockify wraps the server program and transparently proxies a WebSocket connection to the server as a standard TCP connection, and so neither program needs be modified. You only have to have cooperation with the server runner to wrap the program like this, and everybody wins. On both sides, you have a unmodified chat client running to… connecting to an unmodified server, and neither have any idea of the mechanisms that are in between each other. Yep? >>: Wait, but you have to go to, like, Microsoft and ICQ and tell them to run all their servers in WebSockify? >> John Vilk: If you want to do that, yeah. You could also run a local proxy, if you wanted to, in some unsafe escape hatch, but ideally, if you are bringing something to the web, you control the server portion as well, and so you can simply wrap your program like this. Yep? >>: Firefox had the same problem with Firefox OS when they wrote the mail client. They needed raw TCP access; what they did was create a privileged API that’s only available through privileged Firefox code called mozTCPSocket. Have you gone, put in a call, and tried to pressure them into—you know— putting it into a standard [indiscernible] like, “Hey makes me cry every time I see all these layers of abstraction. Please do something about it.” >> John Vilk: No, I haven’t. >>: I mean, it’s very time-consuming, so… and difficult, so totally understand if you didn’t, but just curious. >> John Vilk: Yeah, I haven’t pressured them, ‘cause I’m not entirely certain if it’s a good idea just to let web programs connect to arbitrary servers through TCP. I haven’t really thought through all of the issues with that. They’re very sensitive to these things, but—you know—I… maybe. >>: Okay. >> John Vilk: Not sure. Yeah. I’m more… I was more concerned about the threading, and what I can do to improve that in the web platform than the OS stuff, ‘cause I assume that eventually, all of these services are going to expose some sort of WebSocket connection, once that permeates through all the browsers and becomes more commonplace. Okay, so tho… that’s were the sockets. Now, I’m just going to talk about this unmanaged heap. So when our chat client starts up, it pulls in a wide variety of libraries in the Java class library. And if you invoke this unsafe Java API when they statically initialize—which lets the program do many really fun things—and supporting this library is a requirement to bringing the Java platform and the chat client into the browser. So all we really need here is an implementation of our old friends or enemies— depending on how you feel about them—malloc and free. And implementing these is very wellunderstood and won’t be covered in the talk in detail, but you need to operate somehow on buffers of memory. And funnily enough, therein lies the problem: representing binary data efficiently across all of these browser variants. So we actually use three different representations, depending on the browser and what support it has for these things. So ArrayBuffer and its predecessor, CanvasPixelArray, are guaranteed to compactly represent our heap in memory. And for those in the audience who are familiar with the HTML5 Canvas, the CanvasPixelArray is used as… to back the image data that is stored on the canvas, when we’re just completely abusing it, ‘cause it’s the only thing available in that situation that has a very compact memory representation, where every byte that you write to it maps to one byte of memory. Now unfortunately, if the browser doesn’t support those two objects—such as Internet Explorer 8—we fall back to a vanilla JavaScript array of numbers. And this has a two-x memory overhead, since JavaScript numbers are sixty-four-bit doubles, but it’s the best universal fallback that we can possibly do, since all of the JavaScript bit operations—like OR, AND, et cetera—they coerce the numbers into a thirty-two bit form. And so with these buffers of memory, we can implement a… the unmanaged heap using the data structures, and we can also implement the JVM’s malloc and free interfaces directly on top of this unmanaged heap, and that lets the Java class library perform all of its unsafe voodoo at program startup and during runtime. So I’ve covered the runtime system, and now I’m gonna move into DoppioJVM and how it hooks up into all of this to bring the JVM to the browser. So DoppioJVM uses an unmodified copy of the OpenJDK Java class library to provide the applications with all of the library support that they expect. And as I mentioned before, the various Java class library interfaces within Doppio are mapped… sorry, let me start over. The various Java class library interfaces are mapped directly onto the Doppio operating system support, and using Doppio threads, these interfaces can keep their blocking JVM semantics, even when they need to invoke an asynchronous JavaScript operation. And we also implement all of the native portions of these classes, which we admit on here, but they’re… that’s a part of it as well. So we covered that; let’s talk about the more fundamental details. So we map the core JVM data structures into JavaScript features in a fairly straightforward manner. Java objects become JavaScript objects; Java arrays become JavaScript arrays; most numeric types become JavaScript numbers, which act as both thirty-two bit integers and sixty-four bit doubles. But sixty-four bit integers are not natively provided in the browser, so we emulate them using Google’s gLong Library, which means that if you have any code that operates with long data types, we have no choice but to allocate an object to represent that long in memory. And due to the straightforward mapping, we actually get garbage collection completely for free, because we are already executing within a garbage-collected environment. Finally, there are some features of the JVM that we had to just completely re-implement for the browser. This includes the core bytecode interpreter for JVM bytecodes, the JVM ClassLoader and JVM monitors, which are used for synchronization across JVM threads. And so DoppioJVM is completely real; it exists; it’s been evaluated by the PLDI Artifact evaluation committee; it got the Distinguished Artifact Award; and this is the demo here; and this is our mock terminal interface that you can see yourself at doppiojvm.org and play around with. And in tradition with all of my Microsoft Research talks, I’m actually gonna show you a live demo. If I can figure out what side of the screen… there it is. Okay, so this is the interface. I’m serving it locally, just to avoid any potential network shenanigans to interfere with the demo. So we have a straightforward terminal interface here; we’re in temporary storage, but if I go to the root directory, you see we have this mount directory, which has a bunch of browser storage things mounted. Because we’re in Chrome, I’ve mounted HTML5 file system in local storage in here, and you can go in here, and you can write file. So let’s create a simple Java file here. I have a very blurry screen over here so forgive me in fumbling about. So let’s write a little Hello World program here. So system.out.printline Hello Microsoft Research. Actually, let’s put a syntax error in here just for fun, save, and close. So now, I actually have a choice of two Java compilers that I can use that are completely unmodified. We have javac and the Eclipse compiler. Let’s invoke javac on this; see what it tells us. And so now, what it’s doing is it’s actually pulling in individual class files off the wire, so the first run’s always slower. And you can see here it tells me… oh, I’m missing a semicolon here—oops. So let me edit that and add that back in so we compile that bad boy. >>: So you improving this editor—right—and… >> John Vilk: That’s actually an existing JavaScript library called Ace Editor. >>: Right. >> John Vilk: Yep, so we just… >>: And you implement this—you know… >>: Shell? >>: …from the shell, basically, right? It was [indiscernible] >> John Vilk: Yeah, the shell is actually implemented in JavaScript. I was debating rewriting it in Java at some point just for fun, but… >>: That’s fine—right—but then… and that works directly with the Doppio VM or… right? >> John Vilk: Yeah. This works directly with the Doppio VM and the file system to bring all of it together, so the Doppio file system is accessible nicely within JavaScript. >>: As I understand it, it’s cool you made this in JavaScript, because a problem with the ASM JavaScript stuff—they may really compile C programs in these magic ASM things—it doesn’t work well with the other JavaScript, right? >> John Vilk: No it doesn’t at all. >>: But here, it’s cool, but everything actually is JavaScript, so you can easily interface between them, right? >> John Vilk: Yes. Yeah, there’s no… yeah, ‘cause with that… people who aren’t familiar: asm.js, it puts certain JavaScript engines like Firefox into a different mode where, strangely enough, you can’t use objects, which is kind of a requirement for most JavaScript code. And so if you want to interface between something in asm.js and regular JavaScript, you have to use an FFI between the two which, as far as I can tell, is undocumented, and I couldn’t get it to work. But in addition, all of the stuff like Emscripten and things like that that compile things to asm.js, they don’t do any of the threading things that I do, and so as a result, they can’t map their file system to HTML5 file system or any of the large storage mechanisms now in the browser. >>: Right. >> John Vilk: And in fact, if you want to use them, you have to manually, like, implement sync operations that tells it when to do certain things. Yep? >>: On the other hand—you know—being inside asm.js, you get some isolation properties, apart from these undocumented FFIs… >> John Vilk: Yeah. >>: …that you know that your Ambient JavaScript isn’t going to muck with the invariance of your compile language. Whereas here, you have JavaScript—you know—interfacing with the JVM implemented inside JavaScript, and you may worry that—you know—potentially malicious or buggy JavaScript just completely screws with the invariance of your system. >> John Vilk: That’s true, but that’s also true of any other JavaScript code that you have on the page. >>: Yes, absolutely. >> John Vilk: Yeah. So the way that we view this is that if you are deploying Doppio on the page, you are also controlling what data you feed to it. And much like any other JavaScript library, you guard the global variable that we expose that you use to interface with it to do all the JVM things. And so as a result, we have, like, the same sort of security properties as any other JavaScript library as far as I’m concerned. Right? >>: Really? I mean, for example, if you make a call from inside your JVM abstraction to a JavaScript function… >> John Vilk: Yep. >>: …what prevents… I mean how… the calling convention—for example—that you’re emulating, that’s Java’s calling convention inside JavaScript, which isn’t really the same; those differences may be observable to a native JavaScript program that wasn’t compiled, or it wasn’t run inside your environment. For example, it may try to do—you know—caller dot—you know—callee.stack.blah— right—which may not exist or may be set up differently in your environment than what that JavaScript program expects. And it may be able to notice that difference and do something with it. >> John Vilk: Okay. So you’re talking about if a Java program’s interfacing with a JavaScript library that’s on the page. >>: That’s right, that’s right. Yes, as this program seems to be doing, right? >> John Vilk: Yeah. >>: Like you are calling into javac from here—which is a Java program—and maybe this JavaScript program, I mean, you wrote it, so it’s not particularly malicious, but I mean, if you got it wrong, for example, it… your program may be able to… your JavaScript program may be able to break the invariance of your compiled Java program. >> John Vilk: Yes, that is true. >>: So I’m just saying… which is perfectly… I mean, I think in the setting that you have it’s quite a succ… you know, it’s okay, but I mean, it’s coming back to the counterpoint with asm.js, this kind of isolation between asm.js and the rest of the environment… >> John Vilk: Which is only maintains… >>: …is sort of for a reason, right? >> John Vilk: It’s only maintained, really, within Firefox, as far as I can tell. In other browsers that don’t support the special use ASM flag, they just treat it as regular JavaScript, and so there’s nothing blocking you from mucking about with that. In Firefox, I’m not sure what happens if you break the invariance that they assume… I don’t know if the page reloads and just executes in regular JavaScript mode, or if it fails to execute, but that wasn’t really designed as a security issue; it was just… that wasn’t really designed as a security invariant to maintain; it was designed as… we can turn on extra optimizations now and make it fast. >>: That’s true, that’s true. >> John Vilk: Yeah, so I would not use that as a… as some sort of sandbox mechanism. Okay, so… yep? >>: I mean, just to next point, I guess. I mean, it’s not an… doesn’t sound like you’re making particularly strong promises about the fidelity of the translation just given how difficult it is, and so this is one of the issues there, which is within an environment that could be hostile. >> John Vilk: Mmhmm. >>: You could have all sorts of funny things happening. You could get… >> John Vilk: Absolutely. >>: …it is what it is. >> John Vilk: To build off that, we haven’t implemented the bytecode verifier; so simply malformed class files, if you don’t control that input, would throw the JVM off track, ‘cause we don’t consider that to be an important, hot issue in the overall contributions we’re trying to make here. >>: What about things like—you know—mapping Java’s memory model precisely to your model of threads and the native heap and…? >> John Vilk: That’s a good question. >>: Because this is not difficult enough, clearly. >> John Vilk: Yeah, clearly, yeah. [laughter] I didn’t really consider that to be a priority when I was working on this. So I would not be surprised if you could find byways to the memory model. Could be considered future work, but at the moment, I haven’t found any programs that have triggered any weird memory model issues, so… >>: Okay. >>: Could you show us how much code there is underneath, like the debugger maybe, or just tell us? >> John Vilk: So in terms of lines of code, if you include all the native bits with the JVM and everything— the DoppioJVM—it’s, like, less than twenty-five K of JavaScript from what I remember—last time I measured. That includes the file system, and DoppioJVM, and its native implementations, and everything else. That does not include the Google Long library that I’m importing; I don’t know how large that is. But overall, it’s not an unreasonable amount of JavaScript. Now, the big part is actually the class files that I’m pulling in. The Java Class library itself—the core part of it compressed in ZIP form—is thirty megabytes, and uncompressed, it’s sixty, but that’s only if you pull in the entire thing. Every program, typically, used probably about, like, five megabytes, ten megabytes of that—and that’s uncompressed sized. So if you Gzip that, you get huge savings there. So it really depends on the program, and how much of the JCL it uses—that’s the biggest cost. The JavaScript is almost nothing compared to that. But… so yeah, let’s see; I fixed my syntax error; I’m just gonna compile this using javac. Takes about—I think—eight seconds, last time I measured. And now, if I run it with Java, it’ll just print that out. And also, we have ECJ, which is the Eclipse compiler, which—yeah—all those little options are here. And that’s just… we didn’t modify any of this, it’s just… it’s direct class files. So in addition to being able to do that, let’s see if javap works—which is the disassembler—so we can just see that this actually has the structure that we desire. And in addition, other languages that work on the JVM, work. So for example, Kawa-Scheme is an implementation of Scheme on the JVM, so we can boot that up. This is loading all the files from the JAR file, which takes a bit for the first time, but… now we have it’s little REPL, and gonna do one plus one, give us two. I’m not much of a Scheme hacker, so I can’t do anything really cool here, but you can mess around with it at doppiojvm.org, and let me know if you break anything. And also, finally—just for one final thing before I switch back to the slides—Rhino is a JavaScript implementation on top of the JVM, so naturally, we wanted to go a little bit meta. So if we run Rhino, we’re gonna get to a JavaScript REPL that is executing on our JVM that is executing in JavaScript. [laughter] I have yet to complete the loop, because I have to… the only thing remaining to complete the loop in which I can run Doppio in Rhino on Doppio—oh, this thing went to sleep, it’s back—is I have to actually port a file system backend to my file system that maps to Rhino, which maps to Doppio, which maps to browser—all that stuff. But I’m very close to completing the loop; I’m sure next demo, I’ll have it ready. So yeah, we have a JavaScript REPL here. >>: It’s amazing. >>: It’s also amazing, like that… like, when you do javac, it runs an entire Java compiler inside your browser, right? And JavaScript interprets it. >> John Vilk: Yep. >>: And so that means that JavaScript interpreters are… they’re good. This is… I mean, it is amazing. >> John Vilk: It is. >>: It works, right? >> John Vilk: Yeah. >>: Yeah, right. >> John Vilk: Oh, what did I forget? >>: Well, maybe you don’t have much experience with JavaScript. [Laughter] >>: You kidding [commotion] >> John Vilk: Oh, oops. >>: Everybody’s a critic. >> John Vilk: Ah, I thought it was WriteLine. Maybe it’s just write. >>: Document [indiscernible] >>: Sprite, I think. >> John Vilk: No, the… ‘cause it’s a… it has different interface completely from... >>: It’s [indiscernible] >>: Print, print. >> John Vilk: Oh, it’s print. >>: Print, print. >> John Vilk: It’s print. >>: This is amazing that we have this issue. >> John Vilk: This is like peer programming, guys. [Laughter] >>: Right brain [indiscernible] just print. >> John Vilk: Yeah, there we go. Print doesn’t add the new line, so I think it’ll mess up the console a little bit… so if I do this it’ll just… >>: Do alert. [laughter] >> John Vilk: I don’t think you have access to alert from this, ‘cause there’s no DOM. Yeah, look at that. Okay, so let’s exit… I think it’s exit or it’s quit. >>: How about barcode toolkits for Java, like Swing, AWT, STWT? >> John Vilk: Good point. So we tried to port AWT—which is the Abstract Window Toolkit, which is what Swing is implemented on top of on the web—but there’s a well-documented issue with OpenJDK in that the AWT is hard-coded, funnily enough, to the platforms it supports. Even though it’s called the Abstract Window Toolkit, it’s not abstract at all. In fact, it calls a bunch of final Sun classes that are hardcoded to different platforms, and so if you wanted to port it to the web, we’d have to modify the Java class library, which we don’t want to do. With that said, I did find that someone on the internet is porting JavaFX to Doppio, and they have a basic demo working with, like, shapes moving around the canvas, both with a complete Java software renderer, running at full speed in the interpreter, and also one that’s has some native methods implemented, so it’s using the canvas and hardware acceleration directly. >>: And how about SWT? >> John Vilk: What was that? >>: SWT. >> John Vilk: I haven’t looked into that at all. >>: Okay. Because in that case, we could open Eclipse. [Laughs] >> John Vilk: Yes. Yeah. So the only thing that you have to do is write that in the methods for that, and if it requires a special backend for the platform, you have to do that as well. So it’s the same as porting it to a different… you have to put in as much effort as porting that to a different operating system, or a different flavor of Linux, or something. But yeah, I haven’t looked into that in particular. >>: Thanks. >> John Vilk: So that’s the little demo. And again, this is at doppiojvm.org; feel free to mess around with it. You can also mount Dropbox in here—yeah—which takes a bit sometimes, ‘cause it’s hitting Dropbox server every time I do a file system thing. But I have little… is this actually…? So this is actually downloading this from my Dropbox account. I’m not sure if this’ll work—meaning, I don’t know if the network connection will cut out. Ah… it’s taking too long. So this is actually downloading this JAR file from my Dropbox account, and control C kills it. So yeah, feel free to mess around doppiojvm.org, and its—also—source is on GitHub. And if you want to see that it’s just static files, you can clone the demo repository and look at the gh-pages branch, and you’ll see it’s just files. So let me go back to my presentation to finish up. Okay, yes, so as I showed you, doppiojvm… oh this thing, like, just minimized. Sorry, okay. I was reconnecting with the question interface. So DoppioJVM runs with the real, unmodified programs that they just showed you. These… those four programs were actually our little benchmark programs, and in some cases, they’re not so little—they’re quite large. Those are the… that’s how large they are in Java. And we’ll jump into the benchmark results. So we’re comparing DoppioJVMs performance to the HotSpot interpreter, because DoppioJVM’s also an interpreter. And we want to note that DoppioJVM is totally untuned; it’s just a proof-of-concept; and HotSpot is highly optimized, and it’s written natively. But despite this, in our best browser—Google Chrome—DoppioJVM, on these benchmark programs, is twenty-four to forty-two times slower than the HotSpot interpreter. >>: Is the HotSpot interpreter? >> John Vilk: Oh, the HotSpot interpreter is when you get Java from Oracle; it’s their Java implementation, and the interpreter is with JIT compilation turned off. >>: Running on…? >> John Vilk: Running on the same server… so these are both running on a MAC Mini with a Core i7 at two gigahertz, I think. It’s in the paper, but yeah, they’re running on the same system. In fact, I don’t think I could find out how to turn off multi-threading, so the HotSpot interpreter’s actually using multithreading to get ahead in some cases. But any case, we’re comparing against that. >>: So I had a quick question on this. >> John Vilk: Yeah? >>: So I assume all these benchmarks are run in a very compute-intensive manner. >> John Vilk: Yes. >>: So this is sort of the worst-case scenario. >> John Vilk: Yes. >>: You wouldn’t even want to really do this. You’re more interested in sort of the UI-bound… >> John Vilk: No, you would not. >>: Do you have any examples of like...? >> John Vilk: I do. >>: Okay. >> John Vilk: I’m actually getting to that point. >>: Okay, good. >> John Vilk: Yeah. Yeah. So yeah, these are the results. You’ll see that it differs a lot between browsers. We developed this in Chrome, and we profiled it in Chrome, and so we probably are a bit tightly coupled with it. And because it’s an interpreter, any small changes in the… how we dispatch op codes and such, is going to have a huge impact on program runtime. Also, you’ll notice that Safari had an issue with javap. We found an issue in Safari, where it wasn’t garbage-collecting certain things, and that’s been fixed now; so that’s no longer an issue. But yeah, these are all compute-intensive code, like you’d give it a command, and it goes on forever; it’s the worst-case. And the browsers don’t generally run this type of code. And so we found the DoppioJVM’s fast enough for many people already who have discovered it. So for example, the University of Illinois came to me with some… for some help, and they’ve launched a website called CodeMoo.com, which uses DoppioJVM to teach Java programming— or basic Java programming—skills to children. So this is the little game that they can play; this is like a level-one game. So children go here; they string together function calls to guide the character in red to the goal without bumping into bad guys. And when ready, after arranging all of these things, the child clicks the green button and watches the character carry out the instructed actions. Under the covers, these instructions are placed into a Java file in the Doppio file system, compiled with the Eclipse compiler running within Doppio, and then the resulting class file is run in DoppioJVM again, and that all harnesses the power of the visitor’s own browser. So existing things like this, existing platforms people use—and universities use—to teach children how to program in Java use server backends to run the Java code. In this case, it’s just using the browser directly, and all they have to do is serve the static files. So yeah, in this talk, I introduced Doppio—a full runtime system that bridges the impedance mismatch between conventional languages and the browser—I showed off our proof-of-concept Java Virtual Machine—DoppioJVM—which can run unmodified Java programs in the browser. I also didn’t mention that our file system can sometimes integrate into Emscripten programs, and so that’s been used in a variety of web pages. And I encourage you to check out Doppio at doppiojvm.org and thank you all for your attention. [applause] >> Mark Marron: Thanks a lot. So I think we got a lot of questions throughout, but definitely time for more. >> John Vilk: Yeah. >>: So that execution was from February; what’s been going on in the last eleven months? >> John Vilk: So we been looking at speed; we been looking at supporting other languages; and I also, in my spare time, got Java8 working. So variety of things on the plate right now that I’m exploring—not much to talk about just yet, but I’m hoping I’ll have some news on that in a few months. Yep? >>: You mentioned compatibility with fairly old browsers, such as IE8. >> John Vilk: Yes. >>: Why is that important for you? >> John Vilk: Yeah, I wanted to see what all the issues were with browser diversity. Now, I think I broke IE8; I think it’s broken on our demo right now, but IE9 definitely works. But yeah, I wanted to see what web developers currently face in bringing programs to the web, and I wanted to see if IE8 could work. And I did have it working at one point; I think there’s a weird bug in there somewhere. >>: Fair enough. >> John Vilk: Yep? >>: I’m curious what the take loop for executing individual Java bytecodes is. Are you… is it like a array index into a bunch of function, or is it…? >> John Vilk: Me think… um… as of the demo—I’ve rewritten it recently—so as of the demo that I showed you, that actually has an object allocated for every interpreter instruction, which has, like, a run command, and so that allows for some nice allotting in some cases. The version that I have now is a lot simpler, and it has an array of functions for every interpreter op code, and dispatches it to… using the number at a certain op set in the bytecode directly. So those are the two that I’ve used, and they have similar performance. I don’t know if that was clear but… >>: Is it a big switch statement or is it a chief…? >> John Vilk: No. >>: Do you know? >> John Vilk: No, no. So actually, switch statements, in some JavaScript JIT engines, are not optimized if you have more than a hundred and twenty-eight cases. >>: So it… you index an array of functions? >> John Vilk: Yeah, I index an array. Yep. >>: Okay. >>: Alright. Well let’s thank John again. [applause] >>: Thank you, Johnny.