google / closure-compiler

A JavaScript checker and optimizer.
https://developers.google.com/closure/compiler/
Apache License 2.0
7.35k stars 1.14k forks source link

@nocollapse is not honored by DevirtualizePrototypeMethods #2420

Open Ludobaka opened 7 years ago

Ludobaka commented 7 years ago

As discussed here, compiler seems to not work properly when using @nocollapse JSDoc tag. The compiler is properly not collapsing objects attributes but is sometimes collapsing objects prototypes when using the tag.

Example of code before compilation :

/** @constructor */
function MyClass() = { // Some code }
/** @nocollapse */
MyClass.someAttribute = function(someParam) { // Some code };
/** @nocollapse */
MyClass.prototype.someFunc = function() { // Some code calling someOtherFunc };
/** @nocollapse */
MyClass.prototype.someOtherFunc = function(someParam) { // Some code };

Example of code after compilation :

function MyCompiledClass = { // Some code }
MyCompiledClass.someCompiledAttribute = function(someParam) { // Some code };
MyCompiledClass.prototype.someCompiledFunc = function() { // Some code calling someOtherFunc }
function someOtherCompiledFunc(that, someParam) = { // Some code }

I've tried to set @this and @preserve tags without success. Using @export is not a good solution.

Compiler flags are :

Google-Closure-Compiler versions tested :

concavelenz commented 7 years ago

Can provide some details on why you care if it is collapsed? That is why this is problematic for you?

ChadKillingsworth commented 7 years ago

He was looping over the prototype.

concavelenz commented 7 years ago

For what purpose?

Ludobaka commented 7 years ago

I'm creating webworkers on runtime by using this code base. I've improved the system to include my dependencies objects prototypes so I need to keep them.

concavelenz commented 7 years ago

How are the methods being called? Generally, if you are running into problems with devirtualization you will also run into problems with other optimizations (remove unused X, inline methods). If you are using the methods in a way that isn't seen by the compiler then you need to export the methods.

Ludobaka commented 7 years ago

I'm retrieving each dependencies objects of my worker recursively and I concatenate and then generate a Blob file containing them. I didn't encountered any of the other problems you said. My problem is not that unused methods are removed. They are sometimes written in a different way when using prototypes, so they are not recovered properly when creating the Blob.

I also prefer to not export those methods, because they are used internally and I am asked to keep the code obfuscated at maximum for IP protection purpose.

The perfect solution for me would be just to tell closure compiler to avoid to devirtualize prototypes, maybe by using @nocollapse, because every other optimization are working fine for now.