clojure 继续深入

clojure fn 编译为一个类.
(def 的全局变量) 编译为一个 var
loading__5569__auto__.class .是 ns 宏生成的类

(defmacro with-loading-context [& body]
  `((fn loading# []   ;loading 类在这里生成的. 因为这里有个fn 每个fn 都会被编译为一个类
        (. clojure.lang.Var (pushThreadBindings {clojure.lang.Compiler/LOADER
                                                 (.getClassLoader (.getClass ^Object loading#))}))
        (try
         ~@body
         (finally
          (. clojure.lang.Var (popThreadBindings)))))))

java -jar clojure.jar -i one/one.clj 直接运行一个文件.
java -jar clojure.jar -e "(* 3 2)" 直接eval 一个字符串
这里面的核心1在 RT.init 和 RT 的static中. 把环境都初始化好了.
java -jar clojure.jar 没有直接 compile 的方法. 在文件中 加入:gen-class 在内存中生成了类.

只有调用 Compiler.compile 方法的时候 才会生成 _init 类.  直接
java -jar clojure.jar -i one/one.clj 这样运行文件 因为 RT.var 全局环境中已经有了对应的对象.  不需要init 了...

internalName1:clojure/core/specs/alpha$eval134
internalName1:user$eval136
internalName1:one$eval138$loading__6725__auto____139
internalName1:one$eval138
internalName1:one$eval142$fn__143
internalName1:one$eval142
internalName1:one$_main
internalName1:one$eval147

例如


(ns ast.compiletest
 ; (:require [])
 )
(def fenga 3)
(defn ashuchu [x]
 (+ fenga x)
 )
clojure.core__init.class 有 6000多行 . clojure.10.1.jar 中第一层有 2283个类..
 (compile 'ast.compiletest) 后 会生成一个 __init类
package ast;
import ast.compiletest.ashuchu;
import ast.compiletest.fn__27216;
import ast.compiletest.loading__6721__auto____27214;
import clojure.lang.AFn;
import clojure.lang.Compiler;
import clojure.lang.IFn;
import clojure.lang.IPersistentMap;
import clojure.lang.LockingTransaction;
import clojure.lang.PersistentList;
import clojure.lang.RT;
import clojure.lang.Symbol;
import clojure.lang.Tuple;
import clojure.lang.Var;
import java.util.Arrays;
import java.util.concurrent.Callable;

public class compiletest__init {
    public static final Var const__3;
    public static final AFn const__9;
    public static final Object const__10;

    public static void __init0() {
        const__0 = (Var)RT.var("clojure.core", "in-ns");
        const__1 = (AFn)Symbol.intern((String)null, "ast.compiletest");
        const__2 = (AFn)Symbol.intern((String)null, "clojure.core");
        const__3 = (Var)RT.var("ast.compiletest", "fenga");
        const__10 = 3L;
        const__11 = (Var)RT.var("ast.compiletest", "ashuchu");
    }
 public static void load() {
        Var var10003 = const__3;
        var10003.setMeta((IPersistentMap)const__9);
        var10003.bindRoot(const__10);
    }

    static {
        __init0();
        load();
    }
}

静态编译
简称 AOT(Ahead-Of-Time)即 提前编译 ,静态编译的程序会在执行前,会使用指定编译器,将全部代码编译成机器码。

动态解释
简称 JIT(Just-In-Time)即 即时编译 ,动态解释的程序会使用指定解释器,一边编译一边执行程序。

然而,以上这些难度,其实并非 parser 本身造成的,
人们常用的、手写的递归下降 LL(k) 解析器,已经可以解决大多数问题了。
所以,在学习 parser 之前,得先不要被它吓倒。

clojure 中每个fn 都被编译成了java的一个独立类. 方法中的内嵌方法 使用了内部类 使用$连接.
clojure 启动的时候,会使用Rt.java默默的把clojure.core中的函数类都加载到namespace中.
Symbol NameSpace Var 构成了 clojure 运行在jvm的地基.

clojure 使用Ifn 体系 让asm 把fn转化成 extend RestFn的基类

public interface IFn extends Callable, Runnable{

public Object invoke() ;

public Object invoke(Object arg1) ;

public Object invoke(Object arg1, Object arg2) ;
.......
public Object applyTo(ISeq arglist) ;

static public interface L{long invokePrim();}
static public interface D{double invokePrim();}
static public interface OL{long invokePrim(Object arg0);}
....
}

clojure.core$desc class文件 反编译代码

package clojure;

import clojure.lang.AFunction;
import clojure.lang.Numbers;

public final class core$dec extends AFunction {
    public core$dec() {
    }

    public static Object invokeStatic(Object x) {
        Object var10000 = x;
        x = null;
        return Numbers.dec(var10000);
    }

    public Object invoke(Object var1) {
        Object var10000 = var1;
        var1 = null;
        return invokeStatic(var10000);
    }
}

image.png

clojure 方法整体调用 . load-file -> eval ->analyze -> parse -> compile ->emit (里面互相递归调用)

clojure 前期开发的时候 使用了 common lisp
git checkout da14d89c
经过 88元红包在群里请教 . clisp 能运行
本次clisp 运行clojure 是在wsl ubuntu 上直接 apt install clisp 搞的.

clisp (load "clojure.lisp") (in-package "clojure")
然后把clojure.lisp中的一段代码粘贴运行. (需要先设置好文件夹和文件. )

(let ((*clojure-source-path* #p"/dev/clojure/src/lisp/")
      (*clojure-target-path* #p"/dev/clojure/classes/"))
  (compile-to :jvm "clojure.lib" "Clojure"
              "lib.lisp"))

输出的时候会提示安全问题 直接输入 continue 则会生成Clojure.java

https://hub.fastgit.org/sbcl/sbcl/tree/master/src/compiler
使用sbcl 编译器体验 下
win10 下载安装
https://download.fastgit.org/sbcl/sbcl/releases/download/sbcl-1.4.14/sbcl-1.4.14-x86-64-windows-binary.msi
命令行下
sbcl --script .\test.lisp

https://acl.readthedocs.io/en/latest/index.html

https://www.infoq.com/presentations/Design-Composition-Performance/?itm_source=infoq&itm_campaign=user_page&itm_medium=link

2021年3月18日 不小心又深入到了 chezschema racket sbcl ... nanopass

(早期的 clojure.lisp 是用sbcl . 但现在运行报错.. psil)
https://raw.fastgit.org/kanaka/mal

lisp 解释器


image.png

kanaka/mal
mal - Make a Lisp
Mal is a Clojure inspired Lisp interpreter. (语法都是从clojure中吸取的)
(超多語言都有XDD)

clojure.lisp中的 注释 #| 之间 |#
Comments
;; Single line comments start with a semicolon, and can start at any point in the line

|

This is a multi-line comment.

|

They can be nested!

|#
|#
https://stackoverflow.com/questions/2320348/symbols-in-clojure

var 的 bound 比较重要

有一个较大社区的lisp 很不容易. clojure 有力的在成长

Why Clojure over other JVM Lisps: Kawa, Armed Bear or SISC?

麻杆打狼,两头怕

struct 就是 class 就是 map {:type "onetype" :p1 3 }
根据各种具体的类型来做各种编译操作. (要深刻知道理解这三者在本质上是一样的. 这样ast 和 各种语言编译的本质抓住了. 对各种具体类型的数据做具体操作)

早期( git checkout 348f4fa0 ) Compiler 放弃了clojure.lisp 使用java 把clj代码生成了 java代码

static String compile(String ns, String className, LineNumberingPushbackReader... files) throws Exception {
    StringWriter w = new StringWriter();
    try
        {
        _CRT_OUT.pushThreadBinding(w);
        KEYWORDS.pushThreadBinding(null);
        VARS.pushThreadBinding(null);
        METHOD.pushThreadBinding(null);
        LOCAL_ENV.pushThreadBinding(null);
        FNS.pushThreadBinding(new PersistentArrayList(4));

        format("/* Generated by Clojure */~%~%");
        format("package ~A;~%", ns);
        format("import clojure.lang.*;~%~%");
        format("public class ~A{~%", className);

        PersistentArrayList forms = new PersistentArrayList(20);
        for (LineNumberingPushbackReader reader : files)
            {
            try
                {
                IMPORTS.pushThreadBinding(null);
                USES.pushThreadBinding(null);

                Object eof = new Object();
                Object form = null;

                while ((form = LispReader.read(reader, false, eof, false)) != eof)
                    {
                    form = macroexpand(form);
                    if (!(form instanceof ISeq))
                        throw new Exception("No atoms allowed at top level");
                    Object op = RT.first(form);

                    //enact import and use at compile-time
                    if (op == IMPORT)
                        {
                        //(import org.package ThisClass ThatClass ...)
                        //makes entries in IMPORTS for:
                        //"ThisClass"->"org.package.ThisClass"
                        //"ThatClass"->"org.package.ThatClass"
                        IPersistentMap importMap = (IPersistentMap) IMPORTS.getValue();
                        String pkg = RT.second(form).toString();
                        for (ISeq classes = RT.rest(RT.rest(form)); classes != null; classes = classes.rest())
                            {
                            String iclassName = classes.first().toString();
                            importMap = (IPersistentMap) RT.assoc(iclassName, pkg + "." + iclassName, importMap);
                            }
                        IMPORTS.setValue(importMap);
                        }
                    else if (op == USE)
                        {
                        //todo implement use
                        }
                    else
                        forms = forms.cons(analyze(C.STATEMENT, form));
                    }
                }
            finally
                {
                IMPORTS.popThreadBinding();
                USES.popThreadBinding();
                }
            }
        //declare static members for keywords, vars
        for (ISeq keys = RT.seq(KEYWORDS.getValue()); keys != null; keys = keys.rest())
            {
            KeywordExpr k = (KeywordExpr) ((IMapEntry) keys.first()).val();
            format("static Keyword ~A;~%", k.emitExpressionString());
            }
        for (ISeq vars = RT.seq(VARS.getValue()); vars != null; vars = vars.rest())
            {
            Var v = (Var) ((IMapEntry) vars.first()).val();
            format("static Var ~A;~%", munge(v.toString()));
            }

        //todo declare static members for syms, quoted aggregates

        //emit nested static class/method declarations for nested fns
        PersistentArrayList fns = (PersistentArrayList) FNS.getValue();
        for (int f = 0; f < fns.count(); f++)
            {
            FnExpr fn = (FnExpr) fns.nth(f);
            fn.emitDeclaration();
            }

        //define the load function
        format("public void load() throws Exception{~%");
        //init the keywords and vars
        for (ISeq keys = RT.seq(KEYWORDS.getValue()); keys != null; keys = keys.rest())
            {
            KeywordExpr k = (KeywordExpr) ((IMapEntry) keys.first()).val();
            format("~A = (Keyword)Symbol.intern(~S);~%", k.emitExpressionString(), k.sym.name);
            }
        for (ISeq vars = RT.seq(VARS.getValue()); vars != null; vars = vars.rest())
            {
            Var v = (Var) ((IMapEntry) vars.first()).val();
            format("~A = Module.intern(~S,~S);~%", munge(v.toString()), v.module.name, v.name.name);
            }
        //todo init syms and quoted aggregates
        //emit the top level forms
        for (int i = 0; i < forms.count(); i++)
            {
            Expr e = (Expr) forms.nth(i);
            e.emitStatement();
            }
        //close load function
        format("}~%");

        //close class def
        format("}~%");
        }
    catch (Exception e)
        {
        e.printStackTrace();
        }
    finally
        {
        _CRT_OUT.popThreadBinding();
        KEYWORDS.popThreadBinding();
        VARS.popThreadBinding();
        METHOD.popThreadBinding();
        LOCAL_ENV.popThreadBinding();
        FNS.popThreadBinding();
        }
    return w.toString();
}

“悦刻已经证明行业没有问题,发展方向没有问题,那产品没有做好最大的问题就是管理层,人不对,那就换人。” Thomas告诉《深网》,而本人则正式担任喜雾CEO,随后则亲自抓产品、找新的代工。
git checkout b8e4aa52
需要传的参数.
feng.one First E:\clojure\luminusweb\clojureyanjiu\src\one.clj


image.png
one.clj 内容 
(def xa 12 )
(3 2 xa)

/* Generated by Clojure */

package feng.one;
import clojure.lang.*;

public class First{
static Var clj_DSH_user_CLN_xa;
public void load() throws Exception{
clj_DSH_user_CLN_xa = Module.intern("clj-user","xa");
clj_DSH_user_CLN_xa.bind(12);
((IFn)3).invoke(2, clj_DSH_user_CLN_xa.getValue());
}
}
(def onefn  (fn (x) x))
(def xa 12 )
(3 2 xa)
(onefn 3)

/* Generated by Clojure */

package feng.one;
import clojure.lang.*;

public class First{
static Var clj_DSH_user_CLN_onefn;
static Var clj_DSH_user_CLN_xa;
static public class FN__onefn__2 extends AFn{
public Object invoke(Object x) throws Exception{
return x;
}
}
public void load() throws Exception{
clj_DSH_user_CLN_onefn = Module.intern("clj-user","onefn");
clj_DSH_user_CLN_xa = Module.intern("clj-user","xa");
clj_DSH_user_CLN_onefn.bind((new FN__onefn__2()));
clj_DSH_user_CLN_xa.bind(12);
((IFn)3).invoke(2, clj_DSH_user_CLN_xa.getValue());
((IFn)clj_DSH_user_CLN_onefn.getValue()).invoke();
}
}
 

天才设计.?

static Var clojure__assoc_if = Namespace.intern("clojure", "assoc_if");
Namespace.intern("clojure", "assoc_if").bind(new assoc_if());

/* Generated by Clojure from the following Lisp:

(defn* assoc-if ((fun alist) (assoc-if fun alist nil))
 ((fun alist keys)
  (cond ((atom? alist) nil)
   ((and (cons? (first alist)) (fun (if (:key keys) ((:key keys) (ffirst alist)) (ffirst alist)))) (first alist))
   (t (assoc-if fun (rest alist) keys)))))

*/

    static public class assoc_if extends AFn {
        public Object invoke(Object fun, Object alist) throws Exception {
            return clojure__assoc_if.fn().invoke(fun, alist, null);
        }

        public Object invoke(Object fun, Object alist, Object keys) throws Exception {
            if (clojure__atomQMARK__.fn().invoke(alist) != null) {
                return null;
            } else {
                if ((((clojure__consQMARK__.fn().invoke(clojure__first.fn().invoke(alist)) != null))
                        ? ((IFn) fun).invoke((((IFn) KEY__key).invoke(keys) != null ?
                        ((IFn) ((IFn) KEY__key).invoke(keys)).invoke(clojure__ffirst.fn().invoke(alist)) :
                        clojure__ffirst.fn().invoke(alist))) : null) != null) {
                    return clojure__first.fn().invoke(alist);
                } else {
                    return clojure__assoc_if.fn().invoke(fun, clojure__rest.fn().invoke(alist), keys);
                }
            }
        }
    }
image.png

git chekout 3ed36822 clojure 尝试了 antlr

http://uternet.github.io/TLS/10.html
good

git checkout 92075ac2 got rid of ANTLR reader 摆脱了ANTLR阅读器

git checkout 4b899d76 加入了 boot.clj
540e1195 加入了 pom.xml

2021年3月26日 终于初步明白了 一个clj fn 或宏 如何转化为一个可被jvm执行的class

static class FnExpr implements Expr{
    IPersistentCollection methods;
    //if there is a variadic overload (there can only be one) it is stored here
    FnMethod variadicMethod = null;
    String name;
    String simpleName;
    String internalName;
    Type fntype;
    //localbinding->itself
    IPersistentMap closes = PersistentHashMap.EMPTY;
    //Keyword->KeywordExpr
    IPersistentMap keywords = PersistentHashMap.EMPTY;
    IPersistentMap vars = PersistentHashMap.EMPTY;
    Class compiledClass;
    int line;

    final static Method kwintern = Method.getMethod("clojure.lang.Keyword intern(String, String)");
    final static Method symcreate = Method.getMethod("clojure.lang.Symbol create(String, String)");
    final static Method varintern = Method.getMethod("clojure.lang.Var intern(clojure.lang.Symbol)");
    final static Method afnctor = Method.getMethod("void ()");
    final static Method restfnctor = Method.getMethod("void (int)");
    final static Type aFnType = Type.getType(AFn.class);
    final static Type restFnType = Type.getType(RestFn.class);

    static Expr parse(C context, ISeq form, String name) throws Exception{
        FnExpr fn = new FnExpr();
        FnMethod enclosingMethod = (FnMethod) METHOD.get();
        String basename = enclosingMethod != null ?
                          (enclosingMethod.fn.name + "$")
                          : (munge(currentNS().name) + ".");
        fn.simpleName = (name != null ?
                         munge(name)
                         : ("fn__" + RT.nextID()));
        fn.name = basename + fn.simpleName;
        fn.internalName = fn.name.replace('.', '/');
        fn.fntype = Type.getObjectType(fn.internalName);
        try
            {
            Var.pushThreadBindings(
                    RT.map(
                            KEYWORDS, PersistentHashMap.EMPTY,
                            VARS, PersistentHashMap.EMPTY));
            //(fn [args] body...) or (fn ([args] body...) ([args2] body2...) ...)
            //turn former into latter
            if(RT.second(form) instanceof IPersistentVector)
                form = RT.list(FN, RT.rest(form));
            fn.line = (Integer) LINE.get();
            FnMethod[] methodArray = new FnMethod[MAX_POSITIONAL_ARITY + 1];
            FnMethod variadicMethod = null;
            for(ISeq s = RT.rest(form); s != null; s = RT.rest(s))
                {
                FnMethod f = FnMethod.parse(fn, (ISeq) RT.first(s));
                if(f.isVariadic())
                    {
                    if(variadicMethod == null)
                        variadicMethod = f;
                    else
                        throw new Exception("Can't have more than 1 variadic overload");
                    }
                else if(methodArray[f.reqParms.count()] == null)
                    methodArray[f.reqParms.count()] = f;
                else
                    throw new Exception("Can't have 2 overloads with same arity");
                }
            if(variadicMethod != null)
                {
                for(int i = variadicMethod.reqParms.count() + 1; i <= MAX_POSITIONAL_ARITY; i++)
                    if(methodArray[i] != null)
                        throw new Exception(
                                "Can't have fixed arity function with more params than variadic function");
                }

            IPersistentCollection methods = null;
            for(int i = 0; i < methodArray.length; i++)
                if(methodArray[i] != null)
                    methods = RT.conj(methods, methodArray[i]);
            if(variadicMethod != null)
                methods = RT.conj(methods, variadicMethod);

            fn.methods = methods;
            fn.variadicMethod = variadicMethod;
            fn.keywords = (IPersistentMap) KEYWORDS.get();
            fn.vars = (IPersistentMap) VARS.get();
            }
        finally
            {
            Var.popThreadBindings();
            }
        fn.compile();
        return fn;
    }

    boolean isVariadic(){
        return variadicMethod != null;
    }

    private void compile(){
        //create bytecode for a class
        //with name current_ns.defname[$letname]+
        //anonymous fns get names fn__id
        //derived from AFn/RestFn
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
//      ClassWriter cw = new ClassWriter(0);
        ClassVisitor cv = cw;
        //ClassVisitor cv = new TraceClassVisitor(new CheckClassAdapter(cw), new PrintWriter(System.out));
        //ClassVisitor cv = new TraceClassVisitor(cw, new PrintWriter(System.out));
        cv.visit(V1_5, ACC_PUBLIC, internalName, null, isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFn", null);
        String source = (String) SOURCE.get();
        String smap = "SMAP\n" +
                      simpleName + ".java\n" +
                      "Clojure\n" +
                      "*S Clojure\n" +
                      "*F\n" +
                      "+ 1 " + source + "\n" +
                      (String) SOURCE_PATH.get() + "\n" +
                      "*L\n" +
                      "1#1,1000:1\n" +
                      "*E";
        if(source != null && SOURCE_PATH.get() != null)
        //cv.visitSource(source, null);
            cv.visitSource(source, smap);
        //static fields for keywords
        for(ISeq s = RT.keys(keywords); s != null; s = s.rest())
            {
            Keyword k = (Keyword) s.first();
            cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, munge(k.sym.toString()),
                          KEYWORD_TYPE.getDescriptor(), null, null);
            }
        //static fields for vars
        for(ISeq s = RT.keys(vars); s != null; s = s.rest())
            {
            Var v = (Var) s.first();
            cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, munge(v.sym.toString()),
                          VAR_TYPE.getDescriptor(), null, null);
            }
        //static init for keywords and vars
        GeneratorAdapter clinitgen = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC,
                                                          Method.getMethod("void  ()"),
                                                          null,
                                                          null,
                                                          cv);
        clinitgen.visitCode();
        clinitgen.visitLineNumber(line, clinitgen.mark());
        for(ISeq s = RT.keys(keywords); s != null; s = s.rest())
            {
            Keyword k = (Keyword) s.first();
            clinitgen.push(k.sym.ns);
            clinitgen.push(k.sym.name);
            clinitgen.invokeStatic(KEYWORD_TYPE, kwintern);
            clinitgen.putStatic(fntype, munge(k.sym.toString()), KEYWORD_TYPE);
            }
        for(ISeq s = RT.keys(vars); s != null; s = s.rest())
            {
            Var v = (Var) s.first();
            clinitgen.push(v.sym.ns);
            clinitgen.push(v.sym.name);
            clinitgen.invokeStatic(SYMBOL_TYPE, symcreate);
            clinitgen.invokeStatic(VAR_TYPE, varintern);
            clinitgen.putStatic(fntype, munge(v.sym.toString()), VAR_TYPE);
            }
        clinitgen.returnValue();
        clinitgen.endMethod();
//      clinitgen.visitMaxs(1, 1);
        //instance fields for closed-overs
        for(ISeq s = RT.keys(closes); s != null; s = s.rest())
            {
            LocalBinding lb = (LocalBinding) s.first();
            cv.visitField(ACC_PUBLIC + ACC_FINAL, lb.name, OBJECT_TYPE.getDescriptor(), null, null);
            }
        //ctor that takes closed-overs and inits base + fields
        Method m = new Method("", Type.VOID_TYPE, ARG_TYPES[closes.count()]);
        GeneratorAdapter ctorgen = new GeneratorAdapter(ACC_PUBLIC,
                                                        m,
                                                        null,
                                                        null,
                                                        cv);
        ctorgen.visitCode();
        ctorgen.visitLineNumber(line, ctorgen.mark());
        ctorgen.loadThis();
        if(isVariadic()) //RestFn ctor takes reqArity arg
            {
            ctorgen.push(variadicMethod.reqParms.count());
            ctorgen.invokeConstructor(restFnType, restfnctor);
            }
        else
            ctorgen.invokeConstructor(aFnType, afnctor);
        int a = 1;
        for(ISeq s = RT.keys(closes); s != null; s = s.rest(), ++a)
            {
            LocalBinding lb = (LocalBinding) s.first();
            ctorgen.loadThis();
            ctorgen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), a);
            ctorgen.putField(fntype, lb.name, OBJECT_TYPE);
            }
        ctorgen.returnValue();
        //  ctorgen.visitMaxs(1, 1);
        ctorgen.endMethod();

        //override of invoke/doInvoke for each method
        for(ISeq s = RT.seq(methods); s != null; s = s.rest())
            {
            FnMethod method = (FnMethod) s.first();
            method.emit(this, cv);
            }
        //end of class
        cv.visitEnd();

        //define class and store feng: 此处动态生成了一个class jvm可以执行的.  
        DynamicClassLoader loader = (DynamicClassLoader) LOADER.get();
        compiledClass = loader.defineClass(name, cw.toByteArray());
    }

    public Object eval() throws Exception{
        return compiledClass.newInstance();
    }

    public void emit(C context, FnExpr fn, GeneratorAdapter gen){
        //emitting a Fn means constructing an instance, feeding closed-overs from enclosing scope, if any
        //fn arg is enclosing fn, not this
        if(context != C.STATEMENT)
            {
            gen.newInstance(fntype);
            gen.dup();
            for(ISeq s = RT.keys(closes); s != null; s = s.rest())
                {
                LocalBinding lb = (LocalBinding) s.first();
                fn.emitLocal(gen, lb);
                }
            gen.invokeConstructor(fntype, new Method("", Type.VOID_TYPE, ARG_TYPES[closes.count()]));
            }
    }

    public boolean hasJavaClass() throws Exception{
        return true;
    }

    public Class getJavaClass() throws Exception{
        return IFn.class;
    }

    private void emitLocal(GeneratorAdapter gen, LocalBinding lb){
        if(closes.containsKey(lb))
            {
            gen.loadThis();
            gen.getField(fntype, lb.name, OBJECT_TYPE);
            }
        else
            gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), lb.idx);
    }

    public void emitVar(GeneratorAdapter gen, Var var){
        gen.getStatic(fntype, munge(var.sym.toString()), VAR_TYPE);
    }

    public void emitKeyword(GeneratorAdapter gen, Keyword k){
        gen.getStatic(fntype, munge(k.sym.toString()), KEYWORD_TYPE);
    }
}

操作系统开始加载一个exe 或linux下的执行文件的时候,会给该程序 init 堆栈 空间. 后才进入 main 函数.
不然直接使用malloc 就会报错.
在main函数执行前 .需要执行 getversion() _heap_init getcommandlina setenvp _cinit

这就是一个进程堆栈的来源.是操作系统赐予的.
一条汇编指令包含的步骤. 汇编指令在语言层面可以看做是原子的. 但在cpu内部又是很多电子步骤组成的


image.png

printf 不定参数,由编译器计算 平衡堆栈


image.png

image.png

这就是在反编译其他人发布的程序的时候,大部分都是用esp..

image.png

c++ this 终于明白入门了. malloc 返回的地址 用ecx 传给了成员函数.


image.png
image.png

画的最后好的一个 push pop后 sp永远指向栈顶. 该地址保存着栈顶数据.是相等的.不是大于1 或 小于1 的.


image.png

image.png

pop 导致的栈越界

image.png

“提供机制,而非策略

系统根据 用户的数据 逐步提供完善的 操作... (feng 灵感. 这样刚开始从极为简单开始, 让系统根据数据生长. 更多的分类,更多的按钮)

“所谓了解,就是知道对方 心灵最深的地方的痛处,痛在哪里”

最后,让我们以下面这段代码来结束第一章。再好的书,再好的资料,最多只能帮助我 们少走弯路,让我们在无助时有个依靠。但是“有些事,只能一个人做。有些关,只能一个 人过。有些路啊,只能一个人走”。 while(还没读懂 ucc\examples\sc){ 阅读并上机运行 ucc\examples\sc 的代码 }

E:\clojure\luminusweb\ucc162.3 非常好的项目.里面包含了 非常好的书籍... 感恩.阿弥陀佛

jvm 分 class 文件中的常量池 和 运行时的 常量池. hotspot 有个专门的Stringtable.用来存放全局的String常量 (一种优化手段)

http://asm.itstack.org/#/notes/2.1%E7%BB%93%E6%9E%84

java class file 编译类中不包含 package 和 import 部分,因此,所有类型名字都必须是完全限定的

这个asm 的方法有点巧妙 (不好理解)

  public final FieldVisitor visitField(
      final int access,
      final String name,
      final String descriptor,
      final String signature,
      final Object value) {
    FieldWriter fieldWriter = new FieldWriter(symbolTable, access, name, descriptor, signature, value);
//理解要点 : 第一次 firstfield = lastfield  . 然后是链表了. 让每个对象的 fv 指向下一个. 
    if (firstField == null) {
      firstField = fieldWriter;
    } else {
      lastField.fv = fieldWriter;     
    }

    return lastField = fieldWriter;
  }

https://www.jianshu.com/p/cf78e68e3a99

clojure 手写的递归下降算法.在analyze中.

Go 编译器里基本上使用的都是经典的算法:经典的递归下降算法、经典的 SSA 格式的 IR 和 CFG、经典的优化算法、经典的 Lower 和代码生成,因此你可以通过一个编译器就把这些算法都贯穿起来。

你可能感兴趣的:(clojure 继续深入)