Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Quasar: lightweight threads and actors for the JVM.
* Copyright (c) 2013-2016, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.fibers;
import java.io.Serializable;
import java.util.Arrays;
/**
* Internal Class - DO NOT USE! (Public so that instrumented code can access it)
*
* ANY CHANGE IN THIS CLASS NEEDS TO BE SYNCHRONIZED WITH {@link co.paralleluniverse.fibers.instrument.InstrumentMethod}
*
* @author Matthias Mann
* @author Ron Pressler
*/
public final class Stack implements Serializable {
/*
* sp points to the first slot to contain data.
* The _previous_ FRAME_RECORD_SIZE slots contain the frame record.
* The frame record currently occupies a single long:
* - entry (PC) : 14 bits
* - num slots : 16 bits
* - prev method slots : 16 bits
*/
public static final int MAX_ENTRY = (1 << 14) - 1;
public static final int MAX_SLOTS = (1 << 16) - 1;
private static final int INITIAL_METHOD_STACK_DEPTH = 16;
private static final int FRAME_RECORD_SIZE = 1;
private static final long serialVersionUID = 12786283751253L;
private final Fiber fiber;
private int sp;
private transient boolean pushed;
private long[] dataLong; // holds primitives on stack as well as each method's entry point and the stack pointer
private Object[] dataObject; // holds refs on stack
Stack(Fiber fiber, int stackSize) {
if (stackSize <= 0)
throw new IllegalArgumentException("stackSize");
this.fiber = fiber;
this.dataLong = new long[stackSize + (FRAME_RECORD_SIZE * INITIAL_METHOD_STACK_DEPTH)];
this.dataObject = new Object[stackSize + (FRAME_RECORD_SIZE * INITIAL_METHOD_STACK_DEPTH)];
resumeStack();
}
public static Stack getStack() {
final Fiber currentFiber = Fiber.currentFiber();
return currentFiber != null ? currentFiber.stack : null;
}
Fiber getFiber() {
return fiber;
}
/**
* called when resuming a stack
*/
final void resumeStack() {
sp = 0;
}
// for testing/benchmarking only
void resetStack() {
resumeStack();
}
/**
* called at the beginning of a method
*
* @return the entry point of this method
*/
public final int nextMethodEntry() {
int idx = 0;
int slots = 0;
if (sp > 0) {
slots = getNumSlots(dataLong[sp - FRAME_RECORD_SIZE]);
idx = sp + slots;
}
sp = idx + FRAME_RECORD_SIZE;
long record = dataLong[idx];
int entry = getEntry(record);
dataLong[idx] = setPrevNumSlots(record, slots);
if (fiber.isRecordingLevel(2))
fiber.record(2, "Stack", "nextMethodEntry", "%s %s %s", Thread.currentThread().getStackTrace()[2], entry, sp /*Arrays.toString(fiber.getStackTrace())*/);
return entry;
}
/**
* called when nextMethodEntry returns 0
*/
public final boolean isFirstInStackOrPushed() {
boolean p = pushed;
pushed = false;
if (sp == FRAME_RECORD_SIZE | p)
return true;
// not first, but nextMethodEntry returned 0: revert changes
sp -= FRAME_RECORD_SIZE + getPrevNumSlots(dataLong[sp - FRAME_RECORD_SIZE]);
return false;
}
/**
* Called before a method is called.
*
* @param entry the entry point in the current method for resume
* @param numSlots the number of required stack slots for storing the state of the current method
*/
public final void pushMethod(int entry, int numSlots) {
pushed = true;
int idx = sp - FRAME_RECORD_SIZE;
long record = dataLong[idx];
record = setEntry(record, entry);
record = setNumSlots(record, numSlots);
dataLong[idx] = record;
int nextMethodIdx = sp + numSlots;
int nextMethodSP = nextMethodIdx + FRAME_RECORD_SIZE;
if (nextMethodSP >= dataObject.length)
growStack(nextMethodSP);
// clear next method's frame record
dataLong[nextMethodIdx] = 0L;
// for (int i = 0; i < FRAME_RECORD_SIZE; i++)
// dataLong[nextMethodIdx + i] = 0L;
if (fiber.isRecordingLevel(2))
fiber.record(2, "Stack", "pushMethod ", "%s %d %d", Thread.currentThread().getStackTrace()[2], entry, sp /*Arrays.toString(fiber.getStackTrace())*/);
}
public final void popMethod(int slots) {
pushed = false;
final int oldSP = sp;
final int idx = oldSP - FRAME_RECORD_SIZE;
final long record = dataLong[idx];
// final int slots = getNumSlots(record);
final int newSP = idx - getPrevNumSlots(record);
// clear frame record (probably unnecessary)
dataLong[idx] = 0L;
// for (int i = 0; i < FRAME_RECORD_SIZE; i++)
// dataLong[idx + i] = 0L;
// help GC
for (int i = oldSP; i < oldSP + slots && i < dataObject.length; i++)
dataObject[i] = null;
sp = newSP;
if (fiber.isRecordingLevel(2))
fiber.record(2, "Stack", "popMethod ", "%s %d", Thread.currentThread().getStackTrace()[2], sp /*Arrays.toString(fiber.getStackTrace())*/);
}
public final void postRestore() throws SuspendExecution, InterruptedException {
fiber.onResume();
}
public final void preemptionPoint(int type) throws SuspendExecution {
fiber.preemptionPoint(type);
}
private void growStack(int required) {
int newSize = dataObject.length;
do {
newSize *= 2;
} while (newSize < required);
dataLong = Arrays.copyOf(dataLong, newSize);
dataObject = Arrays.copyOf(dataObject, newSize);
}
void dump() {
int m = 0;
int k = 0;
while (k < sp - 1) {
final long record = dataLong[k++];
final int slots = getNumSlots(record);
System.err.println("\tm=" + (m++) + " entry=" + getEntry(record) + " sp=" + k + " slots=" + slots + " prevSlots=" + getPrevNumSlots(record));
for (int i = 0; i < slots; i++, k++)
System.err.println("\t\tsp=" + k + " long=" + dataLong[k] + " obj=" + dataObject[k]);
}
}
public static void push(int value, Stack s, int idx) {
// if (s.fiber.isRecordingLevel(3))
// s.fiber.record(3, "Stack", "push", "%d (%d) %s", idx, s.sp + idx, value);
s.dataLong[s.sp + idx] = value;
}
public static void push(float value, Stack s, int idx) {
// if (s.fiber.isRecordingLevel(3))
// s.fiber.record(3, "Stack", "push", "%d (%d) %s", idx, s.sp + idx, value);
s.dataLong[s.sp + idx] = Float.floatToRawIntBits(value);
}
public static void push(long value, Stack s, int idx) {
// if (s.fiber.isRecordingLevel(3))
// s.fiber.record(3, "Stack", "push", "%d (%d) %s", idx, s.sp + idx, value);
s.dataLong[s.sp + idx] = value;
}
public static void push(double value, Stack s, int idx) {
// if (s.fiber.isRecordingLevel(3))
// s.fiber.record(3, "Stack", "push", "%d (%d) %s", idx, s.sp + idx, value);
s.dataLong[s.sp + idx] = Double.doubleToRawLongBits(value);
}
public static void push(Object value, Stack s, int idx) {
// if (s.fiber.isRecordingLevel(3))
// s.fiber.record(3, "Stack", "push", "%d (%d) %s", idx, s.sp + idx, value);
s.dataObject[s.sp + idx] = value;
}
public final int getInt(int idx) {
return (int) dataLong[sp + idx];
// final int value = (int) dataLong[sp + idx];
// if (fiber.isRecordingLevel(3))
// fiber.record(3, "Stack", "getInt", "%d (%d) %s", idx, sp + idx, value);
// return value;
}
public final float getFloat(int idx) {
return Float.intBitsToFloat((int) dataLong[sp + idx]);
// final float value = Float.intBitsToFloat((int) dataLong[sp + idx]);
// if (fiber.isRecordingLevel(3))
// fiber.record(3, "Stack", "getFloat", "%d (%d) %s", idx, sp + idx, value);
// return value;
}
public final long getLong(int idx) {
return dataLong[sp + idx];
// final long value = dataLong[sp + idx];
// if (fiber.isRecordingLevel(3))
// fiber.record(3, "Stack", "getLong", "%d (%d) %s", idx, sp + idx, value);
// return value;
}
public final double getDouble(int idx) {
return Double.longBitsToDouble(dataLong[sp + idx]);
// final double value = Double.longBitsToDouble(dataLong[sp + idx]);
// if (fiber.isRecordingLevel(3))
// fiber.record(3, "Stack", "getDouble", "%d (%d) %s", idx, sp + idx, value);
// return value;
}
public final Object getObject(int idx) {
return dataObject[sp + idx];
// final Object value = dataObject[sp + idx];
// if (fiber.isRecordingLevel(3))
// fiber.record(3, "Stack", "getObject", "%d (%d) %s", idx, sp + idx, value);
// return value;
}
///////////////////////////////////////////////////////////////
private static long setEntry(long record, int entry) {
return setBits(record, 0, 14, entry);
}
private static int getEntry(long record) {
return (int) getUnsignedBits(record, 0, 14);
}
private static long setNumSlots(long record, int numSlots) {
return setBits(record, 14, 16, numSlots);
}
private static int getNumSlots(long record) {
return (int) getUnsignedBits(record, 14, 16);
}
private static long setPrevNumSlots(long record, int numSlots) {
return setBits(record, 30, 16, numSlots);
}
private static int getPrevNumSlots(long record) {
return (int) getUnsignedBits(record, 30, 16);
}
///////////////////////////////////////////////////////////////
private static final long MASK_FULL = 0xffffffffffffffffL;
private static long getUnsignedBits(long word, int offset, int length) {
int a = 64 - length;
int b = a - offset;
return (word >>> b) & (MASK_FULL >>> a);
}
private static long getSignedBits(long word, int offset, int length) {
int a = 64 - length;
int b = a - offset;
long xx = (word >>> b) & (MASK_FULL >>> a);
return (xx << a) >> a; // set sign
}
private static long setBits(long word, int offset, int length, long value) {
int a = 64 - length;
int b = a - offset;
//long mask = (MASK_FULL >>> a);
word = word & ~((MASK_FULL >>> a) << b); // clears bits in our region [offset, offset+length)
// value = value & mask;
word = word | (value << b);
return word;
}
private static boolean getBit(long word, int offset) {
return (getUnsignedBits(word, offset, 1) != 0);
}
private static long setBit(long word, int offset, boolean value) {
return setBits(word, offset, 1, value ? 1 : 0);
}
static class TraceLine {
final String method;
final int line;
final boolean pushed;
TraceLine(String method, int line, boolean pushed) {
this.method = method;
this.line = line;
this.pushed = pushed;
}
TraceLine(String method, int line) {
this(method, line, true);
}
}
}