1/*
2 * Permission is hereby granted, free of charge, to any person obtaining a copy of
3 * this software and associated documentation files (the "Software"), to deal in
4 * the Software without restriction, including without limitation the rights to
5 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
6 * of the Software, and to permit persons to whom the Software is furnished to do
7 * so, subject to the following conditions:
8 *
9 * The above copyright notice and this permission notice shall be included in all
10 * copies or substantial portions of the Software.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18 * SOFTWARE.
19 */
20package jdk.nashorn.internal.runtime.regexp.joni;
21
22import java.lang.ref.WeakReference;
23import jdk.nashorn.internal.runtime.regexp.joni.constants.StackPopLevel;
24import jdk.nashorn.internal.runtime.regexp.joni.constants.StackType;
25
26abstract class StackMachine extends Matcher implements StackType {
27    protected static final int INVALID_INDEX = -1;
28
29    protected StackEntry[]stack;
30    protected int stk;  // stkEnd
31
32    protected final int[]repeatStk;
33    protected final int memStartStk, memEndStk;
34
35    protected StackMachine(final Regex regex, final char[] chars, final int p , final int end) {
36        super(regex, chars, p, end);
37
38        this.stack = regex.stackNeeded ? fetchStack() : null;
39        final int n = regex.numRepeat + (regex.numMem << 1);
40        this.repeatStk = n > 0 ? new int[n] : null;
41
42        memStartStk = regex.numRepeat - 1;
43        memEndStk   = memStartStk + regex.numMem;
44        /* for index start from 1, mem_start_stk[1]..mem_start_stk[num_mem] */
45        /* for index start from 1, mem_end_stk[1]..mem_end_stk[num_mem] */
46    }
47
48    private static StackEntry[] allocateStack() {
49        final StackEntry[]stack = new StackEntry[Config.INIT_MATCH_STACK_SIZE];
50        stack[0] = new StackEntry();
51        return stack;
52    }
53
54    private void doubleStack() {
55        final StackEntry[] newStack = new StackEntry[stack.length << 1];
56        System.arraycopy(stack, 0, newStack, 0, stack.length);
57        stack = newStack;
58    }
59
60    static final ThreadLocal<WeakReference<StackEntry[]>> stacks
61            = new ThreadLocal<WeakReference<StackEntry[]>>() {
62        @SuppressWarnings("unused")
63        @Override
64        protected WeakReference<StackEntry[]> initialValue() {
65            return new WeakReference<StackEntry[]>(allocateStack());
66        }
67    };
68
69    @SuppressWarnings("unused")
70    private static StackEntry[] fetchStack() {
71        WeakReference<StackEntry[]> ref = stacks.get();
72        StackEntry[] stack = ref.get();
73        if (stack == null) {
74            ref = new WeakReference<StackEntry[]>(stack = allocateStack());
75            stacks.set(ref);
76        }
77        return stack;
78    }
79
80    protected final void init() {
81        if (stack != null) {
82            pushEnsured(ALT, regex.codeLength - 1); /* bottom stack */
83        }
84        if (repeatStk != null) {
85            for (int i=1; i<=regex.numMem; i++) {
86                repeatStk[i + memStartStk] = repeatStk[i + memEndStk] = INVALID_INDEX;
87            }
88        }
89    }
90
91    protected final StackEntry ensure1() {
92        if (stk >= stack.length) {
93            doubleStack();
94        }
95        StackEntry e = stack[stk];
96        if (e == null) {
97            stack[stk] = e = new StackEntry();
98        }
99        return e;
100    }
101
102    protected final void pushType(final int type) {
103        ensure1().type = type;
104        stk++;
105    }
106
107    private void push(final int type, final int pat, final int s, final int prev) {
108        final StackEntry e = ensure1();
109        e.type = type;
110        e.setStatePCode(pat);
111        e.setStatePStr(s);
112        e.setStatePStrPrev(prev);
113        stk++;
114    }
115
116    protected final void pushEnsured(final int type, final int pat) {
117        final StackEntry e = stack[stk];
118        e.type = type;
119        e.setStatePCode(pat);
120        stk++;
121    }
122
123    protected final void pushAlt(final int pat, final int s, final int prev) {
124        push(ALT, pat, s, prev);
125    }
126
127    protected final void pushPos(final int s, final int prev) {
128        push(POS, -1 /*NULL_UCHARP*/, s, prev);
129    }
130
131    protected final void pushPosNot(final int pat, final int s, final int prev) {
132        push(POS_NOT, pat, s, prev);
133    }
134
135    protected final void pushStopBT() {
136        pushType(STOP_BT);
137    }
138
139    protected final void pushLookBehindNot(final int pat, final int s, final int sprev) {
140        push(LOOK_BEHIND_NOT, pat, s, sprev);
141    }
142
143    protected final void pushRepeat(final int id, final int pat) {
144        final StackEntry e = ensure1();
145        e.type = REPEAT;
146        e.setRepeatNum(id);
147        e.setRepeatPCode(pat);
148        e.setRepeatCount(0);
149        stk++;
150    }
151
152    protected final void pushRepeatInc(final int sindex) {
153        final StackEntry e = ensure1();
154        e.type = REPEAT_INC;
155        e.setSi(sindex);
156        stk++;
157    }
158
159    protected final void pushMemStart(final int mnum, final int s) {
160        final StackEntry e = ensure1();
161        e.type = MEM_START;
162        e.setMemNum(mnum);
163        e.setMemPstr(s);
164        e.setMemStart(repeatStk[memStartStk + mnum]);
165        e.setMemEnd(repeatStk[memEndStk + mnum]);
166        repeatStk[memStartStk + mnum] = stk;
167        repeatStk[memEndStk + mnum] = INVALID_INDEX;
168        stk++;
169    }
170
171    protected final void pushMemEnd(final int mnum, final int s) {
172        final StackEntry e = ensure1();
173        e.type = MEM_END;
174        e.setMemNum(mnum);
175        e.setMemPstr(s);
176        e.setMemStart(repeatStk[memStartStk + mnum]);
177        e.setMemEnd(repeatStk[memEndStk + mnum]);
178        repeatStk[memEndStk + mnum] = stk;
179        stk++;
180    }
181
182    protected final void pushMemEndMark(final int mnum) {
183        final StackEntry e = ensure1();
184        e.type = MEM_END_MARK;
185        e.setMemNum(mnum);
186        stk++;
187    }
188
189    protected final int getMemStart(final int mnum) {
190        int level = 0;
191        int stkp = stk;
192
193        while (stkp > 0) {
194            stkp--;
195            final StackEntry e = stack[stkp];
196            if ((e.type & MASK_MEM_END_OR_MARK) != 0 && e.getMemNum() == mnum) {
197                level++;
198            } else if (e.type == MEM_START && e.getMemNum() == mnum) {
199                if (level == 0) {
200                    break;
201                }
202                level--;
203            }
204        }
205        return stkp;
206    }
207
208    protected final void pushNullCheckStart(final int cnum, final int s) {
209        final StackEntry e = ensure1();
210        e.type = NULL_CHECK_START;
211        e.setNullCheckNum(cnum);
212        e.setNullCheckPStr(s);
213        stk++;
214    }
215
216    protected final void pushNullCheckEnd(final int cnum) {
217        final StackEntry e = ensure1();
218        e.type = NULL_CHECK_END;
219        e.setNullCheckNum(cnum);
220        stk++;
221    }
222
223    // stack debug routines here
224    // ...
225
226    protected final void popOne() {
227        stk--;
228    }
229
230    protected final StackEntry pop() {
231        switch (regex.stackPopLevel) {
232        case StackPopLevel.FREE:
233            return popFree();
234        case StackPopLevel.MEM_START:
235            return popMemStart();
236        default:
237            return popDefault();
238        }
239    }
240
241    private StackEntry popFree() {
242        while (true) {
243            final StackEntry e = stack[--stk];
244
245            if ((e.type & MASK_POP_USED) != 0) {
246                return e;
247            }
248        }
249    }
250
251    private StackEntry popMemStart() {
252        while (true) {
253            final StackEntry e = stack[--stk];
254
255            if ((e.type & MASK_POP_USED) != 0) {
256                return e;
257            } else if (e.type == MEM_START) {
258                repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
259                repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
260            }
261        }
262    }
263
264    private StackEntry popDefault() {
265        while (true) {
266            final StackEntry e = stack[--stk];
267
268            if ((e.type & MASK_POP_USED) != 0) {
269                return e;
270            } else if (e.type == MEM_START) {
271                repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
272                repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
273            } else if (e.type == REPEAT_INC) {
274                //int si = stack[stk + IREPEAT_INC_SI];
275                //stack[si + IREPEAT_COUNT]--;
276                stack[e.getSi()].decreaseRepeatCount();
277            } else if (e.type == MEM_END) {
278                repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
279                repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
280            }
281        }
282    }
283
284    protected final void popTilPosNot() {
285        while (true) {
286            stk--;
287            final StackEntry e = stack[stk];
288
289            if (e.type == POS_NOT) {
290                break;
291            } else if (e.type == MEM_START) {
292                repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
293                repeatStk[memEndStk + e.getMemNum()] = e.getMemStart();
294            } else if (e.type == REPEAT_INC) {
295                //int si = stack[stk + IREPEAT_INC_SI];
296                //stack[si + IREPEAT_COUNT]--;
297                stack[e.getSi()].decreaseRepeatCount();
298            } else if (e.type == MEM_END){
299                repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
300                repeatStk[memEndStk + e.getMemNum()] = e.getMemStart();
301            }
302        }
303    }
304
305    protected final void popTilLookBehindNot() {
306        while (true) {
307            stk--;
308            final StackEntry e = stack[stk];
309
310            if (e.type == LOOK_BEHIND_NOT) {
311                break;
312            } else if (e.type == MEM_START) {
313                repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
314                repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
315            } else if (e.type == REPEAT_INC) {
316                //int si = stack[stk + IREPEAT_INC_SI];
317                //stack[si + IREPEAT_COUNT]--;
318                stack[e.getSi()].decreaseRepeatCount();
319            } else if (e.type == MEM_END) {
320                repeatStk[memStartStk + e.getMemNum()] = e.getMemStart();
321                repeatStk[memEndStk + e.getMemNum()] = e.getMemEnd();
322            }
323        }
324    }
325
326    protected final int posEnd() {
327        int k = stk;
328        while (true) {
329            k--;
330            final StackEntry e = stack[k];
331            if ((e.type & MASK_TO_VOID_TARGET) != 0) {
332                e.type = VOID;
333            } else if (e.type == POS) {
334                e.type = VOID;
335                break;
336            }
337        }
338        return k;
339    }
340
341    protected final void stopBtEnd() {
342        int k = stk;
343        while (true) {
344            k--;
345            final StackEntry e = stack[k];
346
347            if ((e.type & MASK_TO_VOID_TARGET) != 0) {
348                e.type = VOID;
349            } else if (e.type == STOP_BT) {
350                e.type = VOID;
351                break;
352            }
353        }
354    }
355
356    // int for consistency with other null check routines
357    protected final int nullCheck(final int id, final int s) {
358        int k = stk;
359        while (true) {
360            k--;
361            final StackEntry e = stack[k];
362
363            if (e.type == NULL_CHECK_START) {
364                if (e.getNullCheckNum() == id) {
365                    return e.getNullCheckPStr() == s ? 1 : 0;
366                }
367            }
368        }
369    }
370
371    protected final int nullCheckMemSt(final int id, final int s) {
372        // Return -1 here to cause operation to fail
373        return -nullCheck(id, s);
374    }
375
376    protected final int getRepeat(final int id) {
377        int level = 0;
378        int k = stk;
379        while (true) {
380            k--;
381            final StackEntry e = stack[k];
382
383            if (e.type == REPEAT) {
384                if (level == 0) {
385                    if (e.getRepeatNum() == id) {
386                        return k;
387                    }
388                }
389            } else if (e.type == CALL_FRAME) {
390                level--;
391            } else if (e.type == RETURN) {
392                level++;
393            }
394        }
395    }
396
397    protected final int sreturn() {
398        int level = 0;
399        int k = stk;
400        while (true) {
401            k--;
402            final StackEntry e = stack[k];
403
404            if (e.type == CALL_FRAME) {
405                if (level == 0) {
406                    return e.getCallFrameRetAddr();
407                }
408                level--;
409            } else if (e.type == RETURN) {
410                level++;
411            }
412        }
413    }
414}
415