Self-hosted builtins in SpiderMonkey

この記事は技術レビューを必要としています。

この記事はまだ日本語に翻訳されていません。MDN の翻訳はボランティアによって行われています。是非 MDN に登録し、私たちの力になって下さい。

Support for self-hosting is currently a work in progress. While much functionality already works and can be used in production, there are some restrictions. This document describes self-hosting support as implemented in Firefox 25.

Since Firefox 17, SpiderMonkey has the ability to self-host built-in functions in JavaScript.

Differences from normal JavaScript

Two important don'ts when writing self-hosted JS code:
- Don't use fooFunction.call() and fooFunction.apply(). Use callFunction(fooFunction, receiver, [args]) instead, as described below.
- Don't reference other builtins' methods directly, use the std_Obj_Method versions as assigned in builtin/Utilities.js. Using [].forEach(...) would be potentially unsafe, as it can be overridden by content code assigning to Array.prototype.forEach. Using callFunction(Array.prototype.forEach, [], ...), OTOH, is safe, but highly inefficient, as it clones the self-hosting environment's entire Array and Array.prototype objects with all their methods.

Self-hosted functions invoked in a null or undefined scope won't be run in the scope of the global object. Normally, this is only true for strict-mode JS. This deviation has been implemented to work around some serious performance degradations associated with strict mode that made converting natively implemented functions to JS infeasible. Self-hosted code currently cannot be declared strict.

Self-hosted code has access to some functionality that's not available to normal JS code. Most importantly, it's possible to invoke any function within the scope of any object using the syntax callFunction(fun, receiver, ...args), which causes fun to be called within the scope of receiver with ...args as its arguments. In contrast to Function.prototype.call, this syntax makes it impossible for other code to interfere and gets compiled to bytecode that doesn't have any overhead compared to a normal function invocation.

Self-hosted functions by default are not constructors and do not have a prototype property, so that they meet the requirements for standard built-in functions as described in the ECMAScript Language Specification 5.1, clause 15. To make a self-hosted function a constructor, call MakeConstructible(FunctionName) after the function declaration. A prototype property can be added from the self-hosted code itself.

All self-hosted functions have direct access to each other and can rely on references being stable, i.e. not changeable by client JS code.

Self-hosted code can call functions implemented in C++ that are not visible to other JavaScript code if they are implemented as JSNatives and added to the intrinsic_functions array in SelfHosting.cpp. Some general-purpose functions provided in this way are:

  • The abstract operations ToObject, ToInteger, and IsCallable specified in the ECMAScript Language Specification.
  • ThrowError, which self-hosted code should use instead of throw so that the error message is specified in js.msg and can be localized.
  • The MakeConstructible function described above.

Standard built-in functions generally are specified such that their behavior does not change when application code replaces other built-in functions. On the other hand, self-hosted code often relies on other built-in functions, especially for string processing or list handling. The file Utilities.js provides some support for doing so safely:

  • It provides references to standard built-in functions that are cached when the self-hosting support is initialized, before any application code is executed. To call these functions, use callFunction as described above. If your code needs additional standard built-in functions, please add them. Note that this doesn't work for standard built-in functions that are themselves implemented as self-hosted code; for these, call the self-hosted implementations directly.
  • It provides implementations of List and Record, types defined in the ECMAScript specifications that are similar to Array and Object, but can't be modified by application code. If your code needs more methods on List, please add them.

Adding self-hosted functions to host objects

First, the code has to be embedded into SpiderMonkey. The easiest way to accomplish that is to add the code to a pre-existing .js file in builtins/. If it doesn't fit into any of those, create a new .js file in that directory and add it to the selfhosting_srcs list in Makefile.in.

To add a self-hosted function as a method to a host object, add it to that host object's JSFunctionSpec array. Example:

{"forEach",            JSOP_NULLWRAPPER,           1, 0, "ArrayForEach"}

This causes the self-hosted function ArrayForEach to be installed as the host object's method forEach.

Making JSNatives available to self-hosted code

For a JSNative to be available to self-hosted code, add it to the intrinsic_functions JSFunctionSpec array in SelfHosting.cpp.

Debugging self-hosted code

Self-hosted code by default is hidden from client JavaScript code; in particular, self-hosted frames will be filtered out of the stack traces of exceptions. To include self-hosted frames in stack traces (in debug builds only), set the environment variable MOZ_SHOW_ALL_JS_FRAMES.

Testing self-hosted code without recompiling

Because recompiling can take a long time, the ability to test self-hosted code without it is very convenient. Therefore, the JS shell and all Gecko-based applications support loading self-hosted JS code from an external file at startup.

Pre-processing JS code for self-hosting

After setting up an environment for compiling Spidermonkey, simply run make -C js/src selfhosting to pre-process the self-hosted JS code. This produces the file selfhosted.js in your build directory's js/src subdirectory.

Loading external JS code at startup

At startup, the Shell and Gecko-based applications check for the environment variable MOZ_SELFHOSTEDJS. If that is set, it is used to load a file containing pre-processed JS code instead of using the embedded code for self-hosting.

Examples:

# Start the shell with external self-hosted JS from within your build directory's 'js/src' subdir:
MOZ_SELFHOSTEDJS='./selfhosted.js' ./js
# Start Firefox with external self-hosted JS from within your build dir:
MOZ_SELFHOSTEDJS='./js/src/js/src/selfhosted.js' dist/bin/run-mozilla.sh dist/bin/firefox-bin

Document Tags and Contributors

Contributors to this page: kscarfone, tschneidereit, pnkfelix, Norbert
最終更新者: tschneidereit,