Skip to content

Commit

Permalink
Remove LocalVariableTable attributes while processing classes. Fixes #12
Browse files Browse the repository at this point in the history
.
  • Loading branch information
caseif committed Feb 27, 2016
1 parent 6f455f4 commit ff9eba9
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
import static blue.lapis.nocturne.util.Constants.CLASS_FORMAT_CONSTANT_POOL_OFFSET;
import static blue.lapis.nocturne.util.Constants.CLASS_PATH_SEPARATOR_CHAR;
import static blue.lapis.nocturne.util.Constants.MEMBER_PREFIX;
import static blue.lapis.nocturne.util.helper.ByteHelper.asUint;
import static blue.lapis.nocturne.util.helper.ByteHelper.asUshort;
import static blue.lapis.nocturne.util.helper.ByteHelper.getBytes;
import static blue.lapis.nocturne.util.helper.ByteHelper.readBytes;
import static blue.lapis.nocturne.util.helper.StringHelper.getProcessedDescriptor;
import static blue.lapis.nocturne.util.helper.StringHelper.getProcessedName;
import static blue.lapis.nocturne.util.helper.StringHelper.getUnprocessedName;
Expand All @@ -48,12 +48,12 @@
import blue.lapis.nocturne.processor.constantpool.model.structure.Utf8Structure;
import blue.lapis.nocturne.processor.index.model.IndexedClass;
import blue.lapis.nocturne.util.MemberType;
import blue.lapis.nocturne.util.tuple.Pair;

