From: Jean Privat Date: Sat, 28 Mar 2015 01:34:45 +0000 (+0700) Subject: Merge: Fast super strings X-Git-Tag: v0.7.3~9 X-Git-Url: http://nitlanguage.org?hp=-c Merge: Fast super strings Superstrings, like "a{b}c", are managed in the AST as a special group of sub-expression nodes that are either literal string parts or standard expressions. The previous example is basically `["a", b, "c"]` Previously, the compilation of super-strings was direct: the values are grouped in an array and `to_s` is called on it. So in fact `"a{b}c"` was compiled as `["a", b, "c"].to_s`. This basic implementation is simple and correct. But it has some drawbacks: * a new Array[Object] (and a NativeArray[Object]) is allocated each time the super-string is evaluated. * all elements are to_s-ized in `Array::to_s`, even the literal parts. * an additional NativeArray[String] is allocated in `Array:to_s` to do the fast concatenation. Because of the numerous allocations, superstrings caused a lot of work to the GC. This PR provides a better, but more complex implementation: * instead of an Array[Object], a NativeArray[String] is directly build and a fast concatenation `native_to_s` is invoked. * the allocated NativeArray is cached in a static variable so it can be reused in next evaluation. * the literal string parts are stored in the native array as is, and only once just after the allocation of the native array. Results for nitc/nitc/nitc: before: 0m6.076s after: 0m5.512s (-9% not bad!) Pull-Request: #1219 Reviewed-by: Lucas Bajolet --- 87235c87c9a3ec0feab4118fbbb0e8949fae7b87 diff --combined src/compiler/separate_compiler.nit index 00125ea,83749b6..ecfcc8e --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@@ -1580,7 -1580,7 +1580,7 @@@ class SeparateCompilerVisito self.add("{res} = {recv}->attrs[{a.const_color}] != NULL; /* {a} on {recv.inspect}*/") else - if not mtype.is_c_primitive then + if not mtype.is_c_primitive and not mtype.is_tagged then self.add("{res} = {recv}->attrs[{a.const_color}].val != NULL; /* {a} on {recv.inspect} */") else self.add("{res} = 1; /* NOT YET IMPLEMENTED: isset of primitives: {a} on {recv.inspect} */") @@@ -1661,11 -1661,7 +1661,11 @@@ self.require_declaration(a.const_color) if self.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then var attr = "{recv}->attrs[{a.const_color}]" - if mtype.is_c_primitive then + if mtype.is_tagged then + # The attribute is not primitive, thus store it as tagged + var tv = autobox(value, compiler.mainmodule.object_type) + self.add("{attr} = {tv}; /* {a} on {recv.inspect} */") + else if mtype.is_c_primitive then assert mtype isa MClassType # The attribute is primitive, thus we store it in a box # The trick is to create the box the first time then resuse the box @@@ -2047,6 -2043,22 +2047,22 @@@ end end + redef fun native_array_get(nat, i) + do + var nclass = mmodule.native_array_class + var recv = "((struct instance_{nclass.c_name}*){nat})->values" + # Because the objects are boxed, return the box to avoid unnecessary (or broken) unboxing/reboxing + var res = self.new_expr("{recv}[{i}]", compiler.mainmodule.object_type) + return res + end + + redef fun native_array_set(nat, i, val) + do + var nclass = mmodule.native_array_class + var recv = "((struct instance_{nclass.c_name}*){nat})->values" + self.add("{recv}[{i}]={val};") + end + fun link_unresolved_type(mclassdef: MClassDef, mtype: MType) do assert mtype.need_anchor var compiler = self.compiler @@@ -2308,14 -2320,3 +2324,14 @@@ redef class AMethPropde return super end end + +redef class AAttrPropdef + redef fun init_expr(v, recv) + do + super + if is_lazy and v.compiler.modelbuilder.toolcontext.opt_no_union_attribute.value then + var guard = self.mlazypropdef.mproperty + v.write_attribute(guard, recv, v.bool_instance(false)) + end + end +end