1 21 package proguard.preverify; 22 23 import proguard.classfile.*; 24 import proguard.classfile.instruction.InstructionConstants; 25 import proguard.classfile.attribute.*; 26 import proguard.classfile.attribute.preverification.*; 27 import proguard.classfile.attribute.visitor.AttributeVisitor; 28 import proguard.classfile.editor.*; 29 import proguard.classfile.util.SimplifiedVisitor; 30 import proguard.classfile.visitor.*; 31 import proguard.evaluation.*; 32 import proguard.evaluation.value.*; 33 import proguard.optimize.evaluation.*; 34 35 import java.util.*; 36 37 43 public class CodePreverifier 44 extends SimplifiedVisitor 45 implements MemberVisitor, 46 AttributeVisitor 47 { 48 private static final boolean DEBUG = false; 50 53 54 55 private boolean microEdition; 56 57 private PartialEvaluator partialEvaluator = new PartialEvaluator(); 58 private LivenessAnalyzer livenessAnalyzer = new LivenessAnalyzer(partialEvaluator); 59 private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor(); 60 private AttributesEditor attributesEditor = new AttributesEditor(); 61 62 63 66 public CodePreverifier(boolean microEdition) 67 { 68 this.microEdition = microEdition; 69 } 70 71 72 74 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 75 76 77 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 78 { 79 try 82 { 83 visitCodeAttribute0(clazz, method, codeAttribute); 85 } 86 catch (RuntimeException ex) 87 { 88 System.err.println("Unexpected error while preverifying:"); 89 System.err.println(" Class = ["+clazz.getName()+"]"); 90 System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); 91 System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); 92 93 throw ex; 94 } 95 } 96 97 98 public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) 99 { 100 104 ProgramClass programClass = (ProgramClass)clazz; 105 ProgramMethod programMethod = (ProgramMethod)method; 106 107 livenessAnalyzer.visitCodeAttribute(clazz, method, codeAttribute); 110 111 List stackMapFrameList = new ArrayList(); 113 114 for (int offset = 0; offset < codeAttribute.u4codeLength; offset++) 115 { 116 if (partialEvaluator.isTraced(offset) && 118 partialEvaluator.isBranchOrExceptionTarget(offset)) 119 { 120 VerificationType[] variableTypes = 122 correspondingVerificationTypes(programClass, 123 programMethod, 124 codeAttribute, 125 offset, 126 partialEvaluator.getVariablesBefore(offset)); 127 128 VerificationType[] stackTypes = 130 correspondingVerificationTypes(programClass, 131 programMethod, 132 codeAttribute, 133 offset, 134 partialEvaluator.getStackBefore(offset)); 135 stackMapFrameList.add(new FullFrame(offset, 137 variableTypes, 138 stackTypes)); 139 } 140 } 141 142 if (!microEdition && !stackMapFrameList.isEmpty()) 144 { 145 VerificationType[] initialVariables = 147 correspondingVerificationTypes(programClass, 148 programMethod, 149 codeAttribute, 150 PartialEvaluator.AT_METHOD_ENTRY, 151 partialEvaluator.getVariablesBefore(0)); 152 153 if (method.getName(programClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) 155 { 156 initialVariables[0] = VerificationTypeFactory.createUninitializedThisType(); 157 } 158 159 compressStackMapFrames(initialVariables, 160 stackMapFrameList); 161 } 162 163 String stackMapAttributeName = microEdition ? 165 ClassConstants.ATTR_StackMap : 166 ClassConstants.ATTR_StackMapTable; 167 168 int frameCount = stackMapFrameList.size(); 169 170 if (DEBUG) 171 { 172 Attribute originalStackMapAttribute = codeAttribute.getAttribute(clazz, 173 stackMapAttributeName); 174 175 if (originalStackMapAttribute != null) 176 { 177 int originalFrameCount = microEdition ? 178 ((StackMapAttribute)originalStackMapAttribute).u2stackMapFramesCount : 179 ((StackMapTableAttribute)originalStackMapAttribute).u2stackMapFramesCount; 180 181 StackMapFrame[] originalFrames = microEdition ? 182 ((StackMapAttribute)originalStackMapAttribute).stackMapFrames : 183 ((StackMapTableAttribute)originalStackMapAttribute).stackMapFrames; 184 185 if (frameCount != originalFrameCount || 186 !Arrays.equals(stackMapFrameList.toArray(), originalFrames)) 187 { 188 System.out.println("Original preverification ["+clazz.getName()+"]:"); 189 new ClassPrinter().visitProgramMethod(programClass, programMethod); 190 } 191 } 192 else if (frameCount != 0) 193 { 194 System.out.println("Original preverification empty ["+clazz.getName()+"."+method.getName(clazz)+"]"); 195 } 196 } 197 198 if (frameCount == 0) 199 { 200 attributesEditor.deleteAttribute(programClass, 202 programMethod, 203 codeAttribute, 204 stackMapAttributeName); 205 } 206 else 207 { 208 Attribute stackMapAttribute; 209 210 if (microEdition) 212 { 213 FullFrame[] stackMapFrames = new FullFrame[frameCount]; 215 stackMapFrameList.toArray(stackMapFrames); 216 217 stackMapAttribute = new StackMapAttribute(stackMapFrames); 219 } 220 else 221 { 222 StackMapFrame[] stackMapFrames = new StackMapFrame[frameCount]; 224 stackMapFrameList.toArray(stackMapFrames); 225 226 stackMapAttribute = new StackMapTableAttribute(stackMapFrames); 228 } 229 230 stackMapAttribute.u2attributeNameIndex = 232 constantPoolEditor.addUtf8Constant(programClass, stackMapAttributeName); 233 234 attributesEditor.addAttribute(programClass, 236 programMethod, 237 codeAttribute, 238 stackMapAttribute); 239 240 if (DEBUG) 241 { 242 System.out.println("Preverifier ["+programClass.getName()+"."+programMethod.getName(programClass)+"]:"); 243 stackMapAttribute.accept(programClass, programMethod, codeAttribute, new ClassPrinter()); 244 } 245 } 246 } 247 248 249 251 256 private VerificationType[] correspondingVerificationTypes(ProgramClass programClass, 257 ProgramMethod programMethod, 258 CodeAttribute codeAttribute, 259 int offset, 260 TracedVariables variables) 261 { 262 int maximumVariablesSize = variables.size(); 263 int typeCount = 0; 264 int typeIndex = 0; 265 266 for (int index = 0; index < maximumVariablesSize; index++) 269 { 270 Value value = variables.getValue(index); 271 272 typeIndex++; 273 274 if (value != null && 276 (offset == PartialEvaluator.AT_METHOD_ENTRY || 277 livenessAnalyzer.isAliveBefore(offset, index))) 278 { 279 typeCount = typeIndex; 280 281 if (value.isCategory2()) 283 { 284 index++; 285 } 286 } 287 } 288 289 VerificationType[] types = new VerificationType[typeCount]; 291 292 typeIndex = 0; 293 294 for (int index = 0; typeIndex < typeCount; index++) 297 { 298 Value value = variables.getValue(index); 299 Value producerValue = variables.getProducerValue(index); 300 301 VerificationType type; 303 304 if (value != null && 305 (offset == PartialEvaluator.AT_METHOD_ENTRY || 306 livenessAnalyzer.isAliveBefore(offset, index))) 307 { 308 type = correspondingVerificationType(programClass, 309 programMethod, 310 codeAttribute, 311 offset, 312 value, 313 producerValue); 314 315 if (value.isCategory2()) 317 { 318 index++; 319 } 320 } 321 else 322 { 323 type = VerificationTypeFactory.createTopType(); 324 } 325 326 types[typeIndex++] = type; 327 } 328 329 return types; 330 } 331 332 333 338 private VerificationType[] correspondingVerificationTypes(ProgramClass programClass, 339 ProgramMethod programMethod, 340 CodeAttribute codeAttribute, 341 int offset, 342 TracedStack stack) 343 { 344 int maximumStackSize = stack.size(); 345 int typeCount = 0; 346 347 for (int index = 0; index < maximumStackSize; index++) 349 { 350 Value value = stack.getTop(index); 352 353 typeCount++; 354 355 if (value.isCategory2()) 357 { 358 index++; 359 } 360 } 361 362 VerificationType[] types = new VerificationType[typeCount]; 364 365 int typeIndex = typeCount; 366 367 for (int index = 0; index < maximumStackSize; index++) 368 { 369 Value value = stack.getTop(index); 371 Value producerValue = stack.getTopProducerValue(index); 372 373 types[--typeIndex] = 375 correspondingVerificationType(programClass, 376 programMethod, 377 codeAttribute, 378 offset, 379 value, 380 producerValue); 381 382 if (value.isCategory2()) 384 { 385 index++; 386 } 387 } 388 389 return types; 390 } 391 392 393 398 private VerificationType correspondingVerificationType(ProgramClass programClass, 399 ProgramMethod programMethod, 400 CodeAttribute codeAttribute, 401 int offset, 402 Value value, 403 Value producerValue) 404 { 405 if (value == null) 406 { 407 return VerificationTypeFactory.createTopType(); 408 } 409 410 int type = value.computationalType(); 411 412 switch (type) 413 { 414 case Value.TYPE_INSTRUCTION_OFFSET: 415 case Value.TYPE_INTEGER: return VerificationTypeFactory.createIntegerType(); 416 case Value.TYPE_LONG: return VerificationTypeFactory.createLongType(); 417 case Value.TYPE_FLOAT: return VerificationTypeFactory.createFloatType(); 418 case Value.TYPE_DOUBLE: return VerificationTypeFactory.createDoubleType(); 419 case Value.TYPE_TOP: return VerificationTypeFactory.createTopType(); 420 case Value.TYPE_REFERENCE: 421 ReferenceValue referenceValue = value.referenceValue(); 423 if (referenceValue.isNull() == Value.ALWAYS) 424 { 425 return VerificationTypeFactory.createNullType(); 426 } 427 428 if (offset != PartialEvaluator.AT_METHOD_ENTRY) 430 { 431 InstructionOffsetValue producers = producerValue.instructionOffsetValue(); 432 if (producers.instructionOffsetCount() == 1) 433 { 434 int producerOffset = producers.instructionOffset(0); 435 436 if (partialEvaluator.isInitializer() && 440 offset <= partialEvaluator.superInitializationOffset() && 441 producerOffset > PartialEvaluator.AT_METHOD_ENTRY && 442 codeAttribute.code[producerOffset] == InstructionConstants.OP_ALOAD_0) 443 { 444 producerOffset = PartialEvaluator.AT_METHOD_ENTRY; 445 } 446 447 int initializationOffset = producerOffset == PartialEvaluator.AT_METHOD_ENTRY ? 448 partialEvaluator.superInitializationOffset() : 449 partialEvaluator.initializationOffset(producerOffset); 450 if (initializationOffset != PartialEvaluator.NONE) 451 { 452 if (offset <= initializationOffset) 454 { 455 return producerOffset == PartialEvaluator.AT_METHOD_ENTRY ? 457 (VerificationType)VerificationTypeFactory.createUninitializedThisType() : 458 (VerificationType)VerificationTypeFactory.createUninitializedType(producerOffset); 459 } 460 } 461 } 462 } 463 464 return VerificationTypeFactory.createObjectType(createClassConstant(programClass, referenceValue)); 466 } 467 468 throw new IllegalArgumentException ("Unknown computational type ["+type+"]"); 469 } 470 471 472 476 private int createClassConstant(ProgramClass programClass, 477 ReferenceValue referenceValue) 478 { 479 return constantPoolEditor.addClassConstant(programClass, 480 referenceValue.getType(), 481 referenceValue.getReferencedClass()); 482 } 483 484 485 488 private void compressStackMapFrames(VerificationType[] initialVariableTypes, 489 List stackMapFrameList) 490 { 491 int previousVariablesCount = initialVariableTypes.length; 492 VerificationType[] previousVariableTypes = initialVariableTypes; 493 494 int previousOffset = -1; 495 496 for (int index = 0; index < stackMapFrameList.size(); index++) 497 { 498 FullFrame fullFrame = (FullFrame)stackMapFrameList.get(index); 499 500 int variablesCount = fullFrame.variablesCount; 501 VerificationType[] variables = fullFrame.variables; 502 int stackCount = fullFrame.stackCount; 503 VerificationType[] stack = fullFrame.stack; 504 505 StackMapFrame compressedFrame = fullFrame; 508 509 if (variablesCount == previousVariablesCount && 511 equalVerificationTypes(variables, previousVariableTypes, variablesCount)) 512 { 513 if (stackCount == 0) 526 { 527 compressedFrame = new SameZeroFrame(); 528 } 529 else if (stackCount == 1) 531 { 532 compressedFrame = new SameOneFrame(stack[0]); 533 } 534 } 535 else if (stackCount == 0) 537 { 538 int additionalVariablesCount = variablesCount - previousVariablesCount; 539 540 if (additionalVariablesCount < 0 && 542 additionalVariablesCount > -4 && 543 equalVerificationTypes(variables, previousVariableTypes, variablesCount)) 544 { 545 compressedFrame = new LessZeroFrame((byte)-additionalVariablesCount); 546 } 547 else if ( additionalVariablesCount > 0 && 550 additionalVariablesCount < 4 && 551 equalVerificationTypes(variables, previousVariableTypes, previousVariablesCount)) 552 { 553 VerificationType[] additionalVariables = new VerificationType[additionalVariablesCount]; 555 System.arraycopy(variables, variablesCount - additionalVariablesCount, 556 additionalVariables, 0, 557 additionalVariablesCount); 558 559 compressedFrame = new MoreZeroFrame(additionalVariables); 560 } 561 } 562 563 int offset = fullFrame.u2offsetDelta; 565 compressedFrame.u2offsetDelta = offset - previousOffset - 1; 566 previousOffset = offset; 567 568 previousVariablesCount = fullFrame.variablesCount; 570 previousVariableTypes = fullFrame.variables; 571 572 stackMapFrameList.set(index, compressedFrame); 574 } 575 } 576 577 578 582 private boolean equalVerificationTypes(VerificationType[] types1, 583 VerificationType[] types2, 584 int length) 585 { 586 if (length > 0 && 587 (types1.length < length || 588 types2.length < length)) 589 { 590 return false; 591 } 592 593 for (int index = 0; index < length; index++) 594 { 595 if (!types1[index].equals(types2[index])) 596 { 597 return false; 598 } 599 } 600 601 return true; 602 } 603 } 604 | Popular Tags |