Jump to content

Javascript code survey (In relation to JS->C compiler)


whizzter
 Share

Recommended Posts

Hi all, I've been working on a JS->C compiler prototype for my thesis to help making more advanced JS games mainly for iOS without having to compromise performance due to JIT compilers not being allowed.

 

However, to achieve really good performance this compiler has deviated a little bit from standard code semantics so I've made a small survey that i'd hope as many of you as possible would fill in so i'll have an idea of how useful it'd be in practice.

 

If you don't understand some parts of the questions, don't worry as those are usually error prone situations and just answer the best you can.

 

(This form is now closed) https://docs.google.com/forms/d/10dcIUkarUHuCVMFJstNtSd6hdm-QtQmlxYMnb_bfJFo/viewform

 

Gonna put a FAQ in the next comment (or this one) if needed.

 

--------------------------------------------------------------------------------------------------

Edit: 2015-06-13 , turned off the submission form as i've submitted my thesis.

Link to comment
Share on other sites

Just completed the survey.

 

Here's another JS->C compiler: https://github.com/InfiniteFoundation/dopple but not updated for months.

 

Though I'm always looking for such a thing, I just find that the limitations come with it make it useless. It feels like writing C code with JavaScript syntax, which does not have much benefits.

Thanks for completing it.

 

Looked at the dopple compiler now and i can see what your comment refers to as writing C, i started on something similar for an earlier iteration but abandoned it when i realized that it'd be a chore to get even one of my small jam games ported.

 

What i'm working on however is built around the ES specification to be compatible as far as possible with a global analysis to find optimizations rather than to force the code to any certain mould. objects, gc, prototypes, array length semantics, function closures all there.

 

The main limitations for this compiler is the lack of "eval" and "with" (with is forbidden per the ES5 strict mode anyhow), limited support for delete (it'll be working for objects marked as hashmaps), not allowing holes in arrays (various proposals wants to deprecate that anyhow) and those differences mentioned in the survey (if you ever possibly assign anything non-numeric to a variable it'll turn into a "any" variable that can hold multiple types and that enables regular undefined semantics). Otherwise unless it's a really weird corner case if your code works with ES5 strict mode it should work with the compiler.

Link to comment
Share on other sites

  • 2 months later...

Heya, I just found about this thread.

 

I'm the original author of the dopple and still working on it (and almost able to show some visual demos with it). Actually, the only limitation is the lack of the eval, and even some cases of it should be possible to be analysed at compile time. I don't think "eval" has something important to offer, but eventually I will support it with AOT/JIT hybrid too.

 

IMHO, if you will go the route you are going, you will get JIT compiler or worse - JS interpreter.

Link to comment
Share on other sites

Hi, fun to see you here (You should follow me back on twitter so we can banter away on progress :P )

 

I'm the original author of the dopple and still working on it (and almost able to show some visual demos with it). Actually, the only limitation is the lack of the eval, and even some cases of it should be possible to be analysed at compile time. I don't think "eval" has something important to offer, but eventually I will support it with AOT/JIT hybrid too.

 

Depends on what "the only limitation" means, i looked at the dopple code around the time i made the first posts and again now and looking at resolve.js you seem to be doing type deductions on the syntax tree. Now this kind of system will work fine for generating fast code if you allow one type at each point in the code and in fact most research has shown that this is true for most code JS written even for the web and for games i'd expect this to be even more true so in that way what dopple does is fine.

 

