Source Code Cross Referenced for StackFrame.java in  » Scripting » oscript-2.10.4 » oscript » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » oscript 2.10.4 » oscript.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*=============================================================================
002:         *     Copyright Texas Instruments 2003.  All Rights Reserved.
003:         *   
004:         * This program is free software; you can redistribute it and/or
005:         * modify it under the terms of the GNU Lesser General Public
006:         * License as published by the Free Software Foundation; either
007:         * version 2 of the License, or (at your option) any later version.
008:         * 
009:         * This program is distributed in the hope that it will be useful,
010:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
011:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012:         * Lesser General Public License for more details.
013:         * 
014:         * You should have received a copy of the GNU Lesser General Public
015:         * License along with this library; if not, write to the Free Software
016:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
017:         * 
018:         * $ProjectHeader: OSCRIPT 0.155 Fri, 20 Dec 2002 18:34:22 -0800 rclark $
019:         */
020:
021:        package oscript.util;
022:
023:        import java.io.BufferedReader;
024:        import java.io.InputStreamReader;
025:        import java.util.*;
026:
027:        import oscript.exceptions.*;
028:        import oscript.data.*;
029:        import oscript.NodeEvaluator;
030:        import oscript.fs.AbstractFile;
031:
032:        /**
033:         * The "chain" of stack frames is used to track execution context of a
034:         * particular thread and, when debugging is enabled, give the debugger a 
035:         * chance to run breakpoints.
036:         * <p>
037:         * Where possible, the head of the chain of stack frames is passed on the 
038:         * stack, but in cases where it cannot be, such as when control passes to
039:         * java code and back, a hashtable is used to map the current thread to
040:         * a <code>StackFrame</code>.  To access the current stack frame, or
041:         * create one if needed, use {@link #currentStackFrame}.
042:         * <p>
043:         * While on the interface, the stack frame behaves as a chain of 
044:         * <code>StackFrame</code> objects, behind the scenes an array is used
045:         * for the stack, and a fly-weight pattern is used for the stack frame
046:         * objects.  This way we (1) avoid extra memory allocations, and (2)
047:         * can have different implementations of {@link #setLineNumber} depending
048:         * on whether debugging is enabled or not.  (Debugging is automatically
049:         * enabled when a breakpoint is set.)
050:         * <p>
051:         * In order to maintain this allusion, calls to {@link NodeEvaluator#evalNode}
052:         * must go through the {@link #evalNode} call-gate.
053:         * <p>
054:         * The stack frame object is intentionally not thread safe, since it is only 
055:         * accessed from a single thread context.  Because of the use of the fly-
056:         * weight pattern, a stack frame object no longer validly represents a stack
057:         * frame that has exited, either by normally or via an exception.  Because
058:         * of this, any code that wishes to save a reference to a stack frame object
059:         * must {@link #clone} it.
060:         * <p>
061:         * Because the <code>StackFrame</code> is only accessed from a single thread
062:         * context, it can provide a lightweight mechanism to allocate storage for 
063:         * {@link BasicScope} objects.  This can be used in cases where the scope
064:         * object only exists on the stack, and is not held after the program 
065:         * enclosed by the scope has finished execution, ie. there is no function 
066:         * enclosed by the scope.  For cases of an enclosed function, the scope 
067:         * storage must be allocated from the heap so that it can be valid at some 
068:         * point in the future when the enclosed function is potentially called.
069:         * 
070:         * @author Rob Clark (rob@ti.com)
071:         * @version 1
072:         */
073:        public abstract class StackFrame {
074:            /**
075:             * note impericially derived stack size number based on
076:             * a value sufficiently large that a StackOverFlowException
077:             * occurs before the stack frame index reaches this value.
078:             */
079:            private static final int STACK_SIZE = 808; // reduct when growing stack implemented??
080:
081:            /**
082:             * it would be nice to support paging the member stack, so we can keep
083:             * it smaller, and possible save/restore it thru the same call gate as
084:             * <code>idx[0]</code> and <code>membersIdx[0]</code> are saved/restored.
085:             */
086:            private static final int MEMBERS_STACK_SIZE = 4096;
087:
088:            /**
089:             * Maps thread to stack frame.  Because of the fly-weight pattern, there
090:             * is only one stack frame object (well, actually two), so all we need
091:             * is to map the current frame to a stack frame... no need to go
092:             * searching for the tail, or do any extra book-keeping to track the
093:             * tail.
094:             */
095:            private static final Hashtable stackFrameTable = new Hashtable();
096:
097:            /**
098:             * Get the stack frame for the current thread.  If one does not already
099:             * exist, this will create a new one, otherwise it will return the 
100:             * current top of the stack.
101:             */
102:            public static synchronized StackFrame currentStackFrame() {
103:                Thread t = Thread.currentThread();
104:                StackFrame stackFrame = (StackFrame) (stackFrameTable.get(t));
105:
106:                if (stackFrame == null) {
107:                    stackFrame = new RegularStackFrame();
108:                    stackFrameTable.put(t, stackFrame);
109:                }
110:
111:                return stackFrame;
112:            }
113:
114:            /**
115:             * StackFrame to use when not debugging.  This one's {@link #setLineNumber} 
116:             * does not have extra checks for breakpoints for better performance.  This
117:             * should be treated as final.
118:             */
119:            protected StackFrame regularStackFrame;
120:
121:            /**
122:             * StackFrame to use whe debugging.  This one's {@link #setLineNumber} does
123:             * have extra checks for breakpoints, so breakpoints can work properly.
124:             * This should be treated as final.
125:             */
126:            protected StackFrame debugStackFrame;
127:
128:            /**
129:             * The current index, boxed in array so it can be shared between the
130:             * two stack-frame instances (regular & debug)
131:             */
132:            protected final short[] idx;
133:
134:            /**
135:             * The node evaluator, which has file, and id info needed when filling
136:             * in stack trace.
137:             */
138:            protected final NodeEvaluator[] nes;
139:
140:            /**
141:             * The current line number at each stack frame.
142:             */
143:            protected final int[] lines;
144:
145:            /**
146:             * The current scopes at each stack frame.
147:             */
148:            protected final Scope[] scopes;
149:
150:            /**
151:             * The list of scopes allocated at the current frame, which should be
152:             * recycled once the stack frame is released.
153:             */
154:            protected final StackFrameBasicScope[] scopeLists;
155:
156:            /**
157:             * The pool of members that can be used (and re-used) by scope objects
158:             * that only ever exist on the stack.
159:             */
160:            private final Reference[] members;
161:
162:            /**
163:             * The index of the first available slot in the members stack, boxed in
164:             * an array so it can be shared between the two stack-frame instances
165:             * (regular & debug)
166:             */
167:            private final short[] membersIdx;
168:
169:            /**
170:             * The number of slots in <code>members</code>.
171:             */
172:            private final short membersCount;
173:
174:            /**
175:             * Pool of available, pre-allocated SFA's.  Whenever possible, allocating
176:             * a SFA will re-use a SFA from the pool, to avoid dynamic memory allocation
177:             * @see #allocateMemberTable(short)
178:             */
179:            private StackFrameMemberTable sfaPool = null; // XXX should be shared between both StackFrame objects...
180:
181:            /**
182:             * Pool of available, pre-allocated scope objects.  Whenever possible,
183:             * allocating a new scope will re-use one from the pool, in order to avoid
184:             * dynamic memory allocation.
185:             * @see #allocateBasicScope(Scope, SymbolTable)
186:             */
187:            private StackFrameBasicScope basicScopePool = null; // XXX should be shared between both StackFrame objects
188:
189:            /**
190:             * Pool of available, pre-allocated fxn-scope objects.  Whenever possible,
191:             * allocating a new scope will re-use one from the pool, in order to avoid
192:             * dynamic memory allocation.
193:             * @see #allocateFunctionScope(Function, Scope, SymbolTable, MemberTable)
194:             */
195:            private StackFrameFunctionScope functionScopePool = null; // XXX should be shared between both StackFrame objects
196:
197:            /**
198:             * Class Constructor.
199:             */
200:            private StackFrame(short[] idx, NodeEvaluator[] nes, int[] lines,
201:                    Scope[] scopes, StackFrameBasicScope[] scopeLists,
202:                    Reference[] members, short[] membersIdx) {
203:                this .idx = idx;
204:                this .nes = nes;
205:                this .lines = lines;
206:                this .scopes = scopes;
207:                this .scopeLists = scopeLists;
208:
209:                this .members = members;
210:                this .membersIdx = membersIdx;
211:
212:                membersCount = (short) ((members != null) ? members.length : 0);
213:            }
214:
215:            /**
216:             * Push a new stack frame onto the stack, and pass it to <code>ne</code>'s 
217:             * {@link #evalNode} method, returning the result.
218:             * 
219:             * @param ne     the node-evaluator for the node to evaluate
220:             * @param scope  the scope to evalute in
221:             * @return the result
222:             */
223:            public final Object evalNode(NodeEvaluator ne, Scope scope) {
224:                StackFrame sf = Debugger.mayHaveBreakpoints(ne) ? debugStackFrame
225:                        : regularStackFrame;
226:
227:                short idx = ++this .idx[0];
228:                short membersIdx = this .membersIdx[0];
229:
230:                // grow stack, if needed:
231:                if (idx >= nes.length)
232:                    throw new ProgrammingErrorException(
233:                            "growing stack is not implemented yet, so STACK OVERFLOW! (idx="
234:                                    + idx + ")"); // XXX
235:
236:                nes[idx] = ne;
237:
238:                try {
239:                    return ne.evalNode(sf, scope);
240:                } catch (PackagedScriptObjectException e) {
241:                    if (e.val instanceof  OException)
242:                        ((OException) (e.val)).preserveStackFrame();
243:                    throw e;
244:                } finally {
245:                    // reset members, since it is possible this didn't happen in the
246:                    // compiler... if the compiler gets better about always resetting,
247:                    // then we won't need this here:
248:                    for (int i = this .membersIdx[0] - 1; i >= membersIdx; i--)
249:                        if (this .members[i] != null)
250:                            this .members[i].reset();
251:
252:                    StackFrameBasicScope scopeList = scopeLists[idx];
253:                    scopeLists[idx] = null;
254:                    while (scopeList != null) {
255:                        StackFrameBasicScope head = scopeList;
256:                        scopeList = scopeList.next;
257:                        head.next = basicScopePool;
258:                        basicScopePool = head;
259:                    }
260:
261:                    // so things can be GC'd:
262:                    scopes[idx] = null;
263:                    nes[idx] = null; // is this needed??
264:                    this .idx[0] = (short) (idx - 1);
265:                    this .membersIdx[0] = membersIdx;
266:                }
267:            }
268:
269:            /**
270:             * Called by node evaluator to store line number info, and to give the
271:             * debugger a chance to see if we've hit a breakpoint.
272:             * 
273:             * @param scope        the current scope
274:             * @param line         the current line number
275:             */
276:            public void setLineNumber(Scope scope, int line) {
277:                short idx = this .idx[0];
278:                scopes[idx] = scope;
279:                lines[idx] = line;
280:                if (VERBOSE)
281:                    logSetLineNumber(getFile(), line);
282:            }
283:
284:            /**
285:             * Called by node evaluator to store line number info, and to give the
286:             * debugger a chance to see if we've hit a breakpoint.  This method
287:             * is used by the compiler in cases where the scope hasn't changed
288:             * sinced last line number, to save a few instructions.
289:             * 
290:             * @param scope        the current scope
291:             * @param line         the current line number
292:             */
293:            public void setLineNumber(int line) {
294:                lines[idx[0]] = line;
295:                if (VERBOSE)
296:                    logSetLineNumber(getFile(), line);
297:            }
298:
299:            /**
300:             * Allocate a scope from the stack.  The basic-scope is freed automatically
301:             * when the stack-frame is disposed
302:             */
303:            public final BasicScope allocateBasicScope(Scope prev,
304:                    SymbolTable smit) {
305:                short idx = this .idx[0];
306:                StackFrameBasicScope scope;
307:                if (basicScopePool != null) {
308:                    scope = basicScopePool;
309:                    scope.reinit(prev, smit);
310:                    basicScopePool = basicScopePool.next;
311:                    if (VERBOSE)
312:                        log("recycle StackFrameBasicScope");
313:                } else {
314:                    scope = new StackFrameBasicScope(prev, smit);
315:                    if (VERBOSE)
316:                        log("allocate StackFrameBasicScope");
317:                }
318:                scope.next = scopeLists[idx];
319:                scopeLists[idx] = scope;
320:                return scope;
321:            }
322:
323:            /**
324:             * A scope allocated by the stack-frame, which can be recycled
325:             */
326:            private final class StackFrameBasicScope extends BasicScope {
327:                StackFrameBasicScope next;
328:
329:                StackFrameBasicScope(Scope previous, SymbolTable smit) {
330:                    super (previous, smit, allocateMemberTable((short) (smit
331:                            .size())));
332:                }
333:
334:                final void reinit(Scope previous, SymbolTable smit) {
335:                    this .previous = previous;
336:                    this .smit = smit;
337:                    if (members instanceof  StackFrameMemberTable)
338:                        ((StackFrameMemberTable) members).reinit((short) (smit
339:                                .size()));
340:                    else
341:                        members = allocateMemberTable((short) (smit.size()));
342:                }
343:            }
344:
345:            /**
346:             * Allocate a fxn-scope from the stack.  The fxn-scope must be
347:             * freed by the caller.
348:             */
349:            public final FunctionScope allocateFunctionScope(Function fxn,
350:                    Scope prev, SymbolTable smit, MemberTable members) {
351:                StackFrameFunctionScope scope;
352:                if (functionScopePool != null) {
353:                    scope = functionScopePool;
354:                    scope.reinit(fxn, prev, smit, members);
355:                    functionScopePool = functionScopePool.next;
356:                    if (VERBOSE)
357:                        log("recycle StackFrameFunctionScope");
358:                } else {
359:                    scope = new StackFrameFunctionScope(fxn, prev, smit,
360:                            members);
361:                    if (VERBOSE)
362:                        log("allocate StackFrameFunctionScope");
363:                }
364:                return scope;
365:            }
366:
367:            /**
368:             * A scope allocated by the stack-frame, which can be recycled
369:             */
370:            private final class StackFrameFunctionScope extends FunctionScope {
371:                StackFrameFunctionScope next;
372:
373:                StackFrameFunctionScope(Function fxn, Scope prev,
374:                        SymbolTable smit, MemberTable members) {
375:                    super (fxn, prev, smit, members);
376:                }
377:
378:                final void reinit(Function fxn, Scope prev, SymbolTable smit,
379:                        MemberTable members) {
380:                    this .fxn = fxn;
381:                    this .previous = prev;
382:                    this .smit = smit;
383:                    this .members = members;
384:                }
385:
386:                public final void free() {
387:                    this .members = null;
388:                    this .next = functionScopePool;
389:                    functionScopePool = this ;
390:                }
391:            }
392:
393:            /**
394:             * Allocate from the stack.
395:             */
396:            public final MemberTable allocateMemberTable(short sz) {
397:                /* note: not synchronized because only a single thread context
398:                 *       should be allocating/freeing from this stack...
399:                 */
400:                StackFrameMemberTable sfa;
401:                if (sfaPool != null) {
402:                    sfa = sfaPool;
403:                    sfaPool = sfaPool.next;
404:                    if (VERBOSE)
405:                        log("recycle StackFrameMemberTable: " + sfa);
406:                } else {
407:                    sfa = new StackFrameMemberTable();
408:                    if (VERBOSE)
409:                        log("allocate StackFrameMemberTable: " + sfa);
410:                }
411:                sfa.reinit(sz);
412:                return sfa;
413:            }
414:
415:            /**
416:             * An array object which uses the pre-allocated stack.  Note that this array
417:             * is not thread safe, because it is only intended to be used from the thread
418:             * associated with this stack.
419:             */
420:            private final class StackFrameMemberTable implements  MemberTable {
421:                private short off; // offset into 'members'
422:                private short len; // length of our part of 'members'
423:                private short sz; // the actual size of the array, sz <= len
424:
425:                StackFrameMemberTable next;
426:
427:                private Reference[] members;
428:
429:                final void reinit(short len) {
430:                    this .members = StackFrame.this .members;
431:                    this .off = membersIdx[0];
432:                    this .len = len;
433:                    this .sz = 0;
434:
435:                    if ((len + off) > membersCount)
436:                        throw new ProgrammingErrorException(
437:                                "failed to allocate from stack for " + this 
438:                                        + ", idx=" + idx[0]);
439:
440:                    membersIdx[0] = (short) (off + len);
441:                }
442:
443:                private final void checkIndex(int idx) {
444:                    if ((idx < 0) || (idx >= length())) {
445:                        Thread.dumpStack(); // XXX
446:                        throw PackagedScriptObjectException
447:                                .makeExceptionWrapper(new OIllegalArgumentException(
448:                                        "invalid array index: " + idx));
449:                    }
450:                }
451:
452:                /**
453:                 * grow the member table by copying out of stack (or out of current array)
454:                 * @param grow   the number of elements to grow the table by
455:                 */
456:                private final void copyOutOfStack(int grow) {
457:                    Reference[] newMembers = new Reference[len + grow];
458:                    Reference r;
459:                    if (members == StackFrame.this .members) {
460:                        if (VERBOSE)
461:                            log("copy out of stack: " + this  + ", grow=" + grow);
462:                        System.arraycopy(members, off, newMembers, 0, sz);
463:                        // need to null out entries from shared stack to ensure
464:                        // that no-one else tries to recycle a Reference object
465:                        // while it is still used by the safe-copy
466:                        for (int i = off + sz - 1; i >= off; i--)
467:                            members[i] = null;
468:
469:                        if ((off + len) == membersIdx[0])
470:                            membersIdx[0] = off;
471:                        else if (DEBUG)
472:                            System.err.println(" *** cant free"); // XXXXX
473:                    } else {
474:                        if (VERBOSE)
475:                            log("grow: " + this  + ", grow=" + grow);
476:                        System.arraycopy(members, off, newMembers, 0, sz);
477:                    }
478:                    members = newMembers;
479:                    off = 0;
480:                    len += grow;
481:                }
482:
483:                public void reset() {
484:                    if (VERBOSE)
485:                        log("reset: " + this );
486:                    for (int i = off + sz - 1; i >= off; i--)
487:                        members[i].reset();
488:                }
489:
490:                public void free() {
491:                    if (VERBOSE)
492:                        log("free: " + this );
493:
494:                    if (members == StackFrame.this .members) {
495:                        reset();
496:                        membersIdx[0] = off;
497:                    }
498:
499:                    // free the StackFrameMemberTable to the pool:
500:                    members = null;
501:                    next = sfaPool;
502:                    sfaPool = this ;
503:                }
504:
505:                public Reference referenceAt(int idx) {
506:                    if (DEBUG)
507:                        checkIndex(idx);
508:                    idx += off;
509:                    if (members[idx] == null)
510:                        members[idx] = new Reference();
511:                    return members[idx];
512:                }
513:
514:                public int length() {
515:                    return sz;
516:                }
517:
518:                public void ensureCapacity(int sz) {
519:                    sz++;
520:                    int grow = sz - len;
521:                    if (grow > 0) {
522:                        if (members == StackFrame.this .members) {
523:                            // if off+len == membersIdx, then we are the topmost array on the stack
524:                            // so it is safe to grow up:
525:                            if (membersIdx[0] == (off + len)) {
526:                                if (VERBOSE)
527:                                    log("growing table on stack: " + this );
528:                                len += grow;
529:                                membersIdx[0] += grow;
530:                            } else {
531:                                if (VERBOSE)
532:                                    log("cannot grow table (shouldn't normally happen): "
533:                                            + this );
534:                                copyOutOfStack(grow);
535:                            }
536:                        } else if ((sz + off) > members.length) {
537:                            copyOutOfStack(sz + off - members.length);
538:                        }
539:                    }
540:
541:                    if (sz > this .sz)
542:                        this .sz = (short) sz;
543:                }
544:
545:                public MemberTable safeCopy() {
546:                    if (VERBOSE)
547:                        log("safe copy: " + this );
548:
549:                    if (members == StackFrame.this .members)
550:                        copyOutOfStack(0);
551:
552:                    // we need to use this OArray constructor to ensure that the same Reference
553:                    // objects in the members table get used... otherwise there could be problems
554:                    // with the compiler's cached Reference's (as local vars) getting out of
555:                    // sync:
556:                    return new OArray(members, sz);
557:                }
558:
559:                public void push1(Value val) {
560:                    int idx = sz;
561:                    ensureCapacity(idx);
562:                    referenceAt(idx).reset(val);
563:                }
564:
565:                public void push2(Value val1, Value val2) {
566:                    int idx = sz;
567:                    ensureCapacity(idx + 1);
568:                    referenceAt(idx++).reset(val1);
569:                    referenceAt(idx).reset(val2);
570:                }
571:
572:                public void push3(Value val1, Value val2, Value val3) {
573:                    int idx = sz;
574:                    ensureCapacity(idx + 2);
575:                    referenceAt(idx++).reset(val1);
576:                    referenceAt(idx++).reset(val2);
577:                    referenceAt(idx).reset(val3);
578:                }
579:
580:                public void push4(Value val1, Value val2, Value val3, Value val4) {
581:                    int idx = sz;
582:                    ensureCapacity(idx + 3);
583:                    referenceAt(idx++).reset(val1);
584:                    referenceAt(idx++).reset(val2);
585:                    referenceAt(idx++).reset(val3);
586:                    referenceAt(idx).reset(val4);
587:                }
588:
589:                public String toString() {
590:                    return "[" + hashCode() + ": off=" + off + ", sz=" + sz
591:                            + ", len=" + len + "]";
592:                }
593:            }
594:
595:            /**
596:             * Convenience wrapper for {@link #getId}, mainly provided for the benefit
597:             * of script code that probably doesn't want to know about ids, and just
598:             * wants to think in terms of names.
599:             */
600:            public oscript.data.Value getName() {
601:                int id = getId();
602:                if (id == -1)
603:                    return null;
604:                return Symbol.getSymbol(id);
605:            }
606:
607:            /**
608:             * The function name for the current stack frame, if there is one, otherwise
609:             * <code>-1</code>.
610:             */
611:            public final int getId() {
612:                return nes[idx[0]].getId();
613:            }
614:
615:            /**
616:             * The file corresponding to the current stack frame.
617:             */
618:            public final AbstractFile getFile() {
619:                return nes[idx[0]].getFile();
620:            }
621:
622:            /**
623:             * The current line number in the current stack frame.
624:             */
625:            public final int getLineNumber() {
626:                return lines[idx[0]];
627:            }
628:
629:            /**
630:             * The current scope in the current line number.
631:             */
632:            public final Scope getScope() {
633:                return scopes[idx[0]];
634:            }
635:
636:            /**
637:             * Return an iterator of stack frames, starting with the top of the
638:             * stack, and iterating to root of stack.
639:             */
640:            public Iterator iterator() {
641:                return new CollectionIterator(new Iterator() {
642:
643:                    private short idx = StackFrame.this .idx[0];
644:
645:                    public boolean hasNext() {
646:                        return idx > 0;
647:                    }
648:
649:                    public Object next() {
650:                        return new ReadOnlyStackFrame(idx--, nes, lines, scopes);
651:                    }
652:
653:                    public void remove() {
654:                        throw new UnsupportedOperationException("remove");
655:                    }
656:
657:                });
658:            }
659:
660:            public StackFrame getSafeCopy() {
661:                return (StackFrame) clone();
662:            }
663:
664:            /**
665:             * Clone the stack frame, which is necessary in cases where you need to keep
666:             * a reference to the stack frame (and it's parents) after the original
667:             * stack frame has exited, such as to store in an exception.
668:             */
669:            public final Object clone() {
670:                short idx = this .idx[0];
671:
672:                NodeEvaluator[] nes = new NodeEvaluator[idx + 1];
673:                System.arraycopy(this .nes, 0, nes, 0, idx + 1);
674:
675:                int[] lines = new int[idx + 1];
676:                System.arraycopy(this .lines, 0, lines, 0, idx + 1);
677:
678:                Scope[] scopes = new Scope[idx + 1];
679:                for (int i = 0; i < scopes.length; i++)
680:                    if (this .scopes[i] != null)
681:                        scopes[i] = this .scopes[i].getSafeCopy();
682:
683:                return new ReadOnlyStackFrame(idx, nes, lines, scopes);
684:            }
685:
686:            /**
687:             * Convert to string, to print out a line in the stack-trace.
688:             */
689:            public String toString() {
690:                String fileline = getFile() + ":" + getLineNumber();
691:                int id = getId();
692:                if (id == -1)
693:                    return fileline;
694:                return Symbol.getSymbol(id) + " (" + fileline + ")";
695:            }
696:
697:            public int hashCode() {
698:                return getId() ^ getLineNumber();
699:            }
700:
701:            public boolean equals(Object obj) {
702:                if (obj instanceof  StackFrame) {
703:                    StackFrame other = (StackFrame) obj;
704:                    AbstractFile file = getFile();
705:                    return (other.getId() == getId())
706:                            && (other.getLineNumber() == getLineNumber())
707:                            && ((file == null) ? (other.getFile() == null)
708:                                    : other.getFile().equals(getFile()));
709:                }
710:                return false;
711:            }
712:
713:            /*=======================================================================*/
714:            /**
715:             * StackFrame fly-weight to use when not debugging.
716:             */
717:            private static class RegularStackFrame extends StackFrame {
718:                RegularStackFrame(short[] idx, NodeEvaluator[] nes,
719:                        int[] lines, Scope[] scopes,
720:                        StackFrameBasicScope[] scopeLists, Reference[] members,
721:                        short[] membersIdx) {
722:                    super (idx, nes, lines, scopes, scopeLists, members,
723:                            membersIdx);
724:
725:                    regularStackFrame = this ;
726:                    debugStackFrame = new DebugStackFrame(this , idx, nes,
727:                            lines, scopes, scopeLists, members, membersIdx);
728:                }
729:
730:                RegularStackFrame() {
731:                    this (new short[] { 0 }, new NodeEvaluator[STACK_SIZE],
732:                            new int[STACK_SIZE], new Scope[STACK_SIZE],
733:                            new StackFrameBasicScope[STACK_SIZE],
734:                            new Reference[MEMBERS_STACK_SIZE],
735:                            new short[] { 1 } // XXX for debugging, need to not start at 0
736:                    );
737:                }
738:            }
739:
740:            /*=======================================================================*/
741:            /**
742:             * StackFrame fly-weight object to use while debugging.  This functions
743:             * essentially as a facade for the regularStackFrame, but with the calls
744:             * out to the Debugger subsystem.
745:             */
746:            private final static class DebugStackFrame extends StackFrame {
747:                DebugStackFrame(StackFrame sf, short[] idx,
748:                        NodeEvaluator[] nes, int[] lines, Scope[] scopes,
749:                        StackFrameBasicScope[] scopeLists, Reference[] members,
750:                        short[] membersIdx) {
751:                    super (idx, nes, lines, scopes, scopeLists, members,
752:                            membersIdx);
753:
754:                    regularStackFrame = sf;
755:                    debugStackFrame = this ;
756:                }
757:
758:                public void setLineNumber(Scope scope, int line) {
759:                    super .setLineNumber(scope, line);
760:                    Debugger.runBreakpoints(scope, getFile(), line);
761:                }
762:
763:                public void setLineNumber(int line) {
764:                    super .setLineNumber(line);
765:                    Debugger.runBreakpoints(getScope(), getFile(), line);
766:                }
767:            }
768:
769:            /*=======================================================================*/
770:            /**
771:             * A read-only copy of a stack frame, used for a variety of purposes.
772:             */
773:            private static class ReadOnlyStackFrame extends RegularStackFrame {
774:                ReadOnlyStackFrame(short idx, NodeEvaluator[] nes, int[] lines,
775:                        Scope[] scopes) {
776:                    super (new short[] { idx }, nes, lines, scopes, null, null,
777:                            null);
778:                }
779:
780:                public void setLineNumber(Scope scope, int line) {
781:                    throw new ProgrammingErrorException(
782:                            "cloned stack frames are read-only");
783:                }
784:
785:                public void setLineNumber(int line) {
786:                    throw new ProgrammingErrorException(
787:                            "cloned stack frames are read-only");
788:                }
789:
790:                public StackFrame getSafeCopy() {
791:                    return this ;
792:                }
793:            }
794:
795:            /*=======================================================================*/
796:            /**
797:             * For debugging
798:             */
799:
800:            public static final void dumpStack(java.io.OutputStream out) {
801:                dumpStack(new java.io.OutputStreamWriter(out));
802:            }
803:
804:            public static final void dumpStack(java.io.Writer out) {
805:                java.io.PrintWriter ps;
806:
807:                if (out instanceof  java.io.PrintWriter)
808:                    ps = (java.io.PrintWriter) out;
809:                else
810:                    ps = new java.io.PrintWriter(out);
811:
812:                for (Iterator itr = currentStackFrame().iterator(); itr
813:                        .hasNext();)
814:                    ps.println(" at " + itr.next());
815:
816:                ps.flush();
817:            }
818:
819:            private static final boolean DEBUG = false;
820:            private static final boolean VERBOSE = false || DEBUG;
821:
822:            public static final void log(String str) {
823:                if (lastLine != -1) {
824:                    String[] lines = (String[]) (fileTable.get(lastFile));
825:                    if (lines == null) {
826:                        LinkedList linesList = new LinkedList();
827:                        try {
828:                            BufferedReader br = new BufferedReader(
829:                                    new InputStreamReader(lastFile
830:                                            .getInputStream()));
831:                            String tmp;
832:                            while ((tmp = br.readLine()) != null)
833:                                linesList.add(tmp);
834:                        } catch (java.io.IOException e) {
835:                        }
836:                        lines = (String[]) (linesList
837:                                .toArray(new String[linesList.size()]));
838:                        fileTable.put(lastFile, lines);
839:                    }
840:                    lastLine--;
841:                    if (lastLine >= 0 && lastLine < lines.length)
842:                        System.err.println(lastLine + ": "
843:                                + lines[lastLine - 1]);
844:                    lastLine = -1;
845:                }
846:                if (VERBOSE)
847:                    System.err.println("    " + str);
848:            }
849:
850:            private static AbstractFile lastFile = null;
851:            private static int lastLine = -1;
852:            private static Hashtable fileTable = new Hashtable();
853:
854:            private static final void logSetLineNumber(AbstractFile file,
855:                    int line) {
856:                if (file == null)
857:                    return; // ???
858:
859:                if (file != lastFile) {
860:                    System.err.println("file: " + file);
861:                    lastFile = file;
862:                }
863:
864:                lastLine = line;
865:            }
866:        }
867:
868:        /*
869:         *   Local Variables:
870:         *   tab-width: 2
871:         *   indent-tabs-mode: nil
872:         *   mode: java
873:         *   c-indentation-style: java
874:         *   c-basic-offset: 2
875:         *   eval: (c-set-offset 'substatement-open '0)
876:         *   eval: (c-set-offset 'case-label '+)
877:         *   eval: (c-set-offset 'inclass '+)
878:         *   eval: (c-set-offset 'inline-open '0)
879:         *   End:
880:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.