Skip to content

[BUGFIX beta] Avoid creating enumerable properties on all objects created by DI.#15177

Merged
rwjblue merged 1 commit intoemberjs:masterfrom
rwjblue:take-two-dont-mutate-own-properties
Apr 27, 2017
Merged

[BUGFIX beta] Avoid creating enumerable properties on all objects created by DI.#15177
rwjblue merged 1 commit intoemberjs:masterfrom
rwjblue:take-two-dont-mutate-own-properties

Conversation

@rwjblue
Copy link
Member

@rwjblue rwjblue commented Apr 27, 2017

Prior to these changes, every object created via owner.factoryFor(...).create() was populated with NAME_KEY, _debugContainerKey, and OWNER.

After these changes:

  • For Ember.Object's, only actual injections are included in the create arguments.
  • For non-Ember.Object's, only OWNER is included in the create arguments.

OWNER is still provided for non-Ember.Object's in order to support various classes that are used in the rendering layer that expect to be passed options[OWNER] so they can function properly. Examples are ember-glimmer/environment and ember-glimmer/template. These should be refactored away from OWNER being passed in, and this fallback should be removed.

A handful of tests were added / updated. In some cases _debugContainerKey assertions were removed, since this is no longer supported configuration (e.g. there is no way to inject _debugContainerKey onto the class itself without double extend).

@rwjblue rwjblue force-pushed the take-two-dont-mutate-own-properties branch from 67f6b55 to 34daea8 Compare April 27, 2017 00:20
@rwjblue
Copy link
Member Author

rwjblue commented Apr 27, 2017

Did a quick benchmark via ember-macro-benchmark to see if this has an effect on perf and it looks pretty good to me.

@krisselden / @stefanpenner - Mind confirming my interpretation?

phases

Raw data: results-pr-15177.zip

@rwjblue
Copy link
Member Author

rwjblue commented Apr 27, 2017

I chatted with @krisselden in slack about the results, we came to roughly the same conclusion. That the changes in this PR do not reject the null hypothesis (that the variance between control and experiment are random) and therefore these changes do not represent a change in the performance profile of the application under test (emberaddons.com in this case).

@rwjblue
Copy link
Member Author

rwjblue commented Apr 27, 2017

Changes like this (changing the makeCtor functionality) should receive significant scrutiny, so I'd still like @stefanpenner and/or @krisselden to review this PR and approve....

Copy link
Member

@stefanpenner stefanpenner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good, left some nit-picks.

// the customized toString, _debugContainerKey,
// owner, etc. without a double extend and without
// modifying the objects properties
if (this.class._initFactory) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typeof this.class._initFactory === 'function' (more correct, and makes the JIT happy)

let extension = hasToStringExtension ? `:${this.toStringExtension()}` : '';
let ret = `<${this[NAME_KEY] || this.constructor.toString()}:${guidFor(this)}${extension}>`;

let m = meta(this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

550 and 551 are only required if this[NAME_KEY] isn't set, and it will be set most of the time. Can we avoid 550 and 551 unless we need to access it?

something like:

this[NAME_KEY] || meta(this).getFactory() || this.cosntructor.toString()

}
}

setFactory(factory) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any preference to function accessors vs normal accessors? I can be fine with either, was just surprised this isn't a accessor and am curious if there was a reason for it

Copy link
Member Author

@rwjblue rwjblue Apr 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get / set seem fine to me, I just slightly dislike the babel transpilation (which requires the createClass helper):

// input

class Foo {
  get derp() { }
  set derp(value) { }
}

// output
var Foo = function () {
  function Foo() {
    _classCallCheck(this, Foo);
  }

  _createClass(Foo, [{
    key: "derp",
    get: function get() {},
    set: function set(value) {}
  }]);

  return Foo;
}();

}

let meta = peekMeta(this);
let factory = meta.getFactory();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we peekMeta meta may be undefined so we must guard before accessing getFactory

something like:

let meta = peekMeta(this)
if (meta === undefined) { return; }
let factory = meta.getFactory();
if (factory === undefined) { return ; }
return factory.fullName;

return factory && factory.owner;
},

// we need a setter here largely to support the legacy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, so this [OVERRIDE_OWNER] both in the setter and getter can be removed once the legacy support is dropped?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, confirm

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confirm, OVERRIDE_OWNER is only for deprecated container setter

return this[OVERRIDE_OWNER];
}

let meta = peekMeta(this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to have a ember-object without a meta? As we create its meta during within its constructor.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is not possible for it not to exists

Copy link
Member

@stefanpenner stefanpenner Apr 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't it a tad strange to use peekMeta instead of meta ? But i'm fine if you are.

return this[OVERRIDE_CONTAINER_KEY];
}

let meta = peekMeta(this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to have a ember-object without a meta? As we create its meta during within its constructor.

return this[OVERRIDE_OWNER];
}

let meta = peekMeta(this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is not possible for it not to exists

return factory && factory.owner;
},

// we need a setter here largely to support the legacy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confirm, OVERRIDE_OWNER is only for deprecated container setter

…ated by DI.

Prior to these changes, every object created via `owner.factoryFor(...).create()`
was populated with `NAME_KEY`, `_debugContainerKey`, and `OWNER`.

After these changes:

* For `Ember.Object`'s, only actual injections are included in the create arguments.
* For non-`Ember.Object`'s, only `OWNER` is included in the create arguments.

`OWNER` is still provided for non-`Ember.Object`'s in order to support various
classes that are used in the rendering layer that expect to be passed `options[OWNER]`
so they can function properly. Examples are `ember-glimmer/environment` and
`ember-glimmer/template`. These should be refactored away from `OWNER` being passed
in, and this fallback should be removed.

A handful of tests were added / updated. In some cases `_debugContainerKey` assertions
were removed, since this is no longer supported configuration (e.g. there is no way to
inject `_debugContainerKey` onto the class itself without double extend).
@rwjblue rwjblue force-pushed the take-two-dont-mutate-own-properties branch from 34daea8 to 652adee Compare April 27, 2017 15:48
@rwjblue
Copy link
Member Author

rwjblue commented Apr 27, 2017

Addressed concerns:

  • Swapped usage of peekMeta to meta
  • Moved Meta#getFactory / Meta#setFactory to simple getters
  • Avoid accessing meta(this).factory when this[NAME_KEY] is present.

Anything else?

@rwjblue rwjblue merged commit d222081 into emberjs:master Apr 27, 2017
@rwjblue rwjblue deleted the take-two-dont-mutate-own-properties branch April 27, 2017 16:14
@homu homu mentioned this pull request Apr 27, 2017
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants