Where is the main event loop in the Firefox source code? - javascript

I am looking through the Firefox source code and trying to determine the source for the main loop that executes all the event handlers in Javascript.
I have looked over this overview of the directory structure, but I still cannot find the event loop.
Which source lines should I look at to find the main event loop?
Update: I am building and running Firefox on Linux x86_64.

Disclaimer: I worked on the Chakra JavaScript engine between 2014 and 2015 while at Microsoft.
Firefox's JavaScript engine is called SpiderMonkey, and can be considered a separate project - and it can be used by other applications too ( https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/How_to_embed_the_JavaScript_engine ).
Modern JavaScript engines are JIT-based: they don't interpret code in a giant loop - instead they compile JavaScript functions into native code - effectively their own program, and this dynamically generated program will have its own event flow - but it isn't necessarily a "loop" - and there isn't necessarily "one" individual program either - because it depends on the JavaScript hosting environment: a web-page can run multiple JavaScript "workers" simultaneously (acting as different threads - this is beyond JavaScript's current asynchronous model). Also note that "Firefox" is just a wrapper around Gecko - and Firefox runs multiple Gecko instances side-by-side, and in different runtime worker processes.
That said, pretty much all JIT JavaScript engines still retain their interpreters - Chakra does - because the JIT process takes a while, so they will initially run script in interpreted mode for immediate results - and the interpreter part of the engine may as well be a completely independent JavaScript engine implementation (ignoring the parser and standard library components).
It's been almost 18 months since I last worked with the Chakra source code (it's open-source now) but from what I remember (and without breaking my NDA) the only real main "loop" in Chakra was the interpreter loop (a giant switch statement for the current opcode enum value) - the event handlers were handled through asynchronous IO - so it's actually up to the Chakra host to provide the asynchronous IO functionality - so in short, there is no "event loop". I'd be surprised if Firefox's SpiderMonkey or Chrome's V8 didn't work on the same basis.

Related

What exactly does "Javascript can be run outside the browser" mean in plain English? [duplicate]

This question already has answers here:
What is client side javascript and what is server side javascript?
(8 answers)
Closed 9 months ago.
I'm learning Javascript, and I keep seeing this phrase being used when speakers are explaining NodeJS and the V8 engine in relation to Javascript. I know because of Node, we can run JS "outside of the browser," but what does that mean? Oftentimes, instructors use terms I don't know yet (like "server-side scripting") to explain, which makes it difficult to understand.
From what I know so far, it means that you can use JS like a back-end language..? Whereas "running inside a browser," means you can only code visual/front-end interactions, things only users see. Am I correct?
Yes you are more or less on the right track. The V8 engine is what powers both chrome and nodejs. When used with nodejs, it provides a runtime environment for javascript that allows JS code to be run "outside the browser". Traditionally the only place javascript could run was in a browser that implemented support for ECMAScript (all major browsers). But then along came node.js, which pulled out the critical v8 engine from chrome, and mixed with LibUV for C++ support, created the first runtime that successfully allowed Javascript to run without a browser to run the code. With Node.js (and Deno if you are curious) we can implement a variety of "back-end", server-side, code. Think anything you could program in another language now available to be programmed in Javascript. Node.js and Express js are absolutely great for running web servers, microservices, and many other services independent from a browser run time environment.
Originally, the ability to process the JavaScript language was something that Netscape added to their browser so that it could process not only HTML and CSS, but also JavaScript. Microsoft followed suit and so did all the other browsers. That's what we call running JavaScript within the browser.
But (as an example) Node.js is a command line runtime that includes the core JavaScript runtime, but extracted from the Chrome browser itself. So, with Node, you have the ability to write and run JavaScript, but you aren't running it inside of a browser and therefore you don't have the Document Object Model (DOM) or the Browser Object Model (BOM) available to you because those are APIs that are native to browsers.
But you do have the core JavaScript language and can create applications that do all sorts of non-browser tasks.
You'll find that many other development environments and tools have similar set ups, where the core JavaScript runtime has been added so that you can develop with JavaScript, but outside of a browser.

Are Runtime environments and Compilers/Interpreters the same?

