diff --git a/core/src/main/java/org/teavm/backend/c/util/BufferedFile.java b/core/src/main/java/org/teavm/backend/c/util/BufferedFile.java new file mode 100644 index 000000000..2845092d6 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/c/util/BufferedFile.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019 konsoletyper. + * + * 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. + */ +package org.teavm.backend.c.util; + +import java.io.IOException; +import java.io.RandomAccessFile; + +class BufferedFile { + private RandomAccessFile out; + private byte[] buffer; + private int pos; + + BufferedFile(RandomAccessFile out) { + this.out = out; + buffer = new byte[4096]; + } + + void flush() throws IOException { + if (pos > 0) { + out.write(buffer, 0, pos); + pos = 0; + } + } + + void writeInt(int v) throws IOException { + byte[] buffer = this.buffer; + int localPos = pos; + if (localPos + 4 >= buffer.length) { + flush(); + localPos = pos; + } + + buffer[localPos++] = (byte) (v >>> 24); + buffer[localPos++] = (byte) ((v >>> 16) & 255); + buffer[localPos++] = (byte) ((v >>> 8) & 255); + buffer[localPos++] = (byte) (v & 255); + + pos = localPos; + } + + void writeShort(int v) throws IOException { + byte[] buffer = this.buffer; + int localPos = pos; + if (localPos + 2 >= buffer.length) { + flush(); + localPos = pos; + } + + buffer[localPos++] = (byte) ((v >>> 8) & 255); + buffer[localPos++] = (byte) (v & 255); + + pos = localPos; + } + + void write(byte[] data) throws IOException { + write(data, 0, data.length); + } + + void write(byte[] data, int start, int length) throws IOException { + if (pos + length >= buffer.length) { + flush(); + } + if (length > buffer.length) { + out.write(data, start, length); + } else { + System.arraycopy(data, start, buffer, pos, length); + pos += length; + } + } + + void write(int b) throws IOException { + if (pos + 1 >= buffer.length) { + flush(); + } + buffer[pos++] = (byte) b; + } + + long getFilePointer() throws IOException { + return out.getFilePointer() + pos; + } + + void seek(long pointer) throws IOException { + flush(); + out.seek(pointer); + } +} diff --git a/core/src/main/java/org/teavm/backend/c/util/HeapDumpConverter.java b/core/src/main/java/org/teavm/backend/c/util/HeapDumpConverter.java index dccd3f5d9..6e95694e7 100644 --- a/core/src/main/java/org/teavm/backend/c/util/HeapDumpConverter.java +++ b/core/src/main/java/org/teavm/backend/c/util/HeapDumpConverter.java @@ -21,7 +21,6 @@ import com.carrotsearch.hppc.LongObjectMap; import com.carrotsearch.hppc.ObjectIntHashMap; import com.carrotsearch.hppc.ObjectIntMap; import java.io.BufferedInputStream; -import java.io.DataOutput; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; @@ -215,9 +214,12 @@ public final class HeapDumpConverter { output.write("JAVA PROFILE 1.0.2\0".getBytes(StandardCharsets.UTF_8)); output.writeInt(idSize); output.writeLong(System.currentTimeMillis()); - writeSymbols(output, symbolTable); - writeStack(output, symbolTable); - writeHeapDump(reader, output, symbolTable); + + BufferedFile bufferedOutput = new BufferedFile(output); + writeSymbols(bufferedOutput, symbolTable); + writeStack(bufferedOutput, symbolTable); + writeHeapDump(reader, bufferedOutput, symbolTable); + bufferedOutput.flush(); output.write(0x2C); output.writeInt(0); @@ -225,7 +227,7 @@ public final class HeapDumpConverter { output.setLength(output.getFilePointer()); } - private static void writeSymbols(RandomAccessFile output, SymbolTable symbolTable) throws IOException { + private static void writeSymbols(BufferedFile output, SymbolTable symbolTable) throws IOException { List strings = symbolTable.getStrings(); for (int i = 0; i < strings.size(); ++i) { byte[] bytes = strings.get(i).getBytes(StandardCharsets.UTF_8); @@ -238,7 +240,7 @@ public final class HeapDumpConverter { } } - private static void writeStack(RandomAccessFile output, SymbolTable symbolTable) throws IOException { + private static void writeStack(BufferedFile output, SymbolTable symbolTable) throws IOException { for (int i = 0; i < symbolTable.stack.size(); ++i) { Frame frame = symbolTable.stack.get(i); output.write(4); @@ -271,7 +273,7 @@ public final class HeapDumpConverter { } } - private static void writeGcRoots(RandomAccessFile output, SymbolTable symbolTable) throws IOException { + private static void writeGcRoots(BufferedFile output, SymbolTable symbolTable) throws IOException { List stack = symbolTable.stack; for (int i = 0; i < stack.size(); i++) { Frame frame = stack.get(i); @@ -295,7 +297,7 @@ public final class HeapDumpConverter { } } - private static void writeHeapDump(Reader reader, RandomAccessFile output, SymbolTable symbolTable) + private static void writeHeapDump(Reader reader, BufferedFile output, SymbolTable symbolTable) throws IOException { for (ClassDescriptor classDescriptor : symbolTable.getClasses()) { if (classDescriptor.primitiveType != null) { @@ -330,7 +332,7 @@ public final class HeapDumpConverter { output.seek(pointerBackup); } - private static void writeClassObjects(RandomAccessFile output, SymbolTable symbolTable) throws IOException { + private static void writeClassObjects(BufferedFile output, SymbolTable symbolTable) throws IOException { Collection classes = symbolTable.getClasses(); for (ClassDescriptor cls : classes) { if (cls.primitiveType == null) { @@ -339,7 +341,7 @@ public final class HeapDumpConverter { } } - private static void writeClassDump(RandomAccessFile output, SymbolTable symbolTable, ClassDescriptor cls) + private static void writeClassDump(BufferedFile output, SymbolTable symbolTable, ClassDescriptor cls) throws IOException { output.write(0x20); writeId(output, cls.id); @@ -377,14 +379,14 @@ public final class HeapDumpConverter { } static class ObjectDumpVisitor extends JsonAllErrorVisitor { - private DataOutput output; + private BufferedFile output; private SymbolTable symbolTable; private JsonPropertyVisitor propertyVisitor = new JsonPropertyVisitor(true); private long id; private long classId; private byte[] data; - ObjectDumpVisitor(DataOutput output, SymbolTable symbolTable) { + ObjectDumpVisitor(BufferedFile output, SymbolTable symbolTable) { this.output = output; this.symbolTable = symbolTable; propertyVisitor.addProperty("id", idVisitor); @@ -437,7 +439,7 @@ public final class HeapDumpConverter { if (itemCls.primitiveType == null) { writeId(output, classId); } else { - output.writeByte(typeToInt(itemCls.primitiveType)); + output.write(typeToInt(itemCls.primitiveType)); } for (int i = 0; i < size; ++i) { int ptr = i * itemSize; @@ -869,11 +871,11 @@ public final class HeapDumpConverter { } } - private static void writeId(DataOutput out, long id) throws IOException { + private static void writeId(BufferedFile out, long id) throws IOException { writeLongBytes(out, id, idSize); } - private static void writeLongBytes(DataOutput out, long v, int size) throws IOException { + private static void writeLongBytes(BufferedFile out, long v, int size) throws IOException { for (int i = size - 1; i >= 0; --i) { buffer[i] = (byte) (v & 255); v >>>= 8;