aboutsummaryrefslogtreecommitdiff
path: root/smali
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2015-02-18 17:38:30 -0800
committerIgor Murashkin <iam@google.com>2015-03-16 11:40:58 -0700
commit144951a9e9e6c87866245f2bdeebf0ebedaa0e38 (patch)
treebdbc5c4f2ad3ea320798ade74888490123c30ad5 /smali
parentf70084bdfeba10dfb68c2c63eb1bedd4e42b4b0f (diff)
downloadsmali-144951a9e9e6c87866245f2bdeebf0ebedaa0e38.tar.gz
Add lambda experimental dalvik opcodes
* Add new -X/--experimental flag to [dis]assemble opcodes not in art yet * Add new opcodes liberate-variable, box-lambda, unbox-lambda, capture-variable, create-lambda, invoke-lambda * Add support for encoding 25x instructions * Adds LambdaTest to check new opcodes assemble/disassemble properly TODO: invoke-lambda-range Change-Id: I5c8bcbfa8b6cb9a13ef2017fce2d1b7fda6e11c3
Diffstat (limited to 'smali')
-rw-r--r--smali/src/main/antlr/smaliParser.g42
-rw-r--r--smali/src/main/antlr/smaliTreeWalker.g79
-rw-r--r--smali/src/main/java/org/jf/smali/SmaliTestUtils.java14
-rw-r--r--smali/src/main/java/org/jf/smali/main.java29
-rw-r--r--smali/src/main/jflex/smaliLexer.jflex19
-rw-r--r--smali/src/test/resources/LexerTest/InstructionTest.smali6
-rw-r--r--smali/src/test/resources/LexerTest/InstructionTest.tokens6
7 files changed, 180 insertions, 15 deletions
diff --git a/smali/src/main/antlr/smaliParser.g b/smali/src/main/antlr/smaliParser.g
index d057b4a4..6d07452c 100644
--- a/smali/src/main/antlr/smaliParser.g
+++ b/smali/src/main/antlr/smaliParser.g
@@ -86,6 +86,8 @@ tokens {
INSTRUCTION_FORMAT21c_FIELD_ODEX;
INSTRUCTION_FORMAT21c_STRING;
INSTRUCTION_FORMAT21c_TYPE;
+ INSTRUCTION_FORMAT21c_LAMBDA;
+ INSTRUCTION_FORMAT21c_METHOD;
INSTRUCTION_FORMAT21ih;
INSTRUCTION_FORMAT21lh;
INSTRUCTION_FORMAT21s;
@@ -94,12 +96,14 @@ tokens {
INSTRUCTION_FORMAT22c_FIELD;
INSTRUCTION_FORMAT22c_FIELD_ODEX;
INSTRUCTION_FORMAT22c_TYPE;
+ INSTRUCTION_FORMAT22c_STRING;
INSTRUCTION_FORMAT22cs_FIELD;
INSTRUCTION_FORMAT22s;
INSTRUCTION_FORMAT22s_OR_ID;
INSTRUCTION_FORMAT22t;
INSTRUCTION_FORMAT22x;
INSTRUCTION_FORMAT23x;
+ INSTRUCTION_FORMAT25x;
INSTRUCTION_FORMAT30t;
INSTRUCTION_FORMAT31c;
INSTRUCTION_FORMAT31i;
@@ -209,6 +213,8 @@ tokens {
I_STATEMENT_FORMAT21c_TYPE;
I_STATEMENT_FORMAT21c_FIELD;
I_STATEMENT_FORMAT21c_STRING;
+ I_STATEMENT_FORMAT21c_LAMBDA;
+ I_STATEMENT_FORMAT21c_METHOD;
I_STATEMENT_FORMAT21ih;
I_STATEMENT_FORMAT21lh;
I_STATEMENT_FORMAT21s;
@@ -216,10 +222,12 @@ tokens {
I_STATEMENT_FORMAT22b;
I_STATEMENT_FORMAT22c_FIELD;
I_STATEMENT_FORMAT22c_TYPE;
+ I_STATEMENT_FORMAT22c_STRING;
I_STATEMENT_FORMAT22s;
I_STATEMENT_FORMAT22t;
I_STATEMENT_FORMAT22x;
I_STATEMENT_FORMAT23x;
+ I_STATEMENT_FORMAT25x;
I_STATEMENT_FORMAT30t;
I_STATEMENT_FORMAT31c;
I_STATEMENT_FORMAT31i;
@@ -252,7 +260,7 @@ import org.jf.dexlib2.Opcodes;
private boolean verboseErrors = false;
private boolean allowOdex = false;
private int apiLevel = 15;
- private Opcodes opcodes = new Opcodes(apiLevel);
+ private Opcodes opcodes = new Opcodes(apiLevel, false);
public void setVerboseErrors(boolean verboseErrors) {
this.verboseErrors = verboseErrors;
@@ -262,8 +270,8 @@ import org.jf.dexlib2.Opcodes;
this.allowOdex = allowOdex;
}
- public void setApiLevel(int apiLevel) {
- this.opcodes = new Opcodes(apiLevel);
+ public void setApiLevel(int apiLevel, boolean experimental) {
+ this.opcodes = new Opcodes(apiLevel, experimental);
this.apiLevel = apiLevel;
}
@@ -561,14 +569,18 @@ simple_name
| INSTRUCTION_FORMAT21c_FIELD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_FIELD_ODEX]
| INSTRUCTION_FORMAT21c_STRING -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_STRING]
| INSTRUCTION_FORMAT21c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_TYPE]
+ | INSTRUCTION_FORMAT21c_LAMBDA -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_LAMBDA]
+ | INSTRUCTION_FORMAT21c_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_METHOD]
| INSTRUCTION_FORMAT21t -> SIMPLE_NAME[$INSTRUCTION_FORMAT21t]
| INSTRUCTION_FORMAT22c_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_FIELD]
| INSTRUCTION_FORMAT22c_FIELD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_FIELD_ODEX]
| INSTRUCTION_FORMAT22c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_TYPE]
+ | INSTRUCTION_FORMAT22c_STRING -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_STRING]
| INSTRUCTION_FORMAT22cs_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT22cs_FIELD]
| INSTRUCTION_FORMAT22s_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT22s_OR_ID]
| INSTRUCTION_FORMAT22t -> SIMPLE_NAME[$INSTRUCTION_FORMAT22t]
| INSTRUCTION_FORMAT23x -> SIMPLE_NAME[$INSTRUCTION_FORMAT23x]
+ | INSTRUCTION_FORMAT25x -> SIMPLE_NAME[$INSTRUCTION_FORMAT25x]
| INSTRUCTION_FORMAT31i_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT31i_OR_ID]
| INSTRUCTION_FORMAT31t -> SIMPLE_NAME[$INSTRUCTION_FORMAT31t]
| INSTRUCTION_FORMAT35c_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_METHOD]
@@ -806,6 +818,8 @@ instruction
| insn_format21c_field_odex
| insn_format21c_string
| insn_format21c_type
+ | insn_format21c_lambda
+ | insn_format21c_method
| insn_format21ih
| insn_format21lh
| insn_format21s
@@ -814,11 +828,13 @@ instruction
| insn_format22c_field
| insn_format22c_field_odex
| insn_format22c_type
+ | insn_format22c_string
| insn_format22cs_field
| insn_format22s
| insn_format22t
| insn_format22x
| insn_format23x
+ | insn_format25x
| insn_format30t
| insn_format31c
| insn_format31i
@@ -912,6 +928,16 @@ insn_format21c_type
INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA nonvoid_type_descriptor
-> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER nonvoid_type_descriptor);
+insn_format21c_lambda
+ : //e.g. capture-variable v1, "foobar"
+ INSTRUCTION_FORMAT21c_LAMBDA REGISTER COMMA STRING_LITERAL
+ -> ^(I_STATEMENT_FORMAT21c_LAMBDA[$start, "I_STATEMENT_FORMAT21c_LAMBDA"] INSTRUCTION_FORMAT21c_LAMBDA REGISTER STRING_LITERAL);
+
+insn_format21c_method
+ : //e.g. create-lambda v1, java/io/PrintStream/print(Ljava/lang/Stream;)V
+ INSTRUCTION_FORMAT21c_METHOD REGISTER COMMA method_reference
+ -> ^(I_STATEMENT_FORMAT21c_METHOD[$start, "I_STATEMENT_FORMAT21c_METHOD"] INSTRUCTION_FORMAT21c_METHOD REGISTER method_reference);
+
insn_format21ih
: //e.g. const/high16 v1, 1234
INSTRUCTION_FORMAT21ih REGISTER COMMA fixed_32bit_literal
@@ -957,6 +983,11 @@ insn_format22c_type
INSTRUCTION_FORMAT22c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor
-> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor);
+insn_format22c_string
+ : //e.g. liberate-variable v0, v1, "baz"
+ INSTRUCTION_FORMAT22c_STRING REGISTER COMMA REGISTER COMMA STRING_LITERAL
+ -> ^(I_STATEMENT_FORMAT22c_STRING[$start, "I_STATEMENT_FORMAT22c_STRING"] INSTRUCTION_FORMAT22c_STRING REGISTER REGISTER STRING_LITERAL);
+
insn_format22cs_field
: //e.g. iget-quick v0, v1, field@0xc
INSTRUCTION_FORMAT22cs_FIELD REGISTER COMMA REGISTER COMMA FIELD_OFFSET
@@ -984,6 +1015,11 @@ insn_format23x
INSTRUCTION_FORMAT23x REGISTER COMMA REGISTER COMMA REGISTER
-> ^(I_STATEMENT_FORMAT23x[$start, "I_STATEMENT_FORMAT23x"] INSTRUCTION_FORMAT23x REGISTER REGISTER REGISTER);
+insn_format25x
+ : //e.g. invoke-lambda vClosure, {vA, vB, vC, vD} -- up to 4 parameters + the closure.
+ INSTRUCTION_FORMAT25x REGISTER COMMA OPEN_BRACE register_list CLOSE_BRACE
+ -> ^(I_STATEMENT_FORMAT25x[$start, "I_STATEMENT_FORMAT25x"] INSTRUCTION_FORMAT25x REGISTER register_list);
+
insn_format30t
: //e.g. goto/32 endloop:
INSTRUCTION_FORMAT30t label_ref
diff --git a/smali/src/main/antlr/smaliTreeWalker.g b/smali/src/main/antlr/smaliTreeWalker.g
index f49f10ef..d319b2ca 100644
--- a/smali/src/main/antlr/smaliTreeWalker.g
+++ b/smali/src/main/antlr/smaliTreeWalker.g
@@ -77,15 +77,15 @@ import java.util.*;
public String classType;
private boolean verboseErrors = false;
private int apiLevel = 15;
- private Opcodes opcodes = new Opcodes(apiLevel);
+ private Opcodes opcodes = new Opcodes(apiLevel, false);
private DexBuilder dexBuilder;
public void setDexBuilder(DexBuilder dexBuilder) {
this.dexBuilder = dexBuilder;
}
- public void setApiLevel(int apiLevel) {
- this.opcodes = new Opcodes(apiLevel);
+ public void setApiLevel(int apiLevel, boolean experimental) {
+ this.opcodes = new Opcodes(apiLevel, experimental);
this.apiLevel = apiLevel;
}
@@ -674,6 +674,22 @@ register_list returns[byte[\] registers, byte registerCount]
$registers[$registerCount++] = parseRegister_nibble($REGISTER.text);
})*);
+register_list4 returns[byte[\] registers, byte registerCount]
+ @init
+ {
+ $registers = new byte[4];
+ $registerCount = 0;
+ }
+ : ^(I_REGISTER_LIST
+ (REGISTER
+ {
+ if ($registerCount == 4) {
+ throw new SemanticException(input, $I_REGISTER_LIST, "A list4 of registers can only have a maximum of 4 " +
+ "registers. Use the <op>/range alternate opcode instead.");
+ }
+ $registers[$registerCount++] = parseRegister_nibble($REGISTER.text);
+ })*);
+
register_range returns[int startRegister, int endRegister]
: ^(I_REGISTER_RANGE (startReg=REGISTER endReg=REGISTER?)?)
{
@@ -726,6 +742,8 @@ instruction
| insn_format21c_field
| insn_format21c_string
| insn_format21c_type
+ | insn_format21c_lambda
+ | insn_format21c_method
| insn_format21ih
| insn_format21lh
| insn_format21s
@@ -733,10 +751,12 @@ instruction
| insn_format22b
| insn_format22c_field
| insn_format22c_type
+ | insn_format22c_string
| insn_format22s
| insn_format22t
| insn_format22x
| insn_format23x
+ | insn_format25x
| insn_format30t
| insn_format31c
| insn_format31i
@@ -861,6 +881,30 @@ insn_format21c_type
dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
};
+insn_format21c_lambda
+ : //e.g. capture-variable v1, "foobar"
+ ^(I_STATEMENT_FORMAT21c_LAMBDA INSTRUCTION_FORMAT21c_LAMBDA REGISTER string_literal)
+ {
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_LAMBDA.text);
+ short regA = parseRegister_byte($REGISTER.text);
+
+ $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
+ dexBuilder.internStringReference($string_literal.value)));
+ };
+
+insn_format21c_method
+ : //e.g. create-lambda v1, java/io/PrintStream/print(Ljava/lang/Stream;)V
+ ^(I_STATEMENT_FORMAT21c_METHOD INSTRUCTION_FORMAT21c_METHOD REGISTER method_reference)
+ {
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_METHOD.text);
+ short regA = parseRegister_byte($REGISTER.text);
+
+ ImmutableMethodReference methodReference = $method_reference.methodReference;
+
+ $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
+ dexBuilder.internMethodReference(methodReference)));
+ };
+
insn_format21ih
: //e.g. const/high16 v1, 1234
^(I_STATEMENT_FORMAT21ih INSTRUCTION_FORMAT21ih REGISTER fixed_32bit_literal)
@@ -947,6 +991,18 @@ insn_format22c_type
dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
};
+insn_format22c_string
+ : //e.g. liberate-variable v0, v1, "baz"
+ ^(I_STATEMENT_FORMAT22c_STRING INSTRUCTION_FORMAT22c_STRING registerA=REGISTER registerB=REGISTER string_literal)
+ {
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22c_STRING.text);
+ byte regA = parseRegister_nibble($registerA.text);
+ byte regB = parseRegister_nibble($registerB.text);
+
+ $method::methodBuilder.addInstruction(new BuilderInstruction22c(opcode, regA, regB,
+ dexBuilder.internStringReference($string_literal.value)));
+ };
+
insn_format22s
: //e.g. add-int/lit16 v0, v1, 12345
^(I_STATEMENT_FORMAT22s INSTRUCTION_FORMAT22s registerA=REGISTER registerB=REGISTER short_integral_literal)
@@ -994,6 +1050,23 @@ insn_format23x
$method::methodBuilder.addInstruction(new BuilderInstruction23x(opcode, regA, regB, regC));
};
+insn_format25x
+ : //e.g. invoke-lambda vClosure, {vD, vE, vF, vG} -- up to 4 parameters + the closure.
+ ^(I_STATEMENT_FORMAT25x INSTRUCTION_FORMAT25x REGISTER register_list4)
+ {
+ Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT25x.text);
+
+ byte closureRegister = parseRegister_nibble($REGISTER.text);
+
+ //this depends on the fact that register_list4 returns a byte[4]
+ byte[] registers = $register_list4.registers;
+ int parameterRegisterCount = $register_list4.registerCount; // don't count closure register
+
+ $method::methodBuilder.addInstruction(new BuilderInstruction25x(opcode,
+ parameterRegisterCount, closureRegister, registers[0], registers[1],
+ registers[2], registers[3]));
+ };
+
insn_format30t
: //e.g. goto/32 endloop:
^(I_STATEMENT_FORMAT30t INSTRUCTION_FORMAT30t label_ref)
diff --git a/smali/src/main/java/org/jf/smali/SmaliTestUtils.java b/smali/src/main/java/org/jf/smali/SmaliTestUtils.java
index 9fd73473..26de0089 100644
--- a/smali/src/main/java/org/jf/smali/SmaliTestUtils.java
+++ b/smali/src/main/java/org/jf/smali/SmaliTestUtils.java
@@ -48,10 +48,16 @@ import java.io.Reader;
import java.io.StringReader;
public class SmaliTestUtils {
+
public static ClassDef compileSmali(String smaliText) throws RecognitionException, IOException {
+ return compileSmali(smaliText, 15, false);
+ }
+
+ public static ClassDef compileSmali(String smaliText, int apiLevel, boolean experimental)
+ throws RecognitionException, IOException {
CommonTokenStream tokens;
LexerErrorInterface lexer;
- DexBuilder dexBuilder = DexBuilder.makeDexBuilder(15);
+ DexBuilder dexBuilder = DexBuilder.makeDexBuilder(apiLevel);
Reader reader = new StringReader(smaliText);
@@ -61,7 +67,7 @@ public class SmaliTestUtils {
smaliParser parser = new smaliParser(tokens);
parser.setVerboseErrors(true);
parser.setAllowOdex(false);
- parser.setApiLevel(15);
+ parser.setApiLevel(apiLevel, experimental);
smaliParser.smali_file_return result = parser.smali_file();
@@ -75,6 +81,7 @@ public class SmaliTestUtils {
treeStream.setTokenStream(tokens);
smaliTreeWalker dexGen = new smaliTreeWalker(treeStream);
+ dexGen.setApiLevel(apiLevel, experimental);
dexGen.setVerboseErrors(true);
dexGen.setDexBuilder(dexBuilder);
dexGen.smali_file();
@@ -87,7 +94,8 @@ public class SmaliTestUtils {
dexBuilder.writeTo(dataStore);
- DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15), dataStore.getData());
+ DexBackedDexFile dexFile = new DexBackedDexFile(
+ new Opcodes(apiLevel, experimental), dataStore.getData());
return Iterables.getFirst(dexFile.getClasses(), null);
}
diff --git a/smali/src/main/java/org/jf/smali/main.java b/smali/src/main/java/org/jf/smali/main.java
index c6095bf3..31f65a88 100644
--- a/smali/src/main/java/org/jf/smali/main.java
+++ b/smali/src/main/java/org/jf/smali/main.java
@@ -34,6 +34,7 @@ import org.antlr.runtime.Token;
import org.antlr.runtime.TokenSource;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
+import org.antlr.runtime.tree.TreeNodeStream;
import org.apache.commons.cli.*;
import org.jf.dexlib2.writer.builder.DexBuilder;
import org.jf.dexlib2.writer.io.FileDataStore;
@@ -110,6 +111,7 @@ public class main {
boolean allowOdex = false;
boolean verboseErrors = false;
boolean printTokens = false;
+ boolean experimental = false;
int apiLevel = 15;
@@ -142,6 +144,9 @@ public class main {
case 'x':
allowOdex = true;
break;
+ case 'X':
+ experimental = true;
+ break;
case 'a':
apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
break;
@@ -198,11 +203,12 @@ public class main {
final boolean finalPrintTokens = printTokens;
final boolean finalAllowOdex = allowOdex;
final int finalApiLevel = apiLevel;
+ final boolean finalExperimental = experimental;
for (final File file: filesToProcess) {
tasks.add(executor.submit(new Callable<Boolean>() {
@Override public Boolean call() throws Exception {
return assembleSmaliFile(file, dexBuilder, finalVerboseErrors, finalPrintTokens,
- finalAllowOdex, finalApiLevel);
+ finalAllowOdex, finalApiLevel, finalExperimental);
}
}));
}
@@ -252,7 +258,8 @@ public class main {
}
private static boolean assembleSmaliFile(File smaliFile, DexBuilder dexBuilder, boolean verboseErrors,
- boolean printTokens, boolean allowOdex, int apiLevel)
+ boolean printTokens, boolean allowOdex, int apiLevel,
+ boolean experimental)
throws Exception {
CommonTokenStream tokens;
@@ -267,7 +274,7 @@ public class main {
if (printTokens) {
tokens.getTokens();
-
+
for (int i=0; i<tokens.size(); i++) {
Token token = tokens.get(i);
if (token.getChannel() == smaliParser.HIDDEN) {
@@ -276,12 +283,14 @@ public class main {
System.out.println(smaliParser.tokenNames[token.getType()] + ": " + token.getText());
}
+
+ System.out.flush();
}
smaliParser parser = new smaliParser(tokens);
parser.setVerboseErrors(verboseErrors);
parser.setAllowOdex(allowOdex);
- parser.setApiLevel(apiLevel);
+ parser.setApiLevel(apiLevel, experimental);
smaliParser.smali_file_return result = parser.smali_file();
@@ -294,7 +303,13 @@ public class main {
CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);
treeStream.setTokenStream(tokens);
+ if (printTokens) {
+ System.out.println(t.toStringTree());
+ }
+
smaliTreeWalker dexGen = new smaliTreeWalker(treeStream);
+ dexGen.setApiLevel(apiLevel, experimental);
+
dexGen.setVerboseErrors(verboseErrors);
dexGen.setDexBuilder(dexBuilder);
dexGen.smali_file();
@@ -363,6 +378,11 @@ public class main {
.withArgName("API_LEVEL")
.create("a");
+ Option experimentalOption = OptionBuilder.withLongOpt("experimental")
+ .withDescription("enable experimental opcodes to be assembled, even if they " +
+ " aren't necessarily supported by the Android runtime yet")
+ .create("X");
+
Option jobsOption = OptionBuilder.withLongOpt("jobs")
.withDescription("The number of threads to use. Defaults to the number of cores available, up to a " +
"maximum of 6")
@@ -383,6 +403,7 @@ public class main {
basicOptions.addOption(outputOption);
basicOptions.addOption(allowOdexOption);
basicOptions.addOption(apiLevelOption);
+ basicOptions.addOption(experimentalOption);
basicOptions.addOption(jobsOption);
debugOptions.addOption(verboseErrorsOption);
diff --git a/smali/src/main/jflex/smaliLexer.jflex b/smali/src/main/jflex/smaliLexer.jflex
index f329c7b5..bc17362f 100644
--- a/smali/src/main/jflex/smaliLexer.jflex
+++ b/smali/src/main/jflex/smaliLexer.jflex
@@ -461,6 +461,14 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
return newToken(INSTRUCTION_FORMAT21c_TYPE);
}
+ "capture-variable" { // e.g. 'capture-variable vB, <string id>'
+ return newToken(INSTRUCTION_FORMAT21c_LAMBDA);
+ }
+
+ "create-lambda" { // e.g. 'create-lambda vClosure, <method id>'
+ return newToken(INSTRUCTION_FORMAT21c_METHOD);
+ }
+
"const/high16" {
return newToken(INSTRUCTION_FORMAT21ih);
}
@@ -492,10 +500,13 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
return newToken(INSTRUCTION_FORMAT22c_FIELD_ODEX);
}
- "instance-of" | "new-array" {
+ "instance-of" | "new-array" | "unbox-lambda" {
return newToken(INSTRUCTION_FORMAT22c_TYPE);
}
+ "liberate-variable" {
+ return newToken(INSTRUCTION_FORMAT22c_STRING);
+ }
"iget-quick" | "iget-wide-quick" | "iget-object-quick" | "iput-quick" | "iput-wide-quick" | "iput-object-quick" {
return newToken(INSTRUCTION_FORMAT22cs_FIELD);
}
@@ -513,7 +524,7 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
return newToken(INSTRUCTION_FORMAT22t);
}
- "move/from16" | "move-wide/from16" | "move-object/from16" {
+ "move/from16" | "move-wide/from16" | "move-object/from16" | "box-lambda" {
return newToken(INSTRUCTION_FORMAT22x);
}
@@ -527,6 +538,10 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
return newToken(INSTRUCTION_FORMAT23x);
}
+ "invoke-lambda" { // e.g. invoke-lambda vClosure, {vD, vE, vF, vG} -- at most 4 params
+ return newToken(INSTRUCTION_FORMAT25x);
+ }
+
"goto/32" {
return newToken(INSTRUCTION_FORMAT30t);
}
diff --git a/smali/src/test/resources/LexerTest/InstructionTest.smali b/smali/src/test/resources/LexerTest/InstructionTest.smali
index 2247adc0..f6dcbb1e 100644
--- a/smali/src/test/resources/LexerTest/InstructionTest.smali
+++ b/smali/src/test/resources/LexerTest/InstructionTest.smali
@@ -84,6 +84,8 @@ const-string
check-cast
new-instance
const-class
+capture-variable
+create-lambda
const/high16
const-wide/high16
const/16
@@ -122,6 +124,8 @@ iput-wide-volatile
iput-object-volatile
instance-of
new-array
+unbox-lambda
+liberate-variable
iget-quick
iget-wide-quick
iget-object-quick
@@ -144,6 +148,7 @@ if-le
move/from16
move-wide/from16
move-object/from16
+box-lambda
cmpl-float
cmpg-float
cmpl-double
@@ -194,6 +199,7 @@ add-double
sub-double
mul-double
div-double
+invoke-lambda
goto/32
const-string/jumbo
const
diff --git a/smali/src/test/resources/LexerTest/InstructionTest.tokens b/smali/src/test/resources/LexerTest/InstructionTest.tokens
index a5574ab4..fb5503b5 100644
--- a/smali/src/test/resources/LexerTest/InstructionTest.tokens
+++ b/smali/src/test/resources/LexerTest/InstructionTest.tokens
@@ -84,6 +84,8 @@ INSTRUCTION_FORMAT21c_STRING("const-string")
INSTRUCTION_FORMAT21c_TYPE("check-cast")
INSTRUCTION_FORMAT21c_TYPE("new-instance")
INSTRUCTION_FORMAT21c_TYPE("const-class")
+INSTRUCTION_FORMAT21c_LAMBDA("capture-variable")
+INSTRUCTION_FORMAT21c_METHOD("create-lambda")
INSTRUCTION_FORMAT21ih("const/high16")
INSTRUCTION_FORMAT21lh("const-wide/high16")
INSTRUCTION_FORMAT21s("const/16")
@@ -122,6 +124,8 @@ INSTRUCTION_FORMAT22c_FIELD_ODEX("iput-wide-volatile")
INSTRUCTION_FORMAT22c_FIELD_ODEX("iput-object-volatile")
INSTRUCTION_FORMAT22c_TYPE("instance-of")
INSTRUCTION_FORMAT22c_TYPE("new-array")
+INSTRUCTION_FORMAT22c_TYPE("unbox-lambda")
+INSTRUCTION_FORMAT22c_STRING("liberate-variable")
INSTRUCTION_FORMAT22cs_FIELD("iget-quick")
INSTRUCTION_FORMAT22cs_FIELD("iget-wide-quick")
INSTRUCTION_FORMAT22cs_FIELD("iget-object-quick")
@@ -144,6 +148,7 @@ INSTRUCTION_FORMAT22t("if-le")
INSTRUCTION_FORMAT22x("move/from16")
INSTRUCTION_FORMAT22x("move-wide/from16")
INSTRUCTION_FORMAT22x("move-object/from16")
+INSTRUCTION_FORMAT22x("box-lambda")
INSTRUCTION_FORMAT23x("cmpl-float")
INSTRUCTION_FORMAT23x("cmpg-float")
INSTRUCTION_FORMAT23x("cmpl-double")
@@ -194,6 +199,7 @@ INSTRUCTION_FORMAT23x("add-double")
INSTRUCTION_FORMAT23x("sub-double")
INSTRUCTION_FORMAT23x("mul-double")
INSTRUCTION_FORMAT23x("div-double")
+INSTRUCTION_FORMAT25x("invoke-lambda")
INSTRUCTION_FORMAT30t("goto/32")
INSTRUCTION_FORMAT31c("const-string/jumbo")
INSTRUCTION_FORMAT31i_OR_ID("const")