Bug 147183 - Introducing construct ability into JS executables
Summary: Introducing construct ability into JS executables
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Yusuke Suzuki
URL:
Keywords:
Depends on:
Blocks: 147133
  Show dependency treegraph
 
Reported: 2015-07-21 20:03 PDT by Yusuke Suzuki
Modified: 2015-07-22 19:37 PDT (History)
7 users (show)

See Also:


Attachments
Patch (22.41 KB, patch)
2015-07-21 20:35 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Patch (27.60 KB, patch)
2015-07-22 10:14 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Patch (32.98 KB, patch)
2015-07-22 14:32 PDT, Yusuke Suzuki
ggaren: review+
ggaren: commit-queue-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Yusuke Suzuki 2015-07-21 20:03:23 PDT
Introducing construct ability into JS executables
Comment 1 Yusuke Suzuki 2015-07-21 20:03:44 PDT
Let's decouple the construct ability from the builtin functions.
Currently, builtin functions are not constructor by this patch http://trac.webkit.org/changeset/182995.
In this patch, when the given function is builtin JS function, we recognize it as the non-constructor function.

But, we need to relax it to implement some constructors in builtins JS.
By decoupling the construct ability from whether the function is builtin or not, we can provide

1. constructors written in builtin JS
2. non-constructors in normal JS functions

(1) is needed for Promise constructor. And (2) is needed for method functions and arrow functions.
Comment 2 Yusuke Suzuki 2015-07-21 20:09:46 PDT
http://www.ecma-international.org/ecma-262/6.0/#sec-functioncreate
If kind is not Normal, let allocKind be "non-constructor".
Comment 3 Yusuke Suzuki 2015-07-21 20:35:02 PDT
Created attachment 257243 [details]
Patch

WIP, the test forthcomming
Comment 4 Yusuke Suzuki 2015-07-22 09:44:20 PDT
I've asked for the clarification in static MethodDefinition and construct ability.
https://esdiscuss.org/topic/propertydefinitionevaluation-for-static-methoddefinition
Comment 5 Yusuke Suzuki 2015-07-22 10:14:50 PDT
Created attachment 257280 [details]
Patch
Comment 6 Oliver Hunt 2015-07-22 13:42:20 PDT
Comment on attachment 257280 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=257280&action=review

r- as i don't like the subtlety of the current behaviour

> Source/JavaScriptCore/ChangeLog:26
> +        Currenctly, we make the builtin function the constructor when the function name is capitalized.

I think that's kind of icky -- something we consider doing that i think would be clearer would be to allow builtins defined as

constructor thing(...) { ... }

This would actually allow us (in a later patch) to use builtins to more cleanly define those functions that have distinct construct vs. call behaviours, e.g

constructor thing(...) {}
function thing( ... ) {}

would register the distinct executables for the construct vs. call behavior of "thing"
Comment 7 Yusuke Suzuki 2015-07-22 13:50:41 PDT
Comment on attachment 257280 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=257280&action=review

Thank you for your review.

>> Source/JavaScriptCore/ChangeLog:26
>> +        Currenctly, we make the builtin function the constructor when the function name is capitalized.
> 
> I think that's kind of icky -- something we consider doing that i think would be clearer would be to allow builtins defined as
> 
> constructor thing(...) { ... }
> 
> This would actually allow us (in a later patch) to use builtins to more cleanly define those functions that have distinct construct vs. call behaviours, e.g
> 
> constructor thing(...) {}
> function thing( ... ) {}
> 
> would register the distinct executables for the construct vs. call behavior of "thing"

That sounds very nice to me. I'll upload the revised patch.
Comment 8 Yusuke Suzuki 2015-07-22 14:32:01 PDT
Created attachment 257294 [details]
Patch
Comment 9 Geoffrey Garen 2015-07-22 16:37:31 PDT
Comment on attachment 257294 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=257294&action=review

r=me with some suggested fixups below.

> Source/JavaScriptCore/builtins/BuiltinExecutables.cpp:63
> +UnlinkedFunctionExecutable* BuiltinExecutables::createExecutableInternal(const SourceCode& source, const Identifier& name, ConstructorKind constructorKind, bool hasConstruct)

Let's use the enum type (ConstructAbility) for the function argument instead of a bool. Bool is not nice as an argument type because it is often difficult to understand what "f(false)" or "f(true)" means just by reading it.

> Source/JavaScriptCore/builtins/BuiltinExecutables.h:64
> -    UnlinkedFunctionExecutable* createBuiltinExecutable(const SourceCode& code, const Identifier& name)
> +    UnlinkedFunctionExecutable* createBuiltinExecutable(const SourceCode& code, const Identifier& name, bool hasConstruct)
>      {
> -        return createExecutableInternal(code, name, ConstructorKind::None);
> +        return createExecutableInternal(code, name, ConstructorKind::None, hasConstruct);
>      }
> -    UnlinkedFunctionExecutable* createExecutableInternal(const SourceCode&, const Identifier&, ConstructorKind);
> +    UnlinkedFunctionExecutable* createExecutableInternal(const SourceCode&, const Identifier&, ConstructorKind, bool hasConstruct);

Ditto: Let's use the enum type instead of bool here.

> Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp:104
> +    , m_hasConstruct(constructAbility == ConstructAbility::HasConstruct)

Let's store the enum type instead of a bool.

> Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h:103
> +    HasConstruct,
> +    NoConstruct,

Let's call these "CanConstruct" and "CannotConstruct".
Comment 10 Yusuke Suzuki 2015-07-22 16:54:32 PDT
Comment on attachment 257294 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=257294&action=review

Thank you for your review and suggestions.

>> Source/JavaScriptCore/builtins/BuiltinExecutables.cpp:63
>> +UnlinkedFunctionExecutable* BuiltinExecutables::createExecutableInternal(const SourceCode& source, const Identifier& name, ConstructorKind constructorKind, bool hasConstruct)
> 
> Let's use the enum type (ConstructAbility) for the function argument instead of a bool. Bool is not nice as an argument type because it is often difficult to understand what "f(false)" or "f(true)" means just by reading it.

OK, so I'll fix it by,

1. Create the ConstructAbility.h
2. Include the header in JSCBuiltins.cpp generated by the script
3. Use it

>> Source/JavaScriptCore/builtins/BuiltinExecutables.h:64
>> +    UnlinkedFunctionExecutable* createExecutableInternal(const SourceCode&, const Identifier&, ConstructorKind, bool hasConstruct);
> 
> Ditto: Let's use the enum type instead of bool here.

Fixed.

>> Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp:104
>> +    , m_hasConstruct(constructAbility == ConstructAbility::HasConstruct)
> 
> Let's store the enum type instead of a bool.

Here, due to the object size limitation, we used m_hasConstruct with the bit field (width 1). This is because the other fields also use the bit field to reduce the UnlinkedFunctionExecutable size.
Just storing the enum type enlarges the object size...
So, instead of storing the enum type, storing the bit and add the getter that converts the boolean to the enum value.

>> Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h:103
>> +    NoConstruct,
> 
> Let's call these "CanConstruct" and "CannotConstruct".

Thanks. Fixed.
Comment 11 Oliver Hunt 2015-07-22 17:00:52 PDT
Comment on attachment 257294 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=257294&action=review

>>> Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp:104
>>> +    , m_hasConstruct(constructAbility == ConstructAbility::HasConstruct)
>> 
>> Let's store the enum type instead of a bool.
> 
> Here, due to the object size limitation, we used m_hasConstruct with the bit field (width 1). This is because the other fields also use the bit field to reduce the UnlinkedFunctionExecutable size.
> Just storing the enum type enlarges the object size...
> So, instead of storing the enum type, storing the bit and add the getter that converts the boolean to the enum value.

you can set an enum to be stored as a bitfield :D
Comment 12 Yusuke Suzuki 2015-07-22 17:02:31 PDT
Comment on attachment 257294 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=257294&action=review

>>>> Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp:104
>>>> +    , m_hasConstruct(constructAbility == ConstructAbility::HasConstruct)
>>> 
>>> Let's store the enum type instead of a bool.
>> 
>> Here, due to the object size limitation, we used m_hasConstruct with the bit field (width 1). This is because the other fields also use the bit field to reduce the UnlinkedFunctionExecutable size.
>> Just storing the enum type enlarges the object size...
>> So, instead of storing the enum type, storing the bit and add the getter that converts the boolean to the enum value.
> 
> you can set an enum to be stored as a bitfield :D

That's fine! So just storing the enum type directly with the bitfield.
Comment 13 Yusuke Suzuki 2015-07-22 17:02:32 PDT
Comment on attachment 257294 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=257294&action=review

>>>> Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp:104
>>>> +    , m_hasConstruct(constructAbility == ConstructAbility::HasConstruct)
>>> 
>>> Let's store the enum type instead of a bool.
>> 
>> Here, due to the object size limitation, we used m_hasConstruct with the bit field (width 1). This is because the other fields also use the bit field to reduce the UnlinkedFunctionExecutable size.
>> Just storing the enum type enlarges the object size...
>> So, instead of storing the enum type, storing the bit and add the getter that converts the boolean to the enum value.
> 
> you can set an enum to be stored as a bitfield :D

That's fine! So just storing the enum type directly with the bitfield.
Comment 14 Yusuke Suzuki 2015-07-22 19:03:07 PDT
Comment on attachment 257294 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=257294&action=review

>>>>>> Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp:104
>>>>>> +    , m_hasConstruct(constructAbility == ConstructAbility::HasConstruct)
>>>>> 
>>>>> Let's store the enum type instead of a bool.
>>>> 
>>>> Here, due to the object size limitation, we used m_hasConstruct with the bit field (width 1). This is because the other fields also use the bit field to reduce the UnlinkedFunctionExecutable size.
>>>> Just storing the enum type enlarges the object size...
>>>> So, instead of storing the enum type, storing the bit and add the getter that converts the boolean to the enum value.
>>> 
>>> you can set an enum to be stored as a bitfield :D
>> 
>> That's fine! So just storing the enum type directly with the bitfield.
> 
> That's fine! So just storing the enum type directly with the bitfield.

Oops, warned by the style checker, "Please declare enum bitfields as unsigned integral types."
So just follow the other accessors (like FunctionMode, ConstructorKind etc.), storing enum directly to the bitfield (unsigned) and retrieve it by static_cast in the accessor.
Comment 15 Yusuke Suzuki 2015-07-22 19:37:38 PDT
Committed r187205: <http://trac.webkit.org/changeset/187205>