1+ const opcodeNames = require ( "./opcodeNames" ) ;
12module . exports = {
2- disassemble, parseClassFile
3+ disassemble,
4+ parseClassFile,
35} ;
46
57function disassemble ( ast , constantPool ) {
@@ -49,7 +51,7 @@ function disassemble(ast, constantPool) {
4951 return {
5052 className,
5153 name : nameAndType . name ,
52- descriptor : nameAndType . descriptor
54+ descriptor : nameAndType . descriptor ,
5355 } ;
5456 }
5557 return null ;
@@ -63,7 +65,7 @@ function disassemble(ast, constantPool) {
6365 return {
6466 className,
6567 name : nameAndType . name ,
66- descriptor : nameAndType . descriptor
68+ descriptor : nameAndType . descriptor ,
6769 } ;
6870 }
6971 return null ;
@@ -77,7 +79,7 @@ function disassemble(ast, constantPool) {
7779 return {
7880 className,
7981 name : nameAndType . name ,
80- descriptor : nameAndType . descriptor
82+ descriptor : nameAndType . descriptor ,
8183 } ;
8284 }
8385 return null ;
@@ -89,13 +91,12 @@ function disassemble(ast, constantPool) {
8991 class : {
9092 0x0001 : "public" ,
9193 0x0010 : "final" ,
92- 0x0020 : "super" ,
9394 0x0200 : "interface" ,
9495 0x0400 : "abstract" ,
9596 0x1000 : "synthetic" ,
9697 0x2000 : "annotation" ,
9798 0x4000 : "enum" ,
98- 0x8000 : "module"
99+ 0x8000 : "module" ,
99100 } ,
100101 method : {
101102 0x0001 : "public" ,
@@ -109,7 +110,7 @@ function disassemble(ast, constantPool) {
109110 0x0100 : "native" ,
110111 0x0400 : "abstract" ,
111112 0x0800 : "strictfp" ,
112- 0x1000 : "synthetic"
113+ 0x1000 : "synthetic" ,
113114 } ,
114115 field : {
115116 0x0001 : "public" ,
@@ -120,8 +121,8 @@ function disassemble(ast, constantPool) {
120121 0x0040 : "volatile" ,
121122 0x0080 : "transient" ,
122123 0x1000 : "synthetic" ,
123- 0x4000 : "enum"
124- }
124+ 0x4000 : "enum" ,
125+ } ,
125126 } ;
126127
127128 for ( const flag in flagMap [ context ] ) {
@@ -141,15 +142,21 @@ function disassemble(ast, constantPool) {
141142 const classAccess = getAccessFlags ( ast . accessFlags , "class" ) ;
142143 const className = ast . className ;
143144 const superClassName = ast . superClassName ;
144- output . push ( `${ classAccess } class ${ className } extends ${ superClassName } {` ) ;
145+ let classDecl = `${ classAccess } class ${ className } ` ;
146+ if ( superClassName && superClassName !== "java.lang.Object" ) {
147+ classDecl += ` extends ${ superClassName } ` ;
148+ }
149+ output . push ( classDecl + " {" ) ;
145150
146151 // Fields
147- for ( const field of ast . fields ) {
148- const fieldAccess = getAccessFlags ( field . accessFlags , "field" ) ;
149- const fieldDescriptor = field . descriptor ;
150- output . push ( ` ${ fieldDescriptor } ${ field . name } ;` ) ;
152+ if ( ast . fields . length > 0 ) {
153+ for ( const field of ast . fields ) {
154+ const fieldAccess = getAccessFlags ( field . accessFlags , "field" ) ;
155+ const fieldDescriptor = field . descriptor ;
156+ output . push ( ` ${ fieldAccess } ${ fieldDescriptor } ${ field . name } ;` ) ;
157+ }
158+ output . push ( "" ) ;
151159 }
152- output . push ( "" ) ;
153160
154161 // Methods
155162 for ( const method of ast . methods ) {
@@ -158,27 +165,34 @@ function disassemble(ast, constantPool) {
158165 const methodName = method . name ;
159166 const exceptions = method . exceptions ;
160167
161- // Simplify method signature for display purposes
162- const returnType = methodDescriptor . substring (
163- methodDescriptor . lastIndexOf ( ")" ) + 1
164- ) ;
165- const methodSignature = `${ methodAccess } ${ returnType } ${ methodName } (${ methodDescriptor . substring (
166- 1 ,
167- methodDescriptor . lastIndexOf ( ")" )
168- ) } );`;
168+ let methodSignature ;
169+ if ( methodName === "<init>" ) {
170+ methodSignature = ` ${ methodAccess } ${ className } (${ methodDescriptor . substring (
171+ 1 ,
172+ methodDescriptor . lastIndexOf ( ")" )
173+ ) } );`;
174+ } else {
175+ const returnType = methodDescriptor . substring (
176+ methodDescriptor . lastIndexOf ( ")" ) + 1
177+ ) ;
178+ const args = methodDescriptor . substring (
179+ 1 ,
180+ methodDescriptor . lastIndexOf ( ")" )
181+ ) ;
182+ methodSignature = ` ${ methodAccess } ${ returnType } ${ methodName } (${ args } );` ;
183+ }
169184
170- let methodLine = ` ${ methodSignature } ` ;
171185 if ( exceptions && exceptions . length > 0 ) {
172- methodLine += ` throws ${ exceptions . join ( ", " ) } ` ;
186+ methodSignature += ` throws ${ exceptions . join ( ", " ) } ` ;
173187 }
174- output . push ( methodLine ) ;
188+ output . push ( methodSignature ) ;
175189
176190 // Output Code:
177191 if ( method . code ) {
192+ output . push ( " Code:" ) ;
178193 const codeOutput = processMethod ( method ) ;
179- codeOutput . split ( "\n" ) . forEach ( ( line ) => output . push ( ` ${ line } ` ) ) ;
194+ codeOutput . split ( "\n" ) . forEach ( ( line ) => output . push ( ` ${ line } ` ) ) ;
180195 }
181- output . push ( "" ) ;
182196 }
183197
184198 output . push ( "}" ) ;
@@ -198,19 +212,24 @@ function disassemble(ast, constantPool) {
198212 let line = `${ pc } : ${ opcodeName } ` ;
199213
200214 // Process operands
201- if ( opcodeName === "tableswitch" ) {
215+ if ( opcodeName === "wide" ) {
216+ const wideOpcodeName = opcodeNames [ operands . modifiedOpcode ] ;
217+ line = `${ pc } : ${ wideOpcodeName } _w ${ operands . index } ` ;
218+ if ( operands . info && "const" in operands . info ) {
219+ line += `, ${ operands . info . const } ` ;
220+ }
221+ } else if ( opcodeName === "tableswitch" ) {
202222 // Handle 'tableswitch'
203- line += " { // " ;
204- line += `${ operands . low } to ${ operands . high } ` ;
223+ line += ` { // ${ operands . low } to ${ operands . high } ` ;
205224 output . push ( line ) ;
206225
207226 for ( let i = 0 ; i < operands . jumpOffsets . length ; i ++ ) {
208227 const value = operands . low + i ;
209228 const targetPc = operands . jumpOffsets [ i ] ;
210- output . push ( ` res ${ value } : ${ targetPc } ` ) ;
229+ output . push ( ` ${ value } : ${ targetPc } ` ) ;
211230 }
212231 const defaultPc = operands . default ;
213- output . push ( ` default: ${ defaultPc } ` ) ;
232+ output . push ( ` default: ${ defaultPc } ` ) ;
214233 output . push ( " }" ) ;
215234 continue ;
216235 } else if (
@@ -233,7 +252,7 @@ function disassemble(ast, constantPool) {
233252 "new" ,
234253 "anewarray" ,
235254 "checkcast" ,
236- "instanceof"
255+ "instanceof" ,
237256 ] . includes ( opcodeName )
238257 ) {
239258 const index = operands . index ;
@@ -310,8 +329,8 @@ function disassemble(ast, constantPool) {
310329
311330 // Output exception table
312331 if ( method . code . exceptionTable && method . code . exceptionTable . length > 0 ) {
313- output . push ( "Exception table:" ) ;
314- output . push ( " from to target type" ) ;
332+ output . push ( " Exception table:" ) ;
333+ output . push ( " from to target type" ) ;
315334 for ( const exception of method . code . exceptionTable ) {
316335 const startPc = exception . start_pc ;
317336 const endPc = exception . end_pc ;
@@ -322,7 +341,7 @@ function disassemble(ast, constantPool) {
322341 catchTypeName = getClassName ( catchTypeIndex ) ;
323342 }
324343 output . push (
325- ` ${ startPc } ${ endPc } ${ handlerPc } Class ${ catchTypeName } `
344+ ` ${ startPc } ${ endPc } ${ handlerPc } Class ${ catchTypeName } `
326345 ) ;
327346 }
328347 }
@@ -333,7 +352,6 @@ function disassemble(ast, constantPool) {
333352 return output . join ( "\n" ) ;
334353}
335354
336-
337355function parseClassFile ( jsonObject , opcodeNames ) {
338356 const cpEntries = jsonObject . constant_pool . entries ;
339357 const constantPool = [ ] ; // Use 1-based indexing for constant pool
@@ -378,7 +396,7 @@ function parseClassFile(jsonObject, opcodeNames) {
378396 return {
379397 className,
380398 name : nameAndType . name ,
381- descriptor : nameAndType . descriptor
399+ descriptor : nameAndType . descriptor ,
382400 } ;
383401 }
384402 return null ;
@@ -392,7 +410,7 @@ function parseClassFile(jsonObject, opcodeNames) {
392410 return {
393411 className,
394412 name : nameAndType . name ,
395- descriptor : nameAndType . descriptor
413+ descriptor : nameAndType . descriptor ,
396414 } ;
397415 }
398416 return null ;
@@ -406,7 +424,7 @@ function parseClassFile(jsonObject, opcodeNames) {
406424 return {
407425 className,
408426 name : nameAndType . name ,
409- descriptor : nameAndType . descriptor
427+ descriptor : nameAndType . descriptor ,
410428 } ;
411429 }
412430 return null ;
@@ -421,7 +439,7 @@ function parseClassFile(jsonObject, opcodeNames) {
421439 fields : [ ] ,
422440 methods : [ ] ,
423441 major_version : jsonObject . major_version ,
424- minor_version : jsonObject . minor_version
442+ minor_version : jsonObject . minor_version ,
425443 } ;
426444
427445 // Resolve source file name
@@ -439,7 +457,7 @@ function parseClassFile(jsonObject, opcodeNames) {
439457 ast . fields . push ( {
440458 name : fieldName ,
441459 descriptor : fieldDescriptor ,
442- accessFlags : field . access_flags
460+ accessFlags : field . access_flags ,
443461 } ) ;
444462 }
445463
@@ -452,7 +470,7 @@ function parseClassFile(jsonObject, opcodeNames) {
452470 descriptor : methodDescriptor ,
453471 accessFlags : method . access_flags ,
454472 code : null ,
455- exceptions : [ ]
473+ exceptions : [ ] ,
456474 } ;
457475
458476 // Find the Code attribute
@@ -463,21 +481,17 @@ function parseClassFile(jsonObject, opcodeNames) {
463481 const codeInfo = codeAttr . info ;
464482 const instructions = [ ] ;
465483 let pc = 0 ;
466-
467484 for ( const inst of codeInfo . code . instructions ) {
468485 const opcode = inst . instruction . opcode ;
469486 const opcodeInfo = inst . instruction . info || { } ;
470- const opcodeLength = opcodeInfo . length || 1 ;
471-
472487 const instruction = {
473488 pc,
474489 opcode,
475- opcodeName : opcodeNames [ opcode ] , // To be resolved later
490+ opcodeName : opcodeNames [ opcode ] ,
476491 operands : opcodeInfo ,
477- comment : null
492+ comment : null ,
478493 } ;
479494
480- // Resolve operands for specific opcodes
481495 if ( "index" in opcodeInfo ) {
482496 const index = opcodeInfo . index ;
483497 if (
@@ -486,7 +500,6 @@ function parseClassFile(jsonObject, opcodeNames) {
486500 opcode === 180 ||
487501 opcode === 181
488502 ) {
489- // getstatic, putstatic, getfield, putfield
490503 const fieldRef = getFieldRef ( index ) ;
491504 instruction . comment = `Field ${ fieldRef . className } .${ fieldRef . name } :${ fieldRef . descriptor } ` ;
492505 } else if (
@@ -495,7 +508,6 @@ function parseClassFile(jsonObject, opcodeNames) {
495508 opcode === 184 ||
496509 opcode === 185
497510 ) {
498- // invokevirtual, invokespecial, invokestatic, invokeinterface
499511 const methodRef =
500512 opcode === 185
501513 ? getInterfaceMethodRef ( index )
@@ -507,11 +519,9 @@ function parseClassFile(jsonObject, opcodeNames) {
507519 opcode === 192 ||
508520 opcode === 193
509521 ) {
510- // new, anewarray, checkcast, instanceof
511522 const className = getClassName ( index ) ;
512523 instruction . comment = `Class ${ className } ` ;
513524 } else if ( opcode === 18 || opcode === 19 || opcode === 20 ) {
514- // ldc, ldc_w, ldc2_w
515525 const cpEntry = constantPool [ index ] ;
516526 if ( cpEntry ) {
517527 if ( cpEntry . tag === 8 ) {
@@ -527,14 +537,20 @@ function parseClassFile(jsonObject, opcodeNames) {
527537 }
528538 }
529539 } else if ( opcode === 197 ) {
530- // multianewarray
531540 const className = getClassName ( index ) ;
532541 instruction . comment = `Class ${ className } ` ;
533542 }
534543 }
535544
536545 instructions . push ( instruction ) ;
537- pc += opcodeLength ; // Simplification; in reality, instruction lengths vary
546+ let opcodeLength = opcodeInfo . length ;
547+ if ( opcodeInfo . length === undefined ) {
548+ opcodeLength = 1 ;
549+ }
550+ if ( opcode === 0xc4 ) {
551+ opcodeLength ++ ;
552+ }
553+ pc += opcodeLength ;
538554 }
539555
540556 methodInfo . code = {
@@ -543,7 +559,7 @@ function parseClassFile(jsonObject, opcodeNames) {
543559 codeLength : codeInfo . code_length ,
544560 instructions,
545561 exceptionTable : codeInfo . exception_table ,
546- attributes : codeInfo . attributes
562+ attributes : codeInfo . attributes ,
547563 } ;
548564 }
549565
0 commit comments