summaryrefslogtreecommitdiff
path: root/chapter28a
diff options
context:
space:
mode:
Diffstat (limited to 'chapter28a')
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/Chapter10Test.java5
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/Chapter15Test.java8
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/Chapter19Test.java16
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/Chapter20Test.java8
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/Chapter21Test.java16
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/PrivacyTest.java196
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter20Test-testString.smp8
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter21AllocTest-testString.smp8
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter21Test-testStringExport.smp8
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter23AllocTest-testString.smp8
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter24AllocTest-testBubbleSort.smp9
11 files changed, 244 insertions, 46 deletions
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter28a/src/test/java/com/seaofnodes/simple/Chapter10Test.java
index 39c7040e..ca840088 100644
--- a/chapter28a/src/test/java/com/seaofnodes/simple/Chapter10Test.java
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/Chapter10Test.java
@@ -245,8 +245,9 @@ if (arg) bar = null;
if( bar ) bar.a = 1;
return bar.a;
""");
- code.driver(CodeGen.Phase.FinalizeIR);
- assertEquals("return Phi(Region,1,.a);", code.print());
+ // An erroneous load stays intact instead of partially forwarding it.
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
+ catch( Parser.ParseException e ) { assertEquals("Might be null accessing 'a'",e.getMessage()); }
}
@Test
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter28a/src/test/java/com/seaofnodes/simple/Chapter15Test.java
index c2071cb6..84bc28de 100644
--- a/chapter28a/src/test/java/com/seaofnodes/simple/Chapter15Test.java
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/Chapter15Test.java
@@ -221,15 +221,15 @@ return rez;""");
CodeGen code = new CodeGen(
"""
// Can we define a forward-reference array?
-struct _Tree { !_Tree?[]? !_kids; };
+struct _Tree { !_Tree?[]? !kids; };
!_Tree !root = new _Tree;
-root._kids = new !_Tree?[2]; // NO BANG SO ARRAY IS OF IMMUTABLE TREES????
-root._kids[0] = new _Tree;
+root.kids = new !_Tree?[2]; // NO BANG SO ARRAY IS OF IMMUTABLE TREES????
+root.kids[0] = new _Tree;
return root;
""");
code.driver(CodeGen.Phase.TypeCheck);
assertEquals("return Test._Tree;", code.print());
- assertEquals("Test._Tree{_kids=*Test._Tree {*[]*Test._Tree?[mutable]? !_kids; }?[ Test._Tree{_kids=null},null]}", Eval2.eval(code, 0));
+ assertEquals("Test._Tree{kids=*Test._Tree {*[]*Test._Tree?[mutable]? !kids; }?[ Test._Tree{kids=null},null]}", Eval2.eval(code, 0));
}
@Test
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/Chapter19Test.java b/chapter28a/src/test/java/com/seaofnodes/simple/Chapter19Test.java
index d5fe207a..a54377fa 100644
--- a/chapter28a/src/test/java/com/seaofnodes/simple/Chapter19Test.java
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/Chapter19Test.java
@@ -85,7 +85,7 @@ return 0;
"""
struct String {
u8[~] !cs;
- int _hashCode;
+ int cachedHash; // Public fixture storage: hashing helpers are outside String.
new String = { u8[~] s -> cs=s; };
};
@@ -110,15 +110,15 @@ val _hashCodeString = { !String self ->
// Return the String hashCode (cached, and never 0)
val hashCode = { !String self ->
- self._hashCode
- ? self._hashCode
- : (self._hashCode = _hashCodeString(self));
+ self.cachedHash
+ ? self.cachedHash
+ : (self.cachedHash = _hashCodeString(self));
};
hashCode(new String("Hello, World!"));
""";
CodeGen code = new CodeGen(src).driver(Phase.LocalSched);
- assertEquals("Stop[ return Phi(Region,123456789,(!=0)Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash)))); return MEM[ 2:___ 3:___ 4:___ 5:.cs=Parm_s(Test.String.String,*[]u8[final]); 6:._hashCode=0;]; return MEM[ 2:___ 3:___ 4:___ 5:___ 6:._hashCode=0;]; return Test.String; return Phi(Region,0,1,0,1); return Phi(Region,(!=0)._hashCode,Phi(Region,123456789,(!=0)Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash))))); ]", code.print());
+ assertEquals("Stop[ return Phi(Region,123456789,(!=0)Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash)))); return MEM[ 2:___ 3:___ 4:___ 5:.cs=Parm_s(Test.String.String,*[]u8[final]); 6:.cachedHash=0;]; return MEM[ 2:___ 3:___ 4:___ 5:___ 6:.cachedHash=0;]; return Test.String; return Phi(Region,0,1,0,1); return Phi(Region,(!=0).cachedHash,Phi(Region,123456789,(!=0)Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash))))); ]", code.print());
assertEquals("4029215624828139541", Eval2.eval(code, 2));
}
@@ -128,16 +128,16 @@ hashCode(new String("Hello, World!"));
"""
struct String {
u8[~] !cs;
- int _hashCode;
+ int cachedHash; // Public fixture storage: hashing helpers are outside String.
new String = { u8[~] s -> cs=s; };
};
val f = { !String self -> 7; };
val hashCode = { !String self ->
- self._hashCode
+ self.cachedHash
? 3
- : (self._hashCode = f(self));
+ : (self.cachedHash = f(self));
};
hashCode(new String("Hello"));
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter28a/src/test/java/com/seaofnodes/simple/Chapter20Test.java
index cdfd16a7..c1355bf2 100644
--- a/chapter28a/src/test/java/com/seaofnodes/simple/Chapter20Test.java
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/Chapter20Test.java
@@ -227,7 +227,7 @@ return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6
"""
struct String {
u8[] !cs;
- int _hashCode;
+ int cachedHash; // Public fixture storage: hashing helpers are outside String.
new String = { u8[] data -> cs=data; };
};
@@ -243,9 +243,9 @@ val equals = { !String !self, !String s ->
// Return the String hashCode (cached, and never 0)
val hashCode = { !String self ->
- self._hashCode
- ? self._hashCode
- : (self._hashCode = _hashCodeString(self));
+ self.cachedHash
+ ? self.cachedHash
+ : (self.cachedHash = _hashCodeString(self));
};
val _hashCodeString = { !String self ->
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter28a/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index 2fcf65e9..d5d208b6 100644
--- a/chapter28a/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -354,7 +354,7 @@ return v0;
"""
struct String {
u8[] !cs;
- int _hashCode;
+ int cachedHash; // Public fixture storage: hashing helpers are outside String.
new String = { u8[] data -> cs=data; };
};
@@ -370,9 +370,9 @@ val equals = { !String !self, !String s ->
// Return the String hashCode (cached, and never 0)
val hashCode = { !String self ->
- self._hashCode
- ? self._hashCode
- : (self._hashCode = _hashCodeString(self));
+ self.cachedHash
+ ? self.cachedHash
+ : (self.cachedHash = _hashCodeString(self));
};
val _hashCodeString = { !String self ->
@@ -393,7 +393,7 @@ val _hashCodeString = { !String self ->
"""
struct String {
u8[] !cs;
- int _hashCode;
+ int cachedHash; // Public fixture storage: hashing helpers are outside String.
new String = { u8[] data -> cs=data; };
};
@@ -409,9 +409,9 @@ val equals = { !String !self, !String s ->
// Return the String hashCode (cached, and never 0)
val hashCode = { !String self ->
- self._hashCode
- ? self._hashCode
- : (self._hashCode = _hashCodeString(self));
+ self.cachedHash
+ ? self.cachedHash
+ : (self.cachedHash = _hashCodeString(self));
};
val _hashCodeString = { !String self ->
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/PrivacyTest.java b/chapter28a/src/test/java/com/seaofnodes/simple/PrivacyTest.java
new file mode 100644
index 00000000..21e7f2ff
--- /dev/null
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/PrivacyTest.java
@@ -0,0 +1,196 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.type.TypeInteger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class PrivacyTest {
+ private static void rejects(String src, String message) {
+ for( long seed : new long[]{1,13,123} )
+ try {
+ new CodeGen(src,seed,true).driver(CodeGen.Phase.TypeCheck);
+ fail("Accepted private access: "+src);
+ } catch( Parser.ParseException e ) {
+ assertTrue(e.getMessage(),e.getMessage().contains(message));
+ assertNotNull(e._loc);
+ assertTrue(e.getMessage(),e.getMessage().contains(": error: "));
+ }
+ }
+
+ @Test public void testFieldsAndMethods() {
+ String box = "struct Box { int _x=7; val _get={ -> _x; }; }; val b=new Box(); ";
+ for( String use : new String[]{"return b._x;",
+ "b._x=8; return 0;", "b._x+=1; return 0;", "b._x++; return 0;",
+ "return b._get();", "val f=b._get; return 0;"} )
+ rejects(box+use,"Private field");
+ // Constant fields must not bypass the check in generic constant folding.
+ rejects("struct Box { val _x=7; }; return new Box()._x;","Private field");
+ rejects("struct Box { flt _x=7.0; }; return new Box()._x;","Private field");
+
+ for( String use : new String[]{"b._x; return 0;",
+ "if(false) b._x; return 0;"} ) {
+ CodeGen dead = new CodeGen(box+use).driver(CodeGen.Phase.TypeCheck);
+ assertEquals("0",Eval2.eval(dead,0));
+ }
+
+ CodeGen code = new CodeGen("""
+ struct Box {
+ int _x;
+ new Box={int n -> _x=n; ++_x;};
+ val _get={ -> _x; };
+ val sum={Box other -> _get()+other._x; };
+ };
+ val a=new Box(2);
+ return a.sum(new Box(3));
+ """).driver(CodeGen.Phase.TypeCheck);
+ assertEquals("7",Eval2.eval(code,0));
+ // An underscore on a function-local variable does not make it a field.
+ code = new CodeGen("val run={int n -> int _x=n; ++_x; return _x;}; return run(arg);")
+ .driver(CodeGen.Phase.TypeCheck);
+ assertEquals("5",Eval2.eval(code,4));
+ }
+
+ @Test public void testNestedOwners() {
+ // One shared forward ref can have both legal and illegal source uses.
+ rejects("val own={ -> _x; }; struct Child { val get={ -> _x; }; }; val _x=7; return own()+new Child().get();","Private field");
+ rejects("struct Child { val get={ -> _x; }; }; val _x=7; return new Child().get();","Private field");
+ rejects("struct Child { val get={ -> _f(); }; }; val _f={ -> 7; }; return new Child().get();","Private field");
+ rejects("int _x=7; struct Child { val get={ -> _x; }; }; return 0;","Private field");
+ rejects("int _x=7; struct Child { val get={ -> _x=8; }; }; return 0;","Private field");
+ rejects("int _x=7; struct Child { val get={ -> ++_x; }; }; return 0;","Private field");
+ rejects("""
+ struct Outer {
+ int _x=7;
+ struct Inner { val get={Outer o -> o._x;}; };
+ };
+ return 0;
+ ""","Private field");
+ rejects("""
+ struct Outer {
+ struct Inner { int _x=7; };
+ val get={Inner i -> i._x;};
+ };
+ return 0;
+ ""","Private field");
+ rejects("""
+ struct A { int _x=7; };
+ struct B { val get={A a -> a._x;}; };
+ return 0;
+ ""","Private field");
+ }
+
+ @Test public void testPrivateClasses() {
+ // The private root class name is in scope throughout its own body,
+ // including nested classes, without exposing its private fields.
+ new CodeGen(null,null,"_Private",
+ "struct Child { val root={ -> _Private; }; }; return 0;",
+ 123,true,TypeInteger.BOT).driver(CodeGen.Phase.TypeCheck);
+ CodeGen code = new CodeGen("""
+ struct _Box {
+ int _x=7;
+ val get={ -> _x; };
+ val sum={_Box b -> _x+b._x;};
+ };
+ val b=new _Box();
+ return b.sum(new _Box());
+ """).driver(CodeGen.Phase.TypeCheck);
+ assertEquals("14",Eval2.eval(code,0));
+
+ String outer = "struct Outer { struct _Hidden { int x=7; struct Public { int x=8; }; }; }; ";
+ for( String use : new String[]{"return new Outer._Hidden();",
+ "Outer._Hidden? x; return 0;", "return Outer._Hidden;",
+ "return new Outer._Hidden.Public();"} )
+ rejects(outer+use,"Private class");
+ rejects("struct _Box { int _x=7; }; return new _Box()._x;","Private field");
+
+
+ }
+
+ static final String LIB = """
+ struct _Hidden { int _x=7; val get={ -> _x; }; };
+ val make={ -> new _Hidden(); };
+ int _secret=11;
+ val read={ -> _secret; };
+ { i32 -> i32 } _exit="C";
+ """;
+
+ @Test public void testSourceModules() throws Exception {
+ Path base = Path.of("build/objs/privacy");
+ Files.createDirectories(base);
+ Path root = Files.createTempDirectory(base,"source-");
+ Files.writeString(root.resolve("App.smp"),"return 0;");
+ Files.createDirectory(root.resolve("App"));
+ Files.writeString(root.resolve("App/Lib.smp"),LIB);
+ Files.writeString(root.resolve("App/Client.smp"),"return Lib.make().get()+Lib.read();");
+ CodeGen code = new CodeGen(root.toString(),root.resolve("obj").toString(),
+ "App/Client",null,123,true,TypeInteger.BOT).driver(CodeGen.Phase.TypeCheck);
+ assertEquals("18",Eval2.eval(code,0));
+ for( String use : new String[]{"return Lib._secret;", "Lib._secret=0; return 0;",
+ "return Lib._exit;", "return new Lib._Hidden();",
+ "Lib._Hidden? h; return 0;", "return Lib._Hidden;",
+ "return Lib.make()._x;"} ) {
+ Files.writeString(root.resolve("App/Client.smp"),use);
+ try {
+ new CodeGen(root.toString(),root.resolve("obj").toString(),
+ "App/Client",null,123,true,TypeInteger.BOT).driver(CodeGen.Phase.TypeCheck);
+ fail("Accepted private access: "+use);
+ } catch( Parser.ParseException e ) {
+ assertTrue(use+": "+e.getMessage(),e.getMessage().contains("Private "));
+ assertTrue(e.getMessage(),e.getMessage().contains("Client.smp:"));
+ }
+ }
+ }
+
+ @Test public void testForwardReceiverAndUnusedAccess() {
+ for( String use : new String[]{"return make()._x;", "return make()._get();",
+ "val b=make(); b._x=9; return b;"} )
+ rejects("""
+ val run={ -> %s };
+ struct Box { int _x=7; val _get={ -> _x; }; };
+ val make={ -> new Box(); };
+ return run();
+ """.formatted(use),"Private field");
+ CodeGen code = new CodeGen("""
+ struct Box {
+ int _x=7;
+ val read={Box b -> identity(b)._x; };
+ val identity={Box b -> b; };
+ };
+ val b=new Box();
+ return b.read(b);
+ """).driver(CodeGen.Phase.TypeCheck);
+ assertEquals("7",Eval2.eval(code,0));
+ // Unused forward accesses disappear through ordinary DCE.
+ for( String use : new String[]{"make()._x;", "val f=make()._get;"} ) {
+ CodeGen dead = new CodeGen("val run={ -> "+use+" return 0; }; "+
+ "struct Box { int _x=7; val _get={ -> _x; }; }; "+
+ "val make={ -> new Box(); }; return run();").driver(CodeGen.Phase.TypeCheck);
+ assertEquals("0",Eval2.eval(dead,0));
+ }
+ // A legal inlined setter must not erase the preceding illegal store.
+ rejects("""
+ val run={ -> val b=make(); b._x=1; b.set(2); return b.get(); };
+ struct Box {
+ int _x=7;
+ val set={int n -> _x=n;};
+ val get={ -> _x;};
+ };
+ val make={ -> new Box(); };
+ return run();
+ ""","Private field");
+ // A dead call has no return type; it must not strand a valid check.
+ code = new CodeGen("""
+ struct Box {
+ int _x=7;
+ val read={Box b -> if(false) identity(b)._x; return 7; };
+ val identity={Box b -> b; };
+ };
+ val b=new Box();
+ return b.read(b);
+ """).driver(CodeGen.Phase.TypeCheck);
+ assertEquals("7",Eval2.eval(code,0));
+ }
+}
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter20Test-testString.smp b/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter20Test-testString.smp
index 951cdc32..3a4b349e 100644
--- a/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter20Test-testString.smp
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter20Test-testString.smp
@@ -1,7 +1,7 @@
struct _String {
u8[] cs;
new _String={ u8[] b -> cs=b; };
- int _hashCode;
+ int cachedHash; // External helpers deliberately use public storage.
};
val _equals = { !_String !self, !_String s ->
@@ -14,9 +14,9 @@ val _equals = { !_String !self, !_String s ->
};
val _hashCode = { !_String self ->
- self._hashCode
- ? self._hashCode
- : (self._hashCode = _hashCodeString(self));
+ self.cachedHash
+ ? self.cachedHash
+ : (self.cachedHash = _hashCodeString(self));
};
val _hashCodeString = { !_String self ->
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter21AllocTest-testString.smp b/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter21AllocTest-testString.smp
index a18a5b88..d7b0e73b 100644
--- a/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter21AllocTest-testString.smp
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter21AllocTest-testString.smp
@@ -1,7 +1,7 @@
// -*- mode: java; -*-
struct _String {
u8[] cs;
- int _hashCode;
+ int cachedHash; // External helpers deliberately use public storage.
new _String = { u8[] data -> cs=data; };
};
@@ -17,9 +17,9 @@ val equals = { !_String !self, !_String s ->
// Return the String hashCode (cached, and never 0)
val hashCode = { !_String self ->
- self._hashCode
- ? self._hashCode
- : (self._hashCode = _hashCodeString(self));
+ self.cachedHash
+ ? self.cachedHash
+ : (self.cachedHash = _hashCodeString(self));
};
val _hashCodeString = { !_String self ->
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter21Test-testStringExport.smp b/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter21Test-testStringExport.smp
index ee5a0560..486a02e2 100644
--- a/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter21Test-testStringExport.smp
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter21Test-testStringExport.smp
@@ -1,6 +1,6 @@
struct String {
u8[] cs;
- int _hashCode;
+ int cachedHash; // External helpers deliberately use public storage.
new String = { u8[] data -> cs=data; };
};
@@ -16,9 +16,9 @@ val equals = { !String !self, !String s ->
// Return the String hashCode (cached, and never 0)
val hashCode = { !String self ->
- self._hashCode
- ? self._hashCode
- : (self._hashCode = _hashCodeString(self));
+ self.cachedHash
+ ? self.cachedHash
+ : (self.cachedHash = _hashCodeString(self));
};
val _hashCodeString = { !String self ->
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter23AllocTest-testString.smp b/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter23AllocTest-testString.smp
index 49c80a99..eb9c52b2 100644
--- a/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter23AllocTest-testString.smp
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter23AllocTest-testString.smp
@@ -1,7 +1,7 @@
// -*- mode: java; -*-
struct _String {
u8[] cs;
- int _hashCode;
+ int cachedHash; // External helpers deliberately use public storage.
new _String = { u8[] data -> cs=data; };
};
@@ -17,9 +17,9 @@ val equals = { !_String !self, !_String s ->
// Return the String hashCode (cached, and never 0)
val hashCode = { !_String self ->
- self._hashCode
- ? self._hashCode
- : (self._hashCode = _hashCodeString(self));
+ self.cachedHash
+ ? self.cachedHash
+ : (self.cachedHash = _hashCodeString(self));
};
val _hashCodeString = { !_String self ->
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter24AllocTest-testBubbleSort.smp b/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter24AllocTest-testBubbleSort.smp
index f292254e..a5ae22a9 100644
--- a/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter24AllocTest-testBubbleSort.smp
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/spill/Chapter24AllocTest-testBubbleSort.smp
@@ -16,7 +16,8 @@
i32 MAP_PRIVATE = 2;
i32 MAP_ANON = 32;
- val _copy = { u8[] dst, int doff, u8[~] src, int soff, int len ->
+ // Shared by the module and its nested collection classes.
+ val copy = { u8[] dst, int doff, u8[~] src, int soff, int len ->
for( int i=0; i<len; i++ )
dst[i+doff] = src[i+soff];
return dst;
@@ -31,7 +32,7 @@
int newlen = buf# * 2;
while( len+len2 >= newlen ) newlen *= 2;
u8[] !buf2 = new u8[newlen];
- _copy(buf2,0,buf,0,buf#);
+ copy(buf2,0,buf,0,buf#);
buf = buf2;
self;
};
@@ -45,7 +46,7 @@
// Add a plain array to the aryu8
val addAry = { u8[~] ary ->
_grow(ary#);
- _copy(buf,len,ary,0,ary#);
+ copy(buf,len,ary,0,ary#);
len += ary#;
self;
};
@@ -176,7 +177,7 @@ struct _aryi64 {
}
// Compress
var dst = new u8[len];
- return _copy(dst,0,buf,0,len);
+ return copy(dst,0,buf,0,len);
};
// -*- mode: java; -*-