Merge: faster new factory
authorJean Privat <jean@pryen.org>
Tue, 26 Apr 2016 00:20:55 +0000 (20:20 -0400)
committerJean Privat <jean@pryen.org>
Tue, 26 Apr 2016 00:20:55 +0000 (20:20 -0400)
new factories are badly implemented.
They assume a stub temporary receiver exists.
This temporary receiver is required because it currently holds the method and the formal types.

However, this object could be reused if the formal types are the same.
It's what is doing the PR.

This is still a temporary workaround solution, doing things correctly need a lot of more work.

Asked by @R4PaSs

Pull-Request: #2038
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>

src/compiler/abstract_compiler.nit
tests/base_new_factory.nit [new file with mode: 0644]
tests/sav/base_new_factory.res [new file with mode: 0644]

index 31dfcc4..0263e11 100644 (file)
@@ -3945,12 +3945,36 @@ redef class ANewExpr
                        return v.native_array_instance(elttype, l)
                end
 
-               var recv = v.init_instance_or_extern(mtype)
-
                var callsite = self.callsite
-               if callsite == null then return recv
+               if callsite == null then return v.init_instance_or_extern(mtype)
                if callsite.is_broken then return null
 
+               var recv
+               # new factories are badly implemented.
+               # They assume a stub temporary receiver exists.
+               # This temporary receiver is required because it
+               # currently holds the method and the formal types.
+               #
+               # However, this object could be reused if the formal types are the same.
+               # Therefore, the following code will `once` it in these case
+               if callsite.mproperty.is_new and not mtype.need_anchor then
+                       var name = v.get_name("varoncenew")
+                       var guard = v.get_name(name + "_guard")
+                       v.add_decl("static {mtype.ctype} {name};")
+                       v.add_decl("static int {guard};")
+                       recv = v.new_var(mtype)
+                       v.add("if (likely({guard})) \{")
+                       v.add("{recv} = {name};")
+                       v.add("\} else \{")
+                       var i = v.init_instance_or_extern(mtype)
+                       v.add("{recv} = {i};")
+                       v.add("{name} = {recv};")
+                       v.add("{guard} = 1;")
+                       v.add("\}")
+               else
+                       recv = v.init_instance_or_extern(mtype)
+               end
+
                var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
                var res2 = v.compile_callsite(callsite, args)
                if res2 != null then
diff --git a/tests/base_new_factory.nit b/tests/base_new_factory.nit
new file mode 100644 (file)
index 0000000..d8b704c
--- /dev/null
@@ -0,0 +1,71 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import core::kernel
+
+interface A
+       new do return new B(5)
+end
+
+class B
+       super A
+       var i: Int
+       redef fun output do
+               'B'.output
+               i.output
+       end
+end
+
+interface G[E: Object]
+       new(a: E) do return new H[E](a)
+       fun dup:G[E] is abstract
+end
+
+class H[F: Object]
+       super G[F]
+       var o: F
+
+       redef fun output do
+               'H'.output
+               o.output
+       end
+
+       redef fun dup do return new G[F](self.o)
+end
+
+var b = new B(1)
+b.output
+var a = new A
+a.output
+
+var ha = new H[A](a)
+ha.output
+var hb = new H[B](b)
+hb.output
+
+var ga = new G[A](a)
+ga.output
+var gb = new G[B](b)
+gb.output
+
+ga.dup.output
+gb.dup.output
+
+var gga = new G[G[A]](ga)
+gga.output
+var ggb = new G[G[B]](gb)
+ggb.output
+
+gga.dup.output
+ggb.dup.output
diff --git a/tests/sav/base_new_factory.res b/tests/sav/base_new_factory.res
new file mode 100644 (file)
index 0000000..238446a
--- /dev/null
@@ -0,0 +1,12 @@
+B1
+B5
+HB5
+HB1
+HB5
+HB1
+HB5
+HB1
+HHB5
+HHB1
+HHB5
+HHB1