The problem comes when you start mixing in dynamic things. Say you want different code to be run depending on if different enemies or a boss character is simulated, in these cases for example the boss character might have many more properties on the object to simulate the AI code. Now this can be hidden and well analyzed if you hide away specific data inside function scopes. But what if the characters are loaded from an external file with JSON? (Now honestly JSON is also a problem for me in terms of analysis due to it's arbitrary nature but i have some solutions designed for this)

 

IMHO, if you will go the route you are going, you will get JIT compiler or worse - JS interpreter.

 

Actually i've been benchmarking my compiler output on some small code snippets agains't C code, JIT compilers and interpreters as part of my thesis works to figure out what the actual performance differences are in reality for different approaches and scenarios.

 

First off, don't bash JIT compilers as they're actually pretty well designed today and even 5 year old Intel machines eats up many of the "slowdowns" they produce like snacks (mainly branch caches that just seems to skip over any bailout tests the JIT compilers has in case the code does something "unpredictable"). Spidermonkey on X86 is only roughly 30% slower than C code on things like a recursive fib and both V8 and Spidermonkey is at par with C code on things like computation on doubles in local variables. But then there's no denying scenarios where particular code patterns will slow down JIT compilers to a crawl compared to C code but in those cases you'd probably need a lot of special case C code to handle these scenarios with speed anyhow.

 

Interpreters on the other hand, i found that even the assembly optimized JavaScriptCore was at best 10x slower than the JIT's or often worse. And the C based interpreters i tested (SpiderMonkey/Duktape) were significantly worse. So avoiding them is something you really want to do to make any decent games.

 

Secondly, like i mentioned with the branch caches of modern Intel machines there's differences in how the CPU works in how well a JIT compiler, C code and so on will perform compared to each other. I was benchmarking the old Raspberry PI B1 with the new B2 models and you can really see how much they improved the FPU between the 2 different ARM cpu's in each machine. And also branch caches seems to be a lot better in more "modern" cpu's compared to older and simpler designs and this favors JIT code quite a bit.

 

Actually, one of my benchmarks tested the use of doubles everywhere and if you use that as the only numeric type your X86 code will be slower than a JIT compiler since their type tagged integers don't have any slowdowns due to float->int conversion when you do an array access.

 

Now my main compiler, it's faster than JIT's in some cases (particular on ARM cpus) but slower in other cases (JIT's usually do better on Intel X86). Each approach has different optimal and bad cases but being much faster than an interpreter is usually not that hard though  :D

 

Now, dopple might be fine for your purposes, i noticed that you have some templates for Array's and that is the right thing to do since they're everywhere with different types but i designed my compiler around how my fast ludumdare game hacks have worked in practice and when i was working on a compiler similar to dopple i remember thinking that i'd either have to fall back to a lot of slower dynamically typed code paths or change my game coding style to such a degree that i'd be better off writing in C++ and using emscripten to target Asm.JS on the web.

 

As dopple seems to work now (looking at the C++ snippets you generate) it will be faster than my compiler in many cases where i try to be compatible with the standard, i'm also going to sacrifice some performance to enable incremental exact garbage collection with write barriers so that generational collections is enabled to avoid world halting stops (The JVM does this and they've only measured a few % of slowdown for this). Theoretically however my compiler might surpass dopple speed in some cases where i can prove things to be integers, now dopple could probably have special cases for most of those regular cases but one nice thing of having a deep analysis system behind things is that sometimes the analysis needed for an optimization is there before you need it  :D

Link to comment
Share on other sites

The problem comes when you start mixing in dynamic things. Say you want different code to be run depending on if different enemies or a boss character is simulated, in these cases for example the boss character might have many more properties on the object to simulate the AI code. Now this can be hidden and well analyzed if you hide away specific data inside function scopes. But what if the characters are loaded from an external file with JSON? (Now honestly JSON is also a problem for me in terms of analysis due to it's arbitrary nature but i have some solutions designed for this)

 

I actually will handle theses cases later in the development as I mainly develop dopple for my own needs and i rarely write super dynamic code because of the hidden costs of doing so. The worst case that dopple will do for super dynamic cases is that it will see that variable as Dynamic and will interpret it similarly as scripting languages do. This of course can be faster if JIT is used to modify dynamic code based on statistics. But currently my biggest focus is on AOT bytecode.

 

I'm not focusing at the moment on super dynamic cases because I want somewhat to compete with native written applications without sacrificing for web version of the app (i'm looking at you emscripten  :ph34r:).

 

That said I will also have GC, but i'll try to use it as minimal as possible - ideally only in places where circular references are possible for given expression. And for dynamic object access will generate hashmap with offsets for that particular object type.

 

First off, don't bash JIT compilers as they're actually pretty well designed today and even 5 year old Intel machines eats up many of the "slowdowns" they produce like snacks (mainly branch caches that just seems to skip over any bailout tests the JIT compilers has in case the code does something "unpredictable"). 

 

Sorry, was not meant as bashing, just developing JIT compiler is time consuming and is competing with existing solutions that has already big teams and financing - though that does not mean that it's not possible in solo to achieve better performance in some of JIT'ing parts. Overall, i'm not big a fan of JIT compilers, they are cool and on paper even should be faster than AOT, but in reality they will be always slower because they have to check shapes and gather statistics, support ability to bail out from optimised code etc.

 

Actually, with static analysis it's even possible to solve object upcasting just by looking what functions are called for that variable, if there are multiple choices - generate branches - the same as would JIT do (only difference they can remove branches if they are not used in hot functions).

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...