Skip to content

gtrak/no.disassemble

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
doc
 
 
 
 
 
 
 
 
 
 
 
 
 
 

nodisassemble

A Clojure library designed to let you inspect bytecode of functions and things.

Artifacts

The Most Recent Release is available on clojars

With Leiningen:

 [nodisassemble "0.1.3"]

HOWEVER, don't use it this way, let lein-nodissassemble's project middleware inject it for you.

{:plugins [[lein-nodisassemble "0.1.3"]]}

Usage

no.disassemble is the runtime library created to negotiate with the agent ClassTransformer that stores class bytes globally.

In order to use no.disassemble, add lein-nodisassemble to your :plugins, which will initialize the agent transformer and make bytecode available.

WARNING: there is no cleanup of bytecode yet, so evaling a lot would surely exhaust the heap.

user=> (require 'no.disassemble)
nil

user=> (in-ns 'no.disassemble)
#<Namespace no.disassemble>

no.disassemble=> (disassemble (fn []))
"// Compiled from NO_SOURCE_FILE (version 1.5 : 49.0, super bit)\npublic final class no.disassemble$eval1170$fn__1171 extends clojure.lang.AFunction {\n  \n  // Method descriptor #7 ()V\n  // Stack: 0, Locals: 0\n  public static {};\n    0  return\n      Line numbers:\n        [pc: 0, line: 1]\n  \n  // Method descriptor #7 ()V\n  // Stack: 1, Locals: 1\n  public disassemble$eval1170$fn__1171();\n    0  aload_0\n    1  invokespecial clojure.lang.AFunction() [10]\n    4  return\n      Line numbers:\n        [pc: 0, line: 1]\n  \n  // Method descriptor #12 ()Ljava/lang/Object;\n  // Stack: 1, Locals: 1\n  public java.lang.Object invoke();\n    0  aconst_null\n    1  areturn\n      Line numbers:\n        [pc: 0, line: 1]\n      Local variable table:\n        [pc: 0, pc: 1] local: this index: 0 type: java.lang.Object\n\n}"

no.disassemble=> (println (disassemble (fn [])))
// Compiled from NO_SOURCE_FILE (version 1.5 : 49.0, super bit)
public final class no.disassemble$eval1174$fn__1175 extends clojure.lang.AFunction {
  
  // Method descriptor #7 ()V
  // Stack: 0, Locals: 0
  public static {};
    0  return
      Line numbers:
        [pc: 0, line: 1]
  
  // Method descriptor #7 ()V
  // Stack: 1, Locals: 1
  public disassemble$eval1174$fn__1175();
    0  aload_0
    1  invokespecial clojure.lang.AFunction() [10]
    4  return
      Line numbers:
        [pc: 0, line: 1]
  
  // Method descriptor #12 ()Ljava/lang/Object;
  // Stack: 1, Locals: 1
  public java.lang.Object invoke();
    0  aconst_null
    1  areturn
      Line numbers:
        [pc: 0, line: 1]
      Local variable table:
        [pc: 0, pc: 1] local: this index: 0 type: java.lang.Object

}
nil
no.disassemble=> 

You can also manipulate the disassembly as a Clojure data structure:

user=> (-> (fn []) disassemble-data pprint)
{:minor-version 0,
 :superclass-name clojure/lang/AFunction,
 :class? true,
 :major-version 49,
 :name user$eval1321$fn__1322,
 :interface-names [],
 :methods
 ({:access-flags #{:public :static},
   :name <clinit>,
   :clinit? true,
   :deprecated? false,
   :code
   {:max-locals 0,
    :max-stack 0,
    :line-numbers {0 1},
    :local-variables nil,
    :exception-table (),
    :raw-bytecode [-79],
    :bytecode [[:return 0]],
    :code-length 1},
   :descriptor "()V",
   :constructor? false,
   :exception nil,
   :synthetic? false}
  {:access-flags #{:public},
   :name <init>,
   :clinit? false,
   :deprecated? false,
   :code
   {:max-locals 1,
    :max-stack 1,
    :line-numbers {0 1},
    :local-variables nil,
    :exception-table (),
    :raw-bytecode [42, -73, 0, 10, -79],
    :bytecode
    [[:aload_0 0]
     [:invokespecial
      1
      10
      {:kind :methodref,
       :class-name "clojure/lang/AFunction",
       :method-name "<init>",
       :method-descriptor "()V"}]
     [:return 4]],
    :code-length 5},
   :descriptor "()V",
   :constructor? true,
   :exception nil,
   :synthetic? false}
  {:access-flags #{:public},
   :name invoke,
   :clinit? false,
   :deprecated? false,
   :code
   {:max-locals 1,
    :max-stack 1,
    :line-numbers {0 1},
    :local-variables
    ({:name this,
      :descriptor "Ljava/lang/Object;",
      :length 1,
      :start-pc 0}),
    :exception-table (),
    :raw-bytecode [1, -80],
    :bytecode [[:aconst_null 0] [:areturn 1]],
    :code-length 2},
   :descriptor "()Ljava/lang/Object;",
   :constructor? false,
   :exception nil,
   :synthetic? false}),
 :attributes
 ("NO_SOURCE_FILE"
  {:type org.eclipse.jdt.internal.core.util.ClassFileAttribute,
   :name "SourceDebugExtension",
   :length 94}),
 :fields (),
 :interface? false}
  • It can even disassemble itself
    no.disassemble=> (println (disassemble disassemble))
    // Compiled from disassemble.clj (version 1.5 : 49.0, super bit)
    public final class no.disassemble$disassemble extends clojure.lang.AFunction {
      
      // Field descriptor #7 Lclojure/lang/Var;
      public static final clojure.lang.Var const__0;
      
      // Field descriptor #7 Lclojure/lang/Var;
      public static final clojure.lang.Var const__1;
      
      // Field descriptor #7 Lclojure/lang/Var;
      public static final clojure.lang.Var const__2;
      
      // Field descriptor #7 Lclojure/lang/Var;
      public static final clojure.lang.Var const__3;
      
      // Field descriptor #7 Lclojure/lang/Var;
      public static final clojure.lang.Var const__4;
      
      // Field descriptor #13 Lclojure/lang/Keyword;
      public static final clojure.lang.Keyword const__5;
      
      // Field descriptor #7 Lclojure/lang/Var;
      public static final clojure.lang.Var const__6;
      
      // Field descriptor #16 Lclojure/lang/KeywordLookupSite;
      static final clojure.lang.KeywordLookupSite __site__0__;
      
      // Field descriptor #18 Lclojure/lang/ILookupThunk;
      static clojure.lang.ILookupThunk __thunk__0__;
      
      // Method descriptor #20 ()V
      // Stack: 4, Locals: 0
      public static {};
          0  ldc  [22]
          2  ldc  [24]
          4  invokestatic clojure.lang.RT.var(java.lang.String, java.lang.String) : clojure.lang.Var [30]
          7  checkcast clojure.lang.Var [32]
         10  putstatic no.disassemble$disassemble.const__0 : clojure.lang.Var [34]
         13  ldc  [36]
         15  ldc  [38]
         17  invokestatic clojure.lang.RT.var(java.lang.String, java.lang.String) : clojure.lang.Var [30]
         20  checkcast clojure.lang.Var [32]
         23  putstatic no.disassemble$disassemble.const__1 : clojure.lang.Var [40]
         26  ldc  [36]
         28  ldc  [42]
         30  invokestatic clojure.lang.RT.var(java.lang.String, java.lang.String) : clojure.lang.Var [30]
         33  checkcast clojure.lang.Var [32]
         36  putstatic no.disassemble$disassemble.const__2 : clojure.lang.Var [44]
         39  ldc  [36]
         41  ldc  [46]
         43  invokestatic clojure.lang.RT.var(java.lang.String, java.lang.String) : clojure.lang.Var [30]
         46  checkcast clojure.lang.Var [32]
         49  putstatic no.disassemble$disassemble.const__3 : clojure.lang.Var [48]
         52  ldc  [22]
         54  ldc  [50]
         56  invokestatic clojure.lang.RT.var(java.lang.String, java.lang.String) : clojure.lang.Var [30]
         59  checkcast clojure.lang.Var [32]
         62  putstatic no.disassemble$disassemble.const__4 : clojure.lang.Var [52]
         65  aconst_null
         66  ldc  [54]
         68  invokestatic clojure.lang.RT.keyword(java.lang.String, java.lang.String) : clojure.lang.Keyword [58]
         71  checkcast clojure.lang.Keyword [60]
         74  putstatic no.disassemble$disassemble.const__5 : clojure.lang.Keyword [62]
         77  ldc  [22]
         79  ldc  [64]
         81  invokestatic clojure.lang.RT.var(java.lang.String, java.lang.String) : clojure.lang.Var [30]
         84  checkcast clojure.lang.Var [32]
         87  putstatic no.disassemble$disassemble.const__6 : clojure.lang.Var [66]
         90  new clojure.lang.KeywordLookupSite [68]
         93  dup
         94  aconst_null
         95  ldc  [54]
         97  invokestatic clojure.lang.RT.keyword(java.lang.String, java.lang.String) : clojure.lang.Keyword [58]
        100  invokespecial clojure.lang.KeywordLookupSite(clojure.lang.Keyword) [72]
        103  dup
        104  putstatic no.disassemble$disassemble.__site__0__ : clojure.lang.KeywordLookupSite [74]
        107  putstatic no.disassemble$disassemble.__thunk__0__ : clojure.lang.ILookupThunk [76]
        110  return
          Line numbers:
            [pc: 0, line: 19]
      
      // Method descriptor #20 ()V
      // Stack: 1, Locals: 1
      public disassemble$disassemble();
        0  aload_0
        1  invokespecial clojure.lang.AFunction() [78]
        4  return
          Line numbers:
            [pc: 0, line: 19]
      
      // Method descriptor #80 (Ljava/lang/Object;)Ljava/lang/Object;
      // Stack: 9, Locals: 4
      public java.lang.Object invoke(java.lang.Object obj);
          0  getstatic no.disassemble$disassemble.const__0 : clojure.lang.Var [34]
          3  invokevirtual clojure.lang.Var.getRawRoot() : java.lang.Object [84]
          6  checkcast clojure.lang.IFn [86]
          9  getstatic no.disassemble$disassemble.const__1 : clojure.lang.Var [40]
         12  invokevirtual clojure.lang.Var.getRawRoot() : java.lang.Object [84]
         15  checkcast clojure.lang.IFn [86]
         18  aload_1 [obj]
         19  invokeinterface clojure.lang.IFn.invoke(java.lang.Object) : java.lang.Object [88] [nargs: 2]
         24  dup
         25  ifnull 40
         28  getstatic java.lang.Boolean.FALSE : java.lang.Boolean [94]
         31  if_acmpeq 41
         34  aload_1 [obj]
         35  aconst_null
         36  astore_1 [obj]
         37  goto 58
         40  pop
         41  getstatic no.disassemble$disassemble.const__2 : clojure.lang.Var [44]
         44  invokevirtual clojure.lang.Var.getRawRoot() : java.lang.Object [84]
         47  checkcast clojure.lang.IFn [86]
         50  aload_1 [obj]
         51  aconst_null
         52  astore_1 [obj]
         53  invokeinterface clojure.lang.IFn.invoke(java.lang.Object) : java.lang.Object [88] [nargs: 2]
         58  ldc  [96]
         60  invokestatic clojure.lang.Reflector.invokeNoArgInstanceMember(java.lang.Object, java.lang.String) : java.lang.Object [102]
         63  invokeinterface clojure.lang.IFn.invoke(java.lang.Object) : java.lang.Object [88] [nargs: 2]
         68  astore_2 [cls_name]
         69  getstatic no.disassemble$disassemble.const__4 : clojure.lang.Var [52]
         72  invokevirtual clojure.lang.Var.getRawRoot() : java.lang.Object [84]
         75  checkcast clojure.lang.IFn [86]
         78  invokeinterface clojure.lang.IFn.invoke() : java.lang.Object [104] [nargs: 1]
         83  aload_2 [cls_name]
         84  aconst_null
         85  astore_2 [cls_name]
         86  invokestatic clojure.lang.RT.get(java.lang.Object, java.lang.Object) : java.lang.Object [107]
         89  astore_3 [bytecode]
         90  new org.eclipse.jdt.internal.core.util.Disassembler [109]
         93  dup
         94  invokespecial org.eclipse.jdt.internal.core.util.Disassembler() [110]
         97  ldc  [112]
         99  iconst_3
        100  anewarray java.lang.Object [114]
        103  dup
        104  iconst_0
        105  aload_3 [bytecode]
        106  aconst_null
        107  astore_3 [bytecode]
        108  aastore
        109  dup
        110  iconst_1
        111  ldc  [116]
        113  aastore
        114  dup
        115  iconst_2
        116  getstatic no.disassemble$disassemble.__thunk__0__ : clojure.lang.ILookupThunk [76]
        119  dup
        120  getstatic no.disassemble$disassemble.const__6 : clojure.lang.Var [66]
        123  invokevirtual clojure.lang.Var.getRawRoot() : java.lang.Object [84]
        126  dup_x2
        127  invokeinterface clojure.lang.ILookupThunk.get(java.lang.Object) : java.lang.Object [120] [nargs: 2]
        132  dup_x2
        133  if_acmpeq 140
        136  pop
        137  goto 162
        140  swap
        141  pop
        142  dup
        143  getstatic no.disassemble$disassemble.__site__0__ : clojure.lang.KeywordLookupSite [74]
        146  swap
        147  invokeinterface clojure.lang.ILookupSite.fault(java.lang.Object) : clojure.lang.ILookupThunk [126] [nargs: 2]
        152  dup
        153  putstatic no.disassemble$disassemble.__thunk__0__ : clojure.lang.ILookupThunk [76]
        156  swap
        157  invokeinterface clojure.lang.ILookupThunk.get(java.lang.Object) : java.lang.Object [120] [nargs: 2]
        162  aastore
        163  invokestatic clojure.lang.Reflector.invokeInstanceMethod(java.lang.Object, java.lang.String, java.lang.Object[]) : java.lang.Object [130]
        166  areturn
          Line numbers:
            [pc: 0, line: 19]
            [pc: 0, line: 21]
            [pc: 9, line: 21]
            [pc: 9, line: 21]
            [pc: 9, line: 21]
            [pc: 41, line: 21]
            [pc: 69, line: 22]
            [pc: 69, line: 22]
            [pc: 90, line: 23]
            [pc: 116, line: 23]
          Local variable table:
            [pc: 69, pc: 166] local: cls_name index: 2 type: java.lang.Object
            [pc: 90, pc: 166] local: bytecode index: 3 type: java.lang.Object
            [pc: 0, pc: 166] local: this index: 0 type: java.lang.Object
            [pc: 0, pc: 166] local: obj index: 1 type: java.lang.Object
      
      // Method descriptor #137 (ILclojure/lang/ILookupThunk;)V
      // Stack: 1, Locals: 3
      public void swapThunk(int arg0, clojure.lang.ILookupThunk arg1);
         0  iload_1
         1  tableswitch default: 27
              case 0: 20
        20  aload_2
        21  putstatic no.disassemble$disassemble.__thunk__0__ : clojure.lang.ILookupThunk [76]
        24  goto 27
        27  return
    
    
    }
    nil
    no.disassemble=> 

License

Copyright © 2013 Gary Trakhman

Distributed under the Eclipse Public License, the same as Clojure.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •