at.dms.kjc.CBinaryClass
. It is quite difficult to handle member
classes correctly when they come from a pre-compiled library, since to my
knowledge there is no official standard on how to compile member classes
to .class files. CBinaryClass contained an assertion that is clearly not
valid in all cases; in this particular case, KopiSusu didn't correctly
understand an inner class (java.lang.ref.Reference$1
) in
Sun's rt.jar, which is an empty inner class that is only used to implement
access to a private constructor from a class that is allowed to access it
according to the Java Language Specification, but not according to the
Java Virtual Machine Specification.
at.dms.kjc.JClassDeclaration.constructDefaultContructor
:
access modifiers should be the same as the public/private/protected modifiers
of the class for which the default constructor is generated.
at.dms.kjc.CSourceMethod
method genCode() renamed to
genBodyCode
at.dms.kjc.CMethod
method genCode(CodeSequence,boolean)
renamed genCallCode.
at.dms.kjc.
JClassFieldExpression, JMethodCallExpression,
JNewObjectExpression, CSourceMethod: changed calls to C[Source]Method.genCode
when necessary because of above two changes.
at.dms.kjc.CSourceMethod
: added property
explicitlyInvokedConstructor
at.dms.kjc.CConstructorBlock
: sets the
CSourceMethod.explicitlyInvoikedConstructor property to the constructor
method that is explicitly invoked in the block using a this()
or
super()
expression, or an implicit explicit invocation
inserted by the compiler.
at.dms.kjc.JClassDeclaration
: added method
checkCycicalConstructor
and code to
check whether constructors invoke other constructors in cycles, which would
result in infinite recursion.
JClassDeclaration
and JInterfaceDeclaration
: when
checking for cycles in extends or implements clauses, added checks for
extending or implementing a class'es own member classes.
CClass
: added descendsFromInside method that checks
whether a class is declared inside the body of another class, or whether
one of the super class or implemented interfaces of the member class or
interface or implemented interfaces is declared inside the body of the other
class. This is necessary to detect cycles in the inheritence of classes or
interfaces.
In CContext, CClassNameType, CClassContext, CBlockContext,
CMethodContext, CCompilationUnitContext, CClass, CCompilationUnit,
CTopLevel
: added checking of access restrictions when when looking up
classes and member classes inside classes. When refering to a member class
with a simple name, and more than one member class matches the simple name,
but only one member class is actually accessible from the context that
refers to the member class, then this is ambiguous type name reference.
class SuperClass implements Interface {
private static class Inner {}
}
interface Interface {
class Inner {}
}
class SubClass extends SuperClass {
Inner field;
}
In this case, the field field in subclass is of the type
Interface.Inner
, and compilation should not result in
an error.
at.dms.classfile.ClassPath,
at.dms.classfile.SourceDescription (new file),
at.dms.classfile.ClassDirectory, at.dms.classfile.DirClassDirectory,
at.dms.classfile.ZipClassDirectory, at.dms.kjc.CTopLevel,
at.dms.kjc.Compiler, at.dms.kjc.Main
: added support for loading
source files from the classpath.
JPostFixExpression, JPrefixExpression
: don't evaluate
expression as 'left-side'; that violates the definite assignment rules.
genCode
method in
JExplicitConstructorInvocation
to match the changed
parameter order with respect to the outer-this parameter and synthethic
parameters.
CSourceMethod, JNewObjectExpression,
JExplicitConstructorInvocation
:
Fixed subclassing private member classes with private constructors by other
private member classes in the same class.
Kjc.g
: when creating JExplicitConstructorInvocation, don't
pass it null as prefix, but the real prefix.
JExplicitConstructorInvocation
: make prefixes to explicit
constructor invocations work.
JNewObjectExpression
: refactored code generation.
Fixed in at/dms/kjc/CTopLevel.java, at/dms/kjc/CBinaryClass.java,
at/dms/kjc/CClassType.java, at/dms/kjc/CClassNameType.java
Found out why kjc-1.4F would compile
try { String s; } catch (Blah i) { String s; }
and
Ksusu-1.9b2 wouldn't: KJC allowed shadowing of local vars in blocks, but the
JLS doesn't.
java.lang.Error
are
implicitly assumed to be throwable by any code; only a completely empty
try clause (try {} catch ...
) cannot throw any exceptions.
This extension correctly analyses code reachability in cases such as:
try {
int i = 5;
int j = 0;
int k = i / j;
}
catch (ClassCastException e) {
// Unreachable
}
and
class SubClassedException
extends ArithmeticException
{
SubClassedException() { super(); }
}
try {
int i = 5;
int j = 0;
int k = i / j;
}
catch (SubClassedException e) {
// Unreachable, only exact class ArithmeticException can be thrown
// by integer division.
}
catch (ArithmeticException e) {
// Reachable.
}
This does not change the rules of checked versus unchecked exceptions. A method does not have to declare unchecked exceptions, but it also not correct to catch unchecked exceptions that cannot be thrown.
Instead of always labeling the target of a continue
or break
immediately when the break or continue statement is
analyzed, this is now done using the at.dms.kjc.CContext
mechanism.
To implement this, code has been added to CAbstractBodyContext
and subclasses to hold off marking the target of a break or continue until
it is certain that the break or continue cannot be interrupted by a
finally
clause that does not complete normally.
This detects unreachable code in more cases, in accordance with the JLS.
Example of illegal java code:
void test()
{
foo: try {
break foo;
}
finally {
return;
}
int i = 42; // Unreachable.
}
void test2()
{
do {
try {
continue;
}
finally {
return;
}
} while (false);
int i = 42; // Unreachable.
}
Fixed bug in JDoStatement: if the do statement is the target of a
continue
statement, then if the condition of the do statement is
not constant and true
, the do statement can complete normally,
even if the body of the do loop cannot complete normally.
Class-field expressions are considered constant expressions
when the field is final, and the expression is of the form
TypeName.field
, and the initializer of the field is constant
Simple class-field expressions of the form fieldname
are constant
when the field is final and the initializer is constant.
Thanks to this fix, a few semantic bugs were discovered in the java.awt implementation of Kaffe 1.0.6.
at.dms.compiler.Scanner
, in which a
a character literal like '\V'
or '\x05'
would
be interpreted as an octal constant with a bad value. Both examples are
invalid character literals.
Fix to bug in at.dms.compiler.Scanner
and at.dms.kjc.JCharLiteral
(the bug was introduced in version 1.9b2) in which a unicode
escape sequence is being recognized and replaced by a unicode character value.
This is double work, however, because at.dms.compiler.InputBuffer
already does this; the JLS requires escapes like \u0020 to be interpreted
at any point in the source code, not only in character or string literals.
This is a valid java source file:
public\u0020class\u0020B{}
Contributed by: Dalibor Topic <robilad@yahoo.com>
Files:
compiler/src/at/dms/kjc/JTryCatchStatement.java
Files:
compiler/src/at/dms/kjc/JNewAnonymousClassExpression.java
Files:
compiler/src/at/dms/compiler/CNumericType.java
That's my favorite style. You may have yours. This style is heavily influenced by the features and limitations of the JDE environment and Java mode for Emacs. I'd have been more conservative in the changes if I knew that KOPI wasn't dead. Someone offered to convert to the GNU style. If that makes people happy, I'm for it, as long as its a consistent and reasonably readable style.
Files:
compiler/src/at/dms/kjc/JAddExpression.java
Files:
all files that do float/double arithmetic in
compiler/src/at/dms/kjc/*.java
classfile/src/at/dms/classfile/*.java
Files:
compiler/src/at/dms/kjc/JRealLiteral.java
Files:
compiler/src/at/dms/kjc/JOrdinalLiteral.java
compiler/src/at/dms/kjc/JUnaryExpression.java
java.util.Hashtable
with
java.util.Map
and java.util.HashMap
or
java.util.Set
/ java.util.HashSet
.
The latter is used when the Hashtable
was used as a set.
java.util.Vector
with
java.util.List
and java.util.ArrayList
java.util.Stack
with
java.util.LinkedList
java.util.Enumeration
with
java.util.Iterator
Files:
majority of source files.
( new File("foobar").mkdir() && false )
cannot be rewritten as ( false )
because of side effects;
neither can ( new File("foobar").mkdir() || true )
be rewritten
as ( true )
.
( false && new File("foobar").mkdir())
can be rewritten as
( false )
, though.
But officially, only a && expression with two constant operands is
a constant expression. So the optimized ( false )
must not be
considered a constant. This is not fixed yet in KopiSusu 1.9b2.
Files:
compiler/src/at/dms/kjc/JConditionalAndExpression.java
compiler/src/at/dms/kjc/JConditionalOrExpression.java
Files:
compiler/src/at/dms/kjc/CSourceMethod.java
compiler/src/at/dms/kjc/CSourceField.java
compiler/src/at/dms/kjc/JClassFieldExpression.java
compiler/src/at/dms/kjc/JMethodCallExpression.java
X.java:4: error:Cannot access method "t" [JLS 15.11.2.1]
public class X { public void test() { A a = new A(); a.t(new Integer(4)); } } class A { private void t(Number n) {} public void t(Object o) {} }
Files:
compiler/src/at/dms/kjc/CClass.java
compiler/src/at/dms/kjc/CClassContext.java
compiler/src/at/dms/kjc/CContext.java
compiler/src/at/dms/kjc/JExplicitConstructorInvocation.java
compiler/src/at/dms/kjc/JMethodCallExpression.java
compiler/src/at/dms/kjc/JNewAnonymousClassExpression.java
compiler/src/at/dms/kjc/JNewObjectExpression.java
Files:
compiler/src/at/dms/kjc/CClass.java
compiler/src/at/dms/kjc/CClassContext.java
compiler/src/at/dms/kjc/CClassNameType.java
compiler/src/at/dms/kjc/JNewObjectExpression.java
Files:
compiler/src/at/dms/kjc/Kjc.g
compiler/src/at/dms/kjc/Kjc.t
.. and all files generated from those two ..
compiler/src/at/dms/kjc/CModifier.java
compiler/src/at/dms/kjc/JClassDeclaration.java
compiler/src/at/dms/kjc/JInterfaceDeclaration.java
compiler/src/at/dms/kjc/JMemberDeclaration.java
compiler/src/at/dms/kjc/JMethodDeclaration.java
classfile/src/at/dms/classfile/Constants.java
Files:
compiler/src/at/dms/kjc/Kjc.g
compiler/src/at/dms/kjc/Kjc.t
.. and all files generated from those two ..
compiler/src/at/dms/kjc/Constants.java
Files:
compiler/src/at/dms/kjc/Kjc.g
Files:
compiler/src/at/dms/kjc/JNewAnonymousClassExpression.java
compiler/src/at/dms/kjc/JNewObjectExpression.java
compiler/src/at/dms/kjc/Kjc.g
Files:
compiler/src/at/dms/kjc/Kjc.g
compiler/src/at/dms/kjc/CSourceMethod.java
compiler/src/at/dms/kjc/JMethodClassExpression.java
Files:
compiler/src/at/dms/kjc/CMember.java
compiler/src/at/dms/kjc/CSourceClass.java
compiler/src/at/dms/kjc/JInitializerDeclaration.java
compiler/src/at/dms/kjc/JTypeDeclaration.java
public class B { public static void main(String[] args) { try { } finally { return; } } }
Effect of bug (compiled with KCJ-1.4F):
Exception in thread "main" java.lang.VerifyError:
(class: B, method: main signature: ([Ljava/lang/String;)V)
Recursive call to jsr entry
Solution: move statement code.popContext(this);
to just before
generating the code for the finally clause.
Files:
compiler/src/at/dms/kjc/JTryFinallyStatement.java
Files:
compiler/src/at/dms/kjc/CSourceClass.java
compiler/src/at/dms/kjc/CClass.java
compiler/src/at/dms/kjc/JConstructorDeclaration.java
Files:
compiler/src/at/dms/kjc/CSourceClass.java
compiler/src/at/dms/kjc/CClass.java
compiler/src/at/dms/kjc/JNewAnonymousClassExpression.java
Files:
compiler/src/at/dms/kjc/JAddExpression.java
compiler/src/at/dms/kjc/JCompountAssignmentExpression.java
Files:
classfile/src/at/dms/classfile/SwitchInstruction.java
Files:
compiler/src/at/dms/kjc/JNewObjectExpression.java
Files:
compiler/src/at/dms/kjc/JClassDeclaration.java
Files:
compiler/src/at/dms/compiler/Compiler.java
Files:
compiler/src/at/dms/compiler/CNumericType.java
Files:
compiler/src/at/dms/kjc/JConditionalExpression.java