Skip to content

Commit

Permalink
Add method inlining to inline constructors filter (#9599)
Browse files Browse the repository at this point in the history
* Remove unused decls array

* Mark inline objects using metadata instead of identifying them by order.

* Remove unused e.etype from match

* Replace e with mark_ctors result.

* Fix mark_ctors

* Remove unused id_start and id_end

* debug hacks

* Make handle field case handle inline methods too.

* Implement inline constructor method inlining (Has known bugs marked with TODO)

* Remove debug prints.

* Fix typing of ethis on method inline.

* For now don't forward captured to the inlined method analysis

* Add missing result of this expression to inlined method.

* Improve names of some variables.

* Analyze aliases in call args of inlined methods and cancel the resulting inline objects if the parent inline object is cancelled.

* Remove commented code.

* Support returning inline objects from inlined methods

* remove debug stuff.

* Factor out call arg analysis

* Some documentation.

* Add return type to mark_ctors

* Set io_has_untyped if inlined method had HasUntyped

* Add @:inlineObject to meta.json and use that instead of Meta.Custom

* Add more comments

* Add inline constructor tests.

* Use record for IOKCtor data

* Check that the expression has inline objects before doing any work.

* Make sure the field we are inlining is a compatible function

This can only happen when dynamic casts are involved.
This is probably over-conservative, instead of type_eq_strict it would be better to check if it unifies.

* Add test for incompatible method inline cancellations.

* Check that the class method type unifies with the field expression type instead.

Also check that the field expression is a function to avoid the Dynamic case.
  • Loading branch information
basro committed Jun 29, 2020
1 parent 5d48282 commit 0d4f2f2
Show file tree
Hide file tree
Showing 10 changed files with 511 additions and 200 deletions.
6 changes: 6 additions & 0 deletions src-json/meta.json
Expand Up @@ -573,6 +573,12 @@
"doc": "Internally used to mark expressions that were passed as arguments of an inlined constructor.",
"internal": true
},
{
"name": "InlineObject",
"metadata": ":inlineObject",
"doc": "Internally used by inline constructors filter to mark potentially inlineable objects.",
"internal": true
},
{
"name": "Internal",
"metadata": ":internal",
Expand Down
574 changes: 374 additions & 200 deletions src/optimization/inlineConstructors.ml

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions tests/misc/projects/inline-constructors/Extern.hx
@@ -0,0 +1,11 @@
class Inl {
public var i : Int = 0;
public extern inline function new() {}
}

class Extern {
public static function main() {
var a = new Inl();
trace(a);
}
}
11 changes: 11 additions & 0 deletions tests/misc/projects/inline-constructors/ForceInline.hx
@@ -0,0 +1,11 @@
class Inl {
public var i : Int = 0;
public function new() {}
}

class ForceInline {
public static function main() {
var a = inline new Inl();
trace(a);
}
}
@@ -0,0 +1,2 @@
Extern
-js extern.js
@@ -0,0 +1,2 @@
Extern.hx:8: characters 11-20 : Forced inline constructor could not be inlined
Extern.hx:9: characters 9-10 : Cancellation happened here
@@ -0,0 +1,2 @@
ForceInline
-js force-inline.js
@@ -0,0 +1,2 @@
ForceInline.hx:8: characters 11-27 : Forced inline constructor could not be inlined
ForceInline.hx:9: characters 9-10 : Cancellation happened here
1 change: 1 addition & 0 deletions tests/optimization/run.hxml
Expand Up @@ -21,5 +21,6 @@
--macro Macro.register('TestJs')
--macro Macro.register('TestLocalDce')
--macro Macro.register('TestTreGeneration')
--macro Macro.register('TestInlineConstructors')
--macro Macro.register('issues')
--dce std
100 changes: 100 additions & 0 deletions tests/optimization/src/TestInlineConstructors.hx
@@ -0,0 +1,100 @@
class InlineClass {
public var a = 1;
public var b = "";
public var c = "hello";
public inline function new() {
}

public inline function method() {
return a + b + c;
}
}

class NestedInlineClass {
public var a : InlineClass;
public var b : Array<Int>;
public var c : {a: Int};

public inline function new() {
a = new InlineClass();
b = [1,2,3];
c = {a:4};
}
}

class TestInlineConstructors extends TestBase {
@:js('return [1,2,3,3];')
static function testArrayInlining() {
var a = [1,2,3];
return [a[0], a[1], a[2], a.length];
}

@:js('return [2,"hello","world"];')
static function testAnonymousStructureInlining() {
var a = {a: 1, b: "", c: "hello"};
a.a = 2;
a.b = a.c;
a.c = "world";
return ([a.a,a.b,a.c] : Array<Dynamic>);
}

@:js('return [2,"hello","world"];')
static function testClassConstructorInlining() {
var a = new InlineClass();
a.a = 2;
a.b = a.c;
a.c = "world";
return return ([a.a,a.b,a.c] : Array<Dynamic>);
}

@:js('return [1,2,4,"test",2,1,4,3,4];')
static function testNestedInlining() {
var a = {
a: new NestedInlineClass(),
b: [new NestedInlineClass()],
c: {test: new NestedInlineClass()}
};
a.b[0].a.c = "test";
return ([a.a.a.a, a.a.b[1], a.a.c.a, a.b[0].a.c, a.b[0].b[1], a.b.length, a.c.test.c.a, a.c.test.b[2], a.c.test.c.a]:Dynamic);
}

@:js('return [1,"hello","world"];')
static function testMultipleAliasingVariables() {
var a = new InlineClass();
var b = a;
var d = [b,a];
d[1].b = "hello";
a.c = "world";
return ([a.a, a.b, d[1].c]:Array<Dynamic>);
}

@:js('return [1,"","hello"];')
static function testUnassignedVariables() {
var a;
a = new InlineClass();
return ([a.a, a.b, a.c]:Array<Dynamic>);
}

@:js('return [1,3,"hello"];')
static function testNoExplicitVariables() {
return ([
new InlineClass().a,
[1,2,3][2],
new NestedInlineClass().a.c
]:Array<Dynamic>);
}

@:js('return 1 + "" + "hello";')
static function testMethodInlining() {
var a : {function method() : String;} = new InlineClass();
return a.method();
}

@:js('var b = new InlineClass();return [new InlineClass().method(1),b.method(2)];')
static function testIncompatibleMethodCancelling() {
// InlineClass.method doesn't take any arguments, the method should not be inlined.
var a : {function method(arg : Int) : String;} = cast new InlineClass();
var b : Dynamic = new InlineClass();
return [a.method(1), b.method(2)];
}
}

0 comments on commit 0d4f2f2

Please sign in to comment.