Bug 166665 - Super property access in base class constructor doesn't work
Summary: Super property access in base class constructor doesn't work
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: WebKit Local Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-01-03 14:44 PST by Adam Klein
Modified: 2017-01-23 09:17 PST (History)
13 users (show)

See Also:


Attachments
Patch (5.46 KB, patch)
2017-01-14 07:08 PST, GSkachkov
no flags Details | Formatted Diff | Diff
Patch (14.88 KB, patch)
2017-01-17 11:16 PST, GSkachkov
no flags Details | Formatted Diff | Diff
Patch (15.68 KB, patch)
2017-01-18 09:11 PST, GSkachkov
no flags Details | Formatted Diff | Diff
Patch (15.53 KB, patch)
2017-01-18 10:10 PST, GSkachkov
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Adam Klein 2017-01-03 14:44:59 PST
Reproduction in jsc:

>>> class C { constructor() { print(typeof super.hasOwnProperty) } } new C()
Exception: TypeError: undefined is not an object (evaluating 'print')

This seems to work OK for derived classes:

>>> class Base { method() { } } class Derived extends Base { constructor() { super(); print(typeof super.method) } } new Derived()
function
[object Object]
Comment 1 Saam Barati 2017-01-12 17:32:19 PST
This sounds like we're special casing being derived or not.
Comment 2 GSkachkov 2017-01-13 06:43:44 PST
(In reply to comment #1)
> This sounds like we're special casing being derived or not.

Yeah, I remember there was "SyntaxError: super can't be used in such context", will try to check later.
Comment 3 GSkachkov 2017-01-14 07:08:31 PST
Created attachment 298851 [details]
Patch

Load super for all classes
Comment 4 Yusuke Suzuki 2017-01-14 11:11:07 PST
Comment on attachment 298851 [details]
Patch

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

r=me with comment.

> Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp:3777
> +    emitPutHomeObject(generator, constructor.get(), prototype.get());

Can we avoid always putting this home object here?
I think we can avoid it if the constructor does not have super reference (and of course, arrow func using super etc...).
If we can do that, please add FIXME with bug URL here.
Comment 5 Yusuke Suzuki 2017-01-14 11:17:14 PST
Comment on attachment 298851 [details]
Patch

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

>> Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp:3777
>> +    emitPutHomeObject(generator, constructor.get(), prototype.get());
> 
> Can we avoid always putting this home object here?
> I think we can avoid it if the constructor does not have super reference (and of course, arrow func using super etc...).
> If we can do that, please add FIXME with bug URL here.

Could you ensure that this patch does not pose perf regression in ES6SampleBench before landing it?
Comment 6 GSkachkov 2017-01-17 11:16:26 PST
Created attachment 299045 [details]
Patch

Small performance improvements
Comment 7 GSkachkov 2017-01-17 11:49:37 PST
(In reply to comment #4)
> Comment on attachment 298851 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=298851&action=review
> 
> r=me with comment.
> 
> > Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp:3777
> > +    emitPutHomeObject(generator, constructor.get(), prototype.get());
> 
> Can we avoid always putting this home object here?
> I think we can avoid it if the constructor does not have super reference
> (and of course, arrow func using super etc...).
> If we can do that, please add FIXME with bug URL here.

I did small refactoring and implement checking if super used inside of the constructor
Comment 8 Ryosuke Niwa 2017-01-17 12:47:56 PST
Comment on attachment 299045 [details]
Patch

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

> Source/JavaScriptCore/ChangeLog:8
> +        Current patch fixed allow to use super inside of the constructor for classes 

Nit: "Current patch fixed allow" -> "Allow".

You should also explain how you're fixing the problem.

> Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp:3696
> +        } else if (metadata->superBinding() == SuperBinding::Needed)
> +            superIsUsedInConstructor = true;

Why don't we just create a new boolean like "needsHomeObject" and set it to true whenever this is true or m_classHeritage is set?

> Source/JavaScriptCore/parser/Parser.h:1605
> +    ALWAYS_INLINE SuperBinding getSuperBindingForConstructor(ConstructorKind constructorKind, SuperBinding superBinding, bool needsSuperBinding, bool currentScopeUsesEval, InnerArrowFunctionCodeFeatures innerArrowFunctionFeatures)

Nit: we don't prefix a getter function with "get" unless there is an out argument.
See https://webkit.org/code-style-guidelines/#names-setter-getter

> Source/JavaScriptCore/parser/Parser.h:1612
> +            methodSuperBinding = (needsSuperBinding || isSuperUsedInInnerArrowFunction || isEvalUsedInInnerArrowFunctions || currentScopeUsesEval) ? SuperBinding::Needed : SuperBinding::NotNeeded;

Why do we need super binding when eval is used inside an arrow function?
I don't see any test case of that either.
Comment 9 GSkachkov 2017-01-18 09:11:05 PST
Created attachment 299148 [details]
Patch

Fix review comments
Comment 10 GSkachkov 2017-01-18 10:09:46 PST
(In reply to comment #8)
> Comment on attachment 299045 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=299045&action=review
> 
> > Source/JavaScriptCore/ChangeLog:8
> > +        Current patch fixed allow to use super inside of the constructor for classes 
> 
> Nit: "Current patch fixed allow" -> "Allow".
> 
> You should also explain how you're fixing the problem.
> 
> > Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp:3696
> > +        } else if (metadata->superBinding() == SuperBinding::Needed)
> > +            superIsUsedInConstructor = true;
> 
> Why don't we just create a new boolean like "needsHomeObject" and set it to
> true whenever this is true or m_classHeritage is set?
> 
> > Source/JavaScriptCore/parser/Parser.h:1605
> > +    ALWAYS_INLINE SuperBinding getSuperBindingForConstructor(ConstructorKind constructorKind, SuperBinding superBinding, bool needsSuperBinding, bool currentScopeUsesEval, InnerArrowFunctionCodeFeatures innerArrowFunctionFeatures)
> 
> Nit: we don't prefix a getter function with "get" unless there is an out
> argument.
> See https://webkit.org/code-style-guidelines/#names-setter-getter
> 
> > Source/JavaScriptCore/parser/Parser.h:1612
> > +            methodSuperBinding = (needsSuperBinding || isSuperUsedInInnerArrowFunction || isEvalUsedInInnerArrowFunctions || currentScopeUsesEval) ? SuperBinding::Needed : SuperBinding::NotNeeded;
> 
> Why do we need super binding when eval is used inside an arrow function?
> I don't see any test case of that either.
I've tried to explicitly cover case when eval in arrow function so there can be used super, but currentScopeUsesEval should cover this case.
Comment 11 GSkachkov 2017-01-18 10:10:22 PST
Created attachment 299152 [details]
Patch

Small improvements
Comment 12 Ryosuke Niwa 2017-01-18 13:21:35 PST
Comment on attachment 299152 [details]
Patch

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

> Source/JavaScriptCore/parser/Parser.cpp:1866
> +            SuperBinding functionSuperBinding = superBindingForConstructor(constructorKind, superBinding, currentScope()->needsSuperBinding(), currentScope()->usesEval(), currentScope()->innerArrowFunctionFeatures());

I think it's confusing to call superBindingForConstructor to compute functionSuperBinding given a function is not always a constructor.
Why don't we call this function something like adjustSuperBindingForBaseConstructor?

> Source/JavaScriptCore/parser/Parser.cpp:1885
> +    SuperBinding functionSuperBinding = superBindingForConstructor(constructorKind, superBinding, currentScope()->needsSuperBinding(), currentScope()->usesEval(), currentScope()->innerArrowFunctionFeatures());

Why don't we add a function overload with takes the scope object instead of passing in three arguments here?

> Source/JavaScriptCore/parser/Parser.h:1605
> +    ALWAYS_INLINE SuperBinding superBindingForConstructor(ConstructorKind constructorKind, SuperBinding superBinding, bool needsSuperBinding, bool currentScopeUsesEval, InnerArrowFunctionCodeFeatures innerArrowFunctionFeatures)

It's very confusing to have two variables named superBinding and needsSuperBinding.
I think the latter should be called scopeNeedsSuperBinding
Comment 13 GSkachkov 2017-01-20 11:56:19 PST
Comment on attachment 299152 [details]
Patch

Clearing flags on attachment: 299152

Committed r210958: <http://trac.webkit.org/changeset/210958>
Comment 14 GSkachkov 2017-01-21 03:51:43 PST
Yusuke Suzuki and Ryosuke Niwa Thanks for review!
Adam Klein Thanks for reporting the bug, could you please close the issue if patch fix your case? I din't have permission to do this.