So why did the author throw out LLVM byte code again? It's BSD, it has bytecode compilers for most platforms browsers exist on (100% vs. 50% speed), and doesn't rely on a subset of another language. It also doesn't have the requirement to fall back to vanilla Javascript. As an added bonus, Javascript could easily compile down to LLVM bytecode.
Seems like the author already preferred their answer and threw out some BS to "justify" their choice.
JS probably will remain the "byte code of the web", but this article adds nothing to that trajectory.
The author is Alon Zakai, creator of emscripten, and the article is quite old (2013) when there was a somewhat heated debate whether a byte code format would be better for the web instead of Javascript, with the byte code fans having fairly theoretical reasons (basically: 'because it is the right way to do it and Javascript sucks anyway'), instead Alon went ahead and demonstrated that in reality the more pragmatic solution to compile to JS has no disadvantages compared to byte code, and you don't need to add a whole new language engine to browsers (like Google PNaCl does), but (in the case of asm.js) only fairly minor modifications to existing JS engines, and you keep full compatibility (but lower performance) with old JS engines.
Interestingly, emscripten now also supports an interpreted byte code mode (called emterpreter), which stores code in a byte code format, and runs this inside an JS interpreter(!). The reason for this was quicker startup time for large scripts, but (my own speculation!) it might also be a path to a future byte code distribution format if there are indeed any other practical advantages.
Another interesting point is that Safari actually has now an LLVM based compilation layer in their Javascript engine, so it's coming together from both sides with LLVM being the glue (emscripten's front end is also LLVM).
> more pragmatic solution to compile to JS has no disadvantages compared to byte code
The disadvantage is that compilation takes a not-insignificant amount of time, particularly if you want to go from running AST on a VM to running platform native code. It takes even longer if you're on an underpowered device which could take the most advantage of a simple IR bytecode -> native bytecode compilation.
This is evidenced in the 50% numbers from the OP's article.
LLVM's IR makes no stability guarantees - it can change from one release to the next, with no backward compatibility. That's not ideal for something you're slinging out to the web.
I believe this is the same reason Khronos defined their own IR (SPIR) instead of using LLVM's. Needs to be stable.
They distribute Rust as Rust code, not as LLVM IR. You use LLVM to compile Rust to a target-specific IR and then to a target-specific binary. Try reading that link your sibling posted.
I don't know if maybe the page relies on JS being enabled to load some content and you have JS disabled or not, but there is significant discussion of LLVM on that page.
> So why did the author throw out LLVM byte code again?
"Again" is right. I don't particularly seek out discussions on this topic, but I've seen this question asked and answered at least half a dozen times before, which is enough for it to start getting annoying.
> So why did the author throw out LLVM byte code again? It's BSD, it has bytecode compilers for most platforms browsers exist on (100% vs. 50% speed), and doesn't rely on a subset of another language. It also doesn't have the requirement to fall back to vanilla Javascript. As an added bonus, Javascript could easily compile down to LLVM bytecode.
LLVM has a single implementation, is very complex, isn't even remotely portable, and is primarily suited to C and C++, or similar languages.
We also already have a very performant transformation format for LLVM IR into JS: asm.js. And asm.js fixes most of LLVM IR's problems:
* It's very simple
* It's portable across architectures
* It doesn't have undefined behaviour
* It has multiple implementations
* It has forwards-compatibility (existing browsers, regardless of explicit support, can run asm.js code)
Well put. One nit: I think you mean backwards compatibility, though asm.js can also be expected to work without modification in future browsers and future versions of javascript.
Yeah, I originally put backwards-compatibility, but I wasn't sure if forwards-compatibility was the right word for allowing old software to use new code.
It got renamed, then somebody made a backroom deal to borrow the new name for another totally different language in order to trick people into confusing the two languages, then the other language became much more popular and widespread than the one that used to be called Oak, totally taking over the browser, and making good headway at taking over the server too.
Incidentally, Arthur van Hoff just pointed out:
>Time flies. This week it is 20 years since we announced Java...
"Why Sun Thinks Hot Java Will Give You a Lift" - March 23 1995
I blagged a copy of Java from Arthur a while before that when I found out he was working at Sun - I'd used HyperNeWS for quite a while and was in awe of his programming skills.
That's me. While I was working at Sun in '90-91 on NeWS, we tried very hard to convince management to hire him to work on HyperNeWS for TNT, but Sun wouldn't give us a requisition (because they intended to kill NeWS, not save it). So I quit Sun and moved out to Glasgow to work with him at the Turing Institute on HyperLook, and ported SimCity to HyperLook.
HyperNeWS aka HyperLook was like HyperCard implemented with PostScript programming and graphics, plus networking. In that alternate universe, PostScript would have been the universal bytecode for the web.
Arthur's programming and entrepreneurial skills are indeed awesome, and I'm glad I quit my day job at Sun and left the country for the opportunity to work with him! He's now an advisor to my current company: http://pantomimecorp.com/the-team
I actually presented a paper at the 2nd International Conference on the Web in Chicago in '94 about "Extending W3 Clients" which including a suggestion for adding a standard bytecode interpreter to web browsers.
I stopped working on that when I found out about Oak/Java in early '95.
You might get a kick out of Sun's proposal for "NFS 3.0" aka "NeFS". The basic idea was to put a PostScript interpreter in the kernel for extensibly and efficiently executing distributed and even local file system operations. It not only cuts down on network transactions for the same reason NeWS and AJAX does, but even locally you can avoid billions of context switches by executing "find" and tasks like that in the kernel, for example.
The Network Extensible File System Protocol Specification 2/12/90
The Network Extensible File System protocol (NeFS) provides transparent remote access to shared
file systems over networks. The NeFS protocol is designed to be machine, operating system,
network architecture, and transport protocol independent. This document is the draft specification
for the protocol. It will remain in draft form during a period of public review. Italicized comments
in the document are intended to present the rationale behind elements of the design and to raise
questions where there are doubts. Comments and suggestions on this draft specification are most
welcome.
1.1 The Network File System
The Network File System (NFS™) has become a de facto standard distributed file system. Since
it was first made generally available in 1985 it has been licensed by more than 120 companies. If
the NFS protocol has been so successful why does there need to be NeFS ? Because the NFS protocol
has deficiencies and limitations that become more apparent and troublesome as it grows older.
1. Size limitations. The NFS version 2 protocol limits filehandles to 32 bytes, file sizes to the
magnitude of a signed 32 bit integer, timestamp accuracy to 1 second. These and other limits
need to be extended to cope with current and future demands.
2. Non-idempotent procedures. A significant number of the NFS procedures are not idempotent.
In certain circumstances these procedures can fail unexpectedly if retried by the client. It is not
always clear how the client should recover from such a failure.
3. Unix bias. The NFS protocol was designed and first implemented in a Unix environment.
This bias is reflected in the protocol: there is no support for record-oriented files, file versions
or non-Unix file attributes. This bias must be removed if NFS is to be truly machine and
operating system independent.
4. No access procedure. Numerous security problems and program anomalies are attributable to
the fact that clients have no facility to ask a server whether they have permission to carry out
certain operations.
5. No facility to support atomic filesystem operations. For instance the POSIX O_EXCL flag
makes a requirement for exclusive file creation. This cannot be guaranteed to work via the NFS
protocol without the support of an auxiliary locking service. Similarly there is no way for a
client to guarantee that data written to a file is appended to the current end of the file.
6. Performance. The NFS version 2 protocol provides a fixed set of operations between client and
server. While a degree of client caching can significantly reduce the amount of client-server
interaction, a level of interaction is required just to maintain cache consistency and there yet
remain many examples of high client-server interaction that cannot be reduced by caching. The
problem becomes more acute when a client’s set of filesystem operations does not map cleanly
into the set of NFS procedures.
1.2 The Network Extensible File System
NeFS addresses the problems just described. Although a draft specification for a revised version of
the NFS protocol has addressed many of the deficiencies of NFS version 2, it has not made non-Unix
implementations easier, not does it provide opportunities for performance improvements. Indeed,
the extra complexity introduced by modifications to the NFS protocol makes all implementations
mor...
The other "universal bytecode" that came out of Sun and actually has seen a lot of use is Mitch Bradley's Open Firmware Forth based boot ROMs, used by Suns' 68k, SPARC and x86 boxes, Apple's PPC Macs, IBM, ARM, OLCP XO-1, and many other systems.
I'd settle for a bytecode that supported numbers (instead of only strings), blocking I/O (in addition to non-blocking), and easy integration with system (or, in this case browser) utilities.
JS implement numbers as strings (has bitten me once).
Last time I looked at, there was no blocking IO at all (there is continuation, but it does not solve the problem because there isn't any locking mechanism - yep, I'd like atomic locking at my bytecode too). That's even the main "selling point" Node.js people throw around as if it was a good thing.
By easy integration I mean the hability of using capabilities available at the system, but not exported into the language runtime. It can be solved by something that would let me query the sandbox enviroment for the existence of a "library" that exports foreign functions, and use it. Also, something that by the other side lets me write and distribute one such "library" so people can install them on their browsers let JS use its functionality.
> JS implement numbers as strings (has bitten me once).
What? JS implements all numbers as 64-bit floating point, which happens to be able to perfectly represent the 32-bit integer space. It can actually perfectly represent a 52-bit integer space. See Number.MAX_SAFE_INTEGER [0] for details.
Now, JS does allow for type coercion between values when using the `==` operator. Luckily, the `===` operator also exists which eliminates this effect.
> Last time I looked at, there was no blocking IO at all.
What does blocking even mean in a single-threaded event-pump context? Does it mean other events can be processed while the IO executes? Because that's exactly what an asynchronous AJAX request does. Or does it mean it blocks the only thread available? Because that's what a synchronous AJAX call does.
Now, if your argument is that JS doesn't have an async / await construct in order to make asynchronous AJAX look like synchronous AJAX in the code, then that's in ES7.
I think you have JS confused with TCL, the other language that Sun announced was going to be the universal web browser scripting language, right before Java happened.
Remember "The Great TCL War of 1994"?
Why you should not use Tcl
Richard Stallman (rms@gnu.ai.mit.edu)
Fri, 23 Sep 94 19:14:52 -0400
The article makes the argument that existing systems are easier to improve incrementally, while designing new systems is more work and not guaranteed to succeed.
The problem is JavaScript-as-bytecode is not especially easy to improve. Anything you want to add/change that would make it a better bytecode has to be balanced with the language's use by humans.
The solution to one-VM-to-rule-them-all is not to cram everything into a higher-level system with lots of assumptions (JavaScript) or to ignore portability (NaCl, LLVM), but to use a bytecode that's low-level enough to implement the various assumptions needed by higher layers.
That way both C++ and JavaScript can run at full speed as well as have their implementations changed (even across websites!) without pushing every change through the browsers- just like native apps, with the browser providing only cross-platform and security, nothing more.
> The problem is JavaScript-as-bytecode is not especially easy to improve. Anything you want to add/change that would make it a better bytecode has to be balanced with the language's use by humans.
There are very few cases where human use causes problems. goto is the only one I can think of. Yet we've gotten loads of great improvements in ES6 to make it a good compiler target, like float32 and better integer multiplication.
35 comments
[ 0.20 ms ] story [ 77.3 ms ] threadWhat does that even mean?
So why did the author throw out LLVM byte code again? It's BSD, it has bytecode compilers for most platforms browsers exist on (100% vs. 50% speed), and doesn't rely on a subset of another language. It also doesn't have the requirement to fall back to vanilla Javascript. As an added bonus, Javascript could easily compile down to LLVM bytecode.
Seems like the author already preferred their answer and threw out some BS to "justify" their choice.
JS probably will remain the "byte code of the web", but this article adds nothing to that trajectory.
Interestingly, emscripten now also supports an interpreted byte code mode (called emterpreter), which stores code in a byte code format, and runs this inside an JS interpreter(!). The reason for this was quicker startup time for large scripts, but (my own speculation!) it might also be a path to a future byte code distribution format if there are indeed any other practical advantages.
Another interesting point is that Safari actually has now an LLVM based compilation layer in their Javascript engine, so it's coming together from both sides with LLVM being the glue (emscripten's front end is also LLVM).
The disadvantage is that compilation takes a not-insignificant amount of time, particularly if you want to go from running AST on a VM to running platform native code. It takes even longer if you're on an underpowered device which could take the most advantage of a simple IR bytecode -> native bytecode compilation.
This is evidenced in the 50% numbers from the OP's article.
I believe this is the same reason Khronos defined their own IR (SPIR) instead of using LLVM's. Needs to be stable.
It might not compile on an AT-MEGA, but it seems portable enough for the purposes of acting as a browser bytecode representation.
> So why did the author throw out LLVM byte code again?
"Again" is right. I don't particularly seek out discussions on this topic, but I've seen this question asked and answered at least half a dozen times before, which is enough for it to start getting annoying.
LLVM has a single implementation, is very complex, isn't even remotely portable, and is primarily suited to C and C++, or similar languages.
We also already have a very performant transformation format for LLVM IR into JS: asm.js. And asm.js fixes most of LLVM IR's problems:
* It's very simple
* It's portable across architectures
* It doesn't have undefined behaviour
* It has multiple implementations
* It has forwards-compatibility (existing browsers, regardless of explicit support, can run asm.js code)
* It is standardised
http://en.wikipedia.org/wiki/Oak_%28programming_language%29#...
If we were going with a bytecode, I wouldn't choose LLVM or JVM. Neither is really suited for the task.
Incidentally, Arthur van Hoff just pointed out:
>Time flies. This week it is 20 years since we announced Java...
"Why Sun Thinks Hot Java Will Give You a Lift" - March 23 1995
http://web.archive.org/web/20060819094743/http://java.sun.co...
Edit: Are you this DonHopkins?
http://art.net/~hopkins/Don/hyperlook/index.html
HyperNeWS aka HyperLook was like HyperCard implemented with PostScript programming and graphics, plus networking. In that alternate universe, PostScript would have been the universal bytecode for the web.
https://www.scribd.com/doc/77192884/HyperLook-Product-Info
https://www.scribd.com/doc/77164708/HyperLook-SimCity-Manual
Arthur's programming and entrepreneurial skills are indeed awesome, and I'm glad I quit my day job at Sun and left the country for the opportunity to work with him! He's now an advisor to my current company: http://pantomimecorp.com/the-team
I stopped working on that when I found out about Oak/Java in early '95.
The Network Extensible File System Protocol Specification 2/12/90
http://www.donhopkins.com/home/nfs3_0.pdf (pages in reverse order)
Introduction
The Network Extensible File System protocol (NeFS) provides transparent remote access to shared file systems over networks. The NeFS protocol is designed to be machine, operating system, network architecture, and transport protocol independent. This document is the draft specification for the protocol. It will remain in draft form during a period of public review. Italicized comments in the document are intended to present the rationale behind elements of the design and to raise questions where there are doubts. Comments and suggestions on this draft specification are most welcome.
1.1 The Network File System
The Network File System (NFS™) has become a de facto standard distributed file system. Since it was first made generally available in 1985 it has been licensed by more than 120 companies. If the NFS protocol has been so successful why does there need to be NeFS ? Because the NFS protocol has deficiencies and limitations that become more apparent and troublesome as it grows older.
1. Size limitations. The NFS version 2 protocol limits filehandles to 32 bytes, file sizes to the magnitude of a signed 32 bit integer, timestamp accuracy to 1 second. These and other limits need to be extended to cope with current and future demands.
2. Non-idempotent procedures. A significant number of the NFS procedures are not idempotent. In certain circumstances these procedures can fail unexpectedly if retried by the client. It is not always clear how the client should recover from such a failure.
3. Unix bias. The NFS protocol was designed and first implemented in a Unix environment. This bias is reflected in the protocol: there is no support for record-oriented files, file versions or non-Unix file attributes. This bias must be removed if NFS is to be truly machine and operating system independent.
4. No access procedure. Numerous security problems and program anomalies are attributable to the fact that clients have no facility to ask a server whether they have permission to carry out certain operations.
5. No facility to support atomic filesystem operations. For instance the POSIX O_EXCL flag makes a requirement for exclusive file creation. This cannot be guaranteed to work via the NFS protocol without the support of an auxiliary locking service. Similarly there is no way for a client to guarantee that data written to a file is appended to the current end of the file.
6. Performance. The NFS version 2 protocol provides a fixed set of operations between client and server. While a degree of client caching can significantly reduce the amount of client-server interaction, a level of interaction is required just to maintain cache consistency and there yet remain many examples of high client-server interaction that cannot be reduced by caching. The problem becomes more acute when a client’s set of filesystem operations does not map cleanly into the set of NFS procedures.
1.2 The Network Extensible File System
NeFS addresses the problems just described. Although a draft specification for a revised version of the NFS protocol has addressed many of the deficiencies of NFS version 2, it has not made non-Unix implementations easier, not does it provide opportunities for performance improvements. Indeed, the extra complexity introduced by modifications to the NFS protocol makes all implementations mor...
http://en.wikipedia.org/wiki/Open_Firmware
Javascript happens to have none.
What are you on about?
Last time I looked at, there was no blocking IO at all (there is continuation, but it does not solve the problem because there isn't any locking mechanism - yep, I'd like atomic locking at my bytecode too). That's even the main "selling point" Node.js people throw around as if it was a good thing.
By easy integration I mean the hability of using capabilities available at the system, but not exported into the language runtime. It can be solved by something that would let me query the sandbox enviroment for the existence of a "library" that exports foreign functions, and use it. Also, something that by the other side lets me write and distribute one such "library" so people can install them on their browsers let JS use its functionality.
What? JS implements all numbers as 64-bit floating point, which happens to be able to perfectly represent the 32-bit integer space. It can actually perfectly represent a 52-bit integer space. See Number.MAX_SAFE_INTEGER [0] for details.
Now, JS does allow for type coercion between values when using the `==` operator. Luckily, the `===` operator also exists which eliminates this effect.
[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
> Last time I looked at, there was no blocking IO at all.
What does blocking even mean in a single-threaded event-pump context? Does it mean other events can be processed while the IO executes? Because that's exactly what an asynchronous AJAX request does. Or does it mean it blocks the only thread available? Because that's what a synchronous AJAX call does.
Now, if your argument is that JS doesn't have an async / await construct in order to make asynchronous AJAX look like synchronous AJAX in the code, then that's in ES7.
No it doesn't. JS numbers are IEEE754-2008 64-bit double-precision floating point.
> Last time I looked at, there was no blocking IO at all
Huh? It's everywhere. XMLHttpRequests, prompt(), localStorage...
> By easy integration I mean the hability of using capabilities available at the system, but not exported into the language runtime.
Not doable for a sandbox. Sorry.
Remember "The Great TCL War of 1994"?
http://www.vanderburg.org/OldPages/Tcl/war/0000.htmlA reply to a comment I made on another post says that the CLR and JVM suffer from GC pauses, which would not be acceptable for web apps.
The problem is JavaScript-as-bytecode is not especially easy to improve. Anything you want to add/change that would make it a better bytecode has to be balanced with the language's use by humans.
The solution to one-VM-to-rule-them-all is not to cram everything into a higher-level system with lots of assumptions (JavaScript) or to ignore portability (NaCl, LLVM), but to use a bytecode that's low-level enough to implement the various assumptions needed by higher layers.
That way both C++ and JavaScript can run at full speed as well as have their implementations changed (even across websites!) without pushing every change through the browsers- just like native apps, with the browser providing only cross-platform and security, nothing more.
There are very few cases where human use causes problems. goto is the only one I can think of. Yet we've gotten loads of great improvements in ES6 to make it a good compiler target, like float32 and better integer multiplication.