Coverage Summary for Class: Memory (org.ethereum.vm.program)

Class Class, % Method, % Line, %
Memory 100% (1/1) 73.3% (11/15) 66% (62/94)


1 /* 2  * This file is part of RskJ 3  * Copyright (C) 2017 RSK Labs Ltd. 4  * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>) 5  * 6  * This program is free software: you can redistribute it and/or modify 7  * it under the terms of the GNU Lesser General Public License as published by 8  * the Free Software Foundation, either version 3 of the License, or 9  * (at your option) any later version. 10  * 11  * This program is distributed in the hope that it will be useful, 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14  * GNU Lesser General Public License for more details. 15  * 16  * You should have received a copy of the GNU Lesser General Public License 17  * along with this program. If not, see <http://www.gnu.org/licenses/>. 18  */ 19  20 package org.ethereum.vm.program; 21  22 import org.ethereum.vm.DataWord; 23 import org.ethereum.vm.program.listener.ProgramListener; 24 import org.ethereum.vm.program.listener.ProgramListenerAware; 25  26 import java.util.LinkedList; 27 import java.util.List; 28  29 import static java.lang.Math.ceil; 30 import static java.lang.Math.min; 31 import static java.lang.String.format; 32 import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY; 33 import static org.ethereum.util.ByteUtil.oneByteToHexString; 34  35 public class Memory implements ProgramListenerAware { 36  37  private static final int CHUNK_SIZE = 1024; 38  private static final int WORD_SIZE = 32; 39  40  private List<byte[]> chunks = new LinkedList<>(); 41  private int softSize; 42  private ProgramListener traceListener; 43  44  @Override 45  public void setTraceListener(ProgramListener traceListener) { 46  this.traceListener = traceListener; 47  } 48  49  public byte[] read(int address, int size) { 50  if (size <= 0) { 51  return EMPTY_BYTE_ARRAY; 52  } 53  54  extend(address, size); 55  byte[] data = new byte[size]; 56  57  int chunkIndex = address / CHUNK_SIZE; 58  int chunkOffset = address % CHUNK_SIZE; 59  60  int toGrab = data.length; 61  int start = 0; 62  63  while (toGrab > 0) { 64  int copied = grabMax(chunkIndex, chunkOffset, toGrab, data, start); 65  66  // read next chunk from the start 67  ++chunkIndex; 68  chunkOffset = 0; 69  70  // mark remind 71  toGrab -= copied; 72  start += copied; 73  } 74  75  return data; 76  } 77  78  public void write(int address, byte[] data, int dataSize, boolean limited) { 79  if (data.length < dataSize) { 80  dataSize = data.length; 81  } 82  83  if (!limited) { 84  extend(address, dataSize); 85  } 86  87  int chunkIndex = address / CHUNK_SIZE; 88  int chunkOffset = address % CHUNK_SIZE; 89  90  int toCapture = 0; 91  if (limited) { 92  toCapture = (address + dataSize > softSize) ? softSize - address : dataSize; 93  } else { 94  toCapture = dataSize; 95  } 96  97  int start = 0; 98  while (toCapture > 0) { 99  int captured = captureMax(chunkIndex, chunkOffset, toCapture, data, start); 100  101  // capture next chunk 102  ++chunkIndex; 103  chunkOffset = 0; 104  105  // mark remind 106  toCapture -= captured; 107  start += captured; 108  } 109  110  if (traceListener != null) { 111  traceListener.onMemoryWrite(address, data, dataSize); 112  } 113  } 114  115  116  public void extendAndWrite(int address, int allocSize, byte[] data) { 117  extend(address, allocSize); 118  write(address, data, data.length, false); 119  } 120  121  public void extend(int address, int size) { 122  if (size <= 0) { 123  return; 124  } 125  126  final int newSize = address + size; 127  128  int toAllocate = newSize - internalSize(); 129  if (toAllocate > 0) { 130  addChunks((int) ceil((double) toAllocate / CHUNK_SIZE)); 131  } 132  133  toAllocate = newSize - softSize; 134  if (toAllocate > 0) { 135  toAllocate = (int) ceil((double) toAllocate / WORD_SIZE) * WORD_SIZE; 136  softSize += toAllocate; 137  138  if (traceListener != null) { 139  traceListener.onMemoryExtend(toAllocate); 140  } 141  } 142  } 143  144  public DataWord readWord(int address) { 145  return DataWord.valueOf(read(address, 32)); 146  } 147  148  // just access expecting all data valid 149  public byte readByte(int address) { 150  151  int chunkIndex = address / CHUNK_SIZE; 152  int chunkOffset = address % CHUNK_SIZE; 153  154  byte[] chunk = chunks.get(chunkIndex); 155  156  return chunk[chunkOffset]; 157  } 158  159  @Override 160  public String toString() { 161  162  StringBuilder memoryData = new StringBuilder(); 163  StringBuilder firstLine = new StringBuilder(); 164  StringBuilder secondLine = new StringBuilder(); 165  166  for (int i = 0; i < softSize; ++i) { 167  168  byte value = readByte(i); 169  170  // Check if value is ASCII 171  String character = ((byte) 0x20 <= value && value <= (byte) 0x7e) ? new String(new byte[]{value}) : "?"; 172  firstLine.append(character).append(""); 173  secondLine.append(oneByteToHexString(value)).append(" "); 174  175  if ((i + 1) % 8 == 0) { 176  String tmp = format("%4s", Integer.toString(i - 7, 16)).replace(" ", "0"); 177  memoryData.append("").append(tmp).append(" "); 178  memoryData.append(firstLine).append(" "); 179  memoryData.append(secondLine); 180  if (i + 1 < softSize) { 181  memoryData.append("\n"); 182  } 183  firstLine.setLength(0); 184  secondLine.setLength(0); 185  } 186  } 187  188  return memoryData.toString(); 189  } 190  191  public int size() { 192  return softSize; 193  } 194  195  public int internalSize() { 196  return chunks.size() * CHUNK_SIZE; 197  } 198  199  public List<byte[]> getChunks() { 200  return new LinkedList<>(chunks); 201  } 202  203  private int captureMax(int chunkIndex, int chunkOffset, int size, byte[] src, int srcPos) { 204  205  byte[] chunk = chunks.get(chunkIndex); 206  int toCapture = min(size, chunk.length - chunkOffset); 207  208  System.arraycopy(src, srcPos, chunk, chunkOffset, toCapture); 209  return toCapture; 210  } 211  212  private int grabMax(int chunkIndex, int chunkOffset, int size, byte[] dest, int destPos) { 213  214  byte[] chunk = chunks.get(chunkIndex); 215  int toGrab = min(size, chunk.length - chunkOffset); 216  217  System.arraycopy(chunk, chunkOffset, dest, destPos, toGrab); 218  219  return toGrab; 220  } 221  222  private void addChunks(int num) { 223  for (int i = 0; i < num; ++i) { 224  chunks.add(new byte[CHUNK_SIZE]); 225  } 226  } 227 }