import com.google.common.collect.ImmutableList;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
Expand All @@ -80,7 +80,9 @@ public class ClassTransformer extends ClassProcessor {
private final Map<Integer, Integer> processedMethodNameMap = new HashMap<>();
private final Map<Integer, Integer> processedMethodDescriptorMap = new HashMap<>();

private static final ImmutableList<String> IGNORED_METHODS = new ImmutableList.Builder<String>()
private static final ImmutableList<String> STUPID_PARAM_NAMES = ImmutableList.<String>builder()

This comment has been minimized.

Copy link
@PizzaCrust

PizzaCrust Feb 28, 2016

STUPID_PARAM_NAMES? -

This comment has been minimized.

Copy link
@caseif

caseif Feb 28, 2016

Author Member

Lol yeah, it's not actually used right now but I plan to use it in the new system planned for 1.1.

.add("\u2603").build();
private static final ImmutableList<String> IGNORED_METHODS = ImmutableList.<String>builder()
.add("<init>").add("<clinit>").build();

public ClassTransformer(String className, byte[] bytes) {
Expand Down Expand Up @@ -198,27 +200,14 @@ public byte[] processMemberBytes(ByteBuffer buffer, boolean isMethod) throws IOE
ByteArrayOutputStream attrOs = new ByteArrayOutputStream();
int attrCount = asUshort(buffer.getShort());
attrOs.write(getBytes((short) attrCount));
for (int i = 0; i < attrCount; i++) {
int attrNameIndex = asUshort(buffer.getShort());
attrOs.write(getBytes((short) attrNameIndex));
if (!isSynthetic) {
String attrName = getString(attrNameIndex);
if (attrName.equals("Synthetic")) {
isSynthetic = true;
}
}

long attrLength = asUint(buffer.getInt());
attrOs.write(getBytes((int) attrLength));
for (int j = 0; j < attrLength; j++) {
try {
attrOs.write(buffer.get());
} catch (BufferUnderflowException ex) {
System.err.println("Class: " + getClassName() + " - m: " + m);
throw ex;
}
}
for (int i = 0; i < attrCount; i++) {
Pair<byte[], Boolean> attr = processAttribute(buffer);
attrOs.write(attr.first());
isSynthetic = attr.second();
}
final byte[] attrArr = attrOs.toByteArray();
final int memberEnd = buffer.position();

buffer.position(memberStart + 2);

Expand Down Expand Up @@ -264,9 +253,8 @@ public byte[] processMemberBytes(ByteBuffer buffer, boolean isMethod) throws IOE
}
os.write(getBytes((short) descriptorIndex));

byte[] attrArr = attrOs.toByteArray();
os.write(attrArr);
buffer.position(buffer.position() + attrArr.length);
buffer.position(memberEnd);
}

return os.toByteArray();
Expand Down Expand Up @@ -400,6 +388,75 @@ private void handleNonClassMember(ConstantStructure cs, ConstantPool pool) {
pool.set(natIndex, new NameAndTypeStructure(buffer.array()));
}

private Pair<byte[], Boolean> processAttribute(ByteBuffer buffer) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
boolean isSynthetic = false;

int attrNameIndex = asUshort(buffer.getShort());
os.write(getBytes((short) attrNameIndex));
String attrName = getString(attrNameIndex);

int attrLength = buffer.getInt();

switch (attrName) {
case "Code": {
// note: we're now at max_stack
ByteArrayOutputStream bufferOs = new ByteArrayOutputStream();
bufferOs.write(readBytes(buffer, 4)); // skip max_stack and max_locals

// skip the actual code (also unimportant to us)
int codeLength = buffer.getInt(); // read code_length
bufferOs.write(getBytes(codeLength));
bufferOs.write(readBytes(buffer, codeLength)); // read code

// skip the exception table
int exceptionTableLength = asUshort(buffer.getShort()); // read exception_table_length
bufferOs.write(getBytes((short) exceptionTableLength));
bufferOs.write(readBytes(buffer, exceptionTableLength * 8)); // exception_table (each entry is 8 bytes)

// now we get to the good stuff
// note: we're now at attribute_count
ByteArrayOutputStream subOs = new ByteArrayOutputStream(); // since the length can change
int attrCount = asUshort(buffer.getShort()); // read attributes_count
int actualAttrCount = 0;
for (int a = 0; a < attrCount; a++) {
// now we're in a sub-attribute
int subAttrNameIndex = asUshort(buffer.getShort()); // read attribute_name_index
String subAttrName = getString(subAttrNameIndex);
int subAttrLength = buffer.getInt(); // read attribute_length

if (subAttrName.equals("LocalVariableTable")) {
attrLength -= subAttrLength + 6;
readBytes(buffer, subAttrLength); // read and discard attribute body
} else {
actualAttrCount++;
subOs.write(getBytes((short) subAttrNameIndex)); // write attribute_name_index
subOs.write(getBytes(subAttrLength)); // write attribute_length
subOs.write(readBytes(buffer, subAttrLength)); // read and write attribute body
}
}

bufferOs.write(getBytes((short) actualAttrCount));
bufferOs.write(subOs.toByteArray());

os.write(getBytes(attrLength));
os.write(bufferOs.toByteArray());

break;
}
case "Synthetic": {
isSynthetic = true;
}
default: {
os.write(getBytes(attrLength));
os.write(readBytes(buffer, attrLength));
break;
}
}

return new Pair<>(os.toByteArray(), isSynthetic);
}

private NameAndType getNameAndType(RefStructure rs) {
int natStructIndex = rs.getNameAndTypeIndex();
assert natStructIndex <= constantPool.size();
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/blue/lapis/nocturne/util/helper/ByteHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,10 @@ public static byte[] getBytes(int i) {
return ByteBuffer.allocate(Integer.BYTES).putInt(i).array();
}

public static byte[] readBytes(ByteBuffer src, int toRead) {
byte[] arr = new byte[toRead];
src.get(arr);
return ByteBuffer.allocate(toRead).put(arr).array();
}

}
49 changes: 49 additions & 0 deletions src/main/java/blue/lapis/nocturne/util/tuple/Pair.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Nocturne
* Copyright (c) 2015-2016, Lapis <https://github.com/LapisBlue>
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package blue.lapis.nocturne.util.tuple;

/**
* Represents a pair of objects.
*/
public class Pair<A, B> {

private final A first;
private final B second;

public Pair(A first, B second) {
this.first = first;
this.second = second;
}

public A first() {
return first;
}

public B second() {
return second;
}

}

0 comments on commit ff9eba9

Please sign in to comment.