package doglet.misc;
import nova.Handler;
import nova.Machine;
import nova.Store;
import nova.special;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.StringTokenizer;
/**
* Warranty & Liability
* To the extent permitted by applicable law and unless explicitly
* otherwise agreed upon, XLOG Technologies AG makes no warranties
* regarding the provided information. XLOG Technologies AG assumes
* no liability that any problems might be solved with the information
* provided by XLOG Technologies AG.
*
* Rights & License
* All industrial property rights regarding the information - copyright
* and patent rights in particular - are the sole property of XLOG
* Technologies AG. If the company was not the originator of some
* excerpts, XLOG Technologies AG has at least obtained the right to
* reproduce, change and translate the information.
*
* Reproduction is restricted to the whole unaltered document. Reproduction
* of the information is only allowed for non-commercial uses. Selling,
* giving away or letting of the execution of the library is prohibited.
* The library can be distributed as part of your applications and libraries
* for execution provided this comment remains unchanged.
*
* Restrictions
* Only to be distributed with programs that add significant and primary
* functionality to the library. Not to be distributed with additional
* software intended to replace any components of the library.
*
* Trademarks
* Jekejeke is a registered trademark of XLOG Technologies AG.
*/
public final class hacklib {
private static final int MAX_TILT = 64;
private static final int GROUP_SIZE = 8;
private static final class CpuMap {
private int[] code;
private int[] offset;
private int[] state;
}
private static final class CpuWarp extends Thread {
private CpuMap map;
private int from;
private int to;
private int id;
private int tilt;
private boolean cmd;
private int[] buf;
private Thread thread;
}
private static void run(CpuWarp warp) {
for (int i = warp.from; i < warp.to; i++)
warp.map.state[warp.map.offset[i]-3] = i;
run_warp(warp, warp.from, warp.to);
while (warp.cmd) {
warp.buf = read_ints();
run_warp(warp, warp.from, warp.to);
}
}
private static void run_warp(CpuWarp warp, int from, int to) {
boolean active = true;
while (active) {
active = false;
for (int i = (warp.cmd ? warp.id : from); i < to; i++) {
if (run_id(warp, i)) {
if (warp.cmd) {
warp.id = i;
return;
} else {
active = true;
}
}
}
}
}
private static boolean run_id(CpuWarp warp, int id) {
CpuMap pi = warp.map;
int base = pi.offset[id];
int pc = pi.state[base-2];
int accu = pi.state[base-1];
for (int k = (warp.cmd ? warp.tilt : 0); k < MAX_TILT; k++) {
if (pc < pi.code.length) {
int instr = pi.code[pc];
int value = hack_get(warp, pi, instr, base, pc);
if (warp.cmd) {
pi.state[base-2] = pc;
pi.state[base-1] = accu;
warp.tilt = k;
return true;
} else {
accu = hack_fun(instr, accu, value);
hack_set(pi, instr, accu, base);
pc = pc+1+hack_jump(instr, accu);
}
} else {
pi.state[base-2] = pc;
pi.state[base-1] = accu;
return false;
}
}
pi.state[base-2] = pc;
pi.state[base-1] = accu;
return true;
}
private static int hack_get(CpuWarp warp, CpuMap pi, int instr, int base, int pc) {
int act = instr>>20;
int obj = ((instr>>10) & 0x03FF) - 512;
switch ((act>>4) & 0x0F) {
case 0: /* get */
return pi.state[base+obj];
case 1: /* cst */
return obj;
case 2: /* tbl */
return pi.code[pc+1+obj];
case 3: /* set */
return 0;
case 4: /* out */
return 0;
case 5: /* in */
extra_outline(warp, pi, obj, base);
return 0;
default:
throw new IllegalArgumentException("illegal mode");
}
}
private static int hack_fun(int instr, int accu, int value) {
int act = instr>>20;
switch (act>>8) {
case 0: /* val */
return value;
case 1: /* acc */
return accu;
case 2: /* add */
return value + accu;
case 3: /* sub */
return value - accu;
case 4: /* mul */
return value * accu;
case 5: /* zdiv */
return value / accu;
case 6: /* rem */
return value % accu;
default:
throw new IllegalArgumentException("illegal fun");
}
}
private static void hack_set(CpuMap pi, int instr, int accu, int base) {
int act = instr>>20;
int obj = ((instr>>10) & 0x03FF) - 512;
switch ((act>>4) & 0x0F) {
case 0: /* get */
return;
case 1: /* cst */
return;
case 2: /* tbl */
return;
case 3: /* set */
pi.state[base+obj] = accu;
return;
case 4: /* out */
write_ints(load_ints(obj, pi.state, base));
return;
case 5: /* in */
return;
default:
throw new IllegalArgumentException("illegal mode");
}
}
private static int hack_jump(int instr, int accu) {
int act = instr>>20;
int rel = (instr & 0x03FF) - 512;
switch (act & 0x0F) {
case 0: /* true */
return rel;
case 1: /* eq */
return (accu == 0 ? rel : 0);
case 2: /* nq */
return (accu != 0 ? rel : 0);
case 3: /* ls */
return (accu < 0 ? rel : 0);
case 4: /* gr */
return (accu > 0 ? rel : 0);
case 5: /* lq */
return (accu <= 0 ? rel : 0);
case 6: /* gq */
return (accu >= 0 ? rel : 0);
default:
throw new IllegalArgumentException("illegal cond");
}
}
/******************************************************************/
/* π-WAM Input/Output */
/******************************************************************/
private static int[] read_ints() {
try {
System.out.print(": ");
System.out.flush();
StringTokenizer st = new StringTokenizer(new LineNumberReader(
new InputStreamReader(System.in)).readLine());
ArrayList list = new ArrayList();
while (st.hasMoreTokens())
list.add(new BigInteger(st.nextToken()));
int[] res = new int[list.size()];
for (int i = 0; i < list.size(); i++)
res[i] = ((BigInteger)list.get(i)).intValue();
return res;
} catch (IOException e) {
throw new IllegalArgumentException("read aborted");
} catch (NumberFormatException e) {
throw new IllegalArgumentException("read aborted");
}
}
private static void write_ints(int[] res) {
for (int i = 0; i < res.length; i++) {
System.out.print(res[i]);
System.out.print(" ");
}
System.out.println();
}
/******************************************************************/
/* π-WAM Store/Load */
/******************************************************************/
private static void store_ints(int[] res, int max,
int[] state, int base) {
for (int i = 0; i < max; i++) {
if (i < res.length) {
state[base+i] = res[i];
} else {
state[base+i] = 0;
}
}
}
private static int[] load_ints(int max, int[] state, int base) {
int[] res = new int[max];
for (int i = 0; i < max; i++)
res[i] = state[base+i];
return res;
}
private static void extra_outline(CpuWarp warp, CpuMap pi,
int obj, int base) {
if (warp.cmd) {
store_ints(warp.buf, obj, pi.state, base);
warp.buf = null;
warp.cmd = false;
} else {
warp.cmd = true;
}
}
/******************************************************************/
/* π-WAM Buffers */
/******************************************************************/
/**
* test_cpu_data_new(A, B): internal only
* The predicate succeeds in B with a pi-WAM buffer for the list A.
*/
private static boolean test_cpu_data_new(Object[] args) {
Object alpha = Machine.exec_build(args[0]);
int[] res = cpu_list_ints(alpha);
return Machine.exec_unify(args[1], res);
}
private static int[] cpu_list_ints(Object obj) {
Object peek = obj;
int i = 0;
while (Store.is_structure(peek) &&
".".equals(((Store.Structure) peek).functor) &&
((Store.Structure) peek).args.length == 2 &&
i < special.MAX_ARITY) {
i++;
peek = Store.deref(((Store.Structure) peek).args[1]);
}
special.check_nil(peek);
int[] args = new int[i];
peek = obj;
i = 0;
while (Store.is_structure(peek) &&
".".equals(((Store.Structure) peek).functor) &&
((Store.Structure) peek).args.length == 2) {
Number val = (Number)Store.deref(((Store.Structure) peek).args[0]);
args[i++] = val.intValue();
peek = Store.deref(((Store.Structure) peek).args[1]);
}
return args;
}
/**
* test_cpu_comp_new(C, O, S, M): internal only
* The predicate succeeds in M with a new CPU backed π-WAM for
* the code buffer C, the offsets O and the state buffer S.
*/
private static boolean test_cpu_comp_new(Object[] args) {
CpuMap res = new CpuMap();
res.code = (int[])Machine.exec_build(args[0]);
res.offset = (int[])Machine.exec_build(args[1]);
res.state = (int[])Machine.exec_build(args[2]);
return Machine.exec_unify(args[3], res);
}
/**
* test_cpu_comp_work(M, W): internal only
* The predicate succeeds in W with the current
* group size of the CPU backed π-WAM M.
*/
private static boolean test_cpu_comp_work(Object[] args) {
CpuMap alpha = (CpuMap)Machine.exec_build(args[0]);
Object res = Integer.valueOf(GROUP_SIZE);
return Machine.exec_unify(args[1], res);
}
/******************************************************************/
/* π-WAM Interface */
/******************************************************************/
/**
* test_cpu_group_new(M, G): internal only
* The predicate succeeds in G with a
* new group for the CPU backed π-WAM M.
*/
private static boolean test_cpu_group_new(Object[] args) {
CpuMap alpha = (CpuMap)Machine.exec_build(args[0]);
CpuWarp res = new CpuWarp();
res.map = alpha;
res.thread = new Thread(() -> run(res));
return Machine.exec_unify(args[1], res);
}
/**
* test_cpu_group_start(G, I): internal only
* The predicate succeeds. As a side effect it
* starts the group G at group index I.
*/
private static boolean test_cpu_group_start(Object[] args) {
CpuWarp alpha = (CpuWarp)Machine.exec_build(args[0]);
Number beta = (Number)Machine.exec_build(args[1]);
int at = beta.intValue()*GROUP_SIZE;
int len = Math.min(alpha.map.offset.length - at, GROUP_SIZE);
alpha.from = at;
alpha.to = at+len;
alpha.thread.start();
return true;
}
/**
* test_cpu_group_join(G, P): internal only
* The predicate succeeds in P with a new promise
* that waits for the group G to finish.
*/
private static boolean test_cpu_group_join(Object[] args) {
CpuWarp alpha = (CpuWarp)Machine.exec_build(args[0]);
Object buf = Machine.ctx;
return Machine.exec_unify(args[1], join_promise(buf, alpha.thread));
}
private static Handler.Promise join_promise(Object buf, Thread alpha) {
return new Handler.Promise(() -> {
Thread self = Thread.currentThread();
Machine.register_interrupt(buf, self::interrupt);
try {
alpha.join();
} catch (InterruptedException x) {
/* */
} finally {
Machine.register_interrupt(buf, () -> {});
}
});
}
/**
* test_cpu_group_free(G): internal only
* The predicate succeeds. As a side effect
* it frees the group G.
*/
private static boolean test_cpu_group_free(Object[] args) {
return true;
}
/******************************************************************/
/* Hack Lib Init */
/******************************************************************/
public static void main() {
Store.set("cpu_data_new", 2, special.make_check(hacklib::test_cpu_data_new));
Store.set("cpu_comp_new", 4, special.make_check(hacklib::test_cpu_comp_new));
Store.set("cpu_comp_work", 2, special.make_check(hacklib::test_cpu_comp_work));
Store.set("cpu_group_new", 2, special.make_check(hacklib::test_cpu_group_new));
Store.set("cpu_group_start", 2, special.make_check(hacklib::test_cpu_group_start));
Store.set("cpu_group_join", 2, special.make_check(hacklib::test_cpu_group_join));
Store.set("cpu_group_free", 1, special.make_check(hacklib::test_cpu_group_free));
}
}