PageRenderTime 41ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/aspectj-1.6.9/aspectjtools1.6.9/org/aspectj/org/eclipse/jdt/internal/compiler/ast/Clinit.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 377 lines | 257 code | 37 blank | 83 comment | 51 complexity | 79de47e189a5ae94d9f822e9fe7c2b99 MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright (c) 2000, 2007 IBM Corporation and others.
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * IBM Corporation - initial API and implementation
  10. * Palo Alto Research Center, Incorporated - AspectJ adaptation
  11. ******************************************************************************/
  12. package org.aspectj.org.eclipse.jdt.internal.compiler.ast;
  13. import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
  14. import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
  15. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  16. import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
  17. import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.CodeStream;
  18. import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
  19. import org.aspectj.org.eclipse.jdt.internal.compiler.flow.ExceptionHandlingFlowContext;
  20. import org.aspectj.org.eclipse.jdt.internal.compiler.flow.FlowInfo;
  21. import org.aspectj.org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext;
  22. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding;
  23. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
  24. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
  30. import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortMethod;
  31. /**
  32. * AspectJ Extension added template method for subclasses to insert more code.
  33. */
  34. public class Clinit extends AbstractMethodDeclaration {
  35. private FieldBinding assertionSyntheticFieldBinding = null;
  36. private FieldBinding classLiteralSyntheticField = null;
  37. public Clinit(CompilationResult compilationResult) {
  38. super(compilationResult);
  39. modifiers = 0;
  40. selector = TypeConstants.CLINIT;
  41. }
  42. public void analyseCode(
  43. ClassScope classScope,
  44. InitializationFlowContext staticInitializerFlowContext,
  45. FlowInfo flowInfo) {
  46. if (ignoreFurtherInvestigation)
  47. return;
  48. try {
  49. ExceptionHandlingFlowContext clinitContext =
  50. new ExceptionHandlingFlowContext(
  51. staticInitializerFlowContext.parent,
  52. this,
  53. Binding.NO_EXCEPTIONS,
  54. scope,
  55. FlowInfo.DEAD_END);
  56. // check for missing returning path
  57. if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
  58. this.bits |= ASTNode.NeedFreeReturn;
  59. }
  60. // check missing blank final field initializations
  61. flowInfo = flowInfo.mergedWith(staticInitializerFlowContext.initsOnReturn);
  62. FieldBinding[] fields = scope.enclosingSourceType().fields();
  63. for (int i = 0, count = fields.length; i < count; i++) {
  64. FieldBinding field;
  65. if ((field = fields[i]).isStatic()
  66. && field.isFinal()
  67. && (!flowInfo.isDefinitelyAssigned(fields[i]))) {
  68. scope.problemReporter().uninitializedBlankFinalField(
  69. field,
  70. scope.referenceType().declarationOf(field.original()));
  71. // can complain against the field decl, since only one <clinit>
  72. }
  73. }
  74. // check static initializers thrown exceptions
  75. staticInitializerFlowContext.checkInitializerExceptions(
  76. scope,
  77. clinitContext,
  78. flowInfo);
  79. } catch (AbortMethod e) {
  80. this.ignoreFurtherInvestigation = true;
  81. }
  82. }
  83. /**
  84. * Bytecode generation for a <clinit> method
  85. *
  86. * @param classScope org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope
  87. * @param classFile org.aspectj.org.eclipse.jdt.internal.compiler.codegen.ClassFile
  88. */
  89. public void generateCode(ClassScope classScope, ClassFile classFile) {
  90. int clinitOffset = 0;
  91. if (ignoreFurtherInvestigation) {
  92. // should never have to add any <clinit> problem method
  93. return;
  94. }
  95. try {
  96. clinitOffset = classFile.contentsOffset;
  97. this.generateCode(classScope, classFile, clinitOffset);
  98. } catch (AbortMethod e) {
  99. // should never occur
  100. // the clinit referenceContext is the type declaration
  101. // All clinit problems will be reported against the type: AbortType instead of AbortMethod
  102. // reset the contentsOffset to the value before generating the clinit code
  103. // decrement the number of method info as well.
  104. // This is done in the addProblemMethod and addProblemConstructor for other
  105. // cases.
  106. if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) {
  107. // a branch target required a goto_w, restart code gen in wide mode.
  108. try {
  109. classFile.contentsOffset = clinitOffset;
  110. classFile.methodCount--;
  111. classFile.codeStream.wideMode = true; // request wide mode
  112. this.generateCode(classScope, classFile, clinitOffset);
  113. // restart method generation
  114. } catch (AbortMethod e2) {
  115. classFile.contentsOffset = clinitOffset;
  116. classFile.methodCount--;
  117. }
  118. } else {
  119. // produce a problem method accounting for this fatal error
  120. classFile.contentsOffset = clinitOffset;
  121. classFile.methodCount--;
  122. }
  123. }
  124. }
  125. /**
  126. * Bytecode generation for a <clinit> method
  127. *
  128. * @param classScope org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope
  129. * @param classFile org.aspectj.org.eclipse.jdt.internal.compiler.codegen.ClassFile
  130. */
  131. private void generateCode(
  132. ClassScope classScope,
  133. ClassFile classFile,
  134. int clinitOffset) {
  135. ConstantPool constantPool = classFile.constantPool;
  136. int constantPoolOffset = constantPool.currentOffset;
  137. int constantPoolIndex = constantPool.currentIndex;
  138. classFile.generateMethodInfoHeaderForClinit();
  139. int codeAttributeOffset = classFile.contentsOffset;
  140. classFile.generateCodeAttributeHeader();
  141. CodeStream codeStream = classFile.codeStream;
  142. this.resolve(classScope);
  143. codeStream.reset(this, classFile);
  144. TypeDeclaration declaringType = classScope.referenceContext;
  145. // initialize local positions - including initializer scope.
  146. MethodScope staticInitializerScope = declaringType.staticInitializerScope;
  147. staticInitializerScope.computeLocalVariablePositions(0, codeStream);
  148. // 1.4 feature
  149. // This has to be done before any other initialization
  150. // AspectJ Extension - move logic to helper method
  151. // was:
  152. //if (this.assertionSyntheticFieldBinding != null) {
  153. // // generate code related to the activation of assertion for this class
  154. // codeStream.generateClassLiteralAccessForType(
  155. // classScope.outerMostClassScope().enclosingSourceType(),
  156. // this.classLiteralSyntheticField);
  157. // codeStream.invokeJavaLangClassDesiredAssertionStatus();
  158. // BranchLabel falseLabel = new BranchLabel(codeStream);
  159. // codeStream.ifne(falseLabel);
  160. // codeStream.iconst_1();
  161. // BranchLabel jumpLabel = new BranchLabel(codeStream);
  162. // codeStream.decrStackSize(1);
  163. // codeStream.goto_(jumpLabel);
  164. // falseLabel.place();
  165. // codeStream.iconst_0();
  166. // jumpLabel.place();
  167. // codeStream.putstatic(this.assertionSyntheticFieldBinding);
  168. //}
  169. generateSyntheticCode(classScope, codeStream);
  170. // End AspectJ Extension
  171. // generate static fields/initializers/enum constants
  172. final FieldDeclaration[] fieldDeclarations = declaringType.fields;
  173. BlockScope lastInitializerScope = null;
  174. if (TypeDeclaration.kind(declaringType.modifiers) == TypeDeclaration.ENUM_DECL) {
  175. int enumCount = 0;
  176. int remainingFieldCount = 0;
  177. if (fieldDeclarations != null) {
  178. for (int i = 0, max = fieldDeclarations.length; i < max; i++) {
  179. FieldDeclaration fieldDecl = fieldDeclarations[i];
  180. if (fieldDecl.isStatic()) {
  181. if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
  182. fieldDecl.generateCode(staticInitializerScope, codeStream);
  183. enumCount++;
  184. } else {
  185. remainingFieldCount++;
  186. }
  187. }
  188. }
  189. }
  190. // enum need to initialize $VALUES synthetic cache of enum constants
  191. // $VALUES := new <EnumType>[<enumCount>]
  192. codeStream.generateInlinedValue(enumCount);
  193. codeStream.anewarray(declaringType.binding);
  194. if (enumCount > 0) {
  195. if (fieldDeclarations != null) {
  196. for (int i = 0, max = fieldDeclarations.length; i < max; i++) {
  197. FieldDeclaration fieldDecl = fieldDeclarations[i];
  198. // $VALUES[i] = <enum-constant-i>
  199. if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
  200. codeStream.dup();
  201. codeStream.generateInlinedValue(fieldDecl.binding.id);
  202. codeStream.getstatic(fieldDecl.binding);
  203. codeStream.aastore();
  204. }
  205. }
  206. }
  207. }
  208. codeStream.putstatic(declaringType.enumValuesSyntheticfield);
  209. if (remainingFieldCount != 0) {
  210. // if fields that are not enum constants need to be generated (static initializer/static field)
  211. for (int i = 0, max = fieldDeclarations.length; i < max; i++) {
  212. FieldDeclaration fieldDecl = fieldDeclarations[i];
  213. switch (fieldDecl.getKind()) {
  214. case AbstractVariableDeclaration.ENUM_CONSTANT :
  215. break;
  216. case AbstractVariableDeclaration.INITIALIZER :
  217. if (!fieldDecl.isStatic())
  218. break;
  219. lastInitializerScope = ((Initializer) fieldDecl).block.scope;
  220. fieldDecl.generateCode(staticInitializerScope, codeStream);
  221. break;
  222. case AbstractVariableDeclaration.FIELD :
  223. if (!fieldDecl.binding.isStatic())
  224. break;
  225. lastInitializerScope = null;
  226. fieldDecl.generateCode(staticInitializerScope, codeStream);
  227. break;
  228. }
  229. }
  230. }
  231. } else {
  232. if (fieldDeclarations != null) {
  233. for (int i = 0, max = fieldDeclarations.length; i < max; i++) {
  234. FieldDeclaration fieldDecl = fieldDeclarations[i];
  235. switch (fieldDecl.getKind()) {
  236. case AbstractVariableDeclaration.INITIALIZER :
  237. if (!fieldDecl.isStatic())
  238. break;
  239. lastInitializerScope = ((Initializer) fieldDecl).block.scope;
  240. fieldDecl.generateCode(staticInitializerScope, codeStream);
  241. break;
  242. case AbstractVariableDeclaration.FIELD :
  243. if (!fieldDecl.binding.isStatic())
  244. break;
  245. lastInitializerScope = null;
  246. fieldDecl.generateCode(staticInitializerScope, codeStream);
  247. break;
  248. }
  249. }
  250. }
  251. }
  252. // AspectJ Extension
  253. generatePostSyntheticCode(classScope, codeStream);
  254. // End AspectJ Extension
  255. if (codeStream.position == 0) {
  256. // do not need to output a Clinit if no bytecodes
  257. // so we reset the offset inside the byte array contents.
  258. classFile.contentsOffset = clinitOffset;
  259. // like we don't addd a method we need to undo the increment on the method count
  260. classFile.methodCount--;
  261. // reset the constant pool to its state before the clinit
  262. constantPool.resetForClinit(constantPoolIndex, constantPoolOffset);
  263. } else {
  264. if ((this.bits & ASTNode.NeedFreeReturn) != 0) {
  265. int before = codeStream.position;
  266. codeStream.return_();
  267. if (lastInitializerScope != null) {
  268. // expand the last initializer variables to include the trailing return
  269. codeStream.updateLastRecordedEndPC(lastInitializerScope, before);
  270. }
  271. }
  272. // Record the end of the clinit: point to the declaration of the class
  273. codeStream.recordPositionsFrom(0, declaringType.sourceStart);
  274. classFile.completeCodeAttributeForClinit(codeAttributeOffset);
  275. }
  276. }
  277. // AspectJ Extension
  278. protected void generateSyntheticCode(ClassScope classScope, CodeStream codeStream) {
  279. if (this.assertionSyntheticFieldBinding != null) {
  280. // generate code related to the activation of assertion for this class
  281. codeStream.generateClassLiteralAccessForType(
  282. classScope.outerMostClassScope().enclosingSourceType(),
  283. classLiteralSyntheticField);
  284. codeStream.invokeJavaLangClassDesiredAssertionStatus();
  285. BranchLabel falseLabel = new BranchLabel(codeStream);
  286. codeStream.ifne(falseLabel);
  287. codeStream.iconst_1();
  288. BranchLabel jumpLabel = new BranchLabel(codeStream);
  289. codeStream.decrStackSize(1);
  290. codeStream.goto_(jumpLabel);
  291. falseLabel.place();
  292. codeStream.iconst_0();
  293. jumpLabel.place();
  294. codeStream.putstatic(this.assertionSyntheticFieldBinding);
  295. }
  296. }
  297. protected void generatePostSyntheticCode(
  298. ClassScope classScope,
  299. CodeStream codeStream) {
  300. }
  301. // End AspectJ Extension
  302. public boolean isClinit() {
  303. return true;
  304. }
  305. public boolean isInitializationMethod() {
  306. return true;
  307. }
  308. public boolean isStatic() {
  309. return true;
  310. }
  311. public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
  312. //the clinit is filled by hand ....
  313. }
  314. public StringBuffer print(int tab, StringBuffer output) {
  315. printIndent(tab, output).append("<clinit>()"); //$NON-NLS-1$
  316. printBody(tab + 1, output);
  317. return output;
  318. }
  319. public void resolve(ClassScope classScope) {
  320. this.scope = new MethodScope(classScope, classScope.referenceContext, true);
  321. }
  322. public void traverse(
  323. ASTVisitor visitor,
  324. ClassScope classScope) {
  325. visitor.visit(this, classScope);
  326. visitor.endVisit(this, classScope);
  327. }
  328. public void setAssertionSupport(FieldBinding assertionSyntheticFieldBinding, boolean needClassLiteralField) {
  329. this.assertionSyntheticFieldBinding = assertionSyntheticFieldBinding;
  330. // we need to add the field right now, because the field infos are generated before the methods
  331. if (needClassLiteralField) {
  332. SourceTypeBinding sourceType =
  333. this.scope.outerMostClassScope().enclosingSourceType();
  334. // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=22334
  335. if (!sourceType.isInterface() && !sourceType.isBaseType()) {
  336. this.classLiteralSyntheticField = sourceType.addSyntheticFieldForClassLiteral(sourceType, scope);
  337. }
  338. }
  339. }
  340. }