For what it's worth, on current tm tip the benchmark in bug 200505 shows that the self-hosted join from bug 460336 comment 7 is about 2x slower with -j -m. Curiously, the testcase is faster with either -j alone or -m alone. Filed bug 602479 on that.

I would like to find out what is required to do this and if it might be doable by me.
Some question from irc:
1) When should this compiled/parsed
- I think we should have one file with the js implementation and one with bytecode we load and distribute (xdr?)
2) What is about comparments
3) When and how do define this functions on the global object
4) (more a todo) Making the look native

I think self-hosting is really cool, but I wanted to point out that we keep optimizing Array.prototype.join b/c it keeps showing up (realistically or not) in benchmarks. The most recent patch took us from being slower than everyone to faster (bug 587257 comment 36) by making rather low-level optimizations that may be difficult to achieve in jitted JS. Not impossible, I'm just saying you should think about what the jit will be able to do vs. C++.

Just parroting irc for posterity: see the patch in bug 460904 comment 47. It addressed some of the same problems as would be faced with this bug, viz., how to load self-hosted JS and avoid the security/correctness hazard of content contaminating the environment in which the self-hosted JS is run.

Created attachment 633753[details][diff][review]
First draft patch of self-hosting support
I've modified js_DefineFunction and JSFunctionSpec to support self-hosting using minified one-line scripts.
Currently, the JS source is simply embedded as a string in the JSFunctionSpec struct, but that could be changed to an #include and some build-time minification.
As an example, I've added a self-hosted version of forEach.
The resulting shell and browser work as expected and pass all tests, but the resulting performance numbers are weird:
In the shell, the numbers are as expected: looping over an Array with 10.000.000 entries improves from ~1750ms to ~480ms.
In the browser, however, the loop now takes almost 3s, or about the same time as in the shell without "-m -n".
Based on that, the code doesn't get JITted for some reason.
Other than an explanation for that, I'd be interested in feedback on the general approach I've taken.

