1
package org.perl6.nqp.sixmodel.reprs;
3
import org.perl6.nqp.runtime.CallSiteDescriptor;
4
import org.perl6.nqp.runtime.Ops;
5
import org.perl6.nqp.runtime.ThreadContext;
6
import org.perl6.nqp.sixmodel.SixModelObject;
7
import org.perl6.nqp.sixmodel.TypeObject;
9
public class MultiCacheInstance extends SixModelObject {
10
private static final int MD_CACHE_MAX_ARITY = 4;
11
private static final int MD_CACHE_MAX_ENTRIES = 16;
12
private static final int MD_CACHE_INT = 1;
13
private static final int MD_CACHE_NUM = 2;
14
private static final int MD_CACHE_STR = 3;
16
private SixModelObject zeroArity;
17
private ArityCache[] arityCaches = new ArityCache[MD_CACHE_MAX_ARITY];
19
private class ArityCache
21
/* The number of entries we have in the cache. */
22
public int numEntries;
24
/* This is a bunch of ST hashes, with natives special-cased. We allocate
25
* it arity * MAX_ENTRIES big and go through it in arity sized chunks. */
26
public long typeIds[];
28
/* Whether the entry is allowed to have named arguments. Doesn't say
29
* anything about which ones, though. Something that is ambivalent
30
* about named arguments to the degree it doesn't care about them
31
* even tie-breaking (like NQP) can just throw such entries into the
32
* cache. Things that do care should not make such cache entries. */
33
public boolean namedOK[];
35
/* The results we return from the cache. */
36
public SixModelObject[] results;
39
public void add(CallCaptureInstance capture, SixModelObject result, ThreadContext tc) {
40
/* If there's flattenings, we can't cache. */
41
if (capture.descriptor.hasFlattening)
44
/* If it's zero arity, just stick it in that slot. */
45
Object[] args = capture.args;
46
if (args.length == 0) {
47
this.zeroArity = result;
51
/* Count number of positional args and build type tuple. */
53
byte[] argFlags = capture.descriptor.argFlags;
54
long argTup[] = new long[MD_CACHE_MAX_ARITY];
55
boolean hasNamed = false;
56
for (int i = 0; i < argFlags.length; i++) {
57
switch (argFlags[i]) {
58
case CallSiteDescriptor.ARG_INT:
59
if (numArgs >= MD_CACHE_MAX_ARITY)
61
argTup[numArgs++] = MD_CACHE_INT;
63
case CallSiteDescriptor.ARG_NUM:
64
if (numArgs >= MD_CACHE_MAX_ARITY)
66
argTup[numArgs++] = MD_CACHE_NUM;
68
case CallSiteDescriptor.ARG_STR:
69
if (numArgs >= MD_CACHE_MAX_ARITY)
71
argTup[numArgs++] = MD_CACHE_STR;
73
case CallSiteDescriptor.ARG_OBJ:
74
if (numArgs >= MD_CACHE_MAX_ARITY)
76
SixModelObject decont = Ops.decont((SixModelObject)args[i], tc);
77
long flag = ((long)decont.st.hashCode()) << 1;
78
if (!(decont instanceof TypeObject))
80
argTup[numArgs++] = flag;
83
if ((argFlags[i] & CallSiteDescriptor.ARG_FLAT) != 0)
89
/* If the cache is saturated, don't do anything (we could instead do a random
91
ArityCache ac = this.arityCaches[numArgs - 1];
92
if (ac != null && ac.numEntries == MD_CACHE_MAX_ENTRIES)
95
/* If there's no entries yet, need to do some allocation. */
97
ac = new ArityCache();
98
ac.typeIds = new long[numArgs * MD_CACHE_MAX_ENTRIES];
99
ac.namedOK = new boolean[MD_CACHE_MAX_ENTRIES];
100
ac.results = new SixModelObject[MD_CACHE_MAX_ENTRIES];
101
this.arityCaches[numArgs - 1] = ac;
105
int insType = ac.numEntries * numArgs;
106
for (int i = 0; i < numArgs; i++)
107
ac.typeIds[insType + i] = argTup[i];
108
ac.results[ac.numEntries] = result;
109
ac.namedOK[ac.numEntries] = hasNamed;
113
public SixModelObject lookup(CallCaptureInstance capture, ThreadContext tc) {
114
/* If there's flattenings, we can't use the cache. */
115
if (capture.descriptor.hasFlattening)
118
/* Count number of positional args and build type tuple. */
120
Object[] args = capture.args;
121
byte[] argFlags = capture.descriptor.argFlags;
122
long argTup[] = new long[MD_CACHE_MAX_ARITY];
123
boolean hasNamed = false;
124
for (int i = 0; i < argFlags.length; i++) {
125
switch (argFlags[i]) {
126
case CallSiteDescriptor.ARG_INT:
127
if (numArgs >= MD_CACHE_MAX_ARITY)
129
argTup[numArgs++] = MD_CACHE_INT;
131
case CallSiteDescriptor.ARG_NUM:
132
if (numArgs >= MD_CACHE_MAX_ARITY)
134
argTup[numArgs++] = MD_CACHE_NUM;
136
case CallSiteDescriptor.ARG_STR:
137
if (numArgs >= MD_CACHE_MAX_ARITY)
139
argTup[numArgs++] = MD_CACHE_STR;
141
case CallSiteDescriptor.ARG_OBJ:
142
if (numArgs >= MD_CACHE_MAX_ARITY)
144
SixModelObject decont = Ops.decont((SixModelObject)args[i], tc);
145
long flag = ((long)decont.st.hashCode()) << 1;
146
if (!(decont instanceof TypeObject))
148
argTup[numArgs++] = flag;
151
if ((argFlags[i] & CallSiteDescriptor.ARG_FLAT) != 0)
157
/* If it's zero-arity, return result right off. */
159
return hasNamed ? null : this.zeroArity;
161
/* Look through entries. */
162
ArityCache ac = this.arityCaches[numArgs - 1];
166
for (int i = 0; i < ac.numEntries; i++) {
167
boolean match = true;
168
for (int j = 0; j < numArgs; j++) {
169
if (ac.typeIds[tPos + j] != argTup[j]) {
175
if (hasNamed == ac.namedOK[i])
176
return ac.results[i];