cache: add assembler and split scriptdumper test into disassembler/disassemblertest
This commit is contained in:
73
cache/src/test/java/net/runelite/cache/script/assembler/AssemblerTest.java
vendored
Normal file
73
cache/src/test/java/net/runelite/cache/script/assembler/AssemblerTest.java
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.cache.script.assembler;
|
||||
|
||||
import java.io.InputStream;
|
||||
import net.runelite.cache.definitions.ScriptDefinition;
|
||||
import net.runelite.cache.script.disassembler.Disassembler;
|
||||
import org.apache.commons.compress.utils.IOUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.Before;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.impl.SimpleLogger;
|
||||
|
||||
public class AssemblerTest
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(AssemblerTest.class);
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
{
|
||||
System.setProperty(SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "DEBUG");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssemble() throws Exception
|
||||
{
|
||||
InputStream in = AssemblerTest.class.getResourceAsStream("395.rs2asm");
|
||||
Assert.assertNotNull(in);
|
||||
|
||||
Assembler assembler = new Assembler();
|
||||
ScriptDefinition script = assembler.assemble(in);
|
||||
|
||||
// compare with disassembler
|
||||
Disassembler disassembler = new Disassembler();
|
||||
String out = disassembler.disassemble(script);
|
||||
|
||||
in = AssemblerTest.class.getResourceAsStream("395.rs2asm");
|
||||
Assert.assertNotNull(in);
|
||||
|
||||
String original = new String(IOUtils.toByteArray(in));
|
||||
|
||||
logger.debug(original);
|
||||
logger.debug("-----------------------");
|
||||
logger.debug(out);
|
||||
|
||||
Assert.assertEquals(original, out);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,29 +22,28 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.cache;
|
||||
package net.runelite.cache.script.disassembler;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import com.google.common.io.Files;
|
||||
import java.io.IOException;
|
||||
import net.runelite.cache.IndexType;
|
||||
import net.runelite.cache.StoreLocation;
|
||||
import net.runelite.cache.definitions.ScriptDefinition;
|
||||
import net.runelite.cache.definitions.loaders.ScriptLoader;
|
||||
import net.runelite.cache.fs.Archive;
|
||||
import net.runelite.cache.fs.File;
|
||||
import net.runelite.cache.fs.Index;
|
||||
import net.runelite.cache.fs.Store;
|
||||
import net.runelite.cache.script.Instruction;
|
||||
import net.runelite.cache.script.Instructions;
|
||||
import net.runelite.cache.script.Opcodes;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ScriptDumperTest
|
||||
public class DisassemblerTest
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(ScriptDumperTest.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(DisassemblerTest.class);
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder folder = StoreLocation.getTemporaryFolder();
|
||||
@@ -74,7 +73,11 @@ public class ScriptDumperTest
|
||||
ScriptDefinition script = loader.load(file.getFileId(), contents);
|
||||
|
||||
java.io.File outFile = new java.io.File(outDir, archive.getArchiveId() + ".rs2asm");
|
||||
writeScript(outFile, script);
|
||||
|
||||
Disassembler disassembler = new Disassembler();
|
||||
String out = disassembler.disassemble(script);
|
||||
|
||||
Files.write(out.getBytes(), outFile);
|
||||
|
||||
++count;
|
||||
}
|
||||
@@ -82,112 +85,4 @@ public class ScriptDumperTest
|
||||
|
||||
logger.info("Dumped {} scripts to {}", count, outDir);
|
||||
}
|
||||
|
||||
private boolean isJump(int opcode)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case Opcodes.JUMP:
|
||||
case Opcodes.IF_ICMPEQ:
|
||||
case Opcodes.IF_ICMPGE:
|
||||
case Opcodes.IF_ICMPGT:
|
||||
case Opcodes.IF_ICMPLE:
|
||||
case Opcodes.IF_ICMPLT:
|
||||
case Opcodes.IF_ICMPNE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean[] needLabel(ScriptDefinition script)
|
||||
{
|
||||
int[] instructions = script.getInstructions();
|
||||
int[] iop = script.getIntOperands();
|
||||
boolean[] jumped = new boolean[instructions.length];
|
||||
|
||||
for (int i = 0; i < instructions.length; ++i)
|
||||
{
|
||||
int opcode = instructions[i];
|
||||
|
||||
if (!isJump(opcode))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// + 1 because the jumps go to the instructions prior to the
|
||||
// one you really want, because the pc is incremented on the
|
||||
// next loop
|
||||
int to = i + iop[i] + 1;
|
||||
assert to >= 0 && to < instructions.length;
|
||||
|
||||
jumped[to] = true;
|
||||
}
|
||||
|
||||
return jumped;
|
||||
}
|
||||
|
||||
private void writeScript(java.io.File file, ScriptDefinition script) throws IOException
|
||||
{
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file)))
|
||||
{
|
||||
int[] instructions = script.getInstructions();
|
||||
int[] iops = script.getIntOperands();
|
||||
String[] sops = script.getStringOperands();
|
||||
|
||||
assert iops.length == instructions.length;
|
||||
assert sops.length == instructions.length;
|
||||
|
||||
boolean[] jumps = needLabel(script);
|
||||
|
||||
for (int i = 0; i < instructions.length; ++i)
|
||||
{
|
||||
int opcode = instructions[i];
|
||||
int iop = iops[i];
|
||||
String sop = sops[i];
|
||||
|
||||
Instruction ins = Instructions.find(opcode);
|
||||
if (ins == null)
|
||||
{
|
||||
logger.warn("Unknown instruction {} in script {}", opcode, script.getId());
|
||||
}
|
||||
|
||||
String name;
|
||||
if (ins != null && ins.getName() != null)
|
||||
{
|
||||
name = ins.getName();
|
||||
}
|
||||
else
|
||||
{
|
||||
name = String.format("%03d", opcode);
|
||||
}
|
||||
|
||||
if (jumps[i])
|
||||
{
|
||||
// something jumps here
|
||||
writer.write("LABEL" + i + ":\n");
|
||||
}
|
||||
|
||||
writer.write(String.format(" %-22s", name));
|
||||
|
||||
if (iop != 0 || opcode == Opcodes.LOAD_INT)
|
||||
{
|
||||
if (isJump(opcode))
|
||||
{
|
||||
writer.write(" LABEL" + (i + iop + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.write(" " + iop);
|
||||
}
|
||||
}
|
||||
|
||||
if (sop != null)
|
||||
{
|
||||
writer.write(" \"" + sop + "\"");
|
||||
}
|
||||
writer.write("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
99
cache/src/test/resources/net/runelite/cache/script/assembler/395.rs2asm
vendored
Normal file
99
cache/src/test/resources/net/runelite/cache/script/assembler/395.rs2asm
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
033
|
||||
get_boostedskilllevels
|
||||
int_to_string
|
||||
1112
|
||||
033
|
||||
get_realskilllevels
|
||||
034 3
|
||||
033 3
|
||||
int_to_string
|
||||
1112 1
|
||||
033
|
||||
get_skillexperiences
|
||||
034 4
|
||||
load_string ","
|
||||
036 1
|
||||
035
|
||||
load_string " XP:"
|
||||
037 2
|
||||
036 2
|
||||
033 4
|
||||
035 1
|
||||
040 46
|
||||
036 3
|
||||
load_int 0
|
||||
034 5
|
||||
025 4181
|
||||
load_int 0
|
||||
if_icmpeq LABEL29
|
||||
jump LABEL60
|
||||
LABEL29:
|
||||
033 3
|
||||
load_int 99
|
||||
if_icmplt LABEL33
|
||||
jump LABEL59
|
||||
LABEL33:
|
||||
load_int 105
|
||||
load_int 105
|
||||
load_int 256
|
||||
033 3
|
||||
load_int 1
|
||||
iadd
|
||||
3408
|
||||
034 5
|
||||
035 2
|
||||
load_string "|Next level at:|Remaining XP:"
|
||||
concat_string
|
||||
036 2
|
||||
035 3
|
||||
load_string "|"
|
||||
033 5
|
||||
035 1
|
||||
040 46
|
||||
load_string "|"
|
||||
033 5
|
||||
033 4
|
||||
isub
|
||||
035 1
|
||||
040 46
|
||||
037 4
|
||||
concat_string
|
||||
036 3
|
||||
LABEL59:
|
||||
jump LABEL78
|
||||
LABEL60:
|
||||
035 2
|
||||
load_string "|Next level at:"
|
||||
concat_string
|
||||
036 2
|
||||
035 3
|
||||
load_string "|"
|
||||
load_int 105
|
||||
load_int 105
|
||||
load_int 256
|
||||
033 3
|
||||
load_int 1
|
||||
iadd
|
||||
3408
|
||||
035 1
|
||||
040 46
|
||||
037 2
|
||||
concat_string
|
||||
036 3
|
||||
LABEL78:
|
||||
load_int 992
|
||||
load_int -2147483645
|
||||
load_int -1
|
||||
033 2
|
||||
035 2
|
||||
035 3
|
||||
load_int 495
|
||||
load_int 25
|
||||
load_int 5
|
||||
idiv
|
||||
load_string "IiIssfi"
|
||||
033 1
|
||||
2412
|
||||
load_int 0
|
||||
043 2
|
||||
return
|
||||
Reference in New Issue
Block a user