Package nginx.clojure

Source Code of nginx.clojure.Stack

/*
* Copyright (c) 2008, Matthias Mann
* Copyright (C) 2014, Zhang,Yuexiang (xfeep)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Matthias Mann nor the names of its
*       contributors may be used to endorse or promote products derived from
*       this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package nginx.clojure;

import java.io.Serializable;
import java.lang.reflect.Proxy;

import nginx.clojure.wave.MethodDatabase;
import nginx.clojure.wave.SuspendMethodVerifier.VerifyInfo;
import nginx.clojure.wave.SuspendMethodVerifier.VerifyMethodInfo;
import nginx.clojure.wave.SuspendMethodVerifier.VerifyVarInfo;

/**
* Internal Class - DO NOT USE !
*
* Needs to be public so that instrumented code can access it.
* ANY CHANGE IN THIS CLASS NEEDS TO BE SYNCHRONIZED WITH {@link de.matthiasmann.continuations.instrument.InstrumentMethod}
*
* @author Matthias Mann
*/
public final class Stack implements Serializable {

    private static final long serialVersionUID = 12786283751253L;
   
    private static final ThreadLocal<Stack> tls = new ThreadLocal<Stack>();
   
    private static volatile long vidCounter = 0;
   
    /** sadly this need to be here */
    public static SuspendExecution exception_instance_not_for_user_code = SuspendExecution.instance;
   
    final Coroutine co;
   
    private static  MethodDatabase db;
   
    private int methodTOS = -1;
    private int[] method;
   
    private long[] dataLong;
    private Object[] dataObject;
   
    private VerifyInfo verifyInfo;
   
    transient int curMethodSP;
   
   
    Stack(Coroutine co, int stackSize) {
        if(stackSize <= 0) {
            throw new IllegalArgumentException("stackSize");
        }
        this.co = co;
        this.method = new int[8];
        this.dataLong = new long[stackSize];
        this.dataObject = new Object[stackSize];
        if (db.isVerify()) {
          verifyInfo = new VerifyInfo();
          verifyInfo.vid = vidCounter++;
        }
    }
   
    public static VerifyInfo getVerifyInfo() {
      Stack stack = tls.get();
      if (stack == null) {
        return null;
      }
      return stack.verifyInfo;
    }
   
    public static Stack getStack() {
        return tls.get();
    }
   
    /**
     * For inner usage, Don't call it.
     */
    public static void setStack(Stack s) {
        tls.set(s);
    }
   
   
    /**
     * Called before a method is called.
     * @param entry the entry point in the method for resume
     * @param numSlots the number of required stack slots for storing the state
     */
    public final void pushMethodAndReserveSpace(int entry, int numSlots) {
     
     
        final int methodIdx = methodTOS;
       
       
        if(method.length - methodIdx < 2) {
            growMethodStack();
        }
       
        int oldDataTos = method[methodIdx+1];
        curMethodSP = method[methodIdx-1];
        int dataTOS = curMethodSP + numSlots;
       
        method[methodIdx] = entry;
        method[methodIdx+1] = dataTOS;
       
        //maybe in the same method the previous suspendable invoke finished
        if (oldDataTos > dataTOS) {
          for (int i = dataTOS; i < oldDataTos; i++) {
            dataObject[i] = null;
          }
        }
       
        if(dataTOS > dataObject.length) {
            growDataStack(dataTOS);
        }
    }
   
