Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/utilities/soql/JSJavaScriptEngine.java @ 3960:f08d439fab8c
7089790: integrate bsd-port changes
Reviewed-by: kvn, twisti, jrose
Contributed-by: Kurt Miller <kurt@intricatesoftware.com>, Greg Lewis <glewis@eyesbeyond.com>, Jung-uk Kim <jkim@freebsd.org>, Christos Zoulas <christos@zoulas.com>, Landon Fuller <landonf@plausible.coop>, The FreeBSD Foundation <board@freebsdfoundation.org>, Michael Franz <mvfranz@gmail.com>, Roger Hoover <rhoover@apple.com>, Alexander Strange <astrange@apple.com>
author | never |
---|---|
date | Sun, 25 Sep 2011 16:03:29 -0700 |
parents | c18cbe5936b8 |
children | da91efe96a93 |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
2 * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
25 package sun.jvm.hotspot.utilities.soql; | |
26 | |
27 import java.io.*; | |
28 import java.util.*; | |
29 import javax.script.Invocable; | |
30 import javax.script.ScriptContext; | |
31 import javax.script.ScriptEngine; | |
32 import javax.script.ScriptEngineManager; | |
33 import javax.script.ScriptException; | |
34 import sun.jvm.hotspot.debugger.*; | |
35 import sun.jvm.hotspot.oops.*; | |
36 import sun.jvm.hotspot.runtime.*; | |
37 import sun.jvm.hotspot.utilities.*; | |
38 import sun.jvm.hotspot.tools.*; | |
39 import sun.jvm.hotspot.tools.jcore.*; | |
40 import java.lang.reflect.Method; | |
41 import java.lang.reflect.Modifier; | |
42 | |
43 /** | |
44 * Simple wrapper around jsr-223 JavaScript script engine. | |
45 * In addition to wrapping useful functionality of jsr-223 engine, | |
46 * this class exposed certain "global" functions to the script. | |
47 */ | |
48 public abstract class JSJavaScriptEngine extends MapScriptObject { | |
49 /** | |
50 * Start a read-eval-print loop with this engine. | |
51 */ | |
52 public void startConsole() { | |
53 start(true); | |
54 } | |
55 | |
56 /** | |
57 * Initialize the engine so that we can "eval" strings | |
58 * and files later. | |
59 */ | |
60 public void start() { | |
61 start(false); | |
62 } | |
63 | |
64 /** | |
65 * Define a global function that invokes given Method. | |
66 */ | |
67 public void defineFunction(Object target, Method method) { | |
68 putFunction(target, method, false); | |
69 } | |
70 | |
71 /** | |
72 * Call the script function of given name passing the | |
73 * given arguments. | |
74 */ | |
75 public Object call(String name, Object[] args) { | |
76 Invocable invocable = (Invocable)engine; | |
77 try { | |
78 return invocable.invokeFunction(name, args); | |
79 } catch (RuntimeException re) { | |
80 throw re; | |
81 } catch (Exception exp) { | |
82 throw new RuntimeException(exp); | |
83 } | |
84 } | |
85 | |
86 /** | |
87 address function returns address of JSJavaObject as String. For other | |
88 type of objects, the result is undefined. | |
89 */ | |
90 public Object address(Object[] args) { | |
91 if (args.length != 1) return UNDEFINED; | |
92 Object o = args[0]; | |
93 if (o != null && o instanceof JSJavaObject) { | |
94 return ((JSJavaObject)o).getOop().getHandle().toString(); | |
95 } else { | |
96 return UNDEFINED; | |
97 } | |
98 } | |
99 | |
100 | |
101 /** | |
102 classof function gets type of given JSJavaInstance or JSJavaArray. Or | |
103 given a string class name, this function gets the class object. For | |
104 other type of objects, the result is undefined. | |
105 */ | |
106 public Object classof(Object[] args) { | |
107 if (args.length != 1) { | |
108 return UNDEFINED; | |
109 } | |
110 Object o = args[0]; | |
111 if (o != null) { | |
112 if (o instanceof JSJavaObject) { | |
113 if (o instanceof JSJavaInstance) { | |
114 return ((JSJavaInstance)o).getJSJavaClass(); | |
115 } else if (o instanceof JSJavaArray) { | |
116 return ((JSJavaArray)o).getJSJavaClass(); | |
117 } else { | |
118 return UNDEFINED; | |
119 } | |
120 } else if (o instanceof String) { | |
121 InstanceKlass ik = SystemDictionaryHelper.findInstanceKlass((String) o); | |
122 return getJSJavaFactory().newJSJavaKlass(ik).getJSJavaClass(); | |
123 } else { | |
124 return UNDEFINED; | |
125 } | |
126 } else { | |
127 return UNDEFINED; | |
128 } | |
129 } | |
130 | |
131 /** | |
132 * dumpClass function creates a .class file for a given Class object. | |
133 * On success, returns true. Else, returns false. Second optional argument | |
134 * specifies the directory in which .class content is dumped. This defaults | |
135 * to '.' | |
136 */ | |
137 public Object dumpClass(Object[] args) { | |
138 if (args.length == 0) { | |
139 return Boolean.FALSE; | |
140 } | |
141 Object clazz = args[0]; | |
142 if (clazz == null) { | |
143 return Boolean.FALSE; | |
144 } | |
145 InstanceKlass ik = null; | |
146 if (clazz instanceof String) { | |
147 String name = (String) clazz; | |
148 if (name.startsWith("0x")) { | |
149 // treat it as address | |
150 VM vm = VM.getVM(); | |
151 Address addr = vm.getDebugger().parseAddress(name); | |
152 Oop oop = vm.getObjectHeap().newOop(addr.addOffsetToAsOopHandle(0)); | |
153 if (oop instanceof InstanceKlass) { | |
154 ik = (InstanceKlass) oop; | |
155 } else { | |
156 return Boolean.FALSE; | |
157 } | |
158 } else { | |
159 ik = SystemDictionaryHelper.findInstanceKlass((String) clazz); | |
160 } | |
161 } else if (clazz instanceof JSJavaClass) { | |
162 JSJavaKlass jk = ((JSJavaClass)clazz).getJSJavaKlass(); | |
163 if (jk != null && jk instanceof JSJavaInstanceKlass) { | |
164 ik = ((JSJavaInstanceKlass)jk).getInstanceKlass(); | |
165 } | |
166 } else { | |
167 return Boolean.FALSE; | |
168 } | |
169 | |
170 if (ik == null) return Boolean.FALSE; | |
171 StringBuffer buf = new StringBuffer(); | |
172 if (args.length > 1) { | |
173 buf.append(args[1].toString()); | |
174 } else { | |
175 buf.append('.'); | |
176 } | |
177 | |
178 buf.append(File.separatorChar); | |
179 buf.append(ik.getName().asString().replace('/', File.separatorChar)); | |
180 buf.append(".class"); | |
181 String fileName = buf.toString(); | |
182 File file = new File(fileName); | |
183 | |
184 try { | |
185 int index = fileName.lastIndexOf(File.separatorChar); | |
186 File dir = new File(fileName.substring(0, index)); | |
187 dir.mkdirs(); | |
188 FileOutputStream fos = new FileOutputStream(file); | |
189 ClassWriter cw = new ClassWriter(ik, fos); | |
190 cw.write(); | |
191 fos.close(); | |
192 } catch (IOException exp) { | |
193 printError(exp.toString(), exp); | |
194 return Boolean.FALSE; | |
195 } | |
196 | |
197 return Boolean.TRUE; | |
198 } | |
199 | |
200 /** | |
201 * dumpHeap function creates a heap dump file. | |
202 * On success, returns true. Else, returns false. | |
203 */ | |
204 public Object dumpHeap(Object[] args) { | |
205 String fileName = "heap.bin"; | |
206 if (args.length > 0) { | |
207 fileName = args[0].toString(); | |
208 } | |
209 return new JMap().writeHeapHprofBin(fileName)? Boolean.TRUE: Boolean.FALSE; | |
210 } | |
211 | |
212 /** | |
213 help function prints help message for global functions and variables. | |
214 */ | |
215 public void help(Object[] args) { | |
216 println("Function/Variable Description"); | |
217 println("================= ==========="); | |
218 println("address(jobject) returns the address of the Java object"); | |
219 println("classof(jobject) returns the class object of the Java object"); | |
220 println("dumpClass(jclass,[dir]) writes .class for the given Java Class"); | |
221 println("dumpHeap([file]) writes heap in hprof binary format"); | |
222 println("help() prints this help message"); | |
223 println("identityHash(jobject) returns the hashCode of the Java object"); | |
224 println("mirror(jobject) returns a local mirror of the Java object"); | |
225 println("load([file1, file2,...]) loads JavaScript file(s). With no files, reads <stdin>"); | |
226 println("object(string) converts a string address into Java object"); | |
227 println("owner(jobject) returns the owner thread of this monitor or null"); | |
228 println("sizeof(jobject) returns the size of Java object in bytes"); | |
229 println("staticof(jclass, field) returns a static field of the given Java class"); | |
230 println("read([prompt]) reads a single line from standard input"); | |
231 println("quit() quits the interactive load call"); | |
232 println("jvm the target jvm that is being debugged"); | |
233 } | |
234 | |
235 /** | |
236 identityHash function gets identity hash code value of given | |
237 JSJavaObject. For other type of objects, the result is undefined. | |
238 */ | |
239 public Object identityHash(Object[] args) { | |
240 if (args.length != 1) return UNDEFINED; | |
241 Object o = args[0]; | |
242 if (o != null && o instanceof JSJavaObject) { | |
243 return new Long(((JSJavaObject)o).getOop().identityHash()); | |
244 } else { | |
245 return UNDEFINED; | |
246 } | |
247 } | |
248 | |
249 | |
250 /** | |
251 * Load and execute a set of JavaScript source files. | |
252 * This method is defined as a JavaScript function. | |
253 */ | |
254 public void load(Object[] args) { | |
255 for (int i = 0; i < args.length; i++) { | |
256 processSource(args[i].toString()); | |
257 } | |
258 } | |
259 | |
260 /** | |
261 mirror function creats local copy of the Oop wrapper supplied. | |
262 if mirror can not be created, return undefined. For other types, | |
263 mirror is undefined. | |
264 */ | |
265 public Object mirror(Object[] args) { | |
266 Object o = args[0]; | |
267 if (o != null && o instanceof JSJavaObject) { | |
268 Oop oop = ((JSJavaObject)o).getOop(); | |
269 Object res = null; | |
270 try { | |
271 if (oop instanceof InstanceKlass) { | |
272 res = getObjectReader().readClass((InstanceKlass) oop); | |
273 } else { | |
274 res = getObjectReader().readObject(oop); | |
275 } | |
276 } catch (Exception e) { | |
277 if (debug) e.printStackTrace(getErrorStream()); | |
278 } | |
279 return (res != null)? res : UNDEFINED; | |
280 } else { | |
281 return UNDEFINED; | |
282 } | |
283 } | |
284 | |
285 /** | |
286 owner function gets owning thread of given JSJavaObjec, if any, else | |
287 returns null. For other type of objects, the result is undefined. | |
288 */ | |
289 public Object owner(Object[] args) { | |
290 Object o = args[0]; | |
291 if (o != null && o instanceof JSJavaObject) { | |
292 return getOwningThread((JSJavaObject)o); | |
293 } else { | |
294 return UNDEFINED; | |
295 } | |
296 } | |
297 | |
298 /** | |
299 object function takes a string address and returns a JSJavaObject. | |
300 For other type of objects, the result is undefined. | |
301 */ | |
302 public Object object(Object[] args) { | |
303 Object o = args[0]; | |
304 if (o != null && o instanceof String) { | |
305 VM vm = VM.getVM(); | |
306 Address addr = vm.getDebugger().parseAddress((String)o); | |
307 Oop oop = vm.getObjectHeap().newOop(addr.addOffsetToAsOopHandle(0)); | |
308 return getJSJavaFactory().newJSJavaObject(oop); | |
309 } else { | |
310 return UNDEFINED; | |
311 } | |
312 } | |
313 | |
314 /** | |
315 sizeof function returns size of a Java object in bytes. For other type | |
316 of objects, the result is undefined. | |
317 */ | |
318 public Object sizeof(Object[] args) { | |
319 if (args.length != 1) return UNDEFINED; | |
320 Object o = args[0]; | |
321 if (o != null && o instanceof JSJavaObject) { | |
322 return new Long(((JSJavaObject)o).getOop().getObjectSize()); | |
323 } else { | |
324 return UNDEFINED; | |
325 } | |
326 } | |
327 | |
328 /** | |
329 staticof function gets static field of given class. Both class and | |
330 field name are specified as strings. undefined is returned if there is | |
331 no such named field. | |
332 */ | |
333 public Object staticof(Object[] args) { | |
334 Object classname = args[0]; | |
335 Object fieldname = args[1]; | |
336 if (fieldname == null || classname == null || | |
337 !(fieldname instanceof String)) { | |
338 return UNDEFINED; | |
339 } | |
340 | |
341 InstanceKlass ik = null; | |
342 if (classname instanceof JSJavaClass) { | |
343 JSJavaClass jclass = (JSJavaClass) classname; | |
344 JSJavaKlass jk = jclass.getJSJavaKlass(); | |
345 if (jk != null && jk instanceof JSJavaInstanceKlass) { | |
346 ik = ((JSJavaInstanceKlass)jk).getInstanceKlass(); | |
347 } | |
348 } else if (classname instanceof String) { | |
349 ik = SystemDictionaryHelper.findInstanceKlass((String)classname); | |
350 } else { | |
351 return UNDEFINED; | |
352 } | |
353 | |
354 if (ik == null) { | |
355 return UNDEFINED; | |
356 } | |
357 JSJavaFactory factory = getJSJavaFactory(); | |
358 try { | |
359 return ((JSJavaInstanceKlass) factory.newJSJavaKlass(ik)).getStaticFieldValue((String)fieldname); | |
360 } catch (NoSuchFieldException e) { | |
361 return UNDEFINED; | |
362 } | |
363 } | |
364 | |
365 /** | |
366 * read function reads a single line of input from standard input | |
367 */ | |
368 public Object read(Object[] args) { | |
369 BufferedReader in = getInputReader(); | |
370 if (in == null) { | |
371 return null; | |
372 } | |
373 if (args.length > 0) { | |
374 print(args[0].toString()); | |
375 print(":"); | |
376 } | |
377 try { | |
378 return in.readLine(); | |
379 } catch (IOException exp) { | |
380 exp.printStackTrace(); | |
381 throw new RuntimeException(exp); | |
382 } | |
383 } | |
384 | |
385 /** | |
386 * Quit the shell. | |
387 * This only affects the interactive mode. | |
388 */ | |
389 public void quit(Object[] args) { | |
390 quit(); | |
391 } | |
392 | |
393 public void writeln(Object[] args) { | |
394 for (int i = 0; i < args.length; i++) { | |
395 print(args[i].toString()); | |
396 print(" "); | |
397 } | |
398 println(""); | |
399 } | |
400 | |
401 public void write(Object[] args) { | |
402 for (int i = 0; i < args.length; i++) { | |
403 print(args[i].toString()); | |
404 print(" "); | |
405 } | |
406 } | |
407 | |
408 //-- Internals only below this point | |
409 protected void start(boolean console) { | |
410 ScriptContext context = engine.getContext(); | |
411 OutputStream out = getOutputStream(); | |
412 if (out != null) { | |
413 context.setWriter(new PrintWriter(out)); | |
414 } | |
415 OutputStream err = getErrorStream(); | |
416 if (err != null) { | |
417 context.setErrorWriter(new PrintWriter(err)); | |
418 } | |
419 // load "sa.js" initialization file | |
420 loadInitFile(); | |
421 // load "~/jsdb.js" (if found) to perform user specific | |
422 // initialization steps, if any. | |
423 loadUserInitFile(); | |
424 | |
425 JSJavaFactory fac = getJSJavaFactory(); | |
426 JSJavaVM jvm = (fac != null)? fac.newJSJavaVM() : null; | |
427 // call "main" function from "sa.js" -- main expects | |
428 // 'this' object and jvm object | |
429 call("main", new Object[] { this, jvm }); | |
430 | |
431 // if asked, start read-eval-print console | |
432 if (console) { | |
433 processSource(null); | |
434 } | |
435 } | |
436 | |
437 protected JSJavaScriptEngine(boolean debug) { | |
438 this.debug = debug; | |
439 ScriptEngineManager manager = new ScriptEngineManager(); | |
440 engine = manager.getEngineByName("javascript"); | |
441 if (engine == null) { | |
442 throw new RuntimeException("can't load JavaScript engine"); | |
443 } | |
444 Method[] methods = getClass().getMethods(); | |
445 for (int i = 0; i < methods.length; i++) { | |
446 Method m = methods[i]; | |
447 if (! Modifier.isPublic(m.getModifiers())) { | |
448 continue; | |
449 } | |
450 Class[] argTypes = m.getParameterTypes(); | |
451 if (argTypes.length == 1 && | |
452 argTypes[0] == Object[].class) { | |
453 putFunction(this, m); | |
454 } | |
455 } | |
456 } | |
457 | |
458 protected JSJavaScriptEngine() { | |
459 this(false); | |
460 } | |
461 | |
462 protected abstract ObjectReader getObjectReader(); | |
463 protected abstract JSJavaFactory getJSJavaFactory(); | |
464 protected void printPrompt(String str) { | |
465 System.err.print(str); | |
466 System.err.flush(); | |
467 } | |
468 | |
469 protected void loadInitFile() { | |
470 InputStream is = JSJavaScriptEngine.class.getResourceAsStream("sa.js"); | |
471 BufferedReader reader = new BufferedReader(new InputStreamReader(is)); | |
472 evalReader(reader, "sa.js"); | |
473 } | |
474 | |
475 protected void loadUserInitFile() { | |
476 File initFile = new File(getUserInitFileDir(), getUserInitFileName()); | |
477 if (initFile.exists() && initFile.isFile()) { | |
478 // load the init script | |
479 processSource(initFile.getAbsolutePath()); | |
480 } | |
481 } | |
482 | |
483 protected String getUserInitFileDir() { | |
484 return System.getProperty("user.home"); | |
485 } | |
486 | |
487 protected String getUserInitFileName() { | |
488 return "jsdb.js"; | |
489 } | |
490 | |
491 protected BufferedReader getInputReader() { | |
492 if (inReader == null) { | |
493 inReader = new BufferedReader(new InputStreamReader(System.in)); | |
494 } | |
495 return inReader; | |
496 } | |
497 | |
498 protected PrintStream getOutputStream() { | |
499 return System.out; | |
500 } | |
501 | |
502 protected PrintStream getErrorStream() { | |
503 return System.err; | |
504 } | |
505 | |
506 protected void print(String name) { | |
507 getOutputStream().print(name); | |
508 } | |
509 | |
510 protected void println(String name) { | |
511 getOutputStream().println(name); | |
512 } | |
513 | |
514 protected void printError(String message) { | |
515 printError(message, null); | |
516 } | |
517 | |
518 protected void printError(String message, Exception exp) { | |
519 getErrorStream().println(message); | |
520 if (exp != null && debug) { | |
521 exp.printStackTrace(getErrorStream()); | |
522 } | |
523 } | |
524 | |
525 protected boolean isQuitting() { | |
526 return quitting; | |
527 } | |
528 | |
529 protected void quit() { | |
530 quitting = true; | |
531 } | |
532 | |
533 protected ScriptEngine getScriptEngine() { | |
534 return engine; | |
535 } | |
536 | |
537 private JSJavaThread getOwningThread(JSJavaObject jo) { | |
538 Oop oop = jo.getOop(); | |
539 Mark mark = oop.getMark(); | |
540 ObjectMonitor mon = null; | |
541 Address owner = null; | |
542 JSJavaThread owningThread = null; | |
543 // check for heavyweight monitor | |
544 if (! mark.hasMonitor()) { | |
545 // check for lightweight monitor | |
546 if (mark.hasLocker()) { | |
547 owner = mark.locker().getAddress(); // save the address of the Lock word | |
548 } | |
549 // implied else: no owner | |
550 } else { | |
551 // this object has a heavyweight monitor | |
552 mon = mark.monitor(); | |
553 | |
554 // The owner field of a heavyweight monitor may be NULL for no | |
555 // owner, a JavaThread * or it may still be the address of the | |
556 // Lock word in a JavaThread's stack. A monitor can be inflated | |
557 // by a non-owning JavaThread, but only the owning JavaThread | |
558 // can change the owner field from the Lock word to the | |
559 // JavaThread * and it may not have done that yet. | |
560 owner = mon.owner(); | |
561 } | |
562 | |
563 // find the owning thread | |
564 if (owner != null) { | |
565 JSJavaFactory factory = getJSJavaFactory(); | |
566 owningThread = (JSJavaThread) factory.newJSJavaThread(VM.getVM().getThreads().owningThreadFromMonitor(owner)); | |
567 } | |
568 return owningThread; | |
569 } | |
570 | |
571 /** | |
572 * Evaluate JavaScript source. | |
573 * @param filename the name of the file to compile, or null | |
574 * for interactive mode. | |
575 */ | |
576 private void processSource(String filename) { | |
577 if (filename == null) { | |
578 BufferedReader in = getInputReader(); | |
579 String sourceName = "<stdin>"; | |
580 int lineno = 0; | |
581 boolean hitEOF = false; | |
582 do { | |
583 int startline = lineno; | |
584 printPrompt("jsdb> "); | |
585 Object source = read(EMPTY_ARRAY); | |
586 if (source == null) { | |
587 hitEOF = true; | |
588 break; | |
589 } | |
590 lineno++; | |
591 Object result = evalString(source.toString(), sourceName, startline); | |
592 if (result != null) { | |
593 printError(result.toString()); | |
594 } | |
595 if (isQuitting()) { | |
596 // The user executed the quit() function. | |
597 break; | |
598 } | |
599 } while (!hitEOF); | |
600 } else { | |
601 Reader in = null; | |
602 try { | |
603 in = new BufferedReader(new FileReader(filename)); | |
604 evalReader(in, filename); | |
605 } catch (FileNotFoundException ex) { | |
606 println("File '" + filename + "' not found"); | |
607 throw new RuntimeException(ex); | |
608 } | |
609 } | |
610 } | |
611 | |
612 protected Object evalString(String source, String filename, int lineNum) { | |
613 try { | |
614 engine.put(ScriptEngine.FILENAME, filename); | |
615 return engine.eval(source); | |
616 } catch (ScriptException sexp) { | |
617 printError(sexp.toString(), sexp); | |
618 } catch (Exception exp) { | |
619 printError(exp.toString(), exp); | |
620 } | |
621 return null; | |
622 } | |
623 | |
624 private Object evalReader(Reader in, String filename) { | |
625 try { | |
626 engine.put(ScriptEngine.FILENAME, filename); | |
627 return engine.eval(in); | |
628 } catch (ScriptException sexp) { | |
629 System.err.println(sexp); | |
630 printError(sexp.toString(), sexp); | |
631 } finally { | |
632 try { | |
633 in.close(); | |
634 } catch (IOException ioe) { | |
635 printError(ioe.toString(), ioe); | |
636 } | |
637 } | |
638 return null; | |
639 } | |
640 | |
641 // lazily initialized input reader | |
642 private BufferedReader inReader; | |
643 // debug mode or not | |
644 protected final boolean debug; | |
645 private boolean quitting; | |
646 // underlying jsr-223 script engine | |
647 private ScriptEngine engine; | |
648 } |