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