    public final void pushMethodAndReserveSpaceV(int entry, int numSlots, String classAndMethod) {
      int idx = methodTOS >> 1;
      pushMethodAndReserveSpace(entry, numSlots);
      if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info("#%d pushMethodAndReserveSpaceV %s, slots=%d tos=%d midx=%d sp=%d", verifyInfo.vid, classAndMethod, numSlots, methodTOS, idx, curMethodSP);
      }
        if (idx >= verifyInfo.methodIdxInfos.length -1) {
          VerifyMethodInfo[] nvmis = new VerifyMethodInfo[verifyInfo.methodIdxInfos.length << 1];
            System.arraycopy(verifyInfo.methodIdxInfos, 0, nvmis, 0, verifyInfo.methodIdxInfos.length);
            verifyInfo.methodIdxInfos = nvmis;
        }
        checkClassAndMethod(idx, "pushMethodAndReserveSpaceV", classAndMethod);
        VerifyMethodInfo vmi = verifyInfo.methodIdxInfos[idx];
        VerifyVarInfo[] mvvis = db.getVerfiyMethodInfos().get(classAndMethod)[entry-1];
        VerifyVarInfo[] vvis = new VerifyVarInfo[mvvis.length];
        for (int i = 0; i < mvvis.length; i++) {
          if (mvvis[i] != null) {
            vvis[i] = mvvis[i].clone();
          }
        }
        vmi.vars = vvis;
    }
   
    /**
     * Called at the end of a method.
     * Undoes the effects of nextMethodEntry() and clears the dataObject[] array
     * to allow the values to be GCed.
     */
    public final void popMethod() {
     
        int idx = methodTOS;
       
        int oldSP = curMethodSP;
        int newSP = method[idx-1];
        curMethodSP = newSP;
        methodTOS = idx-2;

        if (newSP == oldSP && idx < method.length -1) {
          oldSP = method[idx + 1];
        }
       
        for (int i = newSP; i < oldSP; i++) {
      dataObject[i] = null;
    }
       
        method[idx] = 0;
       
        if (idx < method.length - 1) { /*newSP == oldSP*/
          method[idx+1] = 0;
        }
    }
   
    private boolean checkClassAndMethod(int idx, String phrase,  String classAndMethod) {
      VerifyMethodInfo vmi = verifyInfo.methodIdxInfos[idx];
      if ( !classAndMethod.equals(vmi.classAndMethod) ) {
        RuntimeException re = new RuntimeException(buildMessage(this, "#%d %s tos=%d midx=%d sp=%d %s != %s", verifyInfo.vid, phrase, methodTOS, idx, curMethodSP, classAndMethod, vmi.classAndMethod));
        db.error(re);
        return false;
      }
      return true;
    }
   
    public final void popMethodV(String classAndMethod) {
      int idx = methodTOS >> 1;
      popMethod();
      if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info("#%d popMethodV %s tos=%d midx=%d sp=%d", verifyInfo.vid, classAndMethod, methodTOS, idx, curMethodSP);
      }
      checkClassAndMethod(idx, "popMethodV", classAndMethod);
      verifyInfo.methodIdxInfos[idx] = null;
    }
   
    public final int nextMethodEntryV(String classAndMethod) {
      int entry = nextMethodEntry();
      int idx = methodTOS >> 1;
      if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info("#%d nextMethodEntryV %s, entry=%d tos=%d midx=%d sp=%d", verifyInfo.vid, classAndMethod, entry, methodTOS, idx, curMethodSP);
      }
      if (entry < 0) {
      db.warn("#%d nextMethodEntry %s,tos=%d midx=%d sp=%d return -1, we meet a broken suspend methods path because of unwaved methods mingled in the path",
          verifyInfo.vid, classAndMethod, methodTOS, idx, curMethodSP);
    } else {
      if (entry == 0) {
        VerifyMethodInfo vmi = verifyInfo.methodIdxInfos[idx] = verifyInfo.tracerStacks.get(verifyInfo.tracerStacks.size() - 1);
        vmi.idx = methodTOS;
      }
      if (!checkClassAndMethod(idx, "nextMethodEntryV", classAndMethod)){
        db.error("#%d nextMethodEntryV  entry=%d tos=%d midx=%d sp=%d classAndMethod:%s", verifyInfo.vid, entry, methodTOS, idx, curMethodSP, classAndMethod);
      }
    }
      return entry;
    }
   
    /**
     * called at the begin of a method
     * @return the entry point of this method
     */
    public final int nextMethodEntry() {
      if (methodTOS > 0 && (methodTOS + 1 == method.length || method[methodTOS + 1] == 0)) {
        return -1;
      }
        int idx = methodTOS;
        curMethodSP = method[++idx];
        methodTOS = ++idx;
        return method[idx];
    }
   
    public static void push(int value, Stack s, int idx) {
        s.dataLong[s.curMethodSP + idx] = value;
    }
    public static void push(float value, Stack s, int idx) {
        s.dataLong[s.curMethodSP + idx] = Float.floatToRawIntBits(value);
    }
    public static void push(long value, Stack s, int idx) {
        s.dataLong[s.curMethodSP + idx] = value;
    }
    public static void push(double value, Stack s, int idx) {
        s.dataLong[s.curMethodSP + idx] = Double.doubleToRawLongBits(value);
    }
    public static void push(Object value, Stack s, int idx) {
        s.dataObject[s.curMethodSP + idx] = value;
    }
   
    public static void pushV(int value, Stack s, int idx, String classAndMethod) {
      int midx = s.methodTOS >> 1;
      if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info("#%d pushVInt %s, tos=%d midx=%d sp=%d idx=%d v=%d", s.verifyInfo.vid, classAndMethod, s.methodTOS, midx, s.curMethodSP, idx, value);
      }
        s.dataLong[s.curMethodSP + idx] = value;
      s.checkClassAndMethod(midx, "pushV", classAndMethod);
        VerifyVarInfo[] vars = s.verifyInfo.methodIdxInfos[midx].vars;
        vars[(vars.length >> 1) + idx].value = value;
    }
   
    public static void pushV(float value, Stack s, int idx, String classAndMethod) {
      int midx = s.methodTOS >> 1;
      if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info("#%d pushVFloat %s, tos=%d midx=%d sp=%d idx=%d v=%f", s.verifyInfo.vid, classAndMethod, s.methodTOS, midx, s.curMethodSP, idx, value);
      }
      s.checkClassAndMethod(midx, "pushV", classAndMethod);
        s.dataLong[s.curMethodSP + idx] = Float.floatToRawIntBits(value);
        VerifyVarInfo[] vars = s.verifyInfo.methodIdxInfos[s.methodTOS >> 1].vars;
        vars[(vars.length >> 1) + idx].value = value;
    }
   
    public static void pushV(long value, Stack s, int idx, String classAndMethod) {
      int midx = s.methodTOS >> 1;
      if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info("#%d pushVLong %s, tos=%d midx=%d sp=%d idx=%d v=%d", s.verifyInfo.vid, classAndMethod, s.methodTOS, midx, s.curMethodSP, idx, value);
      }
      s.checkClassAndMethod(midx, "pushV", classAndMethod);
        s.dataLong[s.curMethodSP + idx] = value;
        VerifyVarInfo[] vars = s.verifyInfo.methodIdxInfos[s.methodTOS >> 1].vars;
        vars[(vars.length >> 1) + idx].value = value;
    }
   
    public static void pushV(double value, Stack s, int idx, String classAndMethod) {
      int midx = s.methodTOS >> 1;
      if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info("#%d pushVDouble %s, tos=%d midx=%d sp=%d idx=%d v=%f", s.verifyInfo.vid, classAndMethod, s.methodTOS, midx, s.curMethodSP, idx, value);
      }
      s.checkClassAndMethod(midx, "pushV", classAndMethod);
        s.dataLong[s.curMethodSP + idx] = Double.doubleToRawLongBits(value);
        VerifyVarInfo[] vars = s.verifyInfo.methodIdxInfos[s.methodTOS >> 1].vars;
        vars[(vars.length >> 1) + idx].value = value;
    }
   
    private static Object takeValueWithoutRealizeIt(Object v) {
      if (v == null) {
        return null;
      }
      Object fv = v;
      //TODO:!((IPending) fv).isRealized()
    if (fv.getClass().getName().equals("clojure.lang.IPending")) {
      fv = fv.getClass().getName() + Long.toHexString(nginx.clojure.NginxClojureRT.ngx_http_clojure_mem_get_obj_addr(fv));
    }else if (Proxy.isProxyClass(fv.getClass())) {
      Object handler = Proxy.getInvocationHandler(fv);
      fv = "proxy@" + handler.getClass().getName() + Long.toHexString(nginx.clojure.NginxClojureRT.ngx_http_clojure_mem_get_obj_addr(handler));
    }else if (fv != null) {
      fv = fv.toString();
      if (((String)fv).length() > 100) {
        fv = ((String)fv).substring(0, 100);
      }
    }
   
    return fv;
    }
   
    public static void pushV(Object value, Stack s, int idx, String classAndMethod) {
      int midx = s.methodTOS >> 1;
      if (db.meetTraceTargetClassMethod(classAndMethod)) {
        Object fv = value;
        db.info(buildMessage(s, "#%d pushVObject %s, tos=%d midx=%d sp=%d idx=%d v=%s", s.verifyInfo.vid, classAndMethod, s.methodTOS, midx, s.curMethodSP, idx, takeValueWithoutRealizeIt(value)));
      }
      s.checkClassAndMethod(midx, "pushV", classAndMethod);
        s.dataObject[s.curMethodSP + idx] = value;
        VerifyVarInfo[] vars = s.verifyInfo.methodIdxInfos[s.methodTOS >> 1].vars;
        vars[idx].value = value;
    }
   

    public final int getInt(int idx) {
        return (int)dataLong[curMethodSP + idx];
    }
    public final float getFloat(int idx) {
        return Float.intBitsToFloat((int)dataLong[curMethodSP + idx]);
    }
    public final long getLong(int idx) {
        return dataLong[curMethodSP + idx];
    }
    public final double getDouble(int idx) {
        return Double.longBitsToDouble(dataLong[curMethodSP + idx]);
    }
    public final Object getObject(int idx) {
        return dataObject[curMethodSP + idx];
    }
   
    private static String buildMessage(Stack s, String format, Object... args) {
      setStack(null);
      try {
        return String.format(format, args);
      }finally {
        setStack(s);
      }
    }
   
    private static void printErrorMessage(MethodDatabase db, Stack s, String format, Object... args) {
      setStack(null);
      try {
        RuntimeException re = new RuntimeException(String.format(format, args));
        db.error(re);
      }finally {
        setStack(s);
      }
    }
   
    public final int getIntV(int idx, String classAndMethod) {
      int midx = methodTOS >> 1;
      checkClassAndMethod(midx, "getIntV", classAndMethod);
        int rt = (int)dataLong[curMethodSP + idx];
      if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info("#%d getIntV %s, tos=%d mid=%d, sp=%d idx=%d v=%s", verifyInfo.vid, classAndMethod, methodTOS, midx, curMethodSP, idx, rt);
      }
      VerifyVarInfo[] vis = verifyInfo.methodIdxInfos[midx].vars;
      Object ort = vis[(vis.length >> 1) + idx].value;
      int prt = 0;
     
      if (ort instanceof Boolean) {
        prt = (Boolean)ort ? 1 : 0;
      }else if (ort instanceof Number) {
        prt = ((Number)ort).intValue();
      }else if (ort instanceof Character) {
        prt = ((Character)ort).charValue();
      }else {
        printErrorMessage(this.db, this,"#%d getIntV %s tos=%d midx=%d, sp=%d idx=%d  %s != %s",  verifyInfo.vid, classAndMethod, methodTOS, midx, curMethodSP, idx, rt, ort);
        return rt;
      }
       
        if (rt != prt) {
          printErrorMessage(this.db, this ,"#%d getIntV %s tos=%d midx=%d, sp=%d idx=%d  %s != %s", verifyInfo.vid, classAndMethod, methodTOS, midx, curMethodSP, idx, rt, prt);
        }
      return rt;
    }
    public final float getFloatV(int idx, String classAndMethod) {
      int midx = methodTOS >> 1;
      checkClassAndMethod(midx, "getFloatV", classAndMethod);
        float rt = Float.intBitsToFloat((int)dataLong[curMethodSP + idx]);
        if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info("#%d getFloatV %s, tos=%d mid=%d, sp=%d idx=%d v=%s", verifyInfo.vid, classAndMethod, methodTOS, midx, curMethodSP, idx, rt);
      }
      VerifyVarInfo[] vis = verifyInfo.methodIdxInfos[midx].vars;
      Object ort = vis[(vis.length >> 1) + idx].value;
      Float prt;
      if (ort instanceof Float) {
        prt = (Float)ort;
      }else {
        printErrorMessage(this.db, this,"#%d getFloatV %s tos=%d midx=%d, sp=%d idx=%d  %s != %s",  verifyInfo.vid, classAndMethod, methodTOS, midx,curMethodSP, idx, rt, ort);
        return rt;
      }
        if (rt != prt) {
          printErrorMessage(this.db, this ,"#%d getFloatV %s tos=%d midx=%d, sp=%d idx=%d  %s != %s", verifyInfo.vid, classAndMethod, methodTOS, midx, curMethodSP, idx,rt, prt);
        }
      return rt;
    }
    public final long getLongV(int idx, String classAndMethod) {
      int midx = methodTOS >> 1;
      checkClassAndMethod(midx, "getLongV", classAndMethod);
        long rt = dataLong[curMethodSP + idx];
        if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info("#%d getLongV %s, tos=%d midx=%d, sp=%d idx=%d v=%s", verifyInfo.vid, classAndMethod, methodTOS, midx, curMethodSP, idx, rt);
      }
      VerifyVarInfo[] vis = verifyInfo.methodIdxInfos[midx].vars;
      Object ort = vis[(vis.length >> 1) + idx].value;
      Long prt;
      if (ort instanceof Long) {
        prt = (Long)ort;
      }else {
        printErrorMessage(this.db, this ,"#%d getLongV %s tos=%d midx=%d, sp=%d idx=%d  %s != %s",  verifyInfo.vid, classAndMethod, methodTOS, midx, curMethodSP, idx, rt, ort);
        return rt;
      }
        if (rt != prt) {
          printErrorMessage(this.db, this ,"#%d getLongV %s tos=%d midx=%d, sp=%d idx=%d  %s != %s", verifyInfo.vid, classAndMethod, methodTOS, midx,  curMethodSP, idx,rt, prt);
        }
      return rt;
    }
    public final double getDoubleV(int idx, String classAndMethod) {
      int midx = methodTOS >> 1;
      checkClassAndMethod(midx, "getDoubleV", classAndMethod);
        double rt = Double.longBitsToDouble(dataLong[curMethodSP + idx]);
        if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info("#%d getDoubleV %s, tos=%d midx=%d, sp=%d idx=%d v=%s", verifyInfo.vid, classAndMethod, midx, curMethodSP, idx, rt);
      }
      VerifyVarInfo[] vis = verifyInfo.methodIdxInfos[midx].vars;
      Object ort = vis[(vis.length >> 1) + idx].value;
      Double prt;
      if (ort instanceof Double) {
        prt = (Double)ort;
      }else {
        printErrorMessage(this.db, this ,"#%d getDoubleV %s tos=%d midx=%d, sp=%d idx=%d  %s != %s",  verifyInfo.vid, classAndMethod, methodTOS,midx, curMethodSP, idx, rt, ort);
        return rt;
      }
        if (rt != prt) {
          printErrorMessage(this.db, this ,"#%d getDoubleV %s tos=%d midx=%d, sp=%d idx=%d  %s != %s", verifyInfo.vid, classAndMethod, methodTOS, midx, curMethodSP, idx,rt, prt);
        }
      return rt;
    }
    public final Object getObjectV(int idx, String classAndMethod) {
      int midx = methodTOS >> 1;
      checkClassAndMethod(midx, "getObjectV", classAndMethod);
        Object rt = dataObject[curMethodSP + idx];
        if (db.meetTraceTargetClassMethod(classAndMethod)) {
        db.info(buildMessage(this ,"#%d getObjectV %s, tos=%d midx=%d, sp=%d idx=%d v=%s", verifyInfo.vid, classAndMethod, methodTOS, midx, curMethodSP, idx, takeValueWithoutRealizeIt(rt)));
      }
        Object prt = verifyInfo.methodIdxInfos[midx].vars[idx].value;
        if (rt != prt) {
          printErrorMessage(this.db, this ,"#%d getObjectV %s tos=%d midx=%d, sp=%d idx=%d  %s != %s" , verifyInfo.vid, classAndMethod, methodTOS, midx,  curMethodSP, idx, takeValueWithoutRealizeIt(rt), takeValueWithoutRealizeIt(prt));
        }
      return rt;
    }
   
   
    /** called when resuming a stack */
    final void resumeStack() {
        methodTOS = -1;
    }
   
    /* DEBUGGING CODE
    public void dump() {
        int sp = 0;
        for(int i=0 ; i<=methodTOS ; i++) {
            System.out.println("i="+i+" entry="+methodEntry[i]+" sp="+methodSP[i]);
            for(; sp < methodSP[i+1] ; sp++) {
                System.out.println("sp="+sp+" long="+dataLong[sp]+" obj="+dataObject[sp]);
            }
        }
    }
    */

    private void growDataStack(int required) {
        int newSize = dataObject.length;
        do {
            newSize *= 2;
        } while(newSize < required);
       
        dataLong = Util.copyOf(dataLong, newSize);
        dataObject = Util.copyOf(dataObject, newSize);
    }

    private void growMethodStack() {
        int newSize = method.length * 2;
       
        method = Util.copyOf(method, newSize);
    }
   
    public static void setDb(MethodDatabase db) {
    Stack.db = db;
  }
   
    public static MethodDatabase getDb() {
    return db;
  }
   
    /**
     * for junit test to check all objects are null now.
     */
    public boolean allObjsAreNull() {
      if (dataObject != null) {
          for (Object o : dataObject) {
            if (o != null) {
              return false;
            }
          }
      }
      return true;
    }
   
    //TODO: reuse it
    protected void release() {
      method = null;
      dataLong = null;
      dataObject = null;
      verifyInfo = null;
    }
}
TOP

Related Classes of nginx.clojure.Stack

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.