I'm just getting started with Node.js and I have quite a bit of background in Python and C++. I got to know that Node.js is a runtime environment but I'm having a rough time understanding what actually it does to a code that makes it different from a compiler. It would be better if someone can explain how specifically runtime environments differ from typical compilers and interpreters.
Let's take it this way:
Node.js is a JavaScript runtime built on Chrome’s V8 JavaScript engine.
V8 is the Google Javascript engine, the same engine is used by Google Chrome.
There are other JS engines like SpiderMonkey used by Firefox, JavaScriptCore used by Safari, and Edge was originally based on Chakra but it has been rebuilt to use the V8 engine.
We must understand the relationship first before moving to how the V8 works.
JavaScript engine is independent of the browser in which it's hosted. This key feature enabled the rise of Node.js. V8 was chosen to be the engine that powered Node.js.
Since V8 is independent and open-source, we can embed it into our C++ programs, and Nodejs itself is just a program written in C++. Nodejs took the V8 and enhanced it by adding features that a server needs.
JavaScript is generally considered an interpreted language, but modern JavaScript engines no longer just interpret JavaScript, they compile it.
Since you have a C++ background, C++ performs what is called ahead-of-time (AOT) compilation, the code is transformed during compilation into machine code before the execution.
JavaScript on the other side is internally compiled by V8 with just-in-time (JIT) compilation is done during execution. While the code is being executed by the interpreter it will keep track of functions that are called very often and mark them as hot functions then it will compile them to machine code and store them.
A compiler is a program that converts code from one language to another. In Java for example we have a the java compiler javac that you can run on your .java files to compile your code into platform independent java file (can be understood and executed by any jvm).
Since you are new to JavaScript, you will encounter the transpilers (like babel) that turns your next generation JavaScript code into a legacy JavaScript code that can be handled by all browsers (even old ones).
A runtime is a more vague concept. It can go from being a set of functions to run a compiled code on a specefic operating system to being the whole environment in which your program runs.
For the case NodeJS, it's the environment on which you can run a JavaScript program out of the browser. It took the V8 Engine of Chrome that runs JavaScript on the Chrome browser and made it available everywhere. That's how JavaScript moved from being a Client side Programming Language that runs only on the browser to a server side Programming Language that can run on servers equiped with the runtime environment NodeJS.
A few simple points that might help:
C/C++ code will be compiled by the C/C++ compiler into the machine code and will not need any runtime environment to run (mostly, except the run-time libraries)
Python code needs Python interpreter to execute it. As you say you have background in C++/Pythons you must be familiar with all these nitty-gritty
JavaScript was meant to run in the browser and it does mostly, however some smart folks thought of running it outside the browsers and they created the JavaScript execution engine (which is kind of stand alone JavaScript executor) and Node.js is just one of them. It simply runs the JavaScript code outside browser on it's own. The execution is still interpretation of JavaScript code so it is just an interpreter with hell lot of support functions for managing the runtime dependencies, package management, etc.

Launch an external JS engine with forwarding data from the browser

I want to analyze a large and confusing JS code. The code is heavily obfuscated and even tools like JStillery cannot work with it.
I would like to somehow build one of the open JS-interpreters, run it outside the browser and debug in more traditional ways, if necessary, applying patches inside the interpreter.
Unfortunately, the code uses DOM and cannot be executed without a browser.
The question is: are there any known techniques to take any external engine (such as V7, V8, DukTape, JerryScript, MuJS, quad-wheel, QuickJS, tiny-js, ...) and run code inside them that contains calls to DOM and other browser parts?
There are pure-JavaScript implementations of the DOM, such as https://github.com/jsdom/jsdom. Not sure how useful that is for your use case, but it does address your primary question: it allows you to run JavaScript that assumes a browser environment outside the browser environment.
I believe jsdom is fairly accurate in its implementation; there are other implementations out there that are more mock-like. Either way, there are probably some remaining differences, so heavily obfuscated code may well include mechanisms to detect emulated environments...

Is web browser JavaScript runtime?

