KJS

interpreter.cpp
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 1999-2001 Harri Porten ([email protected])
4  * Copyright (C) 2001 Peter Kelly ([email protected])
5  * Copyright (C) 2003 Apple Computer, Inc.
6  * Copyright (C) 2008, 2009 Maksim Orlovich ([email protected])
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB. If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24 
25 #include "interpreter.h"
26 
27 #include "SavedBuiltins.h"
28 #include "array_object.h"
29 #include "bool_object.h"
30 #include "collector.h"
31 #include "date_object.h"
32 #include "debugger.h"
33 #include "error_object.h"
34 #include "function_object.h"
35 #include "internal.h"
36 #include "math_object.h"
37 #include "nodes.h"
38 #include "number_object.h"
39 #include "object.h"
40 #include "object_object.h"
41 #include "operations.h"
42 #include "regexp_object.h"
43 #include "string_object.h"
44 #include "lexer.h"
45 #include "json_object.h"
46 
47 #if USE(BINDINGS)
48 #include "runtime.h"
49 #endif
50 
51 #if defined _WIN32 || defined _WIN64
52 #undef HAVE_SYS_TIME_H // no setitimer in kdewin32
53 #endif
54 #if HAVE_SYS_TIME_H
55 #include <sys/time.h>
56 #endif
57 
58 #include <assert.h>
59 #include <cstdlib>
60 #include <math.h>
61 #include <signal.h>
62 #include <stdio.h>
63 #if HAVE_UNISTD_H
64 #include <unistd.h>
65 #endif
66 
67 namespace KJS
68 {
69 
70 class TimeoutChecker
71 {
72 public:
73  void startTimeoutCheck(Interpreter *);
74  void stopTimeoutCheck(Interpreter *);
75  void pauseTimeoutCheck(Interpreter *);
76  void resumeTimeoutCheck(Interpreter *);
77 
78 private:
79 #if HAVE_SYS_TIME_H
80  static Interpreter *s_executingInterpreter;
81  static void alarmHandler(int);
82 
83  Interpreter *m_oldInterpreter;
84  itimerval m_oldtv;
85  itimerval m_pausetv;
86  void (*m_oldAlarmHandler)(int);
87 #endif
88 };
89 
90 #if HAVE_SYS_TIME_H
91 Interpreter *TimeoutChecker::s_executingInterpreter = nullptr;
92 #endif
93 
94 void TimeoutChecker::startTimeoutCheck(Interpreter *interpreter)
95 {
96  if (!interpreter->m_timeoutTime) {
97  return;
98  }
99 
100  interpreter->m_startTimeoutCheckCount++;
101 
102 #if HAVE_SYS_TIME_H
103  if (s_executingInterpreter == interpreter) {
104  return;
105  }
106 
107  // Block signals
108  m_oldAlarmHandler = signal(SIGALRM, SIG_IGN);
109 
110  m_oldInterpreter = s_executingInterpreter;
111  s_executingInterpreter = interpreter;
112 
113  itimerval tv = {
114  { time_t(interpreter->m_timeoutTime / 1000),
115  suseconds_t((interpreter->m_timeoutTime % 1000) * 1000) },
116  { time_t(interpreter->m_timeoutTime / 1000),
117  suseconds_t((interpreter->m_timeoutTime % 1000) * 1000) }
118  };
119  setitimer(ITIMER_REAL, &tv, &m_oldtv);
120 
121  // Unblock signals
122  signal(SIGALRM, alarmHandler);
123 #endif
124 }
125 
126 void TimeoutChecker::stopTimeoutCheck(Interpreter *interpreter)
127 {
128  if (!interpreter->m_timeoutTime) {
129  return;
130  }
131 
132  ASSERT(interpreter->m_startTimeoutCheckCount > 0);
133 
134  interpreter->m_startTimeoutCheckCount--;
135 
136  if (interpreter->m_startTimeoutCheckCount != 0) {
137  return;
138  }
139 
140 #if HAVE_SYS_TIME_H
141  signal(SIGALRM, SIG_IGN);
142 
143  s_executingInterpreter = m_oldInterpreter;
144 
145  setitimer(ITIMER_REAL, &m_oldtv, nullptr);
146  signal(SIGALRM, m_oldAlarmHandler);
147 #endif
148 }
149 
150 #if HAVE_SYS_TIME_H
151 void TimeoutChecker::alarmHandler(int)
152 {
153  s_executingInterpreter->m_timedOut = true;
154 }
155 #endif
156 
157 void TimeoutChecker::pauseTimeoutCheck(Interpreter *interpreter)
158 {
159  if (interpreter->m_startTimeoutCheckCount == 0) {
160  return;
161  }
162 
163 #if HAVE_SYS_TIME_H
164  ASSERT(interpreter == s_executingInterpreter);
165 
166  void (*currentSignalHandler)(int);
167 
168  // Block signal
169  currentSignalHandler = signal(SIGALRM, SIG_IGN);
170 
171  if (currentSignalHandler != alarmHandler) {
172  signal(SIGALRM, currentSignalHandler);
173  return;
174  }
175 
176  setitimer(ITIMER_REAL, nullptr, &m_pausetv);
177 #endif
178 
179  interpreter->m_pauseTimeoutCheckCount++;
180 }
181 
182 void TimeoutChecker::resumeTimeoutCheck(Interpreter *interpreter)
183 {
184  if (interpreter->m_startTimeoutCheckCount == 0) {
185  return;
186  }
187 
188 #if HAVE_SYS_TIME_H
189  ASSERT(interpreter == s_executingInterpreter);
190 #endif
191 
192  interpreter->m_pauseTimeoutCheckCount--;
193 
194  if (interpreter->m_pauseTimeoutCheckCount != 0) {
195  return;
196  }
197 
198 #if HAVE_SYS_TIME_H
199  void (*currentSignalHandler)(int);
200 
201  // Check so we have the right handler
202  currentSignalHandler = signal(SIGALRM, SIG_IGN);
203 
204  if (currentSignalHandler != SIG_IGN) {
205  signal(SIGALRM, currentSignalHandler);
206  return;
207  }
208 
209  setitimer(ITIMER_REAL, &m_pausetv, nullptr);
210 
211  // Unblock signal
212  currentSignalHandler = signal(SIGALRM, alarmHandler);
213 #endif
214 }
215 
216 Interpreter *Interpreter::s_hook = nullptr;
217 
218 Interpreter::Interpreter(JSGlobalObject *globalObject)
219  : m_globalObject(globalObject),
220  m_globalExec(this, globalObject),
221  globPkg(nullptr)
222 {
223  init();
224 }
225 
227  : m_globalObject(new JSGlobalObject()),
228  m_globalExec(this, m_globalObject),
229  globPkg(nullptr)
230 {
231  init();
232 }
233 
234 void Interpreter::init()
235 {
236  JSLock lock;
237 
238  initInternedStringsTable();
239 
240  m_refCount = 0;
241  m_timeoutTime = 0;
242  m_recursion = 0;
243  m_debugger = nullptr;
244  m_execState = nullptr;
245  m_timedOut = false;
246  m_timeoutChecker = nullptr;
247  m_startTimeoutCheckCount = 0;
248  m_pauseTimeoutCheckCount = 0;
249  m_compatMode = NativeMode;
250 
251  const int initialStackSize = 8192;
252  stackBase = (unsigned char *)std::malloc(initialStackSize);
253  stackPtr = stackBase;
254  stackEnd = stackBase + initialStackSize;
255 
256  m_numCachedActivations = 0;
257 
258  m_globalObject->setInterpreter(this);
259 
260  if (s_hook) {
261  prev = s_hook;
262  next = s_hook->next;
263  s_hook->next->prev = this;
264  s_hook->next = this;
265  } else {
266  // This is the first interpreter
267  s_hook = next = prev = this;
268  }
269 
270  initGlobalObject();
271 }
272 
273 Interpreter::~Interpreter()
274 {
275  JSLock lock;
276 
277  ASSERT(m_startTimeoutCheckCount == 0);
278  ASSERT(m_pauseTimeoutCheckCount == 0);
279 
280  delete m_timeoutChecker;
281 
282  if (m_debugger) {
283  m_debugger->detach(this);
284  }
285 
286  std::free(stackBase);
287 
288  next->prev = prev;
289  prev->next = next;
290  s_hook = next;
291  if (s_hook == this) {
292  // This was the last interpreter
293  s_hook = nullptr;
294  }
295 
296  m_globalObject->setInterpreter(nullptr);
297 }
298 
299 unsigned char *Interpreter::extendStack(size_t needed)
300 {
301  unsigned char *oldBase = stackBase; // needed for fixing up localStores
302 
303  size_t curSize = stackEnd - stackBase;
304  size_t avail = stackEnd - stackPtr;
305  size_t extra = needed - avail;
306 
307  if (extra < 8192) {
308  extra = 8192;
309  }
310  size_t newSize = curSize + extra;
311 
312  //printf("Grow stack:%d -> %d\n", curSize, newSize);
313 
314  stackBase = (unsigned char *)std::malloc(newSize); // Not realloc since we need the old stuff
315  // ### seems optimizeable
316  std::memcpy(stackBase, oldBase, curSize);
317  stackPtr = stackBase + (stackPtr - oldBase);
318  stackEnd = stackBase + newSize;
319 
320  // Now go through and fix up activations..
321  ExecState *e = m_execState;
322  while (e) {
323  if (e->codeType() == FunctionCode) {
324  ActivationImp *act = static_cast<ActivationImp *>(e->activationObject());
325  if (act->localStorage) {
326  act->localStorage = (LocalStorageEntry *)
327  (stackBase + ((unsigned char *)act->localStorage - oldBase));
328  e->updateLocalStorage(act->localStorage);
329  }
330  }
331 
332  e = e->savedExecState();
333  }
334 
335  std::free(oldBase);
336 
337  return stackAlloc(needed);
338 }
339 
340 void Interpreter::recycleActivation(ActivationImp *act)
341 {
342  ASSERT(act->localStorage == nullptr); // Should not refer to anything by now
343  if (m_numCachedActivations >= MaxCachedActivations) {
344  return;
345  }
346 
347  act->clearProperties();
348  m_cachedActivations[m_numCachedActivations] = act;
349  ++m_numCachedActivations;
350 }
351 
352 JSGlobalObject *Interpreter::globalObject() const
353 {
354  return m_globalObject;
355 }
356 
357 void Interpreter::putNamedConstructor(const char *name, JSObject *value)
358 {
359  assert(value->implementsCall());
360  Identifier i(name);
361  m_globalObject->put(&m_globalExec, i, value, DontEnum);
362  static_cast<InternalFunctionImp *>(value)->setFunctionName(i);
363 }
364 
365 void Interpreter::initGlobalObject()
366 {
367  FunctionPrototype *funcProto = new FunctionPrototype(&m_globalExec);
368  m_FunctionPrototype = funcProto;
369  ObjectPrototype *objProto = new ObjectPrototype(&m_globalExec, funcProto);
370  m_ObjectPrototype = objProto;
371  funcProto->setPrototype(m_ObjectPrototype);
372 
373  ArrayPrototype *arrayProto = new ArrayPrototype(&m_globalExec, objProto);
374  m_ArrayPrototype = arrayProto;
375  StringPrototype *stringProto = new StringPrototype(&m_globalExec, objProto);
376  m_StringPrototype = stringProto;
377  BooleanPrototype *booleanProto = new BooleanPrototype(&m_globalExec, objProto, funcProto);
378  m_BooleanPrototype = booleanProto;
379  NumberPrototype *numberProto = new NumberPrototype(&m_globalExec, objProto, funcProto);
380  m_NumberPrototype = numberProto;
381  DatePrototype *dateProto = new DatePrototype(&m_globalExec, objProto);
382  m_DatePrototype = dateProto;
383  RegExpPrototype *regexpProto = new RegExpPrototype(&m_globalExec, objProto, funcProto);
384  m_RegExpPrototype = regexpProto;
385  ErrorPrototype *errorProto = new ErrorPrototype(&m_globalExec, objProto, funcProto);
386  m_ErrorPrototype = errorProto;
387 
388  JSObject *o = m_globalObject;
389  while (JSValue::isObject(o->prototype())) {
390  o = static_cast<JSObject *>(o->prototype());
391  }
392  o->setPrototype(m_ObjectPrototype);
393 
394  // Constructors (Object, Array, etc.)
395  m_Object = new ObjectObjectImp(&m_globalExec, objProto, funcProto);
396  m_Function = new FunctionObjectImp(&m_globalExec, funcProto);
397  m_Array = new ArrayObjectImp(&m_globalExec, funcProto, arrayProto);
398  m_String = new StringObjectImp(&m_globalExec, funcProto, stringProto);
399  m_Boolean = new BooleanObjectImp(&m_globalExec, funcProto, booleanProto);
400  m_Number = new NumberObjectImp(&m_globalExec, funcProto, numberProto);
401  m_Date = new DateObjectImp(&m_globalExec, funcProto, dateProto);
402  m_RegExp = new RegExpObjectImp(&m_globalExec, funcProto, regexpProto);
403  m_Error = new ErrorObjectImp(&m_globalExec, funcProto, errorProto);
404 
405  // Error object prototypes
406  m_EvalErrorPrototype = new NativeErrorPrototype(&m_globalExec, errorProto, EvalError, "EvalError", "EvalError");
407  m_RangeErrorPrototype = new NativeErrorPrototype(&m_globalExec, errorProto, RangeError, "RangeError", "RangeError");
408  m_ReferenceErrorPrototype = new NativeErrorPrototype(&m_globalExec, errorProto, ReferenceError, "ReferenceError", "ReferenceError");
409  m_SyntaxErrorPrototype = new NativeErrorPrototype(&m_globalExec, errorProto, SyntaxError, "SyntaxError", "SyntaxError");
410  m_TypeErrorPrototype = new NativeErrorPrototype(&m_globalExec, errorProto, TypeError, "TypeError", "TypeError");
411  m_UriErrorPrototype = new NativeErrorPrototype(&m_globalExec, errorProto, URIError, "URIError", "URIError");
412 
413  // Error objects
414  m_EvalError = new NativeErrorImp(&m_globalExec, funcProto, m_EvalErrorPrototype);
415  m_RangeError = new NativeErrorImp(&m_globalExec, funcProto, m_RangeErrorPrototype);
416  m_ReferenceError = new NativeErrorImp(&m_globalExec, funcProto, m_ReferenceErrorPrototype);
417  m_SyntaxError = new NativeErrorImp(&m_globalExec, funcProto, m_SyntaxErrorPrototype);
418  m_TypeError = new NativeErrorImp(&m_globalExec, funcProto, m_TypeErrorPrototype);
419  m_UriError = new NativeErrorImp(&m_globalExec, funcProto, m_UriErrorPrototype);
420 
421  // ECMA 15.3.4.1
422  funcProto->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Function, DontEnum);
423 
424  putNamedConstructor("Object", m_Object);
425  putNamedConstructor("Function", m_Function);
426  putNamedConstructor("Array", m_Array);
427  putNamedConstructor("Boolean", m_Boolean);
428  putNamedConstructor("String", m_String);
429  putNamedConstructor("Number", m_Number);
430  putNamedConstructor("Date", m_Date);
431  putNamedConstructor("RegExp", m_RegExp);
432  putNamedConstructor("Error", m_Error);
433  putNamedConstructor("EvalError", m_EvalError);
434  putNamedConstructor("RangeError", m_RangeError);
435  putNamedConstructor("ReferenceError", m_ReferenceError);
436  putNamedConstructor("SyntaxError", m_SyntaxError);
437  putNamedConstructor("TypeError", m_TypeError);
438  putNamedConstructor("URIError", m_UriError);
439 
440  // Set the constructorPropertyName property of all builtin constructors
441  objProto->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Object, DontEnum);
442  funcProto->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Function, DontEnum);
443  arrayProto->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Array, DontEnum);
444  booleanProto->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Boolean, DontEnum);
445  stringProto->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_String, DontEnum);
446  numberProto->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Number, DontEnum);
447  dateProto->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Date, DontEnum);
448  regexpProto->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_RegExp, DontEnum);
449  errorProto->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Error, DontEnum);
450  m_EvalErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_EvalError, DontEnum);
451  m_RangeErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_RangeError, DontEnum);
452  m_ReferenceErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_ReferenceError, DontEnum);
453  m_SyntaxErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_SyntaxError, DontEnum);
454  m_TypeErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_TypeError, DontEnum);
455  m_UriErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_UriError, DontEnum);
456 
457  // built-in values
458  m_globalObject->put(&m_globalExec, "NaN", jsNaN(), DontEnum | DontDelete | ReadOnly);
459  m_globalObject->put(&m_globalExec, "Infinity", jsNumber(Inf), DontEnum | DontDelete | ReadOnly);
460  m_globalObject->put(&m_globalExec, "undefined", jsUndefined(), DontEnum | DontDelete | ReadOnly);
461 
462  // built-in functions
463  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::Eval, 1, "eval"), DontEnum);
464  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::ParseInt, 2, "parseInt"), DontEnum);
465  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::ParseFloat, 1, "parseFloat"), DontEnum);
466  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::IsNaN, 1, "isNaN"), DontEnum);
467  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::IsFinite, 1, "isFinite"), DontEnum);
468  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::Escape, 1, "escape"), DontEnum);
469  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::UnEscape, 1, "unescape"), DontEnum);
470  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::DecodeURI, 1, "decodeURI"), DontEnum);
471  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::DecodeURIComponent, 1, "decodeURIComponent"), DontEnum);
472  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::EncodeURI, 1, "encodeURI"), DontEnum);
473  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::EncodeURIComponent, 1, "encodeURIComponent"), DontEnum);
474 #ifndef NDEBUG
475  m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, funcProto, GlobalFuncImp::KJSPrint, 1, "kjsprint"), DontEnum);
476 #endif
477 
478  // built-in objects
479  m_globalObject->put(&m_globalExec, "Math", new MathObjectImp(&m_globalExec, objProto), DontEnum);
480  m_globalObject->put(&m_globalExec, "JSON", new JSONObjectImp(&m_globalExec, objProto), DontEnum);
481 }
482 
484 {
485  return &m_globalExec;
486 }
487 
489 {
490  globPkg = p;
491 }
492 
494 {
495  return globPkg;
496 }
497 
498 Completion Interpreter::checkSyntax(const UString &sourceURL, int startingLineNumber, const UString &code)
499 {
500  return checkSyntax(sourceURL, startingLineNumber, code.data(), code.size());
501 }
502 
503 Completion Interpreter::checkSyntax(const UString &sourceURL, int startingLineNumber, const UChar *code, int codeLength)
504 {
505  JSLock lock;
506 
507  int errLine;
508  UString errMsg;
509  RefPtr<ProgramNode> progNode = parser().parseProgram(sourceURL, startingLineNumber, code, codeLength, nullptr, &errLine, &errMsg);
510  if (!progNode) {
511  return Completion(Throw, Error::create(&m_globalExec, SyntaxError, errMsg, errLine, 0, sourceURL));
512  }
513  return Completion(Normal);
514 }
515 
516 Completion Interpreter::evaluate(const UString &sourceURL, int startingLineNumber, const UString &code, JSValue *thisV)
517 {
518  return evaluate(sourceURL, startingLineNumber, code.data(), code.size(), thisV);
519 }
520 
521 Completion Interpreter::evaluate(const UString &sourceURL, int startingLineNumber, const UChar *code, int codeLength, JSValue *thisV)
522 {
523  JSLock lock;
524 
525  // prevent against infinite recursion
526  if (m_recursion >= 20) {
527  return Completion(Throw, Error::create(&m_globalExec, GeneralError, "Recursion too deep"));
528  }
529 
530  // parse the source code
531  int sourceId;
532  int errLine;
533  UString errMsg;
534  RefPtr<ProgramNode> progNode = parser().parseProgram(sourceURL, startingLineNumber, code, codeLength, &sourceId, &errLine, &errMsg);
535 
536  // notify debugger that source has been parsed
537  if (m_debugger) {
538  m_debugger->reportSourceParsed(&m_globalExec, progNode.get(), sourceId, sourceURL,
539  UString(code, codeLength), startingLineNumber, errLine, errMsg);
540  }
541 
542  // no program node means a syntax error occurred
543  if (!progNode) {
544  Completion res(Throw, Error::create(&m_globalExec, SyntaxError, errMsg, errLine, sourceId, sourceURL));
545  if (m_debugger) {
546  m_debugger->reportException(&m_globalExec, res.value());
547  }
548 
549  if (shouldPrintExceptions()) {
550  printException(res, sourceURL);
551  }
552  return res;
553  }
554 
555  m_globalExec.clearException();
556 
557  m_recursion++;
558 
559  JSGlobalObject *globalObj = m_globalObject;
560  JSObject *thisObj = globalObj;
561 
562  // "this" must be an object... use same rules as Function.prototype.apply()
563  if (thisV && !JSValue::isUndefinedOrNull(thisV)) {
564  thisObj = JSValue::toObject(thisV, &m_globalExec);
565  }
566 
567  Completion res;
568  if (m_globalExec.hadException())
569  // the thisV->toObject() conversion above might have thrown an exception - if so, propagate it
570  {
571  res = Completion(Throw, m_globalExec.exception());
572  } else {
573  // execute the code
574  InterpreterExecState newExec(this, globalObj, thisObj, progNode.get());
575 
576  if (m_debugger && !m_debugger->enterContext(&newExec, sourceId, startingLineNumber, nullptr, List::empty())) {
577  // debugger requested we stop execution.
578  m_debugger->imp()->abort();
579  return Completion(Break);
580  }
581 
582  progNode->processDecls(&newExec);
583  res = progNode->execute(&newExec);
584 
585  if (m_debugger && !m_debugger->exitContext(&newExec, sourceId, startingLineNumber, nullptr)) {
586  // debugger requested we stop execution.
587  m_debugger->imp()->abort();
588  return Completion(Break);
589  }
590  }
591 
592  m_recursion--;
593 
594  if (shouldPrintExceptions() && res.complType() == Throw) {
595  printException(res, sourceURL);
596  }
597 
598  return res;
599 }
600 
601 bool Interpreter::normalizeCode(const UString &codeIn, UString *codeOut,
602  int *errLine, UString *errMsg)
603 {
604  assert(codeOut);
605  RefPtr<ProgramNode> progNode = parser().parseProgram("", // sourceURL
606  0, // line
607  codeIn.data(),
608  codeIn.size(),
609  nullptr, // &sourceId
610  errLine, errMsg);
611  if (progNode) {
612  *codeOut = progNode->toString();
613  return true;
614  } else {
615  return false;
616  }
617 }
618 
619 JSObject *Interpreter::builtinObject() const
620 {
621  return m_Object;
622 }
623 
625 {
626  return m_Function;
627 }
628 
629 JSObject *Interpreter::builtinArray() const
630 {
631  return m_Array;
632 }
633 
635 {
636  return m_Boolean;
637 }
638 
639 JSObject *Interpreter::builtinString() const
640 {
641  return m_String;
642 }
643 
644 JSObject *Interpreter::builtinNumber() const
645 {
646  return m_Number;
647 }
648 
649 JSObject *Interpreter::builtinDate() const
650 {
651  return m_Date;
652 }
653 
654 JSObject *Interpreter::builtinRegExp() const
655 {
656  return m_RegExp;
657 }
658 
659 JSObject *Interpreter::builtinError() const
660 {
661  return m_Error;
662 }
663 
665 {
666  return m_ObjectPrototype;
667 }
668 
670 {
671  return m_FunctionPrototype;
672 }
673 
675 {
676  return m_ArrayPrototype;
677 }
678 
680 {
681  return m_BooleanPrototype;
682 }
683 
685 {
686  return m_StringPrototype;
687 }
688 
690 {
691  return m_NumberPrototype;
692 }
693 
695 {
696  return m_DatePrototype;
697 }
698 
700 {
701  return m_RegExpPrototype;
702 }
703 
705 {
706  return m_ErrorPrototype;
707 }
708 
710 {
711  return m_EvalError;
712 }
713 
714 JSObject *Interpreter::builtinRangeError() const
715 {
716  return m_RangeError;
717 }
718 
719 JSObject *Interpreter::builtinReferenceError() const
720 {
721  return m_ReferenceError;
722 }
723 
724 JSObject *Interpreter::builtinSyntaxError() const
725 {
726  return m_SyntaxError;
727 }
728 
729 JSObject *Interpreter::builtinTypeError() const
730 {
731  return m_TypeError;
732 }
733 
734 JSObject *Interpreter::builtinURIError() const
735 {
736  return m_UriError;
737 }
738 
739 JSObject *Interpreter::builtinEvalErrorPrototype() const
740 {
741  return m_EvalErrorPrototype;
742 }
743 
744 JSObject *Interpreter::builtinRangeErrorPrototype() const
745 {
746  return m_RangeErrorPrototype;
747 }
748 
749 JSObject *Interpreter::builtinReferenceErrorPrototype() const
750 {
751  return m_ReferenceErrorPrototype;
752 }
753 
754 JSObject *Interpreter::builtinSyntaxErrorPrototype() const
755 {
756  return m_SyntaxErrorPrototype;
757 }
758 
759 JSObject *Interpreter::builtinTypeErrorPrototype() const
760 {
761  return m_TypeErrorPrototype;
762 }
763 
764 JSObject *Interpreter::builtinURIErrorPrototype() const
765 {
766  return m_UriErrorPrototype;
767 }
768 
770 {
771  return Collector::collect();
772 }
773 
775 {
776  if (m_execState) {
777  m_execState->mark();
778  }
779  if (m_globalObject && !m_globalObject->marked()) {
780  m_globalObject->mark();
781  }
782  if (m_globalExec.exception() && !JSValue::marked(m_globalExec.exception())) {
783  JSValue::mark(m_globalExec.exception());
784  }
785 
786  // Do not let cached activations survive the GC; as they have an unfortunate
787  // tendenacy to pin blocks, increasing their number and hence spreading out
788  // the objects somewhat
789  m_numCachedActivations = 0;
790 }
791 
793 {
794  markInternedStringsTable();
795 }
796 
797 #ifdef KJS_DEBUG_MEM
798 void Interpreter::finalCheck()
799 {
800  fprintf(stderr, "Interpreter::finalCheck()\n");
802 
803 // Node::finalCheck();
804  Collector::finalCheck();
805 }
806 #endif
807 
808 static bool printExceptions = false;
809 
810 bool Interpreter::shouldPrintExceptions()
811 {
812  return printExceptions;
813 }
814 
815 void Interpreter::setShouldPrintExceptions(bool print)
816 {
817  printExceptions = print;
818 }
819 
820 void Interpreter::printException(const Completion &c, const UString &sourceURL)
821 {
822  JSLock lock;
823  ExecState *exec = globalExec();
824  CString f = sourceURL.UTF8String();
825  CString message = JSValue::toObject(c.value(), exec)->toString(exec).UTF8String();
826  int line = JSValue::toUInt32(JSValue::toObject(c.value(), exec)->get(exec, "line"), exec);
827 #if PLATFORM(WIN_OS)
828  printf("%s line %d: %s\n", f.c_str(), line, message.c_str());
829 #else
830  printf("[%d] %s line %d: %s\n", getpid(), f.c_str(), line, message.c_str());
831 #endif
832 }
833 
834 // bindings are OS X WebKit-only for now
835 #if USE(BINDINGS)
836 void *Interpreter::createLanguageInstanceForValue(ExecState *exec, int language, JSObject *value, const Bindings::RootObject *origin, const Bindings::RootObject *current)
837 {
838  return Bindings::Instance::createLanguageInstanceForValue(exec, (Bindings::Instance::BindingLanguage)language, value, origin, current);
839 }
840 #endif
841 
842 void Interpreter::saveBuiltins(SavedBuiltins &builtins) const
843 {
844  if (!builtins._internal) {
845  builtins._internal = new SavedBuiltinsInternal;
846  }
847 
848  builtins._internal->m_Object = m_Object;
849  builtins._internal->m_Function = m_Function;
850  builtins._internal->m_Array = m_Array;
851  builtins._internal->m_Boolean = m_Boolean;
852  builtins._internal->m_String = m_String;
853  builtins._internal->m_Number = m_Number;
854  builtins._internal->m_Date = m_Date;
855  builtins._internal->m_RegExp = m_RegExp;
856  builtins._internal->m_Error = m_Error;
857 
858  builtins._internal->m_ObjectPrototype = m_ObjectPrototype;
859  builtins._internal->m_FunctionPrototype = m_FunctionPrototype;
860  builtins._internal->m_ArrayPrototype = m_ArrayPrototype;
861  builtins._internal->m_BooleanPrototype = m_BooleanPrototype;
862  builtins._internal->m_StringPrototype = m_StringPrototype;
863  builtins._internal->m_NumberPrototype = m_NumberPrototype;
864  builtins._internal->m_DatePrototype = m_DatePrototype;
865  builtins._internal->m_RegExpPrototype = m_RegExpPrototype;
866  builtins._internal->m_ErrorPrototype = m_ErrorPrototype;
867 
868  builtins._internal->m_EvalError = m_EvalError;
869  builtins._internal->m_RangeError = m_RangeError;
870  builtins._internal->m_ReferenceError = m_ReferenceError;
871  builtins._internal->m_SyntaxError = m_SyntaxError;
872  builtins._internal->m_TypeError = m_TypeError;
873  builtins._internal->m_UriError = m_UriError;
874 
875  builtins._internal->m_EvalErrorPrototype = m_EvalErrorPrototype;
876  builtins._internal->m_RangeErrorPrototype = m_RangeErrorPrototype;
877  builtins._internal->m_ReferenceErrorPrototype = m_ReferenceErrorPrototype;
878  builtins._internal->m_SyntaxErrorPrototype = m_SyntaxErrorPrototype;
879  builtins._internal->m_TypeErrorPrototype = m_TypeErrorPrototype;
880  builtins._internal->m_UriErrorPrototype = m_UriErrorPrototype;
881 }
882 
883 void Interpreter::restoreBuiltins(const SavedBuiltins &builtins)
884 {
885  if (!builtins._internal) {
886  return;
887  }
888 
889  m_Object = builtins._internal->m_Object;
890  m_Function = builtins._internal->m_Function;
891  m_Array = builtins._internal->m_Array;
892  m_Boolean = builtins._internal->m_Boolean;
893  m_String = builtins._internal->m_String;
894  m_Number = builtins._internal->m_Number;
895  m_Date = builtins._internal->m_Date;
896  m_RegExp = builtins._internal->m_RegExp;
897  m_Error = builtins._internal->m_Error;
898 
899  m_ObjectPrototype = builtins._internal->m_ObjectPrototype;
900  m_FunctionPrototype = builtins._internal->m_FunctionPrototype;
901  m_ArrayPrototype = builtins._internal->m_ArrayPrototype;
902  m_BooleanPrototype = builtins._internal->m_BooleanPrototype;
903  m_StringPrototype = builtins._internal->m_StringPrototype;
904  m_NumberPrototype = builtins._internal->m_NumberPrototype;
905  m_DatePrototype = builtins._internal->m_DatePrototype;
906  m_RegExpPrototype = builtins._internal->m_RegExpPrototype;
907  m_ErrorPrototype = builtins._internal->m_ErrorPrototype;
908 
909  m_EvalError = builtins._internal->m_EvalError;
910  m_RangeError = builtins._internal->m_RangeError;
911  m_ReferenceError = builtins._internal->m_ReferenceError;
912  m_SyntaxError = builtins._internal->m_SyntaxError;
913  m_TypeError = builtins._internal->m_TypeError;
914  m_UriError = builtins._internal->m_UriError;
915 
916  m_EvalErrorPrototype = builtins._internal->m_EvalErrorPrototype;
917  m_RangeErrorPrototype = builtins._internal->m_RangeErrorPrototype;
918  m_ReferenceErrorPrototype = builtins._internal->m_ReferenceErrorPrototype;
919  m_SyntaxErrorPrototype = builtins._internal->m_SyntaxErrorPrototype;
920  m_TypeErrorPrototype = builtins._internal->m_TypeErrorPrototype;
921  m_UriErrorPrototype = builtins._internal->m_UriErrorPrototype;
922 }
923 
924 void Interpreter::startTimeoutCheck()
925 {
926  if (!m_timeoutChecker) {
927  m_timeoutChecker = new TimeoutChecker;
928  }
929 
930  m_timeoutChecker->startTimeoutCheck(this);
931 }
932 
933 void Interpreter::stopTimeoutCheck()
934 {
935  ASSERT(m_timeoutChecker);
936 
937  m_timeoutChecker->stopTimeoutCheck(this);
938 }
939 
940 void Interpreter::restartTimeoutCheck()
941 {
942  if (!m_timeoutChecker || !m_startTimeoutCheckCount) {
943  return;
944  }
945 
946  m_timedOut = false;
947  m_timeoutChecker->stopTimeoutCheck(this);
948  m_timeoutChecker->startTimeoutCheck(this);
949 }
950 
951 void Interpreter::pauseTimeoutCheck()
952 {
953  ASSERT(m_timeoutChecker);
954 
955  m_timeoutChecker->pauseTimeoutCheck(this);
956 }
957 
958 void Interpreter::resumeTimeoutCheck()
959 {
960  ASSERT(m_timeoutChecker);
961 
962  m_timeoutChecker->resumeTimeoutCheck(this);
963 }
964 
965 bool Interpreter::handleTimeout()
966 {
967  m_timedOut = false;
968 
969  pauseTimeoutCheck();
970  bool retval = shouldInterruptScript();
971  resumeTimeoutCheck();
972 
973  return retval;
974 }
975 
976 Interpreter::InternedStringsTable *Interpreter::s_internedStrings;
977 
978 void Interpreter::initInternedStringsTable()
979 {
980  if (!s_internedStrings) {
981  s_internedStrings = new InternedStringsTable();
982  }
983 }
984 
985 StringImp *Interpreter::internString(const UString &literal)
986 {
987  InternedStringsTable::iterator i = s_internedStrings->find(literal.rep());
988 
989  if (i == s_internedStrings->end()) {
990  // Need to add. Note: we can't use ->add() above to avoid a double-hash
991  // as creation of a StringImp may cause a GC, which in turn may
992  // rearrange the hashtable, invalidating the iterator.
993  StringImp *si = static_cast<StringImp *>(jsOwnedString(literal));
994  s_internedStrings->add(literal.rep(), std::make_pair(si, 1));
995  return si;
996  } else {
997  ++i.values()->second; // just bump the ref count
998  return i.values()->first;
999  }
1000 }
1001 
1002 void Interpreter::releaseInternedString(const UString &literal)
1003 {
1004  InternedStringsTable::iterator i = s_internedStrings->find(literal.rep());
1005 
1006  --i.values()->second;
1007  if (i.values()->second == 0) {
1008  s_internedStrings->remove(i);
1009  }
1010 }
1011 
1012 void Interpreter::markInternedStringsTable()
1013 {
1014  for (InternedStringsTable::iterator i = s_internedStrings->begin();
1015  i != s_internedStrings->end(); ++i) {
1016  // Note: the StringImp* may be null here if we got called in the middle
1017  // of internString.
1018  if (i.values()->first && !i.values()->first->marked()) {
1019  i.values()->first->mark();
1020  }
1021  }
1022 }
1023 
1024 SavedBuiltins::SavedBuiltins() :
1025  _internal(nullptr)
1026 {
1027 }
1028 
1029 SavedBuiltins::~SavedBuiltins()
1030 {
1031  delete _internal;
1032 }
1033 
1034 UnicodeSupport::UnicodeSupport()
1035 {
1036 }
1037 
1038 void UnicodeSupport::setIdentStartChecker(bool (*f)(int c))
1039 {
1040  Lexer::setIdentStartChecker(f);
1041 }
1042 
1043 void UnicodeSupport::setIdentPartChecker(bool (*f)(int c))
1044 {
1045  Lexer::setIdentPartChecker(f);
1046 }
1047 
1048 void UnicodeSupport::setToLowerFunction(StringConversionFunction f)
1049 {
1050  StringProtoFunc::setToLowerFunction(f);
1051 }
1052 
1053 void UnicodeSupport::setToUpperFunction(StringConversionFunction f)
1054 {
1055  StringProtoFunc::setToUpperFunction(f);
1056 }
1057 
1058 }
1059 
JSObject * builtinErrorPrototype() const
Returns the builtin "Error.prototype" object.
virtual void mark(bool currentThreadIsMainThread)
Called during the mark phase of the garbage collector.
Completion checkSyntax(const UString &sourceURL, int startingLineNumber, const UString &code)
Parses the supplied ECMAScript code and checks for syntax errors.
virtual void detach(Interpreter *interp)
Detach the debugger from an interpreter.
Definition: debugger.cpp:77
void setGlobalPackage(Package *p)
Sets the package instance that will be used to resolve the first level of identifiers of import state...
JSObject * builtinDatePrototype() const
Returns the builtin "Date.prototype" object.
QAction * print(const QObject *recvr, const char *slot, QObject *parent)
JSGlobalObject * globalObject() const
Returns the object that is used as the global object during all script execution performed by this in...
JSValue is the base type for all primitives (Undefined, Null, Boolean, String, Number) and objects in...
Definition: value.h:58
JSObject * builtinStringPrototype() const
Returns the builtin "String.prototype" object.
int size() const
Definition: ustring.h:420
JSObject * builtinBooleanPrototype() const
Returns the builtin "Boolean.prototype" object.
virtual ExecState * globalExec()
Returns the execution state object which can be used to execute scripts using this interpreter at a t...
JSObject * builtinFunction() const
Returns the builtin "Function" object.
static bool collect()
Run the garbage collection.
Completion objects are used to convey the return status and value from functions.
Definition: completion.h:52
Interpreter()
Creates a new interpreter.
JSObject * builtinObject() const
Returns the builtin "Object" object.
JSObject * builtinRegExp() const
Returns the builtin "RegExp" object.
Represents the current state of script execution.
Definition: ExecState.h:53
static bool normalizeCode(const UString &codeIn, UString *codeOut, int *errLine=nullptr, UString *errMsg=nullptr)
Pretty-prints the supplied ECMAScript code after checking it for syntax errors.
Represents an Identifier for a Javascript object.
Definition: identifier.h:36
static bool collect()
Run the garbage collection.
Definition: collector.cpp:673
JSObject * builtinDate() const
Returns the builtin "Date" object.
Unicode character.
Definition: ustring.h:70
virtual bool enterContext(ExecState *exec, int sourceId, int lineno, JSObject *function, const List &args)
Called when the interpreter enters a new execution context (stack frame).
Definition: debugger.cpp:141
JSObject * builtinObjectPrototype() const
Returns the builtin "Object.prototype" object.
JSObject * builtinArrayPrototype() const
Returns the builtin "Array.prototype" object.
JSObject * builtinString() const
Returns the builtin "String" object.
const UChar * data() const
Definition: ustring.h:391
JSObject * builtinRegExpPrototype() const
Returns the builtin "RegExp.prototype" object.
JSObject * builtinBoolean() const
Returns the builtin "Boolean" object.
Completion evaluate(const UString &sourceURL, int startingLineNumber, const UChar *code, int codeLength, JSValue *thisV=nullptr)
Evaluates the supplied ECMAScript code.
JSObject * builtinArray() const
Returns the builtin "Array" object.
static const List & empty()
Returns a pointer to a static instance of an empty list.
Definition: list.cpp:311
static JSObject * create(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL)
Factory method for error objects.
Definition: object.cpp:813
JSObject * builtinFunctionPrototype() const
Returns the builtin "Function.prototype" object.
Package * globalPackage()
Returns the package that was installed to handle top level package requests.
virtual bool exitContext(ExecState *exec, int sourceId, int lineno, JSObject *function)
Called when the interpreter exits an execution context.
Definition: debugger.cpp:147
JSObject * builtinError() const
Returns the builtin "Error" object.
JSObject * builtinNumberPrototype() const
Returns the builtin "Number.prototype" object.
JSObject * builtinNumber() const
Returns the builtin "Number" object.
QString message
JSObject * builtinEvalError() const
The initial value of "Error" global property.
static void markSourceCachedObjects()
This marks all GC heap resources stored as optimizations; and which have their lifetime managed by th...
Unicode string class.
Definition: ustring.h:153
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Wed May 25 2022 03:58:40 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.