smaliTreeWalker.g revision 6c15046f2b744978bb3b03a0697d7865d132fe6e
1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2010 Ben Gruver 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29tree grammar smaliTreeWalker; 30 31options { 32 tokenVocab=smaliParser; 33 ASTLabelType=CommonTree; 34} 35 36@header { 37package org.jf.smali; 38 39import java.util.HashMap; 40import java.util.Iterator; 41import java.util.Set; 42import java.util.regex.*; 43 44import com.google.common.collect.Lists; 45import com.google.common.collect.ImmutableList; 46import com.google.common.collect.ImmutableSet; 47import com.google.common.collect.Maps; 48import org.jf.dexlib2.AccessFlags; 49import org.jf.dexlib2.AnnotationVisibility; 50import org.jf.dexlib2.Opcode; 51import org.jf.dexlib2.VerificationError; 52import org.jf.dexlib2.dexbacked.raw.*; 53import org.jf.dexlib2.iface.*; 54import org.jf.dexlib2.iface.debug.DebugItem; 55import org.jf.dexlib2.iface.instruction.Instruction; 56import org.jf.dexlib2.iface.instruction.SwitchElement; 57import org.jf.dexlib2.iface.instruction.formats.*; 58import org.jf.dexlib2.iface.reference.*; 59import org.jf.dexlib2.iface.value.EncodedValue; 60import org.jf.dexlib2.immutable.*; 61import org.jf.dexlib2.immutable.debug.*; 62import org.jf.dexlib2.immutable.instruction.*; 63import org.jf.dexlib2.immutable.reference.*; 64import org.jf.dexlib2.immutable.value.*; 65import org.jf.dexlib2.util.MethodUtil; 66 67 68} 69 70@members { 71 public String classType; 72 private boolean verboseErrors = false; 73 74 public void setVerboseErrors(boolean verboseErrors) { 75 this.verboseErrors = verboseErrors; 76 } 77 78 private byte parseRegister_nibble(String register, int totalMethodRegisters, int methodParameterRegisters) 79 throws SemanticException { 80 //register should be in the format "v12" 81 int val = Byte.parseByte(register.substring(1)); 82 if (register.charAt(0) == 'p') { 83 val = totalMethodRegisters - methodParameterRegisters + val; 84 } 85 if (val >= 2<<4) { 86 throw new SemanticException(input, "The maximum allowed register in this context is list of registers is v15"); 87 } 88 //the parser wouldn't have accepted a negative register, i.e. v-1, so we don't have to check for val<0; 89 return (byte)val; 90 } 91 92 //return a short, because java's byte is signed 93 private short parseRegister_byte(String register, int totalMethodRegisters, int methodParameterRegisters) 94 throws SemanticException { 95 //register should be in the format "v123" 96 int val = Short.parseShort(register.substring(1)); 97 if (register.charAt(0) == 'p') { 98 val = totalMethodRegisters - methodParameterRegisters + val; 99 } 100 if (val >= 2<<8) { 101 throw new SemanticException(input, "The maximum allowed register in this context is v255"); 102 } 103 return (short)val; 104 } 105 106 //return an int because java's short is signed 107 private int parseRegister_short(String register, int totalMethodRegisters, int methodParameterRegisters) 108 throws SemanticException { 109 //register should be in the format "v12345" 110 int val = Integer.parseInt(register.substring(1)); 111 if (register.charAt(0) == 'p') { 112 val = totalMethodRegisters - methodParameterRegisters + val; 113 } 114 if (val >= 2<<16) { 115 throw new SemanticException(input, "The maximum allowed register in this context is v65535"); 116 } 117 //the parser wouldn't accept a negative register, i.e. v-1, so we don't have to check for val<0; 118 return val; 119 } 120 121 public String getErrorMessage(RecognitionException e, String[] tokenNames) { 122 if ( e instanceof SemanticException ) { 123 return e.getMessage(); 124 } else { 125 return super.getErrorMessage(e, tokenNames); 126 } 127 } 128 129 public String getErrorHeader(RecognitionException e) { 130 return getSourceName()+"["+ e.line+","+e.charPositionInLine+"]"; 131 } 132} 133 134smali_file returns[ClassDef classDef] 135 : ^(I_CLASS_DEF header methods fields annotations) 136 { 137 $classDef = new ImmutableClassDef($header.classType, $header.accessFlags, $header.superType, 138 $header.implementsList, $header.sourceSpec, $annotations.annotations, $fields.fields, $methods.methods); 139 }; 140 catch [Exception ex] { 141 if (verboseErrors) { 142 ex.printStackTrace(System.err); 143 } 144 reportError(new SemanticException(input, ex)); 145 } 146 147 148header returns[String classType, int accessFlags, String superType, List<String> implementsList, String sourceSpec] 149: class_spec super_spec? implements_list source_spec 150 { 151 classType = $class_spec.type; 152 $classType = classType; 153 $accessFlags = $class_spec.accessFlags; 154 $superType = $super_spec.type; 155 $implementsList = $implements_list.implementsList; 156 $sourceSpec = $source_spec.source; 157 }; 158 159 160class_spec returns[String type, int accessFlags] 161 : CLASS_DESCRIPTOR access_list 162 { 163 $type = $CLASS_DESCRIPTOR.text; 164 $accessFlags = $access_list.value; 165 }; 166 167super_spec returns[String type] 168 : ^(I_SUPER CLASS_DESCRIPTOR) 169 { 170 $type = $CLASS_DESCRIPTOR.text; 171 }; 172 173 174implements_spec returns[String type] 175 : ^(I_IMPLEMENTS CLASS_DESCRIPTOR) 176 { 177 $type = $CLASS_DESCRIPTOR.text; 178 }; 179 180implements_list returns[List<String> implementsList] 181@init { List<String> typeList; } 182 : {typeList = Lists.newArrayList();} 183 (implements_spec {typeList.add($implements_spec.type);} )* 184 { 185 if (typeList.size() > 0) { 186 $implementsList = typeList; 187 } else { 188 $implementsList = null; 189 } 190 }; 191 192source_spec returns[String source] 193 : {$source = null;} 194 ^(I_SOURCE string_literal {$source = $string_literal.value;}) 195 | /*epsilon*/; 196 197access_list returns [int value] 198 @init 199 { 200 $value = 0; 201 } 202 : ^(I_ACCESS_LIST 203 ( 204 ACCESS_SPEC 205 { 206 $value |= AccessFlags.getAccessFlag($ACCESS_SPEC.getText()).getValue(); 207 } 208 )*); 209 210 211fields returns[List<Field> fields] 212 @init {$fields = Lists.newArrayList();} 213 : ^(I_FIELDS 214 (field 215 { 216 $fields.add($field.field); 217 })*); 218 219methods returns[List<Method> methods] 220 @init {$methods = Lists.newArrayList();} 221 : ^(I_METHODS 222 (method 223 { 224 $methods.add($method.ret); 225 })*); 226 227field returns [Field field] 228 :^(I_FIELD SIMPLE_NAME access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) field_initial_value annotations?) 229 { 230 int accessFlags = $access_list.value; 231 232 233 if (!AccessFlags.STATIC.isSet(accessFlags) && $field_initial_value.encodedValue != null) { 234 throw new SemanticException(input, "Initial field values can only be specified for static fields."); 235 } 236 237 $field = new ImmutableField(classType, $SIMPLE_NAME.text, $nonvoid_type_descriptor.type, $access_list.value, 238 $field_initial_value.encodedValue, $annotations.annotations); 239 }; 240 241 242field_initial_value returns[EncodedValue encodedValue] 243 : ^(I_FIELD_INITIAL_VALUE literal) {$encodedValue = $literal.encodedValue;} 244 | /*epsilon*/; 245 246literal returns[EncodedValue encodedValue] 247 : integer_literal { $encodedValue = new ImmutableIntEncodedValue($integer_literal.value); } 248 | long_literal { $encodedValue = new ImmutableLongEncodedValue($long_literal.value); } 249 | short_literal { $encodedValue = new ImmutableShortEncodedValue($short_literal.value); } 250 | byte_literal { $encodedValue = new ImmutableByteEncodedValue($byte_literal.value); } 251 | float_literal { $encodedValue = new ImmutableFloatEncodedValue($float_literal.value); } 252 | double_literal { $encodedValue = new ImmutableDoubleEncodedValue($double_literal.value); } 253 | char_literal { $encodedValue = new ImmutableCharEncodedValue($char_literal.value); } 254 | string_literal { $encodedValue = new ImmutableStringEncodedValue($string_literal.value); } 255 | bool_literal { $encodedValue = ImmutableBooleanEncodedValue.forBoolean($bool_literal.value); } 256 | NULL_LITERAL { $encodedValue = ImmutableNullEncodedValue.INSTANCE; } 257 | type_descriptor { $encodedValue = new ImmutableTypeEncodedValue($type_descriptor.type); } 258 | array_literal { $encodedValue = new ImmutableArrayEncodedValue($array_literal.values); } 259 | subannotation { $encodedValue = new ImmutableAnnotationEncodedValue($subannotation.annotationType, $subannotation.elements); } 260 | field_literal { $encodedValue = new ImmutableFieldEncodedValue($field_literal.value); } 261 | method_literal { $encodedValue = new ImmutableMethodEncodedValue($method_literal.value); } 262 | enum_literal { $encodedValue = new ImmutableEnumEncodedValue($enum_literal.value); }; 263 264 265//everything but string 266fixed_size_literal returns[byte[\] value] 267 : integer_literal { $value = LiteralTools.intToBytes($integer_literal.value); } 268 | long_literal { $value = LiteralTools.longToBytes($long_literal.value); } 269 | short_literal { $value = LiteralTools.shortToBytes($short_literal.value); } 270 | byte_literal { $value = new byte[] { $byte_literal.value }; } 271 | float_literal { $value = LiteralTools.floatToBytes($float_literal.value); } 272 | double_literal { $value = LiteralTools.doubleToBytes($double_literal.value); } 273 | char_literal { $value = LiteralTools.charToBytes($char_literal.value); } 274 | bool_literal { $value = LiteralTools.boolToBytes($bool_literal.value); }; 275 276//everything but string 277fixed_64bit_literal returns[long value] 278 : integer_literal { $value = $integer_literal.value; } 279 | long_literal { $value = $long_literal.value; } 280 | short_literal { $value = $short_literal.value; } 281 | byte_literal { $value = $byte_literal.value; } 282 | float_literal { $value = Float.floatToRawIntBits($float_literal.value); } 283 | double_literal { $value = Double.doubleToRawLongBits($double_literal.value); } 284 | char_literal { $value = $char_literal.value; } 285 | bool_literal { $value = $bool_literal.value?1:0; }; 286 287//everything but string and double 288//long is allowed, but it must fit into an int 289fixed_32bit_literal returns[int value] 290 : integer_literal { $value = $integer_literal.value; } 291 | long_literal { LiteralTools.checkInt($long_literal.value); $value = (int)$long_literal.value; } 292 | short_literal { $value = $short_literal.value; } 293 | byte_literal { $value = $byte_literal.value; } 294 | float_literal { $value = Float.floatToRawIntBits($float_literal.value); } 295 | char_literal { $value = $char_literal.value; } 296 | bool_literal { $value = $bool_literal.value?1:0; }; 297 298array_elements returns[List<byte[\]> values] 299 : {$values = new ArrayList<byte[]>();} 300 ^(I_ARRAY_ELEMENTS 301 (fixed_size_literal 302 { 303 $values.add($fixed_size_literal.value); 304 })*); 305 306packed_switch_elements[int baseAddress, int firstKey] returns[List<SwitchElement> elements] 307 @init {$elements = Lists.newArrayList();} 308 : 309 ^(I_PACKED_SWITCH_ELEMENTS 310 311 (offset_or_label 312 { 313 $elements.add(new ImmutableSwitchElement(firstKey++, 314 ($method::currentAddress + $offset_or_label.offsetValue) - $baseAddress)); 315 })* 316 ); 317 318sparse_switch_elements[int baseAddress] returns[List<SwitchElement> elements] 319 @init {$elements = Lists.newArrayList();} 320 : 321 ^(I_SPARSE_SWITCH_ELEMENTS 322 (fixed_32bit_literal offset_or_label 323 { 324 $elements.add(new ImmutableSwitchElement($fixed_32bit_literal.value, 325 ($method::currentAddress + $offset_or_label.offsetValue) - $baseAddress)); 326 327 })* 328 ); 329 330method returns[Method ret] 331 scope 332 { 333 HashMap<String, Integer> labels; 334 int currentAddress; 335 HashMap<Integer, Integer> packedSwitchDeclarations; 336 HashMap<Integer, Integer> sparseSwitchDeclarations; 337 } 338 @init 339 { 340 int totalMethodRegisters = 0; 341 int methodParameterRegisters = 0; 342 int accessFlags = 0; 343 boolean isStatic = false; 344 $method::labels = new HashMap<String, Integer>(); 345 $method::currentAddress = 0; 346 $method::packedSwitchDeclarations = new HashMap<Integer, Integer>(); 347 $method::sparseSwitchDeclarations = new HashMap<Integer, Integer>(); 348 } 349 : 350 ^(I_METHOD 351 method_name_and_prototype 352 access_list 353 { 354 accessFlags = $access_list.value; 355 isStatic = AccessFlags.STATIC.isSet(accessFlags); 356 methodParameterRegisters = MethodUtil.getParameterRegisterCount($method_name_and_prototype.parameters, isStatic); 357 } 358 (registers_directive 359 { 360 if ($registers_directive.isLocalsDirective) { 361 totalMethodRegisters = $registers_directive.registers + methodParameterRegisters; 362 } else { 363 totalMethodRegisters = $registers_directive.registers; 364 } 365 } 366 )? 367 labels 368 packed_switch_declarations 369 sparse_switch_declarations 370 statements[totalMethodRegisters, methodParameterRegisters] 371 catches 372 parameters[$method_name_and_prototype.parameters] 373 ordered_debug_directives[totalMethodRegisters, methodParameterRegisters] 374 annotations 375 ) 376 { 377 List<TryBlock> tryBlocks = $catches.tryBlocks; 378 List<DebugItem> debugItems = $ordered_debug_directives.debugItems; 379 380 MethodImplementation methodImplementation = null; 381 382 boolean isAbstract = false; 383 boolean isNative = false; 384 385 if ((accessFlags & AccessFlags.ABSTRACT.getValue()) != 0) { 386 isAbstract = true; 387 } else if ((accessFlags & AccessFlags.NATIVE.getValue()) != 0) { 388 isNative = true; 389 } 390 391 if ($statements.instructions.size() == 0) { 392 if (!isAbstract && !isNative) { 393 throw new SemanticException(input, $I_METHOD, "A non-abstract/non-native method must have at least 1 instruction"); 394 } 395 396 String methodType; 397 if (isAbstract) { 398 methodType = "an abstract"; 399 } else { 400 methodType = "a native"; 401 } 402 403 if ($registers_directive.start != null) { 404 if ($registers_directive.isLocalsDirective) { 405 throw new SemanticException(input, $registers_directive.start, "A .locals directive is not valid in \%s method", methodType); 406 } else { 407 throw new SemanticException(input, $registers_directive.start, "A .registers directive is not valid in \%s method", methodType); 408 } 409 } 410 411 if ($method::labels.size() > 0) { 412 throw new SemanticException(input, $I_METHOD, "Labels cannot be present in \%s method", methodType); 413 } 414 415 if ((tryBlocks != null && tryBlocks.size() > 0)) { 416 throw new SemanticException(input, $I_METHOD, "try/catch blocks cannot be present in \%s method", methodType); 417 } 418 419 if (debugItems != null && debugItems.size() > 0) { 420 throw new SemanticException(input, $I_METHOD, "debug directives cannot be present in \%s method", methodType); 421 } 422 } else { 423 if (isAbstract) { 424 throw new SemanticException(input, $I_METHOD, "An abstract method cannot have any instructions"); 425 } 426 if (isNative) { 427 throw new SemanticException(input, $I_METHOD, "A native method cannot have any instructions"); 428 } 429 430 if ($registers_directive.start == null) { 431 throw new SemanticException(input, $I_METHOD, "A .registers or .locals directive must be present for a non-abstract/non-final method"); 432 } 433 434 if (totalMethodRegisters < methodParameterRegisters) { 435 throw new SemanticException(input, $registers_directive.start, "This method requires at least " + 436 Integer.toString(methodParameterRegisters) + 437 " registers, for the method parameters"); 438 } 439 440 methodImplementation = new ImmutableMethodImplementation( 441 totalMethodRegisters, 442 $statements.instructions, 443 tryBlocks, 444 debugItems); 445 } 446 447 $ret = new ImmutableMethod( 448 classType, 449 $method_name_and_prototype.name, 450 $parameters.parameters, 451 $method_name_and_prototype.returnType, 452 accessFlags, 453 $annotations.annotations, 454 methodImplementation); 455 }; 456 457method_prototype returns[List<String> parameters, String returnType] 458 : ^(I_METHOD_PROTOTYPE ^(I_METHOD_RETURN_TYPE type_descriptor) field_type_list) 459 { 460 $returnType = $type_descriptor.type; 461 $parameters = $field_type_list.types; 462 }; 463 464method_name_and_prototype returns[String name, List<String> parameters, String returnType] 465 : SIMPLE_NAME method_prototype 466 { 467 $name = $SIMPLE_NAME.text; 468 $parameters = $method_prototype.parameters; 469 $returnType = $method_prototype.returnType; 470 }; 471 472field_type_list returns[List<String> types] 473 @init 474 { 475 $types = Lists.newArrayList(); 476 } 477 : ( 478 nonvoid_type_descriptor 479 { 480 $types.add($nonvoid_type_descriptor.type); 481 } 482 )*; 483 484 485fully_qualified_method returns[ImmutableMethodReference methodReference] 486 : reference_type_descriptor SIMPLE_NAME method_prototype 487 { 488 $methodReference = new ImmutableMethodReference($reference_type_descriptor.type, $SIMPLE_NAME.text, 489 $method_prototype.parameters, $method_prototype.returnType); 490 }; 491 492fully_qualified_field returns[ImmutableFieldReference fieldReference] 493 : reference_type_descriptor SIMPLE_NAME nonvoid_type_descriptor 494 { 495 $fieldReference = new ImmutableFieldReference($reference_type_descriptor.type, $SIMPLE_NAME.text, 496 $nonvoid_type_descriptor.type); 497 }; 498 499registers_directive returns[boolean isLocalsDirective, int registers] 500 : {$registers = 0;} 501 ^(( I_REGISTERS {$isLocalsDirective = false;} 502 | I_LOCALS {$isLocalsDirective = true;} 503 ) 504 short_integral_literal {$registers = $short_integral_literal.value;} 505 ); 506 507labels 508 : ^(I_LABELS label_def*); 509 510label_def 511 : ^(I_LABEL SIMPLE_NAME address) 512 { 513 if ($method::labels.containsKey($SIMPLE_NAME.text)) { 514 throw new SemanticException(input, $I_LABEL, "Label " + $SIMPLE_NAME.text + " has multiple defintions."); 515 } 516 517 $method::labels.put($SIMPLE_NAME.text, $address.address); 518 }; 519 520packed_switch_declarations 521 : ^(I_PACKED_SWITCH_DECLARATIONS packed_switch_declaration*); 522packed_switch_declaration 523 : ^(I_PACKED_SWITCH_DECLARATION address offset_or_label_absolute[$address.address]) 524 { 525 int switchDataAddress = $offset_or_label_absolute.address; 526 if ((switchDataAddress \% 2) != 0) { 527 switchDataAddress++; 528 } 529 if (!$method::packedSwitchDeclarations.containsKey(switchDataAddress)) { 530 $method::packedSwitchDeclarations.put(switchDataAddress, $address.address); 531 } 532 }; 533 534sparse_switch_declarations 535 : ^(I_SPARSE_SWITCH_DECLARATIONS sparse_switch_declaration*); 536sparse_switch_declaration 537 : ^(I_SPARSE_SWITCH_DECLARATION address offset_or_label_absolute[$address.address]) 538 { 539 int switchDataAddress = $offset_or_label_absolute.address; 540 if ((switchDataAddress \% 2) != 0) { 541 switchDataAddress++; 542 } 543 if (!$method::sparseSwitchDeclarations.containsKey(switchDataAddress)) { 544 $method::sparseSwitchDeclarations.put(switchDataAddress, $address.address); 545 } 546 }; 547 548catches returns[List<TryBlock> tryBlocks] 549 @init {tryBlocks = Lists.newArrayList();} 550 : ^(I_CATCHES (catch_directive { tryBlocks.add($catch_directive.tryBlock); })* 551 (catchall_directive { tryBlocks.add($catchall_directive.tryBlock); })*); 552 553catch_directive returns[TryBlock tryBlock] 554 : ^(I_CATCH address nonvoid_type_descriptor from=offset_or_label_absolute[$address.address] to=offset_or_label_absolute[$address.address] 555 using=offset_or_label_absolute[$address.address]) 556 { 557 String type = $nonvoid_type_descriptor.type; 558 int startAddress = $from.address; 559 int endAddress = $to.address; 560 int handlerAddress = $using.address; 561 562 // We always create try blocks with a single exception handler. These will be merged appropriately when written 563 // to a dex file 564 $tryBlock = new ImmutableTryBlock(startAddress, endAddress-startAddress, 565 ImmutableList.of(new ImmutableExceptionHandler(type, handlerAddress))); 566 }; 567 568catchall_directive returns[TryBlock tryBlock] 569 : ^(I_CATCHALL address from=offset_or_label_absolute[$address.address] to=offset_or_label_absolute[$address.address] 570 using=offset_or_label_absolute[$address.address]) 571 { 572 int startAddress = $from.address; 573 int endAddress = $to.address; 574 int handlerAddress = $using.address; 575 576 // We always create try blocks with a single exception handler. These will be merged appropriately when written 577 // to a dex file 578 $tryBlock = new ImmutableTryBlock(startAddress, endAddress-startAddress, 579 ImmutableList.of(new ImmutableExceptionHandler(null, handlerAddress))); 580 }; 581 582address returns[int address] 583 : I_ADDRESS 584 { 585 $address = Integer.parseInt($I_ADDRESS.text); 586 }; 587 588parameters[List<String> parameterTypes] returns[List<MethodParameter> parameters] 589 @init 590 { 591 Iterator<String> parameterIter = parameterTypes.iterator(); 592 $parameters = Lists.newArrayList(); 593 } 594 : ^(I_PARAMETERS (parameter[parameterIter] { $parameters.add($parameter.parameter); })*) 595 { 596 String paramType; 597 while (parameterIter.hasNext()) { 598 paramType = parameterIter.next(); 599 $parameters.add(new ImmutableMethodParameter(paramType, null, null)); 600 } 601 }; 602 603parameter[Iterator<String> parameterTypes] returns[MethodParameter parameter] 604 : ^(I_PARAMETER string_literal? annotations 605 { 606 if (!$parameterTypes.hasNext()) { 607 throw new SemanticException(input, $I_PARAMETER, "Too many .parameter directives specified."); 608 } 609 String type = $parameterTypes.next(); 610 String name = $string_literal.value; 611 Set<Annotation> annotations = $annotations.annotations; 612 613 $parameter = new ImmutableMethodParameter(type, annotations, name); 614 } 615 ); 616 617ordered_debug_directives[int totalMethodRegisters, int methodParameterRegisters] returns[List<DebugItem> debugItems] 618 @init {debugItems = Lists.newArrayList();} 619 : ^(I_ORDERED_DEBUG_DIRECTIVES 620 ( line { $debugItems.add($line.debugItem); } 621 | local[$totalMethodRegisters, $methodParameterRegisters] { $debugItems.add($local.debugItem); } 622 | end_local[$totalMethodRegisters, $methodParameterRegisters] { $debugItems.add($end_local.debugItem); } 623 | restart_local[$totalMethodRegisters, $methodParameterRegisters] { $debugItems.add($restart_local.debugItem); } 624 | prologue { $debugItems.add($prologue.debugItem); } 625 | epilogue { $debugItems.add($epilogue.debugItem); } 626 | source { $debugItems.add($source.debugItem); } 627 )* 628 ); 629 630line returns[DebugItem debugItem] 631 : ^(I_LINE integral_literal address) 632 { 633 $debugItem = new ImmutableLineNumber($address.address, $integral_literal.value); 634 }; 635 636local[int totalMethodRegisters, int methodParameterRegisters] returns[DebugItem debugItem] 637 : ^(I_LOCAL REGISTER SIMPLE_NAME nonvoid_type_descriptor string_literal? address) 638 { 639 int registerNumber = parseRegister_short($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 640 641 $debugItem = new ImmutableStartLocal($address.address, registerNumber, $SIMPLE_NAME.text, 642 $nonvoid_type_descriptor.type, $string_literal.value); 643 }; 644 645end_local[int totalMethodRegisters, int methodParameterRegisters] returns[DebugItem debugItem] 646 : ^(I_END_LOCAL REGISTER address) 647 { 648 int registerNumber = parseRegister_short($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 649 650 $debugItem = new ImmutableEndLocal($address.address, registerNumber); 651 }; 652 653restart_local[int totalMethodRegisters, int methodParameterRegisters] returns[DebugItem debugItem] 654 : ^(I_RESTART_LOCAL REGISTER address) 655 { 656 int registerNumber = parseRegister_short($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 657 658 $debugItem = new ImmutableRestartLocal($address.address, registerNumber); 659 }; 660 661prologue returns[DebugItem debugItem] 662 : ^(I_PROLOGUE address) 663 { 664 $debugItem = new ImmutablePrologueEnd($address.address); 665 }; 666 667epilogue returns[DebugItem debugItem] 668 : ^(I_EPILOGUE address) 669 { 670 $debugItem = new ImmutableEpilogueBegin($address.address); 671 }; 672 673source returns[DebugItem debugItem] 674 : ^(I_SOURCE string_literal address) 675 { 676 $debugItem = new ImmutableSetSourceFile($address.address, $string_literal.value); 677 }; 678 679statements[int totalMethodRegisters, int methodParameterRegisters] returns[List<Instruction> instructions, int maxOutRegisters] 680 @init 681 { 682 $instructions = Lists.newArrayList(); 683 $maxOutRegisters = 0; 684 } 685 : ^(I_STATEMENTS (instruction[$totalMethodRegisters, $methodParameterRegisters, $instructions] 686 { 687 $method::currentAddress += $instructions.get($instructions.size() - 1).getCodeUnits(); 688 if ($maxOutRegisters < $instruction.outRegisters) { 689 $maxOutRegisters = $instruction.outRegisters; 690 } 691 })*); 692 693label_ref returns[int labelAddress] 694 : SIMPLE_NAME 695 { 696 Integer labelAdd = $method::labels.get($SIMPLE_NAME.text); 697 698 if (labelAdd == null) { 699 throw new SemanticException(input, $SIMPLE_NAME, "Label \"" + $SIMPLE_NAME.text + "\" is not defined."); 700 } 701 702 $labelAddress = labelAdd; 703 }; 704 705offset returns[int offsetValue] 706 : OFFSET 707 { 708 String offsetText = $OFFSET.text; 709 if (offsetText.charAt(0) == '+') { 710 offsetText = offsetText.substring(1); 711 } 712 $offsetValue = LiteralTools.parseInt(offsetText); 713 }; 714 715offset_or_label_absolute[int baseAddress] returns[int address] 716 : offset {$address = $offset.offsetValue + $baseAddress;} 717 | label_ref {$address = $label_ref.labelAddress;}; 718 719offset_or_label returns[int offsetValue] 720 : offset {$offsetValue = $offset.offsetValue;} 721 | label_ref {$offsetValue = $label_ref.labelAddress-$method::currentAddress;}; 722 723 724register_list[int totalMethodRegisters, int methodParameterRegisters] returns[byte[\] registers, byte registerCount] 725 @init 726 { 727 $registers = new byte[5]; 728 $registerCount = 0; 729 } 730 : ^(I_REGISTER_LIST 731 (REGISTER 732 { 733 if ($registerCount == 5) { 734 throw new SemanticException(input, $I_REGISTER_LIST, "A list of registers can only have a maximum of 5 registers. Use the <op>/range alternate opcode instead."); 735 } 736 $registers[$registerCount++] = parseRegister_nibble($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 737 })*); 738 739register_range[int totalMethodRegisters, int methodParameterRegisters] returns[int startRegister, int endRegister] 740 : ^(I_REGISTER_RANGE (startReg=REGISTER endReg=REGISTER?)?) 741 { 742 if ($startReg == null) { 743 $startRegister = 0; 744 $endRegister = -1; 745 } else { 746 $startRegister = parseRegister_short($startReg.text, $totalMethodRegisters, $methodParameterRegisters); 747 if ($endReg == null) { 748 $endRegister = $startRegister; 749 } else { 750 $endRegister = parseRegister_short($endReg.text, $totalMethodRegisters, $methodParameterRegisters); 751 } 752 753 int registerCount = $endRegister-$startRegister+1; 754 if (registerCount < 1) { 755 throw new SemanticException(input, $I_REGISTER_RANGE, "A register range must have the lower register listed first"); 756 } 757 } 758 }; 759 760verification_error_reference returns[ImmutableReference reference] 761 : CLASS_DESCRIPTOR 762 { 763 $reference = new ImmutableTypeReference($CLASS_DESCRIPTOR.text); 764 } 765 | fully_qualified_field 766 { 767 $reference = $fully_qualified_field.fieldReference; 768 } 769 | fully_qualified_method 770 { 771 $reference = $fully_qualified_method.methodReference; 772 }; 773 774verification_error_type returns[int verificationError] 775 : VERIFICATION_ERROR_TYPE 776 { 777 $verificationError = VerificationError.getVerificationError($VERIFICATION_ERROR_TYPE.text); 778 }; 779 780instruction[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 781 : insn_format10t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format10t.outRegisters; } 782 | insn_format10x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format10x.outRegisters; } 783 | insn_format11n[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format11n.outRegisters; } 784 | insn_format11x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format11x.outRegisters; } 785 | insn_format12x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format12x.outRegisters; } 786 | insn_format20bc[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format20bc.outRegisters; } 787 | insn_format20t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format20t.outRegisters; } 788 | insn_format21c_field[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21c_field.outRegisters; } 789 | insn_format21c_string[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21c_string.outRegisters; } 790 | insn_format21c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21c_type.outRegisters; } 791 | insn_format21ih[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21ih.outRegisters; } 792 | insn_format21lh[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21lh.outRegisters; } 793 | insn_format21s[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21s.outRegisters; } 794 | insn_format21t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format21t.outRegisters; } 795 | insn_format22b[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22b.outRegisters; } 796 | insn_format22c_field[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22c_field.outRegisters; } 797 | insn_format22c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22c_type.outRegisters; } 798 | insn_format22s[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22s.outRegisters; } 799 | insn_format22t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22t.outRegisters; } 800 | insn_format22x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format22x.outRegisters; } 801 | insn_format23x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format23x.outRegisters; } 802 | insn_format30t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format30t.outRegisters; } 803 | insn_format31c[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format31c.outRegisters; } 804 | insn_format31i[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format31i.outRegisters; } 805 | insn_format31t[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format31t.outRegisters; } 806 | insn_format32x[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format32x.outRegisters; } 807 | insn_format35c_method[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format35c_method.outRegisters; } 808 | insn_format35c_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format35c_type.outRegisters; } 809 | insn_format3rc_method[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format3rc_method.outRegisters; } 810 | insn_format3rc_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format3rc_type.outRegisters; } 811 | insn_format51l_type[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_format51l_type.outRegisters; } 812 | insn_array_data_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_array_data_directive.outRegisters; } 813 | insn_packed_switch_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_packed_switch_directive.outRegisters; } 814 | insn_sparse_switch_directive[$totalMethodRegisters, $methodParameterRegisters, $instructions] { $outRegisters = $insn_sparse_switch_directive.outRegisters; }; 815 catch [Exception ex] { 816 reportError(new SemanticException(input, ex)); 817 recover(input, null); 818 } 819 820 821insn_format10t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 822 : //e.g. goto endloop: 823 {$outRegisters = 0;} 824 ^(I_STATEMENT_FORMAT10t INSTRUCTION_FORMAT10t offset_or_label) 825 { 826 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT10t.text); 827 828 int addressOffset = $offset_or_label.offsetValue; 829 830 $instructions.add(new ImmutableInstruction10t(opcode, addressOffset)); 831 }; 832 833insn_format10x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 834 : //e.g. return 835 ^(I_STATEMENT_FORMAT10x INSTRUCTION_FORMAT10x) 836 { 837 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT10x.text); 838 $instructions.add(new ImmutableInstruction10x(opcode)); 839 }; 840 841insn_format11n[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 842 : //e.g. const/4 v0, 5 843 ^(I_STATEMENT_FORMAT11n INSTRUCTION_FORMAT11n REGISTER short_integral_literal) 844 { 845 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT11n.text); 846 byte regA = parseRegister_nibble($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 847 848 short litB = $short_integral_literal.value; 849 LiteralTools.checkNibble(litB); 850 851 $instructions.add(new ImmutableInstruction11n(opcode, regA, litB)); 852 }; 853 854insn_format11x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 855 : //e.g. move-result-object v1 856 ^(I_STATEMENT_FORMAT11x INSTRUCTION_FORMAT11x REGISTER) 857 { 858 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT11x.text); 859 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 860 861 $instructions.add(new ImmutableInstruction11x(opcode, regA)); 862 }; 863 864insn_format12x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 865 : //e.g. move v1 v2 866 ^(I_STATEMENT_FORMAT12x INSTRUCTION_FORMAT12x registerA=REGISTER registerB=REGISTER) 867 { 868 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT12x.text); 869 byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters); 870 byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters); 871 872 $instructions.add(new ImmutableInstruction12x(opcode, regA, regB)); 873 }; 874 875insn_format20bc[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 876 : //e.g. throw-verification-error generic-error, Lsome/class; 877 ^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc verification_error_type verification_error_reference) 878 { 879 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT20bc.text); 880 881 int verificationError = $verification_error_type.verificationError; 882 ImmutableReference referencedItem = $verification_error_reference.reference; 883 884 $instructions.add(new ImmutableInstruction20bc(opcode, verificationError, referencedItem)); 885 }; 886 887insn_format20t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 888 : //e.g. goto/16 endloop: 889 ^(I_STATEMENT_FORMAT20t INSTRUCTION_FORMAT20t offset_or_label) 890 { 891 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT20t.text); 892 893 int addressOffset = $offset_or_label.offsetValue; 894 895 $instructions.add(new ImmutableInstruction20t(opcode, addressOffset)); 896 }; 897 898insn_format21c_field[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 899 : //e.g. sget_object v0, java/lang/System/out LJava/io/PrintStream; 900 ^(I_STATEMENT_FORMAT21c_FIELD inst=(INSTRUCTION_FORMAT21c_FIELD | INSTRUCTION_FORMAT21c_FIELD_ODEX) REGISTER fully_qualified_field) 901 { 902 Opcode opcode = Opcode.getOpcodeByName($inst.text); 903 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 904 905 ImmutableFieldReference fieldReference = $fully_qualified_field.fieldReference; 906 907 $instructions.add(new ImmutableInstruction21c(opcode, regA, fieldReference)); 908 }; 909 910insn_format21c_string[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 911 : //e.g. const-string v1, "Hello World!" 912 ^(I_STATEMENT_FORMAT21c_STRING INSTRUCTION_FORMAT21c_STRING REGISTER string_literal) 913 { 914 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21c_STRING.text); 915 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 916 917 ImmutableStringReference stringReference = new ImmutableStringReference($string_literal.value); 918 919 instructions.add(new ImmutableInstruction21c(opcode, regA, stringReference)); 920 }; 921 922insn_format21c_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 923 : //e.g. const-class v2, org/jf/HelloWorld2/HelloWorld2 924 ^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor) 925 { 926 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21c_TYPE.text); 927 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 928 929 ImmutableTypeReference typeReference = new ImmutableTypeReference($reference_type_descriptor.type); 930 931 $instructions.add(new ImmutableInstruction21c(opcode, regA, typeReference)); 932 }; 933 934insn_format21ih[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 935 : //e.g. const/high16 v1, 1234 936 ^(I_STATEMENT_FORMAT21ih INSTRUCTION_FORMAT21ih REGISTER short_integral_literal) 937 { 938 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21ih.text); 939 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 940 941 short litB = $short_integral_literal.value; 942 943 instructions.add(new ImmutableInstruction21ih(opcode, regA, litB<<16)); 944 }; 945 946insn_format21lh[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 947 : //e.g. const-wide/high16 v1, 1234 948 ^(I_STATEMENT_FORMAT21lh INSTRUCTION_FORMAT21lh REGISTER short_integral_literal) 949 { 950 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21lh.text); 951 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 952 953 short litB = $short_integral_literal.value; 954 955 instructions.add(new ImmutableInstruction21lh(opcode, regA, ((long)litB)<<48)); 956 }; 957 958insn_format21s[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 959 : //e.g. const/16 v1, 1234 960 ^(I_STATEMENT_FORMAT21s INSTRUCTION_FORMAT21s REGISTER short_integral_literal) 961 { 962 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21s.text); 963 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 964 965 short litB = $short_integral_literal.value; 966 967 $instructions.add(new ImmutableInstruction21s(opcode, regA, litB)); 968 }; 969 970insn_format21t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 971 : //e.g. if-eqz v0, endloop: 972 ^(I_STATEMENT_FORMAT21t INSTRUCTION_FORMAT21t REGISTER offset_or_label) 973 { 974 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21t.text); 975 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 976 977 int addressOffset = $offset_or_label.offsetValue; 978 979 if (addressOffset < Short.MIN_VALUE || addressOffset > Short.MAX_VALUE) { 980 throw new SemanticException(input, $offset_or_label.start, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-32768, 32767]."); 981 } 982 983 $instructions.add(new ImmutableInstruction21t(opcode, regA, addressOffset)); 984 }; 985 986insn_format22b[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 987 : //e.g. add-int v0, v1, 123 988 ^(I_STATEMENT_FORMAT22b INSTRUCTION_FORMAT22b registerA=REGISTER registerB=REGISTER short_integral_literal) 989 { 990 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22b.text); 991 short regA = parseRegister_byte($registerA.text, $totalMethodRegisters, $methodParameterRegisters); 992 short regB = parseRegister_byte($registerB.text, $totalMethodRegisters, $methodParameterRegisters); 993 994 short litC = $short_integral_literal.value; 995 LiteralTools.checkByte(litC); 996 997 $instructions.add(new ImmutableInstruction22b(opcode, regA, regB, litC)); 998 }; 999 1000insn_format22c_field[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1001 : //e.g. iput-object v1, v0, org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; 1002 ^(I_STATEMENT_FORMAT22c_FIELD inst=(INSTRUCTION_FORMAT22c_FIELD | INSTRUCTION_FORMAT22c_FIELD_ODEX) registerA=REGISTER registerB=REGISTER fully_qualified_field) 1003 { 1004 Opcode opcode = Opcode.getOpcodeByName($inst.text); 1005 byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters); 1006 byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters); 1007 1008 ImmutableFieldReference fieldReference = $fully_qualified_field.fieldReference; 1009 1010 $instructions.add(new ImmutableInstruction22c(opcode, regA, regB, fieldReference)); 1011 }; 1012 1013insn_format22c_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1014 : //e.g. instance-of v0, v1, Ljava/lang/String; 1015 ^(I_STATEMENT_FORMAT22c_TYPE INSTRUCTION_FORMAT22c_TYPE registerA=REGISTER registerB=REGISTER nonvoid_type_descriptor) 1016 { 1017 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22c_TYPE.text); 1018 byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters); 1019 byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters); 1020 1021 ImmutableTypeReference typeReference = new ImmutableTypeReference($nonvoid_type_descriptor.type); 1022 1023 $instructions.add(new ImmutableInstruction22c(opcode, regA, regB, typeReference)); 1024 }; 1025 1026insn_format22s[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1027 : //e.g. add-int/lit16 v0, v1, 12345 1028 ^(I_STATEMENT_FORMAT22s INSTRUCTION_FORMAT22s registerA=REGISTER registerB=REGISTER short_integral_literal) 1029 { 1030 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22s.text); 1031 byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters); 1032 byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters); 1033 1034 short litC = $short_integral_literal.value; 1035 1036 $instructions.add(new ImmutableInstruction22s(opcode, regA, regB, litC)); 1037 }; 1038 1039insn_format22t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1040 : //e.g. if-eq v0, v1, endloop: 1041 ^(I_STATEMENT_FORMAT22t INSTRUCTION_FORMAT22t registerA=REGISTER registerB=REGISTER offset_or_label) 1042 { 1043 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22t.text); 1044 byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters); 1045 byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters); 1046 1047 int addressOffset = $offset_or_label.offsetValue; 1048 1049 if (addressOffset < Short.MIN_VALUE || addressOffset > Short.MAX_VALUE) { 1050 throw new SemanticException(input, $offset_or_label.start, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-32768, 32767]."); 1051 } 1052 1053 $instructions.add(new ImmutableInstruction22t(opcode, regA, regB, addressOffset)); 1054 }; 1055 1056insn_format22x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1057 : //e.g. move/from16 v1, v1234 1058 ^(I_STATEMENT_FORMAT22x INSTRUCTION_FORMAT22x registerA=REGISTER registerB=REGISTER) 1059 { 1060 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22x.text); 1061 short regA = parseRegister_byte($registerA.text, $totalMethodRegisters, $methodParameterRegisters); 1062 int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters); 1063 1064 $instructions.add(new ImmutableInstruction22x(opcode, regA, regB)); 1065 }; 1066 1067insn_format23x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1068 : //e.g. add-int v1, v2, v3 1069 ^(I_STATEMENT_FORMAT23x INSTRUCTION_FORMAT23x registerA=REGISTER registerB=REGISTER registerC=REGISTER) 1070 { 1071 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT23x.text); 1072 short regA = parseRegister_byte($registerA.text, $totalMethodRegisters, $methodParameterRegisters); 1073 short regB = parseRegister_byte($registerB.text, $totalMethodRegisters, $methodParameterRegisters); 1074 short regC = parseRegister_byte($registerC.text, $totalMethodRegisters, $methodParameterRegisters); 1075 1076 $instructions.add(new ImmutableInstruction23x(opcode, regA, regB, regC)); 1077 }; 1078 1079insn_format30t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1080 : //e.g. goto/32 endloop: 1081 ^(I_STATEMENT_FORMAT30t INSTRUCTION_FORMAT30t offset_or_label) 1082 { 1083 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT30t.text); 1084 1085 int addressOffset = $offset_or_label.offsetValue; 1086 1087 $instructions.add(new ImmutableInstruction30t(opcode, addressOffset)); 1088 }; 1089 1090insn_format31c[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1091 : //e.g. const-string/jumbo v1 "Hello World!" 1092 ^(I_STATEMENT_FORMAT31c INSTRUCTION_FORMAT31c REGISTER string_literal) 1093 { 1094 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT31c.text); 1095 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 1096 1097 ImmutableStringReference stringReference = new ImmutableStringReference($string_literal.value); 1098 1099 $instructions.add(new ImmutableInstruction31c(opcode, regA, stringReference)); 1100 }; 1101 1102insn_format31i[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1103 : //e.g. const v0, 123456 1104 ^(I_STATEMENT_FORMAT31i INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal) 1105 { 1106 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT31i.text); 1107 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 1108 1109 int litB = $fixed_32bit_literal.value; 1110 1111 $instructions.add(new ImmutableInstruction31i(opcode, regA, litB)); 1112 }; 1113 1114insn_format31t[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1115 : //e.g. fill-array-data v0, ArrayData: 1116 ^(I_STATEMENT_FORMAT31t INSTRUCTION_FORMAT31t REGISTER offset_or_label) 1117 { 1118 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT31t.text); 1119 1120 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 1121 1122 int addressOffset = $offset_or_label.offsetValue; 1123 if (($method::currentAddress + addressOffset) \% 2 != 0) { 1124 addressOffset++; 1125 } 1126 1127 $instructions.add(new ImmutableInstruction31t(opcode, regA, addressOffset)); 1128 }; 1129 1130insn_format32x[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1131 : //e.g. move/16 v5678, v1234 1132 ^(I_STATEMENT_FORMAT32x INSTRUCTION_FORMAT32x registerA=REGISTER registerB=REGISTER) 1133 { 1134 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT32x.text); 1135 int regA = parseRegister_short($registerA.text, $totalMethodRegisters, $methodParameterRegisters); 1136 int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters); 1137 1138 $instructions.add(new ImmutableInstruction32x(opcode, regA, regB)); 1139 }; 1140 1141insn_format35c_method[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1142 : //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V 1143 ^(I_STATEMENT_FORMAT35c_METHOD INSTRUCTION_FORMAT35c_METHOD register_list[$totalMethodRegisters, $methodParameterRegisters] fully_qualified_method) 1144 { 1145 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT35c_METHOD.text); 1146 1147 //this depends on the fact that register_list returns a byte[5] 1148 byte[] registers = $register_list.registers; 1149 byte registerCount = $register_list.registerCount; 1150 $outRegisters = registerCount; 1151 1152 ImmutableMethodReference methodReference = $fully_qualified_method.methodReference; 1153 1154 $instructions.add(new ImmutableInstruction35c(opcode, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], methodReference)); 1155 }; 1156 1157insn_format35c_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1158 : //e.g. filled-new-array {v0,v1}, I 1159 ^(I_STATEMENT_FORMAT35c_TYPE INSTRUCTION_FORMAT35c_TYPE register_list[$totalMethodRegisters, $methodParameterRegisters] nonvoid_type_descriptor) 1160 { 1161 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT35c_TYPE.text); 1162 1163 //this depends on the fact that register_list returns a byte[5] 1164 byte[] registers = $register_list.registers; 1165 byte registerCount = $register_list.registerCount; 1166 $outRegisters = registerCount; 1167 1168 ImmutableTypeReference typeReference = new ImmutableTypeReference($nonvoid_type_descriptor.type); 1169 1170 $instructions.add(new ImmutableInstruction35c(opcode, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], typeReference)); 1171 }; 1172 1173insn_format3rc_method[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1174 : //e.g. invoke-virtual/range {v25..v26} java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; 1175 ^(I_STATEMENT_FORMAT3rc_METHOD INSTRUCTION_FORMAT3rc_METHOD register_range[$totalMethodRegisters, $methodParameterRegisters] fully_qualified_method) 1176 { 1177 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT3rc_METHOD.text); 1178 int startRegister = $register_range.startRegister; 1179 int endRegister = $register_range.endRegister; 1180 1181 int registerCount = endRegister-startRegister+1; 1182 $outRegisters = registerCount; 1183 1184 ImmutableMethodReference methodReference = $fully_qualified_method.methodReference; 1185 1186 $instructions.add(new ImmutableInstruction3rc(opcode, startRegister, registerCount, methodReference)); 1187 }; 1188 1189insn_format3rc_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1190 : //e.g. filled-new-array/range {v0..v6} I 1191 ^(I_STATEMENT_FORMAT3rc_TYPE INSTRUCTION_FORMAT3rc_TYPE register_range[$totalMethodRegisters, $methodParameterRegisters] nonvoid_type_descriptor) 1192 { 1193 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT3rc_TYPE.text); 1194 int startRegister = $register_range.startRegister; 1195 int endRegister = $register_range.endRegister; 1196 1197 int registerCount = endRegister-startRegister+1; 1198 $outRegisters = registerCount; 1199 1200 ImmutableTypeReference typeReference = new ImmutableTypeReference($nonvoid_type_descriptor.type); 1201 1202 $instructions.add(new ImmutableInstruction3rc(opcode, startRegister, registerCount, typeReference)); 1203 }; 1204 1205insn_format51l_type[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1206 : //e.g. const-wide v0, 5000000000L 1207 ^(I_STATEMENT_FORMAT51l INSTRUCTION_FORMAT51l REGISTER fixed_64bit_literal) 1208 { 1209 Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT51l.text); 1210 short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); 1211 1212 long litB = $fixed_64bit_literal.value; 1213 1214 $instructions.add(new ImmutableInstruction51l(opcode, regA, litB)); 1215 }; 1216 1217insn_array_data_directive[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1218 : //e.g. .array-data 4 1000000 .end array-data 1219 ^(I_STATEMENT_ARRAY_DATA ^(I_ARRAY_ELEMENT_SIZE short_integral_literal) array_elements) 1220 { 1221 // TODO: reimplement, after changing how it's parsed 1222 /* 1223 int elementWidth = $short_integral_literal.value; 1224 List<byte[]> byteValues = $array_elements.values; 1225 1226 int length = 0; 1227 for (byte[] byteValue: byteValues) { 1228 length+=byteValue.length; 1229 } 1230 1231 byte[] encodedValues = new byte[length]; 1232 int index = 0; 1233 for (byte[] byteValue: byteValues) { 1234 System.arraycopy(byteValue, 0, encodedValues, index, byteValue.length); 1235 index+=byteValue.length; 1236 } 1237 1238 $instructions.add(new ImmutableArrayPayload(elementWidth, null)); 1239 */ 1240 }; 1241 1242insn_packed_switch_directive[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1243 : 1244 ^(I_STATEMENT_PACKED_SWITCH ^(I_PACKED_SWITCH_START_KEY fixed_32bit_literal) 1245 { 1246 int startKey = $fixed_32bit_literal.value; 1247 Integer baseAddress = $method::packedSwitchDeclarations.get($method::currentAddress); 1248 if (baseAddress == null) { 1249 baseAddress = 0; 1250 } 1251 } 1252 packed_switch_elements[baseAddress, startKey]) 1253 { 1254 $instructions.add(new ImmutablePackedSwitchPayload($packed_switch_elements.elements)); 1255 }; 1256 1257insn_sparse_switch_directive[int totalMethodRegisters, int methodParameterRegisters, List<Instruction> instructions] returns[int outRegisters] 1258 : 1259 { 1260 Integer baseAddress = $method::sparseSwitchDeclarations.get($method::currentAddress); 1261 if (baseAddress == null) { 1262 baseAddress = 0; 1263 } 1264 } 1265 ^(I_STATEMENT_SPARSE_SWITCH sparse_switch_elements[baseAddress]) 1266 { 1267 $instructions.add(new ImmutableSparseSwitchPayload($sparse_switch_elements.elements)); 1268 }; 1269 1270nonvoid_type_descriptor returns [String type] 1271 : (PRIMITIVE_TYPE 1272 | CLASS_DESCRIPTOR 1273 | ARRAY_DESCRIPTOR) 1274 { 1275 $type = $start.getText(); 1276 }; 1277 1278 1279reference_type_descriptor returns [String type] 1280 : (CLASS_DESCRIPTOR 1281 | ARRAY_DESCRIPTOR) 1282 { 1283 $type = $start.getText(); 1284 }; 1285 1286type_descriptor returns [String type] 1287 : VOID_TYPE {$type = "V";} 1288 | nonvoid_type_descriptor {$type = $nonvoid_type_descriptor.type;} 1289 ; 1290 1291short_integral_literal returns[short value] 1292 : long_literal 1293 { 1294 LiteralTools.checkShort($long_literal.value); 1295 $value = (short)$long_literal.value; 1296 } 1297 | integer_literal 1298 { 1299 LiteralTools.checkShort($integer_literal.value); 1300 $value = (short)$integer_literal.value; 1301 } 1302 | short_literal {$value = $short_literal.value;} 1303 | char_literal {$value = (short)$char_literal.value;} 1304 | byte_literal {$value = $byte_literal.value;}; 1305 1306integral_literal returns[int value] 1307 : long_literal 1308 { 1309 LiteralTools.checkInt($long_literal.value); 1310 $value = (int)$long_literal.value; 1311 } 1312 | integer_literal {$value = $integer_literal.value;} 1313 | short_literal {$value = $short_literal.value;} 1314 | byte_literal {$value = $byte_literal.value;}; 1315 1316 1317integer_literal returns[int value] 1318 : INTEGER_LITERAL { $value = LiteralTools.parseInt($INTEGER_LITERAL.text); }; 1319 1320long_literal returns[long value] 1321 : LONG_LITERAL { $value = LiteralTools.parseLong($LONG_LITERAL.text); }; 1322 1323short_literal returns[short value] 1324 : SHORT_LITERAL { $value = LiteralTools.parseShort($SHORT_LITERAL.text); }; 1325 1326byte_literal returns[byte value] 1327 : BYTE_LITERAL { $value = LiteralTools.parseByte($BYTE_LITERAL.text); }; 1328 1329float_literal returns[float value] 1330 : FLOAT_LITERAL { $value = LiteralTools.parseFloat($FLOAT_LITERAL.text); }; 1331 1332double_literal returns[double value] 1333 : DOUBLE_LITERAL { $value = LiteralTools.parseDouble($DOUBLE_LITERAL.text); }; 1334 1335char_literal returns[char value] 1336 : CHAR_LITERAL { $value = $CHAR_LITERAL.text.charAt(1); }; 1337 1338string_literal returns[String value] 1339 : STRING_LITERAL 1340 { 1341 $value = $STRING_LITERAL.text; 1342 $value = $value.substring(1,$value.length()-1); 1343 }; 1344 1345bool_literal returns[boolean value] 1346 : BOOL_LITERAL { $value = Boolean.parseBoolean($BOOL_LITERAL.text); }; 1347 1348array_literal returns[List<EncodedValue> values] 1349 : {ArrayList<EncodedValue> valuesList = new ArrayList<EncodedValue>();} 1350 ^(I_ENCODED_ARRAY (literal {valuesList.add($literal.encodedValue);})*) 1351 { 1352 $values = valuesList; 1353 }; 1354 1355 1356annotations returns[Set<Annotation> annotations] 1357 : {HashMap<String, Annotation> annotationMap = Maps.newHashMap();} 1358 ^(I_ANNOTATIONS (annotation 1359 { 1360 Annotation anno = $annotation.annotation; 1361 Annotation old = annotationMap.put(anno.getType(), anno); 1362 if (old != null) { 1363 throw new SemanticException(input, "Multiple annotations of type \%s", anno.getType()); 1364 } 1365 })*) 1366 { 1367 if (annotationMap.size() > 0) { 1368 $annotations = ImmutableSet.copyOf(annotationMap.values()); 1369 } 1370 }; 1371 1372annotation returns[Annotation annotation] 1373 : ^(I_ANNOTATION ANNOTATION_VISIBILITY subannotation) 1374 { 1375 int visibility = AnnotationVisibility.getVisibility($ANNOTATION_VISIBILITY.text); 1376 $annotation = new ImmutableAnnotation(visibility, $subannotation.annotationType, $subannotation.elements); 1377 }; 1378 1379annotation_element returns[AnnotationElement element] 1380 : ^(I_ANNOTATION_ELEMENT SIMPLE_NAME literal) 1381 { 1382 $element = new ImmutableAnnotationElement($SIMPLE_NAME.text, $literal.encodedValue); 1383 }; 1384 1385subannotation returns[String annotationType, List<AnnotationElement> elements] 1386 : {ArrayList<AnnotationElement> elements = Lists.newArrayList();} 1387 ^(I_SUBANNOTATION 1388 CLASS_DESCRIPTOR 1389 (annotation_element 1390 { 1391 elements.add($annotation_element.element); 1392 })* 1393 ) 1394 { 1395 $annotationType = $CLASS_DESCRIPTOR.text; 1396 $elements = elements; 1397 }; 1398 1399field_literal returns[FieldReference value] 1400 : ^(I_ENCODED_FIELD fully_qualified_field) 1401 { 1402 $value = $fully_qualified_field.fieldReference; 1403 }; 1404 1405method_literal returns[MethodReference value] 1406 : ^(I_ENCODED_METHOD fully_qualified_method) 1407 { 1408 $value = $fully_qualified_method.methodReference; 1409 }; 1410 1411enum_literal returns[FieldReference value] 1412 : ^(I_ENCODED_ENUM fully_qualified_field) 1413 { 1414 $value = $fully_qualified_field.fieldReference; 1415 }; 1416