In Node.js website, they say Node.js is a JavaScript runtime.
Are web browsers like Chrome, Firefox, Edge, ... JavaScript runtimes?
I thought of course, web browser is JS runtime. But I'm confused, In this video 12:10~ He says Web browser is not just JavaScript runtime because it can do more things
at one time, it can give us other things.
But I think V8 engine only can do one thing at one time, while JS runtime can do more things than one at one time.
Am I wrong?
A browser contains a Javascript engine (for example Chrome v8). The engine implements a Javascript runtime, which includes the call stack, heap and event loop. The browser also usually includes a set of APIs that augment the Javascript runtime and make asynchronous code execution possible.
NodeJS also implements a Javascript runtime using Chrome's v8 engine as well as the Libuv library (event loop and worker threads).
Here's a good video that breaks this all down:
https://www.youtube.com/watch?v=4xsvn6VUTwQ
They are right, a JavaScript runtime just executes the JavaScript code.
All Web browsers include a JavaScript runtime engine(RE) that executes js code for them but they also have other plugins like java or flash, as well as an html/dom parser and renderers that are not part of the RE, even if those modules were written in JavaScript it does not mean they would be part of the RE.

Javascript Engines Advantages

I am confused about JavaScript engines right now. I know that V8 was a big deal because it compiled JavaScript to native code.
Then I started reading about Mozilla SpiderMonkey, which from what I understand is written in C and can compile JavaScript. So how is this different from V8 and if this is true, why does Firefox not do this?
Finally, does Rhino literally compile the JavaScript to Java byte code so you would get all the speed advantages of Java? If not, why do people not run V8 when writing scripts on their desktops?
There are various approaches to JavaScript execution, even when doing JIT. V8 and Nitro (formerly known as SquirrelFish Extreme) choose to do a whole-method JIT, meaning that they compile all JavaScript code down to native instructions when they encounter script, and then simply execute that as if it was compiled C code. SpiderMonkey uses a "tracing" JIT instead, which first compiles the script to bytecode and interprets it, but monitors the execution, looking for "hot spots" such as loops. When it detects one, it then compiles just that hot path to machine code and executes that in the future.
Both approaches have upsides and downsides. Whole-method JIT ensures that all JavaScript that is executed will be compiled and run as machine code and not interpreted, which in general should be faster. However, depending on the implementation it may mean that the engine spends time compiling code that will never be executed, or may only be executed once, and is not performance critical. In addition, this compiled code must be stored in memory, so this can lead to higher memory usage.
The tracing JIT as implemented in SpiderMonkey can produce extremely specialized code compared to a whole-method JIT, since it has already executed the code and can speculate on the types of variables (such as treating the index variable in a for loop as a native integer), where a whole-method JIT would have to treat the variable as an object because JavaScript is untyped and the type could change (SpiderMonkey will simply "fall off" trace if the assumption fails, and return to interpreting bytecode). However, SpiderMonkey's tracing JIT currently does not work efficiently on code with many branches, as the traces are optimized for single paths of execution. In addition, there's some overhead involved in monitoring execution before deciding to compile a trace, and then switching execution to that trace. Also, if the tracer makes an assumption that is later violated (such as a variable changing type), the cost of falling off trace and switching back to interpreting is likely to be higher than with a whole-method JIT.
V8 is the fastest, because it compiles all JS to machine code.
SpiderMonkey (what FF uses) is fast too, but compiles to an intermediate byte-code, not machine code. That's the major difference with V8. EDIT- Newer Firefox releases come with a newer variant of SpideMonkey; TraceMonkey. TraceMonkey does JIT compilation of critical parts, and maybe other smart optimizations.
Rhino compiles Javascript into Java classes, thus allowing you to basically write "Java" applications in Javascript. Rhino is also used as a way to interpret JS in the backend and manipulate it, and have complete code understanding, such as reflection. This is used for example by the YUI Compressor.
The reason why Rhino is used instead of V8 all over the place is probably because V8 is relatively new, so a lot of projects have already been using Rhino/Spidermonkey as their JS engine, for example Yahoo widgets. (I assume that's what you're referring to with "scripts on their desktops")
edit-
This link might also give some insight of why SpiderMonkey is so widely adopted.
Which Javascript engine would you embed in your application?
If you want to see how the various in-browser Javascript engines stack up, install Safari 4 (yes it runs on Windows now too!), Chrome V8, Firefox 3.5, and IE 8 (if you are on windows) and run the benchmark:
http://www2.webkit.org/perf/sunspider-0.9/sunspider.html
I believe as Pointy said above, the new Firefox 3.5 uses TraceMonkey that also compiles to intermedit code on the fly using some form of JIT. So it should compare to V8 somewhat favorably. At least it won't be 10x slower than V8 like Firefox 3 SpiderMonkey (without JIT) was.
For me... safari 4.0.3 was 2.5x faster than Tracemonky in Firefox 3.5.3 on Win XP. IE8 was much much slower. I don't have Chrome installed at the moment.
Don't know about Rhino compiling to java bytecode. If it's still interpreting the dynamic features of Javascript such as being able to add attributes to object instances at runtime (example obj.someNewAttribute="someValue" which is allowed in Javascript)... I'm not so sure that it's entirely "compiled" to bytecode, and you might not get any better performance other than you don't have to compile from Javascript source code text every time your Javascript runs. Remember that Javascript allows very dynamic syntax such as eval("x=10;y=20;z=x*y"); which means you can build up strings of code that get compiled at runtime. That's why I'd think Rhino would be mixed-mode interpreted/compiled even if you did compile to JVM bytecode.
The JVM is still an interpreter, albeit a very good one with JIT support. So I like to think of Rhino-on-JVM as 2 interpreter layers (interpreter-on-interpreter) or interpreter^2. Whereas most of your other Javascript engines are written in C, and as such should perform more like interpreter^1. Each interpreter layer can add 5-10x performance degradation as compared to C or C++ (ref Perl or Python or Ruby for example), but with JIT the performance hit can be much lower on the order of 2-4x. And the JVM has one of the most robust & mature JIT engines ever.
So your mileage will definitely vary and you probably would benefit from doing some serious benchmarks if you want a real answer for your intended application on your own hardware & OS.
Rhino can't be too awfully slow, since I know lots of folks are using it. I think it's main appeal is not its speed, but the fact that is easy-to-code/light-weight/embeddable/interpreter that has hooks into Java libraries, which makes it perfect for scripting/configuration/extensibility of your software project. Some text editors like UltraEdit are even embedding Javascript as an alternative macro scripting engine. Every programmer seems to be able to stumble through javascript pretty easily, so it's easy to pick up as well.
One advantage to Rhino is that it runs pretty much anywhere the JVM runs. In my experience, trying to get stand-alone TraceMonkey or SpiderMonkey to build & run from command line can be a bit painful on systems like Windows. And embedding in your own application can be even more time consuming. But the payback to having an embeddable language would be worth it for a big project, as compared to having to "roll your own" mini scripting solution if that's what you're looking to do.
Scripting with Rhino is really easy if you have Java and the rhino jar, you just write your javascript and run it from command line. I use it all the time for simple tasks.
To respond the question, why native code Vs Byte code...
The native code is faster and for google a strategic choice because they have plan to JS one of them at least is ChromeOS.
A good video about this question is posted on Channel9 with an interview with Lars Bak the man behind V8 can be found here
2022 Update
V8 as also SpiderMonkey do support MultiPass Compilation as also SinglePass Compilation.
Java Rhino got deprecated and replaced by a new concept called Truffle Framework it is part of the GraalVM Stack which is in fact a JVMCI added to the JVM where CI means Compiler Interface. That allows the Truffle Language Implementer Framework to Implement any Language and translate that to Java Byte Code in MultiPass and Single Pass. the ECMAScript implementation is called GraalJS and it comes in 2 Flavors
GraalJS the 1:1 Rhino Replacement including compatability mode for incremental adoption and graal-node a NodeJS Fork where v8 is replaced with the GraalJS Engine.
as sayed Truffle is a Polyglot Language Implementer Framework so that works with any GraalVM Supported Language.
hope that helps and makes some sense since the jar versions do most best work when the whole stack has aligned versions you should alaways install the complet stack:
https://github.com/graalvm/graalvm-ce-builds/releases
download and install that then use the so called gu command to add graaljs
follow the instructions here: https://github.com/oracle/graaljs
Yes GraalVM can in general Compile Single Binary Executeable Files of all Polyglot Languages this is called AOT Compilation it has faster boot times but less throughput it can also do JIT and it can do a mix of both.

Categories

Resources