org.glassfish.pfl.dynamic.codegen.spi.notes.txt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pfl-dynamic Show documentation
Show all versions of pfl-dynamic Show documentation
Functionality that may include class generation
#
# Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Distribution License v. 1.0, which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: BSD-3-Clause
#
Obsolete idea:
Replace _sourceCode and _ByteCode with a single _generate
method.
Idea: we usually want to end up with a class loaded in a
ClassLoader somewhere. But there are a variety of ways
to do this.
Options:
1. Generate: source, class, or both
2. generate debug or not (locals and line numbers)
3. compile source to generate bytecode
4. generate bytecode directly
5. If compiling source:
- classpath (defaults to current VM classpath)
- output dir
- source dir
Encoding as properties and method:
_generate( Properties )
// Use ORBClassLoader as default (util for context CL or system CL)
_generate( Properties, ClassLoader )
// Use PD of specified ClassLoader?
_generate( Properties, ClassLoader, ProtectionDomain ) // Do we need this?
Props (All have com.sun.corba.codegen prefix):
Generation: direct, direct_with_source, javac (default javac for now)
SourceOutputDirectory: (default cwd)
ClassOutputDirectory: (default cwd)
ClassPath: (default classpath of current VM)
Debug: on, off (default on)
Creating a default temporary directory
File defines a temp file facility, but this is only for files.
I think we want a similar directory mechanism.
We can do this as follows:
1. Use the system property java.io.tmpdir
2. create an instance of java.rmi.server.UID.
3. Stringify the UID, which looks something like:
-1cad2ab7:102d8b6f383:-8000
or
e4b375b:102d8b81237:-8000
4. Create the directory /tmp/d_ and use that for all
file generation.
5. Create /tmp/d_/src and /tmp/d_/classes for
generated source and class files.
Should we provide an API for compiling source code?
I think not. There are ways to do this already, and we
just provide a PrintStream for generating the source.
Extending the API for modifying classes.
Class, Method, Local var
ClassInfo contains mostly the correct info.
Just need to make it modifiable in the case of the
interceptor. Could change:
- modifiers
- name
- superClass
- impls
Through the ClassGenerator API:
- add fields
- add methods
- add constructors
- extend initializer
- rename existing method
- intercept field access
- intercept method call
What this really says is just add setters to the API.
How does this actually work?
new CodeGenerator()
set interceptors
byte[] modifyClass( byte[] cls )
Use ClassReader to read cls with a modifier visitor
modifier visitor:
visitClass:
- Construct a ClassGenerator corresponding to cls
- invoke class interceptor with ClassGenerator
visitMethod:
- This will need to be multi-pass
- Can change name, exceptions only
- first pass:
- record all visit calls to be replayed
- initialize slotAllocator to include all current
local variables as determined from visitLocalVariable
calls.
- can modify GETFIELD, PUTFIELD instructions through
visitFieldInsn
- can add local variables
What about JavaDoc and Annotations?
TODO:
1. Method overload resolution
PARTIAL algorithm implemented that uses simple first match.
2. More testing
3. Byte code generation for:
- switch statement
- add break
- operators in expressions
- cast, instanceof
- static field access
- array index
4. Upgrade to latest ASM (probably wait until after ASM 3.0 goes FCS).
5. Remove use of JSR/RET.
6. Revise API into:
spi.codegen: as is.
spi.codegen.tree: move AST here, allow for construction of specialized visitors
impl.codegen: source code visitor (in main branch)
impl.codegen: byte code visitor (in optional branch)
May also want to split up Wrapper to make more extensible.
7. Add support for re-opening _initializer().
8. Implement "dangling expression" handler.
I think this (now) means detect expressions that have never
been copied. We actually need to modify NodeBase.copy to simply
count the number of times copy is called. We also need to keep a
list in the ExpressionFactory of all expressions created. Then when
a block is ended, check that all expressions created have been copied,
which means they have been used somewhere. We also need to check
when an Expression is used that is was created by the correct ExpressionFactory,
or else we have an error (I don't want expression hanging around between
different blocks).
9. Implement short-circuit evaluation of boolean operators.
Note: consider implementing ternary if expression:
A && B is equivalent to A ? B : false
A || B is equivalent to A ? true : B
then add an _ifExpr( Expression cond, Expression truePart, Expression falsePart )
to Wrapper et al. Could then replace && and || directly in Wrapper with
_ifExpr.
Can we use IfStatement to implement this?
We can simple change IfStatement from
class IfStatement extends StatementBase
to
class IfStatement extends ExpressionFactory.ExpressionBase implements Statement
and IfStatement becomes an expression. The visitors would probably need some
adjustment, plus we need to deal with having a Node that is both a Statement and
an Expression (or perhaps eliminate a separate if statement?).
But this does not really work: consider
IfStatement ( Expression cond, Statement truePart, Statement falsePart )
and
IfExpression ( Expression cond, Expression truePart, Expression falsePart )
Also note that the stack is a bit different: at the end, and IfExpression leaves
a value on the stack. In any case, we just duplicate the simple logic of
IfStatement for IfExpression in ASMByteCodeVisitor. But again, I don't think this
matters.
This COULD work, if we decided to make every Statement an Expression, some of
which return void. But this is not very Java-like, and would imply changing
the current statement = void _xxx call/expression = _xxx call returning Expression
design.
10. Convert codegen test suite to TestNG.
11. Consider adding some form of enhanced for loop.
12. Make sure that we check that first statement in constructor is this or super.
13. Finish CodegenProxyCreator and replace BCEL with it.
DONE 14. Reduce/eliminate use of _v, _t. Changes to Wrapper method return types:
Type _import
Expression _data
Variable _arg
Variable _catch
Variable _define
Note that this will cause Expressions to be reused.
This means that expression need to be copied (very carefully).
This is done in NodeBase using the @Copy extensions applied to
NodeBase (attributes, parent, and delegate).
This also required a modification in ASMSetupVisitor: make sure
that requiredEmitterType is correctly set on ALL Variable nodes.
This was not done correctly in the original: it relied on setting
the value of requiredEmitterType to GETTER inside
BlockStatement.splitVariables.
NOTE: THAT IS A VERY BAD IDEA!
One of the design principles of this library is that the construction
of the AST is totally separated from its use. So any of the attributes
needed by ASMSetupVisitor and ASMByteCodeVisitor should only be set up
in those visitors. BlockStatement.splitVariables was a general piece
of code used in a specific way to support a particular visitor. BAD
DESIGN!
15. Modify IDLNameTranslator to use ClassInfo instead of Class,
and MethodInfo instead of Method.
This requires some other changes:
- StubInvocationHandlerImpl takes a method as an argument.
We need to get a MethodInfo object from the Method, and
use that in the call to IDLNameTranslator to get the giopMethodName.
We also need to base DynamicMethodMarshaller on MethodInfo instead
of Method.
- Similarly, ReflectiveTie._invoke gets a Method from the operation
name. Here we actually need a real method (but not for DMM)
for the invoke call.
Plan:
- IDLNameTranslator uses ClassInfo and MethodInfo.
- MethodInfo provides access to Method IF the MethodInfo
was derived from a Method.
- DMM only uses MethodInfo.
This then allows rmic -iiop to directly use IDLNameTranslator to
generate the appropriate names in the Stubs and Ties.
16. Ways to generate ClassInfo:
1. From java.lang.Class
2. From codegen ClassGenerator
3. From Doclet (see com.sun.javadoc)
probably want to create a FieldInfo that has implementation that
reflect java.lang.reflect.Field, impl.codegen.Field, and
com.sun.javadoc.FieldDoc (similarly use MethodDoc and ClassDoc).
(FieldInfo is in place now).
Note how closely this relates to Gilad's mirrors paper.
17. Move BCEL optimized reflective object copier to codegen
- continue optimization work
- investigate transforming ClassLoader that adds useful
bits to class for copying (precursor to fast marshalling)
Other features:
18. Line number generation and debugging support.
23. Add line number generation and verify correct line numbers.
Modify sourceStatementVisitor to annotate the AST with line number
info while generating a source file, then modify the ASM visitor
to generate the appropriate information.
Also need to generate local variable tables.
How do we verify line numbers? By using ASM visitor on class file?
24. Tests for error handling:
1. Detect dangling expressions, multiple expression use
2. Check that concrete base classes have constructors
3. check that every constructor starts with this or super
4. Check that all referenced types exist
5. Check that all type and variable names are not reserved words.
25. Consider extending model to support simultaneous generation of
more than one class (needed for mutual recursive reference
between classes).
26. Consider extending AST for manipulation/modification of existing
classes (initial generation -> continual modification)
27. Consider integration with java.lang.Instrument facilities.
28. Add Javadoc support: _javadoc( String... )
29. Support static import
30. Annotation support?
© 2015 - 2025 Weber Informatics LLC | Privacy Policy