Comment on attachment 633753[details][diff][review]
First draft patch of self-hosting support
Review of attachment 633753[details][diff][review]:
-----------------------------------------------------------------
I love how delightfully simple this patch is, nice work on that. I think, unfortunately, we need a bit more machinery to defend against content corrupting our self-hosted function. The main issues I see in forEach are that the Object and TypeError properties on the global object are mutable. To address this, I think we need a special "self-hosted" compilation mode (triggered by js_DefineFunctions) that allows a magic syntax to let self-hosted JS do what it needs to do (like get the original Object and TypeError values). This feature would also be necessary to self-host other natives (in particular, String.prototype.replace will want to call String.prototype.match (or an optimized version that doesn't create garbage)). To wit, v8 self-hosted JS uses magic syntax extensively.
It would also be good to understand what is preventing jitting. I'd break right before a call to forEach and step through the JSOP_CALL (in particular, mjit::CanMethodJIT) to see what is going on.

(In reply to Luke Wagner [:luke] from comment #12)
> Comment on attachment 633753[details][diff][review]
> First draft patch of self-hosting support
>
> Review of attachment 633753[details][diff][review]:
> -----------------------------------------------------------------
>
> I love how delightfully simple this patch is, nice work on that. I think,
> unfortunately, we need a bit more machinery to defend against content
> corrupting our self-hosted function. The main issues I see in forEach are
> that the Object and TypeError properties on the global object are mutable.
> To address this, I think we need a special "self-hosted" compilation mode
> (triggered by js_DefineFunctions) that allows a magic syntax to let
> self-hosted JS do what it needs to do (like get the original Object and
> TypeError values). This feature would also be necessary to self-host other
> natives (in particular, String.prototype.replace will want to call
> String.prototype.match (or an optimized version that doesn't create
> garbage)). To wit, v8 self-hosted JS uses magic syntax extensively.
That's a very good point. I guess one way to get around using special syntax would be to store references to the original values in a closure. Unfortunately, that would require not only compiling but also running the script immediately, so introducing a special compilation mode is in fact easier to implement.
I will look into that next.
>
> It would also be good to understand what is preventing jitting. I'd break
> right before a call to forEach and step through the JSOP_CALL (in
> particular, mjit::CanMethodJIT) to see what is going on.
Will do, thanks for the pointer.
And thanks for the feedback in general, that's very helpful indeed!

Till, thanks for picking this up! Not only will this help performance for these methods, the self-hosting capability should be very valuable for future library work, like ECMAScript internationalization, and maybe even just to simplify some of our existing functions.

> It would also be good to understand what is preventing jitting. I'd break
> right before a call to forEach and step through the JSOP_CALL (in
> particular, mjit::CanMethodJIT) to see what is going on.
Turns out it does get jitted after all: I just didn't know that code executed in the Scratchpad isn't jitted at all. Executing my simple benchmark in normal content script makes it 3x as fast as with the native forEach implementation.
(In reply to David Mandelin from comment #14)
> Till, thanks for picking this up! Not only will this help performance for
> these methods, the self-hosting capability should be very valuable for
> future library work, like ECMAScript internationalization, and maybe even
> just to simplify some of our existing functions.
Thanks David. I want to make self-hosting as easy to use as possible precisely so that it can be used heavily. Hopefully, that should get us into a position where the transition from a prototype implementation to a production-ready one is only a small bit of special syntax (plus tests) away.

So I thought about the problem of getting the original values of other builtins in self-hosted functions some more.
AFAICT, new syntax doesn't get us that much closer to really solving this problem: we still don't (yet) store these original values anywhere.
So how about we instead add a frozen, non-enumerable object "__builtins__" to the global object that gets initialized as the last step of GlobalObject::initStandardClasses and contains the original values of all builtins we care about in any self-hosted code?
If exposing this object to content script is considered a problem, then we could hide it in some way and add special self-hosting-only syntax to reach it. Having a way to get at original values for builtins seems desirable to me even in content script, but I guess that would need to be proposed to TC39 or the W3C/ WHATWG or so.

(In reply to Till Schneidereit [:till] from comment #16)
> AFAICT, new syntax doesn't get us that much closer to really solving this
> problem: we still don't (yet) store these original values anywhere.
We do, actually in the slots of the global object. We already have to do this since, e.g., ({}) always uses the original value of Object.prototype, not the current. There are nice typed accessors like js::GlobalObject::getOrCreateObjectPrototype and not-so-nice accessors that touch the slots directly (in, e.g., js_GetClassPrototype).
Another benefit of magic syntax is that you can call magic conversion functions as necessary: v8 does this a lot, e.g., to test the int/double representation which not so cheap/easy to test from pure JS.

(In reply to Luke Wagner [:luke] from comment #17)
> (In reply to Till Schneidereit [:till] from comment #16)
> > AFAICT, new syntax doesn't get us that much closer to really solving this
> > problem: we still don't (yet) store these original values anywhere.
>
> We do, actually in the slots of the global object. We already have to do
> this since, e.g., ({}) always uses the original value of Object.prototype,
> not the current. There are nice typed accessors like
> js::GlobalObject::getOrCreateObjectPrototype and not-so-nice accessors that
> touch the slots directly (in, e.g., js_GetClassPrototype).
Ah, nice, thanks! So these values are deep copies of what's available to content scripts, i.e. all of their properties and their prototypes aren't changed if the content script counterpart is changed?
So say I have the syntax "#builtin#Function.prototype.call", which would, roughly, mean "get the original value of "Function" and then look up "prototype.call" on it. If I understand correctly, the steps to do that are the following:
1. get current global
2. use js_GetClassPrototype to get the prototype of Function
3. continue with the normal lookup of "prototype" on Function, etc.
I'm still not entirely sure how to get from a class name used in the script to the corresponding JSProtoKey. Do we have some kind of lookup table for that, or would I need to create one?
Other than that, adding support for special lookup syntax sounds pretty doable.
>
> Another benefit of magic syntax is that you can call magic conversion
> functions as necessary: v8 does this a lot, e.g., to test the int/double
> representation which not so cheap/easy to test from pure JS.
Right, I hadn't considered that. We would have to add more syntax for that, though, right? Meaning just adding support for "#builtin#" (or something similar) wouldn't gain us access to other internal engine functionality?

(In reply to Till Schneidereit [:till] from comment #18)
Great questions!
> Ah, nice, thanks! So these values are deep copies of what's available to
> content scripts, i.e. all of their properties and their prototypes aren't
> changed if the content script counterpart is changed?
They are just copies of the single value. Thus, every single value that was needed "the original Function.prototype.call", "the original Object.prototype", etc would need to be acquired manually.
Btw, a good reference is v8's self-hosted forEach:
http://code.google.com/p/v8/source/browse/trunk/src/array.js#1062
Everything in CAPS and prefixed with % is magic; I guess the CAPS generate inline ops whereas the % is for naming and calling builtin functions?

hey norbert, this all sounds great! after looking at the usage of self-hosting in v8 in some more detail, i've come to really understand how much library api can be implemented in js itself.
hence, i plan on working towards making self-hosting as easy as possible, with the ideal outcome being to match v8 in this regard. if things go as planned, it should be possible to just code in js while using %identifier syntax to safely reference builtins. thus, looking at the link in comment 19 should give you a good idea of what to expect.
i'm on vacation next week, so don't expect any progress until july, but i'm looking forward to working with you once i'm back.

Here's a first crack at defining the prerequisites for self-hosting the Intl module:
- installing Intl and its constructors and related objects before any application code runs, but after ECMAScript built-ins are made available.
- access to HasProperty (ES 5.1, 8.12.6), ToBoolean (ES 5.1, 9.2), ToNumber (ES 5.1, 9.3), ToUint32 (ES 5.1, 9.6), ToString (ES 5.1, 9.8), ToObject (ES 5.1, 9.9), CheckObjectCoercible (ES 5.1, 9.10).
- access to standard implementations of ECMAScript functions such as Array.prototype.indexOf, and ability to call them safely, as discussed in several comments above.
- access to functions that I'll implement in C++, such as compareStrings, formatNumber, and formatDateTime.
- ability to create functions that only implement [[Call]], not [[Construct]].
- "internal properties": properties on objects that outside code cannot access, that aren't affected by setters on Object.prototype, but that are visible across the Intl package. Operations: set value (which also adds the property), get value, test presence. Not needed: delete. The use of internal properties is not limited to objects created within the Intl module - the spec requires that objects created by application code can be initialized with the internal properties of Collator, NumberFormat, DateTimeFormat.
- "Record" type: Container of properties similar to Object, but not affected by changes to Object.prototype (I can probably implement this myself if necessary).
- "List" type: Similar to Array, but not affected by changes to Array.prototype. Operations: push, indexOf, convert to normal Array (I may be able to implement this myself if necessary).
- ability to keep source code in readable form in a separate text file - minified code could be generated at build time, but cannot be the source. The Intl module currently stands at over 2000 lines…

(In reply to Norbert Lindenberg from comment #22)
> Here's a first crack at defining the prerequisites for self-hosting the Intl
> module:
Thanks for the detailed list! Some inline comments below:
> - "internal properties": properties on objects that outside code cannot
> access, that aren't affected by setters on Object.prototype, but that are
> visible across the Intl package. Operations: set value (which also adds the
> property), get value, test presence. Not needed: delete. The use of internal
> properties is not limited to objects created within the Intl module - the
> spec requires that objects created by application code can be initialized
> with the internal properties of Collator, NumberFormat, DateTimeFormat.
Ideally, we'd use private name objects to implement this, instead of using some proprietary functionality. Bug 645416 has a very bit-rotted patch implementing them.
>
> - "Record" type: Container of properties similar to Object, but not affected
> by changes to Object.prototype (I can probably implement this myself if
> necessary).
Would Object.create(null) work for this or do you need an instance with the prototype set to an unmodified version of Object.prototype?
>
> - "List" type: Similar to Array, but not affected by changes to
> Array.prototype. Operations: push, indexOf, convert to normal Array (I may
> be able to implement this myself if necessary).
This requirement should be met by providing access to an unmodified version of Array.prototype as explained in comment 19.
>
> - ability to keep source code in readable form in a separate text file -
> minified code could be generated at build time, but cannot be the source.
> The Intl module currently stands at over 2000 lines…
This is an important requirement in general. Ideally, we will be able to re-use much of V8's preprocessing stuff or at least implement something very similar.

(In reply to David Mandelin [:dmandelin] from comment #24)
> Hey, Till. How's it going? Do you need any help from us?
Hey David, thanks for asking! I'm close to having a first, rough, implementation of support for calling intrinsics with the syntax "%intrinsicsName(args)". I'll combine that with the self-hosting stuff I already did and attach the results tomorrow to get some feedback.
After that, I'll have lots of questions about both the specifics of my implementation and about how best to integrate JS source into the build process.

An update on the requirements in comment 22:
- I got Record and List to work based on Object.create(null) and original Array methods, so these two are off the list.
- I found I need a few more capabilities to meet the requirements for built-in functions, which are a bit different from the properties of normal functions. See (3a) below.
- Dave suggested that I prioritize the requirements a bit.
So here's the updated list:
(1) Needed to get up and running:
(1a) Ability to keep source code in readable form in a separate text file - minified code could be generated at build time, but cannot be the source.
(1b) Installing Intl and its constructors and related objects before any application code runs, but after ECMAScript built-ins are made available.
(1c) Access to standard implementations of ECMAScript functions such as Array.prototype.indexOf, and ability to call them safely, as discussed in several comments above.
(1d) Access to functions that I'll implement in C++, such as compareStrings, formatNumber, and formatDateTime.
(2) Needed to provide a secure environment:
(2a) "Internal properties": properties on objects that outside code cannot access, that aren't affected by setters on Object.prototype, but that are visible across the Intl package. Operations: set value (which also adds the property), get value, test presence. Not needed: delete. The use of internal properties is not limited to objects created within the Intl module - the spec requires that objects created by application code can be initialized with the internal properties of Collator, NumberFormat, DateTimeFormat. I looked at the Harmony proposal for private names, and it looks like they should meet my needs.
(3) Needed to pass compliance tests:
(3a) Ability to create functions that only implement [[Call]], not [[Construct]], do not have a prototype property, and have a length property that can be first set and then be made non-writable.
(4) Needed for better performance and less redundancy:
(4a) Access to HasProperty (ES 5.1, 8.12.6), ToBoolean (ES 5.1, 9.2), ToNumber (ES 5.1, 9.3), ToUint32 (ES 5.1, 9.6), ToString (ES 5.1, 9.8), ToObject (ES 5.1, 9.9), CheckObjectCoercible (ES 5.1, 9.10).

Not completely there, yet, but I'm very close to having all the pieces needed to demonstrate how this can all work. Unfortunately, I'm out of time for today, so I'll attach the preliminary results tomorrow.
(In reply to Norbert Lindenberg from comment #26)
> So here's the updated list:
>
> (1) Needed to get up and running:
>
> (1a) Ability to keep source code in readable form in a separate text file -
> minified code could be generated at build time, but cannot be the source.
The exact mechanism of how to process the readable source at build time is what I'm still the least clear about. My hope is, though, to be able to pretty much use what V8 has for that - if that's not prevented by licensing issues, that is.
>
> (1b) Installing Intl and its constructors and related objects before any
> application code runs, but after ECMAScript built-ins are made available.
This will work in much the same way as the setup of other built-ins, with all built-ins having the option of being implemented using self-hosted JS or JSNatives.
>
> (1c) Access to standard implementations of ECMAScript functions such as
> Array.prototype.indexOf, and ability to call them safely, as discussed in
> several comments above.
I currently have the ability of getting builtin functions via the %_Name syntax. As that syntax only allows for getting functions as if they were globals, they have to be called with the intended this-object as an argument.
Example:
Instead of calling
myArray.indexOf(foo)
you have to call
%_ArrayIndexOf(myArray, foo)
The final part that missing before I can demonstrate a simple example is a mechanism for invoking the indexOf builtin with the this-object properly set.
My current thinking is that that will look very similar to the js_generic_native_method_dispatcher defined in jsapi.cpp.
>
> (1d) Access to functions that I'll implement in C++, such as compareStrings,
> formatNumber, and formatDateTime.
This will work in the same way as accessing other builtin functions.
>
> (2) Needed to provide a secure environment:
>
> (2a) "Internal properties": properties on objects that outside code cannot
> access, that aren't affected by setters on Object.prototype, but that are
> visible across the Intl package. Operations: set value (which also adds the
> property), get value, test presence. Not needed: delete. The use of internal
> properties is not limited to objects created within the Intl module - the
> spec requires that objects created by application code can be initialized
> with the internal properties of Collator, NumberFormat, DateTimeFormat. I
> looked at the Harmony proposal for private names, and it looks like they
> should meet my needs.
The way I have currently implemented access to builtin functions, they're set as properties of an "intrinsics holder" JSObject in a slot of the globalObject. This holder object can be used as the scope for storing internal properties. One possible way to access them would be by introducing a function %_GetInternal("name").
>
> (3) Needed to pass compliance tests:
>
> (3a) Ability to create functions that only implement [[Call]], not
> [[Construct]], do not have a prototype property, and have a length property
> that can be first set and then be made non-writable.
I'll have to talk to Luke or get help on #jsapi for that as I don't know if and how that's possible in SpiderMonkey.
>
> (4) Needed for better performance and less redundancy:
>
> (4a) Access to HasProperty (ES 5.1, 8.12.6), ToBoolean (ES 5.1, 9.2),
> ToNumber (ES 5.1, 9.3), ToUint32 (ES 5.1, 9.6), ToString (ES 5.1, 9.8),
> ToObject (ES 5.1, 9.9), CheckObjectCoercible (ES 5.1, 9.10).
These can most likely be made available as %_HasProperty, etc.

(In reply to Till Schneidereit [:till] from comment #25)
> (In reply to David Mandelin [:dmandelin] from comment #24)
> > Hey, Till. How's it going? Do you need any help from us?
>
> Hey David, thanks for asking! I'm close to having a first, rough,
> implementation of support for calling intrinsics with the syntax
> "%intrinsicsName(args)". I'll combine that with the self-hosting stuff I
> already did and attach the results tomorrow to get some feedback.
Sweet. By the way, since this is not exposed to content, and no one's using it just yet, you should feel free to land it in pieces and fix it up as you go. We can just document which pieces are solid enough to be used (more to the point, that you don't mind people using at that point). No need to create one giant patch (in fact, incremental development is greatly preferred.)

Created attachment 642269[details][diff][review]
interpret op code for intrinsic function calls
These three patches add support for invoking functions with the syntax "%functionName".
To make a function available via this syntax, it needs to be added to the intrinsic_functions array. Setting the flag JSFUN_INTRINSIC_METHOD means that the call is routed through js_generic_native_method_dispatcher to use the first argument as the |this| value.
To store the intrinsic functions, I added a new slot to global objects, containing an "intrinsics holder". This can be used to store not only the functions themselves, but also any internal state that might be required, which can then be retrieved by using a (yet to be introduced) intrinsic function along the lines of %_GetInternal("propname").
Problems that I'm aware of:
- the intrinsic functions stuff should probably be moved into its own source file, or at least moved to a different part of GlobalObject.cpp
- I haven't yet added the flag that enables the intrinsic call syntax - it's currently valid in all JS code. That's because I'm not sure how to set it for tests in the shell and because I want to wait for bug 771705 to land before adding the compile mode
Things that I'm unsure about:
- the whole approach of using a JSObject as a "holder" for intrinsic functions and then sort of borrowing them. I'm not sure if there's a problem associated with that such as too much memory overhead or something
- how to integrate this with the JITs. I really don't know much of anything about the JITs at all, so I'll probably ask lots of questions on #jsapi

Created attachment 642401[details]
Benchmark of self-hosted Array.prototype.forEach
So I managed to at least add basic JM support for JSOP_CALLINTRINSIC. With all patches applied, the attached testcase takes about 15ms without a thisarg (which makes it not use %_CallFunction) and about 260ms with one (which does make it use %_CallFunction).
For comparison, using the native Array.prototype.forEach (e.g. by commenting out line 47 of the testcase), both cases take about 180ms for me.
Commenting out/in lines 35 and 36, respectively (thereby replacing %_CallFunction with the specialized, but forgeable Function.prototype.call) takes the times to 15ms and 25ms without and with thisarg.
It seems to me like it should be possible to completely remove the lookup for %_CallFunction and instead emit code that immediately invokes the given function with the correct object as the |this| value. In difference to Function.prototype.call, this shouldn't even need a guard, as we guarantee %_CallFunction to always mean the same.
For other %_-functions, we should at least be able to cache the returned JSFunction* without any guards, as it has to be stable anyway.

Created attachment 642990[details][diff][review]
special-casing of %_CallFunction in the BytecodeEmitter
This worked out pretty nicely, getting the forEach benchmark to run just as fast with a receiver as without one: both cases now take ~15ms instead of ~185ms on my computer.
For rewriting the argument nodes to work, I had to change EmitCallOrNew to derive argc from the number of emitted argument OPs. I'm not sure if simply deleting the fun and reveicer nodes like this isn't too dirty, really.
As far as I can tell, the other options would involve either changing EmitNameOp to also receive the parent node and properly delete the child nodes from that, or to have a feedback mechanism from EmitNameOp to emitCallOrNew to tell it to omit the first and last arg nodes.
Oh, and the atom for _CallFunction should probably be store somewhere instead of atomizing the char[] on each encounter of JSOP_INTRINSIC_NAME

Created attachment 643079[details]
Benchmark of self-hosted Array.prototype.forEach
With all patches applied, the attached benchmark executes both loops in ~15ms for me.
That's compared to ~185ms each with the built-in Array.prototype.forEach and 120ms/47ms in V8 with their self-hosted Array.prototype.forEach.

Wow, this is looking great! Nice job jumping into the front-end. I'll start with some high-level questions/comments:
With the %_CallFunction change you made in the last patch, can we avoid using generic natives altogether and the associated changes in the third patch?
Instead of having a holder object, I think we could just use a plain array of HeapPtr<JSFunction> stored in the JSCompartment (since there is (now) one per global). This avoids bringing in various messy bits of objects. Later, when we need access to global properties, instead of %_GetInternal("foo"), I think we could just use %_Foo for a statically enumerated set of global properties.
I think the main open question is how to load the self-hosted content. Scripts are per-compartment, so the simplest thing would be to re-parse every time we created a compartment. I think this would have non-trivial size/space overhead (esp. as we add more self-hosted content). Instead, I was thinking that we could:
- when we initialize the runtime, parse the JS (without COMPILE_N_GO set) into the atoms compartment (analogous to how we do with staticStrings.init()),
- when creating a new compartment, the HeapPtr<JSFunction> values start out 'null'
- on the first call to GlobalObject::getIntrinsic for a given function, call js::CloneInterpretedFunction on the corresponding function in the atoms compartment to create a clone in the running compartment.
This way, we only pay for the self-hosted functions that are actually used. Also, CloneInterpretedFunction is much faster than parsing. One remaining question is how to store the source for the runtime to parse. File access in the browser is complicated and scary, so perhaps you can just add a build step that creates a char array in some generated source file (eventually, after minification, etc). Any good JS minifiers written in Python?
Lastly, while small patches are good, it is a bit hard to review when the early patches require later patches to understand; could you fold them together for future reviews? Second, could we separate out the actual self-hosted content (parse_intrinsic_names.js and shell.js) from the machinery? Probably jwalden would be a good reviewer for the latter.

(In reply to Luke Wagner [:luke] from comment #42)
> Wow, this is looking great! Nice job jumping into the front-end. I'll
> start with some high-level questions/comments:
>
> With the %_CallFunction change you made in the last patch, can we avoid
> using generic natives altogether and the associated changes in the third
> patch?
Possibly, yes. We will, however, still need something like JSOP_CALLINTRINSIC for the other, non-specialcased, intrinsic function we want to call. I will check how many and which of these we'll probably need in addition to js_fun_call and whether they all work without the generic natives thing.
>
> Instead of having a holder object, I think we could just use a plain array
> of HeapPtr<JSFunction> stored in the JSCompartment (since there is (now) one
> per global). This avoids bringing in various messy bits of objects. Later,
> when we need access to global properties, instead of %_GetInternal("foo"), I
> think we could just use %_Foo for a statically enumerated set of global
> properties.
Ok, that sounds doable. As I want to keep the syntax identical to what V8 is using as much as possible, I will check what they're doing. But syntax aside, I agree about using a different storing mechanism.
>
> I think the main open question is how to load the self-hosted content.
> Scripts are per-compartment, so the simplest thing would be to re-parse
> every time we created a compartment. I think this would have non-trivial
> size/space overhead (esp. as we add more self-hosted content). Instead, I
> was thinking that we could:
> - when we initialize the runtime, parse the JS (without COMPILE_N_GO set)
> into the atoms compartment (analogous to how we do with
> staticStrings.init()),
> - when creating a new compartment, the HeapPtr<JSFunction> values start out
> 'null'
> - on the first call to GlobalObject::getIntrinsic for a given function,
> call js::CloneInterpretedFunction on the corresponding function in the atoms
> compartment to create a clone in the running compartment.
That's about what I had in mind, yes. There's one problem with it, though: not using CNG means that TI won't work for self-hosted scripts. My forEach test-case takes about 3x to 4x as long without TI enabled, so this might be a problem. I will ask bhackett about that.
>
> This way, we only pay for the self-hosted functions that are actually used.
> Also, CloneInterpretedFunction is much faster than parsing. One remaining
> question is how to store the source for the runtime to parse. File access
> in the browser is complicated and scary, so perhaps you can just add a build
> step that creates a char array in some generated source file (eventually,
> after minification, etc). Any good JS minifiers written in Python?
V8 uses a Python script to preprocess, minify and compress the js sources and embed them into a header file. I want to look into taking that script, modifying is as little as possible.
>
> Lastly, while small patches are good, it is a bit hard to review when the
> early patches require later patches to understand; could you fold them
> together for future reviews? Second, could we separate out the actual
> self-hosted content (parse_intrinsic_names.js and shell.js) from the
> machinery? Probably jwalden would be a good reviewer for the latter.
Makes sense, I will combine the next version of the patches for review. Those JS files aren't actually self-hosted content: they were attempts at adding a proper test-case. I removed them from the last round of patches. Actual self-hosted content is coming up.

(In reply to Till Schneidereit [:till] from comment #43)
> Possibly, yes. We will, however, still need something like
> JSOP_CALLINTRINSIC for the other, non-specialcased, intrinsic function we
> want to call.
Good point
> I will check how many and which of these we'll probably need
> in addition to js_fun_call and whether they all work without the generic
> natives thing.
My thinking was: if code wants to supply 'this', it should use %_CallFunction. Note, if there was some intrinsic _Foo we wanted to call supplying a 'this', we could write: %_CallFunction(thisValue, %_Foo). I noticed v8 has lots of uses like %_CallFunction(obj.receiver, ObjectToString); do you know if ObjectToString is a dynamically-resolved name or is it looked up in some static table?
> There's one problem with it, though:
> not using CNG means that TI won't work for self-hosted scripts. My forEach
> test-case takes about 3x to 4x as long without TI enabled, so this might be
> a problem.
Good point. When we do the CloneInterpretedFunction, I think we could set COMPILE_N_GO on the newly-cloned script since, by construction, it hasn't been specialized to any global.
> V8 uses a Python script to preprocess, minify and compress the js sources
> and embed them into a header file. I want to look into taking that script,
> modifying is as little as possible.
I like your style :) Being able to reuse v8's self-hosted js with minimal effort sounds awesome.

@Benjamin: Thanks for the reviews. The next patch will address your feedback.
(In reply to Luke Wagner [:luke] from comment #44)
> My thinking was: if code wants to supply 'this', it should use
> %_CallFunction. Note, if there was some intrinsic _Foo we wanted to call
> supplying a 'this', we could write: %_CallFunction(thisValue, %_Foo). I
> noticed v8 has lots of uses like %_CallFunction(obj.receiver,
> ObjectToString); do you know if ObjectToString is a dynamically-resolved
> name or is it looked up in some static table?
Looking into V8's self-hosting some more, I think you're right: they're using %_CallFunction in precisely the way you're proposing. I will remove the GENERIC_METHOD stuff.
> Good point. When we do the CloneInterpretedFunction, I think we could set
> COMPILE_N_GO on the newly-cloned script since, by construction, it hasn't
> been specialized to any global.
But won't that code then need to be reparsed? IIUC, CNG leads to other bytecode being emitted, right? Also, at if we want to reuse V8's self-hosted content, we need to enable the functions to directly access each other, without any special syntax. And for the internationalization work, simply accessing fields would simplify things quite a bit.
> I like your style :) Being able to reuse v8's self-hosted js with minimal
> effort sounds awesome.
Indeed :D

Comment on attachment 643075[details][diff][review]
Basic JM support for JSOP_CALLINTRINSIC, rebased
Review of attachment 643075[details][diff][review]:
-----------------------------------------------------------------
Looks good, but I don't see any cases for the INTRINSIC opcodes in analyzeTypesBytecode in jsinfer.cpp. Those will be needed, otherwise the type information will be incorrect and you'll get a crash in debug mode.
::: js/src/jsanalyze.cpp
@@ +314,2 @@
> case JSOP_CALLNAME:
> + case JSOP_CALLINTRINSIC:
The INTRINSIC opcodes do not depend on the scope chain, so they're more like GNAME opcodes than NAME opcodes and should go with those cases below (will allow more optimization).

Comment on attachment 643076[details][diff][review]
special-casing of %_CallFunction in the BytecodeEmitter, rebased
Review of attachment 643076[details][diff][review]:
-----------------------------------------------------------------
::: js/src/frontend/BytecodeEmitter.cpp
@@ +1724,5 @@
> break;
> case JSOP_INTRINSIC_NAME:
> + if (pn->atom() == js_Atomize(cx, "_CallFunction", strlen("_CallFunction"))) {
> + isCallFunction = true;
> + op = JSOP_CALLNAME;
This assignment to op is a bit confusing, it doesn't look like the variable will be used at all later in the function when isCallFunction is set. Can you set op = JSOP_CALLINTRINSIC unconditionally in this case? Also, the js_Atomize needs a NULL check, or (better, but don't know how hard this is) "_CallFunction" could be an atom in the runtime's atomState.
@@ +1764,5 @@
> + pn->pn_next = pn->pn_next->pn_next;
> + funNode = pn->pn_next;
> + ParseNode *pn2;
> + for (pn2 = pn->pn_next; pn2->pn_next->pn_next; pn2 = pn2->pn_next);
> + pn2->pn_next = NULL;
This looks OK, but I'm worried about the modification later on which removes the use of pn_count. The transformations done here should preserve the correctness of the pn_count information for the parse nodes, so that the later change isn't necessary.

(In reply to Brian Hackett (:bhackett) from comment #48)
> I don't think this modification to the API is necessary or desirable. The
> use is pretty specialized, it's not clear from the comment or the code what
> the semantics are, and JSFUN_GENERIC_NATIVE is already a pretty ugly piece
> of the API which it'd be nice to see removed if embedders aren't using it.
Agreed. Luke also pointed that out and I have since removed it in my patch queue. What's more, the later changes to the bytecode for specializing Function.call make even the one current use-case go away.
> Instead of using JSFUN_INTRINSIC_FUNCTION, you can define new natives which
> wrap js_fun_apply / js_fun_call. Maybe move the guts of
> js_generic_native_method_dispatcher into a header to avoid duplicating code.
As said above, this isn't needed anymore at all and has been removed entirely.
> Looks good, but I don't see any cases for the INTRINSIC opcodes in
> analyzeTypesBytecode in jsinfer.cpp. Those will be needed, otherwise the
> type information will be incorrect and you'll get a crash in debug mode.
They're contained in another patch. At Luke's request (and after seeing that the combined diff isn't all that big), I have since folded the entire patch queue into one patch. Subsequent versions will reflect that.
> The INTRINSIC opcodes do not depend on the scope chain, so they're more like
> GNAME opcodes than NAME opcodes and should go with those cases below (will
> allow more optimization).
Cool, will change to that.
> ::: js/src/frontend/BytecodeEmitter.cpp
> @@ +1724,5 @@
> > break;
> > case JSOP_INTRINSIC_NAME:
> > + if (pn->atom() == js_Atomize(cx, "_CallFunction", strlen("_CallFunction"))) {
> > + isCallFunction = true;
> > + op = JSOP_CALLNAME;
>
> This assignment to op is a bit confusing, it doesn't look like the variable
> will be used at all later in the function when isCallFunction is set. Can
> you set op = JSOP_CALLINTRINSIC unconditionally in this case? Also, the
> js_Atomize needs a NULL check, or (better, but don't know how hard this is)
> "_CallFunction" could be an atom in the runtime's atomState.
Adding "_CallFunction" as an atom is on my todo list - always re-atomizing is a crutch to get things going for now.
>
> @@ +1764,5 @@
> > + pn->pn_next = pn->pn_next->pn_next;
> > + funNode = pn->pn_next;
> > + ParseNode *pn2;
> > + for (pn2 = pn->pn_next; pn2->pn_next->pn_next; pn2 = pn2->pn_next);
> > + pn2->pn_next = NULL;
>
> This looks OK, but I'm worried about the modification later on which removes
> the use of pn_count. The transformations done here should preserve the
> correctness of the pn_count information for the parse nodes, so that the
> later change isn't necessary.
Apparently, that's not the case: I got a failing ASSERT because pn_count wasn't correct anymore. I couldn't see any way to fix that up from within EmitNameOp - hence the change in EmitCallOrNew.

(In reply to Till Schneidereit [:till] from comment #47)
> > Good point. When we do the CloneInterpretedFunction, I think we could set
> > COMPILE_N_GO on the newly-cloned script since, by construction, it hasn't
> > been specialized to any global.
>
> But won't that code then need to be reparsed?
When we initially parse the script without CNG (at runtime-init time), the parser will refrain from making any assumptions about the contents of the global. Thus, if we clone the script into a compartment, it is safe to add CNG b/c the cloned script makes no assumptions and will henceforth only be run with a single global.
> Also, at if we want to reuse V8's self-hosted
> content, we need to enable the functions to directly access each other,
> without any special syntax. And for the internationalization work, simply
> accessing fields would simplify things quite a bit.
Hrm, yes, !CNG would produce JSOP_NAME for all inter-function references which means a totally dynamic lookup which is a chance for content to corrupt things. We definitely need to bind, at compile-time, all references between self-hosted functions. Yesterday I was talking with billm about this and we thought that we should assert (when compiling self-hosted code) that there are no unbound name accesses in self-hosted code since it would almost certainly be a bug.
I think there is a simple solution that addresses both these concerns: in BindNameToSlot (in the emitter, where we try to specialize names to local, formal, global access), for any unbound name (the dn->pn_cookie.isFree() branch) where we would try to specialize to a global in CNG code, in self-hosted compiling mode we lookup that atom in the static table of self-hosted functions/globals; if we find it, we emit the equivalent of %_CallFunction, if not, we error out (which should never occur).

Created attachment 645087[details][diff][review]
Support parsing %funName() syntax, emitting correct bytecode and handling it in the interpreter and mjit
This version is pretty much complete.
It fully handles all %funName cases and contains a special-case for %_CallFunction that compiles it to optimal bytecode directly calling the given function in the correct scope.
The only thing still missing is hiding the special syntax behind a flag. I'm waiting on bug 771705 for that.

Created attachment 645096[details][diff][review]
Embed self-hosted JS and install it into standard classes
Applied ontop of the previous patch, this one embeds a self-hosted version of Array#forEach and correctly installs it on the Array prototype.
Things I still have to work on:
- cloning functions into a special object instead of the target compartment's global to hide them from content.
- externalizing JS code and automatically minifying it during the build process.
Numbers:
The following script took ~185ms on trunk and takes ~5ms to ~6ms with the patch applied:
var arr = new Array(1000000);
for (var i = 0; i < arr.length; ++i)
arr[i] = i;
var start = new Date;
arr.forEach(function f(val, idx, list) {list[idx] = val * val;}, {});
print(new Date - start);

Created attachment 645243[details][diff][review]
Embed self-hosted JS and install it into standard classes, v2
This version works in a full browser build, too, and adds preliminary support for Array.forEach.
The in-browser numbers are a little bit worse than the in-shell ones: 10ms in top-level code, 16ms in functions for the same benchmark. That's still a 18x and 11x speedup, respectively.
And for comparison, in Chrome 21 the testcase takes between 100ms and 160ms (with highly fluctuating numbers, for some reason).

Created attachment 646691[details][diff][review]
Support parsing %funName() syntax, emitting correct bytecode and handling it in the interpreter and mjit, v2
(In reply to Luke Wagner [:luke] from comment #56)
Thanks for the quick review!
> Looking good, once the "//TODO: add check for self-hosting parse mode" gets
> sorted out.
I have now added a flag "allowIntrinsicsCalls" to the parser that gets set through the new CompilerOptions struct.
That means that when only applying this patch, there's no way to actually parse the new syntax at all, which should hopefully make it landeable, right?
>
> ::: js/src/frontend/Parser.cpp
> > + PropertyName *name = tokenStream.currentToken().name();
> > + ParseNode *node = NameNode::create(PNK_NAME, name, this, this->tc);
>
> To catch errors, could this do a table lookup and issue an error if 'name'
> isn't in some list of intrinsics?
It can, but I'm not sure where to put that. The simplest thing would be to just look at the JSFunctionSpec[] in GlobalObject.cpp, but I'm a bit hesitant to expose that through the header and include that header into Parser.cpp.
Should I maybe extract the self-hosting stuff into a new .h/.cpp pair?

(In reply to Brian Hackett (:bhackett) from comment #59)
> Comment on attachment 645243[details][diff][review]
> Embed self-hosted JS and install it into standard classes, v2
>
> Review of attachment 645243[details][diff][review]:
> -----------------------------------------------------------------
>
> Nice, sorry for the slow review.
No worries, I know how busy you are.
> > + gcRootsHash.remove((void *)selfHostedGlobal_.address());
>
> This doesn't seem necessary.
I get a leak warning on shell shutdown without it.
> The JS_SetGlobalObject calls here and saving of the old global aren't
> necessary here, they control cx->globalObject which is basically irrelevant
> to the engine's behavior (it is used by the DOM / xpconnect in pretty
> screwed up ways and needs to die).
It seems like the shell uses it in some capacity as well: it crashes in NewContext without it.
> > + js::RootedObject selfHostedGlobal_;
>
> This needs to be a plain JSObject* or HeapPtrObject, using RootedObject and
> specifying the cx as NULL during construction will crash in builds where
> exact rooting is performed.
It only ever gets constructed with a proper cx and lets me get away with not explicitly removing the object root during runtime destruction. Should I still change it, and if so, do you think a plain JSObject* is ok given that it shouldn't ever be reassigned during a runtime's lifetime?

Created attachment 646996[details][diff][review]
Embed self-hosted JS and install it into standard classes, v3
This version addresses bhackett's feedback and adds support for using externally defined JS scripts as self-hosted code.
To do that, it imports a few Python scripts from V8 and adds a make target to use them to create a header (selfhosting.out.h) containing the minified version of (for now) builtin/array.js.
I tried changing the V8 scripts as little as possible, so there's quite a lot of stuff in there that we don't use yet, or in some cases can't even use. Case in point: build/macros.py defines a lot of macros that use intrinsics we haven't (yet) defined.
As my makefile-foo is far too weak for Mozilla's makefiles, this setup for now requires manual invokation of "make prepare-self-hosting" after changes to the self-hosted code.
Apart from that, this code works for Array.prototype.forEach, but has one final, pretty big, hole to it: the self-hosted functions can't refer to each other. Because of that Array.forEach is currently implemented using a reference to Array.prototype.forEach, which can be changed by user-code. Ideally, the code would just be able to refer to ArrayForEach, but that's not possible as it gets installed such that its |this| is Array, not the original scope it got compiled in.

(In reply to Andrew McCreight [:mccr8] from comment #65)
> If you are messing with the build system, make sure to get a review from a
> build system peer like khuey or Ted Mielczarek.
I'm not really planning to mess with it myself, at the very least not without consulting with someone who knows a great deal more about it. :) But yes: I'll make sure to get that reviewed by the right people, especially in light of the planned changes to the build system.

Here's where we stand with the latest couple of patches in terms of requirements for the internationalization stuff:
> (1a) Ability to keep source code in readable form in a separate text file -
> minified code could be generated at build time, but cannot be the source.
check. Just add a file intl.js or similar in the "builtin" dir and change the makefile target "prepare-self-hosting" to include it in selfhosting.out.h.
(The exact place to edit might change a bit.)
>
> (1b) Installing Intl and its constructors and related objects before any
> application code runs, but after ECMAScript built-ins are made available.
For now, this can be implemented using a JSFunctionSpec[] as is done in jsarray.cpp & co. We might want to enable installation of methods and properties from within self-hosted code later on, but this would add quite a bit of complication, so I think we should first land what we have now.
>
> (1c) Access to standard implementations of ECMAScript functions such as
> Array.prototype.indexOf, and ability to call them safely, as discussed in
> several comments above.
All required functions have to be installed using the JSFunctionSpec intrinsic_functions[] in GlobalObject.cpp for now. I toyed with a way to make all self-hosted functions automatically available using %name (e.g. %ArrayForEach for the currently implemented Array.prototype.forEach), but I hope that I can instead ad a way to just refer to them by their normal name. See the last paragraph of comment 64.
>
> (1d) Access to functions that I'll implement in C++, such as compareStrings,
> formatNumber, and formatDateTime.
These definitely have to be added to the intrinsic_functions[] array, which should be straight-forward.
>
> (2) Needed to provide a secure environment:
>
> (2a) "Internal properties": properties on objects that outside code cannot
> access, that aren't affected by setters on Object.prototype, but that are
> visible across the Intl package. Operations: set value (which also adds the
> property), get value, test presence. Not needed: delete. The use of internal
> properties is not limited to objects created within the Intl module - the
> spec requires that objects created by application code can be initialized
> with the internal properties of Collator, NumberFormat, DateTimeFormat. I
> looked at the Harmony proposal for private names, and it looks like they
> should meet my needs.
Again, see the last paragraph of comment 64. Alternatively, a holder object for these properties could be accessed using something like %_Internals().propName, where %_Internals just returns a normal object that's not accessible to client code.
>
> (3) Needed to pass compliance tests:
>
> (3a) Ability to create functions that only implement [[Call]], not
> [[Construct]], do not have a prototype property, and have a length property
> that can be first set and then be made non-writable.
I haven't looked into this, yet.
>
> (4) Needed for better performance and less redundancy:
>
> (4a) Access to HasProperty (ES 5.1, 8.12.6), ToBoolean (ES 5.1, 9.2),
> ToNumber (ES 5.1, 9.3), ToUint32 (ES 5.1, 9.6), ToString (ES 5.1, 9.8),
> ToObject (ES 5.1, 9.9), CheckObjectCoercible (ES 5.1, 9.10).
Some of these should be implemented as intrinsic functions, some as macros in "build/macros.py". For now, this file is just a verbatim copy from V8, so it contains a lot of macros we can't use without further work.
All in all, I think there's not that much more work to be done to get things ready for usage in implementing Intl.

Created attachment 647491[details][diff][review]
Support parsing %funName() syntax, emitting correct bytecode and handling it in the interpreter and mjit, v4
I took another stab at changing EmitCallOrNew. This version doesn't do any parse-node mutation. Instead, it emits the args inside the special-casing block for %_CallFunction and adds a flag `emitArgs` that guards against re-emitting them below.
While this adds a small amount of code-duplication, it feels much cleaner and prevents any problems with the rewritten parse-node down the road.
I also removed the mutation of the PNK and added the required conditions to all places that asserted because of that. I'm fairly certain that the restricted usage of INTRINSICNAME makes these additions sufficient, but even if not, any problems arising from other uses will be caught very early on as all self-hosted code is parsed on startup, anyway.
All additional changes are in BytecodeEmitter.cpp, with all except the ASSERT modifications within EmitCallOrNew.

Created attachment 647570[details][diff][review]
Support parsing %funName() syntax, emitting correct bytecode and handling it in the interpreter and mjit, v5, carrying r+luke
> Excellent choice! I was considering requesting a non-mutating version in
> the last review, but I couldn't come up with a good non-purely-aesthetic
> reason.
I didn't want to be the one setting the precedent that we now do parse-node mutation in the bce :)

Created attachment 647687[details][diff][review]
Support parsing %funName() syntax, emitting correct bytecode and handling it in the interpreter and mjit, v6
Trivial fix for the xpcshell-tests bustage.

Created attachment 648002[details][diff][review]
Embed self-hosted JS and install it into standard classes, v4
This version adds support for directly accessing functions defined in self-hosted code from other self-hosted code. For example. Array.forEach is implemented in terms of Array.prototype.forEach, which it refers to as "ArrayForEach".
As a side-effect, all intrinsic functions can now be accessed with or without the leading "%", with the exception of %_CallFunction, which gets compiled to special bytecode.
Additionally, during global initialization one can install objects into the self-hosting holder such that they can be accessed by self-hosted code. In the current builtin/array.js, this is used to access the |Object()| function in line 4, which would normally not be resolvable from self-hosted code.
As far as I can tell, this completes the set of features required to get most self-hosted code up and running. I'll look into proper build system integration next and deal with the more exotic requirements of the Intl implementation afterwards.

Created attachment 648120[details][diff][review]
Embed self-hosted JS and install it into standard classes, v5
This version adds proper integration with the build system and some more proper exceptions.
The only outstanding issues are:
- making toString on self-hosted function show [native code] instead of the real function body.
- show proper names in exceptions. E.g., invoking [].forEach() currently prints "self-hosted:5: TypeError: missing argument 0 when calling function ArrayForEach"

Created attachment 648397[details][diff][review]
Embed self-hosted JS and install it into standard classes, v6
After a hacking session with evilpie, this is pretty much ready, I think.
Exceptions now show the correct function names and omit frames from within self-hosted functions from the stack. Also, toString() correctly returns [native code] as the body.
Tests are all passing except for one that I can't explain at all:
jit-test/tests/jaeger/bug738525.js crashes with
Assertion failure: allocated(), at ../gc/Heap.h:506
during shutdown of the shell.
I reduced the problem to simply running the script "it.customNative = 1".
I'll ping luke and bhackett about that problem.
@gerv: I've added the following files that where imported from V8:
js/src/jsmin.py
js/src/macros.py
js/src/js2c.py
For now, changes are restricted to js2c.py, but we'll certainly have to change macros.py, too, at some point.
@ted: Please review the changes to Makefile.in, which should be pretty much as we discussed on IRC.
@bhackett: There's lots of new stuff compared to the version of the patch I f?'d you on. Please don't hesitate if you feel like asking me to change lots of stuff - I want to make this as clean as possible.

(In reply to Michael Clackler from comment #82)
> Just wondering if you have done any before/after performance testing with
> sunspider/v8/Kraken. Also, are there are any other functions which would
> help these benchmarks if self-hoisted.
This won't help with these benchmarks, as they don't use Array#forEach, no.
After the infrastructure for self-hosting lands, we'll look into moving more functionality over, so there might or might not be small wins to be had.

Comment on attachment 648397[details][diff][review]
Embed self-hosted JS and install it into standard classes, v6
Review of attachment 648397[details][diff][review]:
-----------------------------------------------------------------
This seems to be going really well. I looked closely at the array.js file, to see what's it like coding with the new feature. I have a few questions/comments below.
::: js/src/builtin/array.js
@@ +1,1 @@
> +function ArrayForEach(fun/*, receiver*/) {
I suppose we don't have jit support for rest arguments yet, but we should do some followup work to get that going and change this function to use 'em.
@@ +3,5 @@
> + %ThrowNoConstructorError();
> + if (arguments.length == 0)
> + %ThrowMissingArgError(0);
> + if (this == null || (typeof fun) !== 'function')
> + %ThrowValueError(0, 22);
Definitely want to do some followup to replace '22' with something better. It seems like if we had that we could also avoid (or embrace, depending on how it's done!) having one intrinsic for each kind of error to report.
Is the first argument to ThrowValueError the argument position? Shouldn't it be 1 in the 'fun' mismatch case?
Does (typeof fun) !== 'function' get fully optimized by the jits? If not, we might want to add an intrinsic for that at some point.
@@ +8,5 @@
> + var array = Object(this);
> + var len = array.length;
> + var receiver = arguments.length > 1 ? arguments[1] : null;
> + for (var i = 0; i < len; i++) {
> + if (i in array)
I'm also curious about the performance of this bit. Would it help to have a special case for dense arrays?
@@ +9,5 @@
> + var len = array.length;
> + var receiver = arguments.length > 1 ? arguments[1] : null;
> + for (var i = 0; i < len; i++) {
> + if (i in array)
> + %_CallFunction(receiver, array[i], i, array, fun);
What's the _ for?
@@ +17,5 @@
> +function ArrayStaticForEach(list, fun, receiver) {
> + if (arguments.length < 2)
> + %ThrowMissingArgError(1);
> + %_CallFunction(list, fun, receiver, ArrayForEach);
> +}
\ No newline at end of file
Last thing - do we have an established style for JS code in the JS engine? If not, I like the idea of 4 spaces to match Python and our C++ code.

(In reply to David Mandelin [:dmandelin] from comment #85)
> Comment on attachment 648397[details][diff][review]
> Embed self-hosted JS and install it into standard classes, v6
>
> Review of attachment 648397[details][diff][review]:
> -----------------------------------------------------------------
>
> This seems to be going really well. I looked closely at the array.js file,
> to see what's it like coding with the new feature. I have a few
> questions/comments below.
>
> ::: js/src/builtin/array.js
> @@ +1,1 @@
> > +function ArrayForEach(fun/*, receiver*/) {
>
> I suppose we don't have jit support for rest arguments yet, but we should do
> some followup work to get that going and change this function to use 'em.
The |receiver| argument is commented out because |forEach| is specified as only having one argument. I don't think rest would gain us anything here.
>
> @@ +3,5 @@
> > + %ThrowNoConstructorError();
> > + if (arguments.length == 0)
> > + %ThrowMissingArgError(0);
> > + if (this == null || (typeof fun) !== 'function')
> > + %ThrowValueError(0, 22);
>
> Definitely want to do some followup to replace '22' with something better.
> It seems like if we had that we could also avoid (or embrace, depending on
> how it's done!) having one intrinsic for each kind of error to report.
I have started implementing a better approach already: Using a Python script, the new approach enables direct usage of the enum entry's symbol as a string. I.e., |22| becomes "JSMSG_NOT_FUNCTION".
And I agree about not letting different error factory functions proliferate.
>
> Is the first argument to ThrowValueError the argument position? Shouldn't it
> be 1 in the 'fun' mismatch case?
Good point: That way I can also throw errors regarding the builtin function itself using the same function.
>
> Does (typeof fun) !== 'function' get fully optimized by the jits? If not, we
> might want to add an intrinsic for that at some point.
I added an intrinsic because this test doesn't entirely cover the test as specified.
>
> @@ +8,5 @@
> > + var array = Object(this);
> > + var len = array.length;
> > + var receiver = arguments.length > 1 ? arguments[1] : null;
> > + for (var i = 0; i < len; i++) {
> > + if (i in array)
>
> I'm also curious about the performance of this bit. Would it help to have a
> special case for dense arrays?>
> @@ +9,5 @@
> > + var len = array.length;
> > + var receiver = arguments.length > 1 ? arguments[1] : null;
> > + for (var i = 0; i < len; i++) {
> > + if (i in array)
> > + %_CallFunction(receiver, array[i], i, array, fun);
>
> What's the _ for?
This way, the name matches what V8 uses, making it easier to reuse their code.
>
> @@ +17,5 @@
> > +function ArrayStaticForEach(list, fun, receiver) {
> > + if (arguments.length < 2)
> > + %ThrowMissingArgError(1);
> > + %_CallFunction(list, fun, receiver, ArrayForEach);
> > +}
> \ No newline at end of file
>
> Last thing - do we have an established style for JS code in the JS engine?
> If not, I like the idea of 4 spaces to match Python and our C++ code.
Yes, I changed that, too. The original indenting was an artifact of using V8 code.
Also, the new code will contain comments about the different spec steps implemented in each part of the code.
I'm still debugging an issue with the new error reporting and will attach a new patch once that's done.

> I'm also curious about the performance of this bit. Would it help to have a
> special case for dense arrays?
I forgot this part: We might check that, yes. It gains another 10%, so maybe it's worth it.

(In reply to Till Schneidereit [:till] from comment #86)
> (In reply to David Mandelin [:dmandelin] from comment #85)
> > Comment on attachment 648397[details][diff][review]
> > Embed self-hosted JS and install it into standard classes, v6
> >
> > Review of attachment 648397[details][diff][review]:
> > -----------------------------------------------------------------
> >
> > This seems to be going really well. I looked closely at the array.js file,
> > to see what's it like coding with the new feature. I have a few
> > questions/comments below.
> >
> > ::: js/src/builtin/array.js
> > @@ +1,1 @@
> > > +function ArrayForEach(fun/*, receiver*/) {
> >
> > I suppose we don't have jit support for rest arguments yet, but we should do
> > some followup work to get that going and change this function to use 'em.
>
> The |receiver| argument is commented out because |forEach| is specified as
> only having one argument. I don't think rest would gain us anything here.
I'm not sure I understand. ES5.1 gives a second argument, |thisArg|, and your implementation handles it using |arguments|. I was just saying that |arguments| is "bad", and that rest arguments are much nicer, but I think you are correct for now in using |arguments|, because our jits know how to make it fast, but not rest args. But we should switch to rest args someday.
> > @@ +3,5 @@
> > > + %ThrowNoConstructorError();
> > > + if (arguments.length == 0)
> > > + %ThrowMissingArgError(0);
> > > + if (this == null || (typeof fun) !== 'function')
> > > + %ThrowValueError(0, 22);
> >
> > Definitely want to do some followup to replace '22' with something better.
> > It seems like if we had that we could also avoid (or embrace, depending on
> > how it's done!) having one intrinsic for each kind of error to report.
>
> I have started implementing a better approach already: Using a Python
> script, the new approach enables direct usage of the enum entry's symbol as
> a string. I.e., |22| becomes "JSMSG_NOT_FUNCTION".
Sounds great.
> > @@ +9,5 @@
> > > + var len = array.length;
> > > + var receiver = arguments.length > 1 ? arguments[1] : null;
> > > + for (var i = 0; i < len; i++) {
> > > + if (i in array)
> > > + %_CallFunction(receiver, array[i], i, array, fun);
> >
> > What's the _ for?
>
> This way, the name matches what V8 uses, making it easier to reuse their
> code.
Ah, good idea.
> Also, the new code will contain comments about the different spec steps
> implemented in each part of the code.
Cool.
> > I'm also curious about the performance of this bit. Would it help to have a
> > special case for dense arrays?
>
> I forgot this part: We might check that, yes. It gains another 10%, so maybe
> it's worth it.
I'd say that's worth it. It definitely shouldn't block your present work, though.

> I'm not sure I understand. ES5.1 gives a second argument, |thisArg|, and
> your implementation handles it using |arguments|. I was just saying that
> |arguments| is "bad", and that rest arguments are much nicer, but I think
> you are correct for now in using |arguments|, because our jits know how to
> make it fast, but not rest args. But we should switch to rest args someday.
Right, I forgot that ...rest is spec'd as not being counted for determining Function#length. I agree: we should investigate the performance of changing to that.
> > > I'm also curious about the performance of this bit. Would it help to have a
> > > special case for dense arrays?
> >
> > I forgot this part: We might check that, yes. It gains another 10%, so maybe
> > it's worth it.
>
> I'd say that's worth it. It definitely shouldn't block your present work,
> though.
Thinking about this some more, I don't think we can special-case this in a satisfactory way, after all. Given that we execute a function that can freely modify the array we're operating on, we'd have to check whether the array is still dense after each step. If that's cheaper than |i in array|, then we should do it, sure.

Created attachment 649117[details][diff][review]
Embed self-hosted JS and install it into standard classes, v7
This version changes various aspects of the self-hosting mechanism:
@ted: I've moved the scripts that are invoked during make into the "config" directory. Seems to me that that location makes more sense.
@gerv: I've changed about:license to add info about files in "js/src/config" being under the V8 license and refreshed the time range of the license. I hope these changes are ok.
@bhackett:
This version contains a complete, by-the-spec self-hosted implementation of Array.prototype.forEach with proper comments and all code as I think it should be.
Of note, errors can now be thrown with just one function, ThrowError, and can be specified using their enum keys from js.msg.
To get proper decompilation of values (e.g. for JSMSG_NOT_FUNCTION), I had to change js_DecompileValueGenerator to add the ability to decompile the expression used to create the value when invoking the self-hosted function, not ThrowError.

(In reply to Till Schneidereit [:till] from comment #89)
> > > > I'm also curious about the performance of this bit. Would it help to have a
> > > > special case for dense arrays?
> > >
> > > I forgot this part: We might check that, yes. It gains another 10%, so maybe
> > > it's worth it.
> >
> > I'd say that's worth it. It definitely shouldn't block your present work,
> > though.
>
> Thinking about this some more, I don't think we can special-case this in a
> satisfactory way, after all. Given that we execute a function that can
> freely modify the array we're operating on, we'd have to check whether the
> array is still dense after each step. If that's cheaper than |i in array|,
> then we should do it, sure.
Good point. I checked the current C++ implementation and it doesn't special-case dense arrays (which you probably already saw), probably for that exact reason. And now that you made me think about it more carefully, I think we can teach the jits to hoist |i in array|.

> Good point. I checked the current C++ implementation and it doesn't
> special-case dense arrays (which you probably already saw), probably for
> that exact reason. And now that you made me think about it more carefully, I
> think we can teach the jits to hoist |i in array|.
I filed bug 780786 and bug 780787 for that.

Created attachment 650251[details][diff][review]
Embed self-hosted JS and install it into standard classes, v9
(In reply to Brian Hackett (:bhackett) from comment #94)
> Comment on attachment 649118[details][diff][review]
> Embed self-hosted JS and install it into standard classes, v8
>
> Review of attachment 649118[details][diff][review]:
Thanks for the review! The new version addresses the comments. Additionally, it changes enough things that I think a re-review is in order.
Most importantly, a sanity check for the changes to js_DecompileValueGenerator and jsop_this would be very much welcome. I introduced the latter because not wrapping |this| is required for correctly implementing ToObject without using "use strict", which unfortunately makes things quite a lot slower.
Also, I still haven't figured out how to prevent the test failure mentioned in comment 81:
jit-test/tests/jaeger/bug738525.js crashes with
Assertion failure: allocated(), at ../gc/Heap.h:506
during shutdown of the shell.
I reduced the problem to simply running the script "it.customNative = 1".
Finally, I have removed any actual self-hosted code and will add that as a follow-up patch (to be attached in a minute).

Comment on attachment 650251[details][diff][review]
Embed self-hosted JS and install it into standard classes, v9
I can't help much with the js_DecompileValueGenerator change, that code is a hack anyways so the change is fine so long as it does the right thing in the cases you've tested and will fail safe when the value isn't found. The jsop_this change is fine.
The allocated() failure means that corrupt memory is being accessed somewhere.

Comment on attachment 649118[details][diff][review]
Embed self-hosted JS and install it into standard classes, v8
Review of attachment 649118[details][diff][review]:
-----------------------------------------------------------------
Sorry, my review was slow going here, so I'll post my half-finished review of this patch.
::: js/src/Makefile.in
@@ +848,5 @@
> +# Prepage self-hosted JS code for embedding
> +export:: selfhosted.out.h
> +
> +SELFHOSTING_SRCS = \
> + $(srcdir)/builtin/array.js
Current Makefile style is two spaces at the beginning of lines after a continuation, and no tabs anywhere they're not required for Makefile syntax.
Also, you have a trailing space at the end of this line.
If you think this list will grow in the future, you can stick a continuation on this line and use $(NULL) as the last line, so that adding new entries is easy.
Finally, we're trying to work on our Makefile style, and one of our (as-yet-unwritten) new conventions is to use lowercase for Makefile variables that are file-local. (Compared to uppercase for variables that have special meaning to the build system.)
@@ +855,5 @@
> + $(SELFHOSTING_SRCS) \
> + $(srcdir)/js.msg \
> + $(srcdir)/config/macros.py \
> + $(srcdir)/config/js2c.py \
> + $(srcdir)/config/embedjs.py
Similarly for the indentation here. If the indentation bothers you, you can assign the deps to a variable and use that instead, like:
selfhosted_out_h_deps := \
$(SELFHOSTING_SRCS) \
...
selfhosted.out.h: $(selfhosted_out_h_deps)
@@ +856,5 @@
> + $(srcdir)/js.msg \
> + $(srcdir)/config/macros.py \
> + $(srcdir)/config/js2c.py \
> + $(srcdir)/config/embedjs.py
> + $(PYTHON) $(srcdir)/config/embedjs.py selfhosted.out.h $(srcdir)/js.msg \
You should use $@ instead of repeating the output filename here.
::: js/src/config/embedjs.py
@@ +1,3 @@
> +# This Source Code Form is subject to the terms of the Mozilla Public
> +# License, v. 2.0. If a copy of the MPL was not distributed with this
> +# file, You can obtain one at http://mozilla.org/MPL/2.0/.
I'm not sure that I agree that putting these in config/ makes the most sense. I would just put them in js/src/builtin next to the input code they're using. (We tend to only put generic build-system stuff in config/.)
@@ +5,5 @@
> +# This utility converts JS files containing self-hosted builtins into a C
> +# header file that can be embedded into SpiderMonkey.
> +#
> +# It expects error messages in the JS code to be referenced by their C enum
> +# keys as literals.
You've got a weird mix of indentation in this file. You have both tabs and spaces, for one. You should follow PEP-8 style and use four-space indent everywhere. You also have a couple of trailing spaces in the comments here.
@@ +11,5 @@
> +import json, re, sys, os, js2c, fileinput
> +
> +def replaceErrorMsgs(source_files, messages_file, output_file):
> + messages = buildMessagesTable(messages_file)
> + with open(output_file, 'w') as output:
You'll need to stick "from __future__ import with_statement" before your other imports for this to work right, because we still support Python 2.5 for now.
@@ +20,5 @@
> + table = {}
> + for line in fileinput.input(messages_file):
> + if not line.startswith('MSG_DEF('):
> + continue
> + match = re.match(r"MSG_DEF\(([\w_]+),\s*(\d+)", line)
Seems a little redundant to have the startswith check and then the re.match. You could just run the re.match and do:
if not match:
continue
Also, if you're going to run this regex multiple times you might want to use re.compile and save the compiled regex.

Created attachment 650571[details][diff][review]
Convert some array extras to self-hosted JS code, wip
And now that I have internet again, here's the previously-mentioned patch that's actually using all this stuff for something.

Created attachment 650699[details][diff][review]
Embed self-hosted JS and install it into standard classes, v10
This version addresses all feedback and fixes the regression mentioned in comment 95.
@ted: Thanks for the in-depth review, much appreciated. I've addressed your comments so this should be ready to land if you don't have additional issues.

I'll debug the linux opt build failures on Monday: for some reason the xpcshell crashes while during precompilation.
The other failures mostly look like they're infrastructure problems, but I guess the next try run will tell.

Created attachment 651744[details][diff][review]
Embed self-hosted JS and install it into standard classes, v11
Fixes exception in xpcshell and addresses feedback.
Apparently, compiling an empty string isn't advisable. Why that causes a Linux-only abort in `make package` (specifically while the xpcshell is running precompile_cache.js and creating a jscontext for that) is beyond me, but at least adding some placeholder code to this base patch instead of any actual self-hosted code fixes it.
@ted: sorry for the unaddressed feedback in the last patch. I seem to have applied some of the fixes to the wrong patch in my queue.
Pushed to try here: https://tbpl.mozilla.org/?tree=Try&rev=fb992c734c77 and ready to go if that turns out green.

Created attachment 652560[details][diff][review]
Embed self-hosted JS and install it into standard classes, v12
This version finally passes a full try run on all platforms and is rebased to current m-c.
Carrying the r+es as the changes are fairly small.

Procedural question: This bug originally requested self-hosting support for "Array.prototype.join and other JS builtins"; it probably wasn't meant to provide support for complete modules such as the ECMAScript Internationalization API. Should we continue to use this bug for everything that's necessary for complete self-hosted modules, or keep this bug to something close to its original scope and file additional bugs for the rest?
In any case, Till has already accomplished a lot, and at some point we should acknowledge that, whether through letting him close the ticket or otherwise...

(In reply to Norbert Lindenberg from comment #112)
> Procedural question: This bug originally requested self-hosting support for
> "Array.prototype.join and other JS builtins"; it probably wasn't meant to
> provide support for complete modules such as the ECMAScript
> Internationalization API. Should we continue to use this bug for everything
> that's necessary for complete self-hosted modules, or keep this bug to
> something close to its original scope and file additional bugs for the rest?
>
> In any case, Till has already accomplished a lot, and at some point we
> should acknowledge that, whether through letting him close the ticket or
> otherwise...
Thanks :)
I fully agree about closing this bug sooner rather than later. Thus, I'm doing so now, changing the title and a few details to reflect what actually happened here.
I've created bug 784288 for tracking additional implementation work and follow-up fixes. Please file bugs blocking that one for additional tasks.

Note

You need to
log in
before you can comment on or make changes to this bug.