Last active
December 7, 2018 16:42
-
-
Save bdw429s/93fb034bc613d1b758f995db3f08ef2c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<cfscript> | |
/* | |
This script will take a relative path to a CFC or CFM file in your application, analyze it's corresponding bytecode and | |
measure approximately how many Bytes of bytecode were generated for each line of your CFML code. There's not any one-to-one | |
correlation between CFML code and bytecode. Some lines of your source code generate no bytecode such as comments or whitespace. | |
Other lines of CFML code may generate hundreds of bytes of code. | |
This is more for the fun of it. It has been tested on Lucee 5.2.9.31. It will not work on Adobe and may cease to work on | |
future versions of Lucee if the BCEL library is no longer bundled by default. | |
*/ | |
// Swap this out with another file to analyze | |
param url.relativeFilePath = 'Application.cfc'; | |
// Force compioation of the template if there's not a class file yet | |
PageSourceImpl = createObject( 'java', 'lucee.runtime.PageSourceImpl' ); | |
PageSourceImpl.best( getPageContext().getPageSources( relativeFilePath ) ).loadPage( getPageContext(), true ); | |
// Get Lucee's page source object for this file | |
ps = getPageContext().getPageSource( relativeFilePath ); | |
// Init an array with each line of code from the file | |
fileMap = arrayMap( ps.getSource(), | |
function( line ) { | |
return { line : line, bytecode = 0 }; | |
} ); | |
// Load up and parse the class file. Requires the BCEL libs in your classpath, which may or may not exist depending on your Lucee version. | |
javaClass = createObject( 'java', 'org.apache.bcel.classfile.ClassParser' ).init( ps.getMapping().getClassRootDirectory() & '/' & ps.getClassName().replace( '.', '/', 'all' ) & '.class' ).parse(); | |
// A counter just to track how much bytecode we account for | |
totalbytecodeaccountedfor = 0; | |
// All methods in the class | |
// The bytecode generated from your CFML can be spread across more than one method in the bytecode depending on how big your CFC is | |
// There is a limit of 65,536 Bytes of bytecode per method in a class file | |
// NOTE THERE IS NO CORRELLATION BETWEEN CFML METHODS AND METHODS IN THE BYTECODE. | |
for( m in javaClass.getMethods() ) { | |
// We need the LineNumberTable which is stored as an attribute on the method | |
attrs = m.getCode().getAttributes(); | |
codeBytesThisMethod = arrayLen( m.getCode().getCode() ); | |
codeByteOffset = 0; | |
lastLineNo = 1; | |
// All attributes on the method | |
for( x in attrs ) { | |
// Looking for the LineNumberTable. | |
if( x.getClass().getName() == 'org.apache.bcel.classfile.LineNumberTable' ) { | |
// All lines in the line number table | |
for( l in x.getLineNumberTable() ) { | |
// The differnce between the bytecode offest start and the previous one gets added to the total for the previous CFML line | |
fileMap[ lastLineNo ].bytecode += l.getStartPC() - codeByteOffset; | |
// And also add it into the total | |
totalbytecodeaccountedfor += l.getStartPC() - codeByteOffset; | |
// Reset out pointers | |
codeByteOffset = l.getStartPC(); | |
lastLineNo = l.getLineNumber() | |
} | |
} | |
} | |
// If at least some bytecode in this method applied to CFML and this isn't the udfDefaultValue method | |
// award all remaining bytecode in the method to the last CFML line to get processed. | |
if( lastLineNo > 1 && not m.toString() contains 'udfDefaultValue' ) { | |
fileMap[ lastLineNo ].bytecode += codeBytesThisMethod - codeByteOffset; | |
totalbytecodeaccountedfor += codeBytesThisMethod - codeByteOffset; | |
} | |
} | |
</cfscript> | |
<cfoutput> | |
#round( totalbytecodeaccountedfor/1000 )#KB of bytecode accounted for below | |
<table border=1 cellspacing=0 cellpadding=2> | |
<tr> | |
<td>Bytes</td> | |
<td>Line of code</td> | |
</tr> | |
<cfloop array="#filemap#" index="line" > | |
<tr> | |
<td><cfif line.bytecode>#line.bytecode#</cfif> </td> | |
<td>#encodeForHTML( line.line.replace( ' ', ' ', 'all' ) ).replace( ' ', ' ', 'all' )#</td> | |
</tr> | |
</cfloop> | |
</table> | |
</cfoutput> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment