|
1 // -*- c-basic-offset: 2 -*- |
|
2 /* |
|
3 * This file is part of the KDE libraries |
|
4 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) |
|
5 * Copyright (C) 2001 Peter Kelly (pmk@post.com) |
|
6 * Copyright (C) 2003 Apple Computer, Inc. |
|
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 "config.h" |
|
26 #include "interpreter.h" |
|
27 |
|
28 #include "SavedBuiltins.h" |
|
29 #include "array_object.h" |
|
30 #include "bool_object.h" |
|
31 #include "collector.h" |
|
32 #include "context.h" |
|
33 #include "date_object.h" |
|
34 #include "debugger.h" |
|
35 #include "error_object.h" |
|
36 #include "function_object.h" |
|
37 #include "internal.h" |
|
38 #include "math_object.h" |
|
39 #include "nodes.h" |
|
40 #include "number_object.h" |
|
41 #include "object.h" |
|
42 #include "object_object.h" |
|
43 #include "operations.h" |
|
44 #include "regexp_object.h" |
|
45 #include "string_object.h" |
|
46 #include "types.h" |
|
47 #include "value.h" |
|
48 |
|
49 #include "runtime.h" |
|
50 |
|
51 #if HAVE(SYS_TIME_H) |
|
52 #include <sys/time.h> |
|
53 #endif |
|
54 |
|
55 #include <assert.h> |
|
56 #include <math.h> |
|
57 #include <signal.h> |
|
58 #include <stdio.h> |
|
59 |
|
60 #if PLATFORM(WIN_OS) |
|
61 #include <windows.h> |
|
62 #endif |
|
63 |
|
64 #if PLATFORM(QT) |
|
65 #include <QDateTime> |
|
66 #endif |
|
67 |
|
68 #if PLATFORM(SYMBIAN) |
|
69 #include "oom.h" |
|
70 #endif |
|
71 |
|
72 namespace KJS { |
|
73 |
|
74 // Default number of ticks before a timeout check should be done. |
|
75 static const int initialTickCountThreshold = 255; |
|
76 |
|
77 // Preferred number of milliseconds between each timeout check |
|
78 static const int preferredScriptCheckTimeInterval = 1000; |
|
79 |
|
80 Interpreter* Interpreter::s_hook = 0; |
|
81 |
|
82 typedef HashMap<JSObject*, Interpreter*> InterpreterMap; |
|
83 static inline InterpreterMap &interpreterMap() |
|
84 { |
|
85 static InterpreterMap* map = new InterpreterMap; |
|
86 return* map; |
|
87 } |
|
88 |
|
89 EXPORT |
|
90 Interpreter::Interpreter(JSObject* globalObject) |
|
91 : m_globalExec(this, 0) |
|
92 , m_globalObject(globalObject) |
|
93 { |
|
94 init(); |
|
95 } |
|
96 |
|
97 Interpreter::Interpreter() |
|
98 : m_globalExec(this, 0) |
|
99 , m_globalObject(new JSObject()) |
|
100 { |
|
101 init(); |
|
102 } |
|
103 |
|
104 void Interpreter::init() |
|
105 { |
|
106 JSLock lock; |
|
107 |
|
108 m_refCount = 0; |
|
109 m_timeoutTime = 0; |
|
110 m_recursion = 0; |
|
111 m_debugger= 0; |
|
112 m_context = 0; |
|
113 |
|
114 resetTimeoutCheck(); |
|
115 m_timeoutCheckCount = 0; |
|
116 |
|
117 m_compatMode = NativeMode; |
|
118 |
|
119 if (s_hook) { |
|
120 prev = s_hook; |
|
121 next = s_hook->next; |
|
122 s_hook->next->prev = this; |
|
123 s_hook->next = this; |
|
124 } else { |
|
125 // This is the first interpreter |
|
126 s_hook = next = prev = this; |
|
127 } |
|
128 interpreterMap().set(m_globalObject, this); |
|
129 |
|
130 initGlobalObject(); |
|
131 } |
|
132 |
|
133 EXPORT |
|
134 Interpreter::~Interpreter() |
|
135 { |
|
136 JSLock lock; |
|
137 |
|
138 if (m_debugger) |
|
139 m_debugger->detach(this); |
|
140 |
|
141 next->prev = prev; |
|
142 prev->next = next; |
|
143 s_hook = next; |
|
144 if (s_hook == this) { |
|
145 // This was the last interpreter |
|
146 s_hook = 0; |
|
147 } |
|
148 interpreterMap().remove(m_globalObject); |
|
149 } |
|
150 |
|
151 EXPORT |
|
152 JSObject* Interpreter::globalObject() const |
|
153 { |
|
154 return m_globalObject; |
|
155 } |
|
156 |
|
157 EXPORT |
|
158 void Interpreter::initGlobalObject() |
|
159 { |
|
160 // Clear before inititalizing, to avoid marking uninitialized (dangerous) or |
|
161 // stale (wasteful) pointers during initialization. |
|
162 |
|
163 // Prototypes |
|
164 m_FunctionPrototype = 0; |
|
165 m_ObjectPrototype = 0; |
|
166 |
|
167 m_ArrayPrototype = 0; |
|
168 m_StringPrototype = 0; |
|
169 m_BooleanPrototype = 0; |
|
170 m_NumberPrototype = 0; |
|
171 m_DatePrototype = 0; |
|
172 m_RegExpPrototype = 0; |
|
173 m_ErrorPrototype = 0; |
|
174 |
|
175 m_EvalErrorPrototype = 0; |
|
176 m_RangeErrorPrototype = 0; |
|
177 m_ReferenceErrorPrototype = 0; |
|
178 m_SyntaxErrorPrototype = 0; |
|
179 m_TypeErrorPrototype = 0; |
|
180 m_UriErrorPrototype = 0; |
|
181 |
|
182 // Constructors |
|
183 m_Object = 0; |
|
184 m_Function = 0; |
|
185 m_Array = 0; |
|
186 m_String = 0; |
|
187 m_Boolean = 0; |
|
188 m_Number = 0; |
|
189 m_Date = 0; |
|
190 m_RegExp = 0; |
|
191 m_Error = 0; |
|
192 |
|
193 m_EvalError = 0; |
|
194 m_RangeError = 0; |
|
195 m_ReferenceError = 0; |
|
196 m_SyntaxError = 0; |
|
197 m_TypeError = 0; |
|
198 m_UriError = 0; |
|
199 |
|
200 // Prototypes |
|
201 m_FunctionPrototype = new FunctionPrototype(&m_globalExec); |
|
202 m_ObjectPrototype = new ObjectPrototype(&m_globalExec, m_FunctionPrototype); |
|
203 m_FunctionPrototype->setPrototype(m_ObjectPrototype); |
|
204 |
|
205 m_ArrayPrototype = new ArrayPrototype(&m_globalExec, m_ObjectPrototype); |
|
206 m_StringPrototype = new StringPrototype(&m_globalExec, m_ObjectPrototype); |
|
207 m_BooleanPrototype = new BooleanPrototype(&m_globalExec, m_ObjectPrototype, m_FunctionPrototype); |
|
208 m_NumberPrototype = new NumberPrototype(&m_globalExec, m_ObjectPrototype, m_FunctionPrototype); |
|
209 m_DatePrototype = new DatePrototype(&m_globalExec, m_ObjectPrototype); |
|
210 m_RegExpPrototype = new RegExpPrototype(&m_globalExec, m_ObjectPrototype, m_FunctionPrototype);; |
|
211 m_ErrorPrototype = new ErrorPrototype(&m_globalExec, m_ObjectPrototype, m_FunctionPrototype); |
|
212 |
|
213 m_EvalErrorPrototype = new NativeErrorPrototype(&m_globalExec, m_ErrorPrototype, EvalError, "EvalError", "EvalError"); |
|
214 m_RangeErrorPrototype = new NativeErrorPrototype(&m_globalExec, m_ErrorPrototype, RangeError, "RangeError", "RangeError"); |
|
215 m_ReferenceErrorPrototype = new NativeErrorPrototype(&m_globalExec, m_ErrorPrototype, ReferenceError, "ReferenceError", "ReferenceError"); |
|
216 m_SyntaxErrorPrototype = new NativeErrorPrototype(&m_globalExec, m_ErrorPrototype, SyntaxError, "SyntaxError", "SyntaxError"); |
|
217 m_TypeErrorPrototype = new NativeErrorPrototype(&m_globalExec, m_ErrorPrototype, TypeError, "TypeError", "TypeError"); |
|
218 m_UriErrorPrototype = new NativeErrorPrototype(&m_globalExec, m_ErrorPrototype, URIError, "URIError", "URIError"); |
|
219 |
|
220 // Constructors |
|
221 m_Object = new ObjectObjectImp(&m_globalExec, m_ObjectPrototype, m_FunctionPrototype); |
|
222 m_Function = new FunctionObjectImp(&m_globalExec, m_FunctionPrototype); |
|
223 m_Array = new ArrayObjectImp(&m_globalExec, m_FunctionPrototype, m_ArrayPrototype); |
|
224 m_String = new StringObjectImp(&m_globalExec, m_FunctionPrototype, m_StringPrototype); |
|
225 m_Boolean = new BooleanObjectImp(&m_globalExec, m_FunctionPrototype, m_BooleanPrototype); |
|
226 m_Number = new NumberObjectImp(&m_globalExec, m_FunctionPrototype, m_NumberPrototype); |
|
227 m_Date = new DateObjectImp(&m_globalExec, m_FunctionPrototype, m_DatePrototype); |
|
228 m_RegExp = new RegExpObjectImp(&m_globalExec, m_FunctionPrototype, m_RegExpPrototype); |
|
229 m_Error = new ErrorObjectImp(&m_globalExec, m_FunctionPrototype, m_ErrorPrototype); |
|
230 |
|
231 m_EvalError = new NativeErrorImp(&m_globalExec, m_FunctionPrototype, m_EvalErrorPrototype); |
|
232 m_RangeError = new NativeErrorImp(&m_globalExec, m_FunctionPrototype, m_RangeErrorPrototype); |
|
233 m_ReferenceError = new NativeErrorImp(&m_globalExec, m_FunctionPrototype, m_ReferenceErrorPrototype); |
|
234 m_SyntaxError = new NativeErrorImp(&m_globalExec, m_FunctionPrototype, m_SyntaxErrorPrototype); |
|
235 m_TypeError = new NativeErrorImp(&m_globalExec, m_FunctionPrototype, m_TypeErrorPrototype); |
|
236 m_UriError = new NativeErrorImp(&m_globalExec, m_FunctionPrototype, m_UriErrorPrototype); |
|
237 |
|
238 m_FunctionPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Function, DontEnum); |
|
239 m_ObjectPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Object, DontEnum | DontDelete | ReadOnly); |
|
240 m_FunctionPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Function, DontEnum | DontDelete | ReadOnly); |
|
241 m_ArrayPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Array, DontEnum | DontDelete | ReadOnly); |
|
242 m_BooleanPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Boolean, DontEnum | DontDelete | ReadOnly); |
|
243 m_StringPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_String, DontEnum | DontDelete | ReadOnly); |
|
244 m_NumberPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Number, DontEnum | DontDelete | ReadOnly); |
|
245 m_DatePrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Date, DontEnum | DontDelete | ReadOnly); |
|
246 m_RegExpPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_RegExp, DontEnum | DontDelete | ReadOnly); |
|
247 m_ErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_Error, DontEnum | DontDelete | ReadOnly); |
|
248 m_EvalErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_EvalError, DontEnum | DontDelete | ReadOnly); |
|
249 m_RangeErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_RangeError, DontEnum | DontDelete | ReadOnly); |
|
250 m_ReferenceErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_ReferenceError, DontEnum | DontDelete | ReadOnly); |
|
251 m_SyntaxErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_SyntaxError, DontEnum | DontDelete | ReadOnly); |
|
252 m_TypeErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_TypeError, DontEnum | DontDelete | ReadOnly); |
|
253 m_UriErrorPrototype->put(&m_globalExec, m_globalExec.propertyNames().constructor, m_UriError, DontEnum | DontDelete | ReadOnly); |
|
254 |
|
255 // Set global object prototype |
|
256 JSObject* o = m_globalObject; |
|
257 while (o->prototype()->isObject()) |
|
258 o = static_cast<JSObject*>(o->prototype()); |
|
259 o->setPrototype(m_ObjectPrototype); |
|
260 |
|
261 // Set global constructors |
|
262 // FIXME: kjs_window.cpp checks Internal/DontEnum as a performance hack, to |
|
263 // see that these values can be put directly without a check for override |
|
264 // properties. Maybe we should call putDirect instead, for better encapsulation. |
|
265 m_globalObject->put(&m_globalExec, "Object", m_Object, DontEnum); |
|
266 m_globalObject->put(&m_globalExec, "Function", m_Function, DontEnum); |
|
267 m_globalObject->put(&m_globalExec, "Array", m_Array, DontEnum); |
|
268 m_globalObject->put(&m_globalExec, "Boolean", m_Boolean, DontEnum); |
|
269 m_globalObject->put(&m_globalExec, "String", m_String, DontEnum); |
|
270 m_globalObject->put(&m_globalExec, "Number", m_Number, DontEnum); |
|
271 m_globalObject->put(&m_globalExec, "Date", m_Date, DontEnum); |
|
272 m_globalObject->put(&m_globalExec, "RegExp", m_RegExp, DontEnum); |
|
273 m_globalObject->put(&m_globalExec, "Error", m_Error, DontEnum); |
|
274 m_globalObject->put(&m_globalExec, "EvalError",m_EvalError, Internal); |
|
275 m_globalObject->put(&m_globalExec, "RangeError",m_RangeError, Internal); |
|
276 m_globalObject->put(&m_globalExec, "ReferenceError",m_ReferenceError, Internal); |
|
277 m_globalObject->put(&m_globalExec, "SyntaxError",m_SyntaxError, Internal); |
|
278 m_globalObject->put(&m_globalExec, "TypeError",m_TypeError, Internal); |
|
279 m_globalObject->put(&m_globalExec, "URIError",m_UriError, Internal); |
|
280 |
|
281 // Set global values |
|
282 m_globalObject->put(&m_globalExec, "Math", new MathObjectImp(&m_globalExec, m_ObjectPrototype), DontEnum); |
|
283 m_globalObject->put(&m_globalExec, "NaN", jsNaN(), DontEnum|DontDelete); |
|
284 m_globalObject->put(&m_globalExec, "Infinity", jsNumber(Inf), DontEnum|DontDelete); |
|
285 m_globalObject->put(&m_globalExec, "undefined", jsUndefined(), DontEnum|DontDelete); |
|
286 |
|
287 // Set global functions |
|
288 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::Eval, 1, "eval"), DontEnum); |
|
289 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::ParseInt, 2, "parseInt"), DontEnum); |
|
290 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::ParseFloat, 1, "parseFloat"), DontEnum); |
|
291 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::IsNaN, 1, "isNaN"), DontEnum); |
|
292 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::IsFinite, 1, "isFinite"), DontEnum); |
|
293 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::Escape, 1, "escape"), DontEnum); |
|
294 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::UnEscape, 1, "unescape"), DontEnum); |
|
295 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::DecodeURI, 1, "decodeURI"), DontEnum); |
|
296 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::DecodeURIComponent, 1, "decodeURIComponent"), DontEnum); |
|
297 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::EncodeURI, 1, "encodeURI"), DontEnum); |
|
298 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::EncodeURIComponent, 1, "encodeURIComponent"), DontEnum); |
|
299 #ifndef NDEBUG |
|
300 m_globalObject->putDirectFunction(new GlobalFuncImp(&m_globalExec, m_FunctionPrototype, GlobalFuncImp::KJSPrint, 1, "kjsprint"), DontEnum); |
|
301 #endif |
|
302 } |
|
303 |
|
304 EXPORT |
|
305 ExecState* Interpreter::globalExec() |
|
306 { |
|
307 return &m_globalExec; |
|
308 } |
|
309 |
|
310 Completion Interpreter::checkSyntax(const UString& sourceURL, int startingLineNumber, const UString& code) |
|
311 { |
|
312 return checkSyntax(sourceURL, startingLineNumber, code.data(), code.size()); |
|
313 } |
|
314 |
|
315 Completion Interpreter::checkSyntax(const UString& sourceURL, int startingLineNumber, const UChar* code, int codeLength) |
|
316 { |
|
317 JSLock lock; |
|
318 |
|
319 int errLine; |
|
320 UString errMsg; |
|
321 RefPtr<ProgramNode> progNode = Parser::parse(sourceURL, startingLineNumber, code, codeLength, 0, &errLine, &errMsg); |
|
322 if (!progNode) |
|
323 return Completion(Throw, Error::create(&m_globalExec, SyntaxError, errMsg, errLine, 0, sourceURL)); |
|
324 return Completion(Normal); |
|
325 } |
|
326 |
|
327 EXPORT |
|
328 Completion Interpreter::evaluate(const UString& sourceURL, int startingLineNumber, const UString& code, JSValue* thisV) |
|
329 { |
|
330 return evaluate(sourceURL, startingLineNumber, code.data(), code.size(), thisV); |
|
331 } |
|
332 |
|
333 EXPORT |
|
334 Completion Interpreter::evaluate(const UString& sourceURL, int startingLineNumber, const UChar* code, int codeLength, JSValue* thisV) |
|
335 { |
|
336 #if PLATFORM(SYMBIAN) |
|
337 resetStatementCount(); |
|
338 // add 2MB memory hard limit for the JS engine to run |
|
339 OOM_PRE_CHECK(2*1024*1024, 0, "InterpreterImp::evaluate") |
|
340 // do nothing |
|
341 OOM_POST_CHECK_FAILED( |
|
342 JSObject *error = Error::create(&m_globalExec, GeneralError, "Out of memory."); |
|
343 m_globalExec.setException(error); |
|
344 return Completion(Throw, error) |
|
345 ) |
|
346 #endif |
|
347 |
|
348 JSLock lock; |
|
349 |
|
350 // prevent against infinite recursion |
|
351 if (m_recursion >= 20) |
|
352 return Completion(Throw, Error::create(&m_globalExec, GeneralError, "Recursion too deep")); |
|
353 |
|
354 // parse the source code |
|
355 int sid; |
|
356 int errLine; |
|
357 UString errMsg; |
|
358 RefPtr<ProgramNode> progNode = Parser::parse(sourceURL, startingLineNumber, code, codeLength, &sid, &errLine, &errMsg); |
|
359 |
|
360 // notify debugger that source has been parsed |
|
361 if (m_debugger) { |
|
362 bool cont = m_debugger->sourceParsed(&m_globalExec, sid, sourceURL, UString(code, codeLength), startingLineNumber, errLine, errMsg); |
|
363 if (!cont) |
|
364 return Completion(Break); |
|
365 } |
|
366 |
|
367 // no program node means a syntax error occurred |
|
368 if (!progNode) |
|
369 return Completion(Throw, Error::create(&m_globalExec, SyntaxError, errMsg, errLine, sid, sourceURL)); |
|
370 |
|
371 m_globalExec.clearException(); |
|
372 |
|
373 m_recursion++; |
|
374 |
|
375 JSObject* globalObj = m_globalObject; |
|
376 JSObject* thisObj = globalObj; |
|
377 |
|
378 // "this" must be an object... use same rules as Function.prototype.apply() |
|
379 if (thisV && !thisV->isUndefinedOrNull()) |
|
380 thisObj = thisV->toObject(&m_globalExec); |
|
381 |
|
382 Completion res; |
|
383 if (m_globalExec.hadException()) |
|
384 // the thisV->toObject() conversion above might have thrown an exception - if so, propagate it |
|
385 res = Completion(Throw, m_globalExec.exception()); |
|
386 else { |
|
387 // execute the code |
|
388 Context ctx(globalObj, this, thisObj, progNode.get()); |
|
389 ExecState newExec(this, &ctx); |
|
390 ctx.setExecState(&newExec); |
|
391 progNode->processVarDecls(&newExec); |
|
392 res = progNode->execute(&newExec); |
|
393 } |
|
394 |
|
395 m_recursion--; |
|
396 |
|
397 if (shouldPrintExceptions() && res.complType() == Throw) { |
|
398 JSLock lock; |
|
399 ExecState* exec = globalExec(); |
|
400 CString f = sourceURL.UTF8String(); |
|
401 CString message = res.value()->toObject(exec)->toString(exec).UTF8String(); |
|
402 int line = res.value()->toObject(exec)->get(exec, "line")->toUInt32(exec); |
|
403 #if PLATFORM(WIN_OS) || PLATFORM(SYMBIAN) |
|
404 printf("%s line %d: %s\n", f.c_str(), line, message.c_str()); |
|
405 #else |
|
406 printf("[%d] %s line %d: %s\n", getpid(), f.c_str(), line, message.c_str()); |
|
407 #endif |
|
408 } |
|
409 |
|
410 return res; |
|
411 } |
|
412 |
|
413 JSObject *Interpreter::builtinObject() const |
|
414 { |
|
415 return m_Object; |
|
416 } |
|
417 |
|
418 EXPORT |
|
419 JSObject *Interpreter::builtinFunction() const |
|
420 { |
|
421 return m_Function; |
|
422 } |
|
423 |
|
424 EXPORT |
|
425 JSObject *Interpreter::builtinArray() const |
|
426 { |
|
427 return m_Array; |
|
428 } |
|
429 |
|
430 JSObject *Interpreter::builtinBoolean() const |
|
431 { |
|
432 return m_Boolean; |
|
433 } |
|
434 |
|
435 JSObject *Interpreter::builtinString() const |
|
436 { |
|
437 return m_String; |
|
438 } |
|
439 |
|
440 JSObject *Interpreter::builtinNumber() const |
|
441 { |
|
442 return m_Number; |
|
443 } |
|
444 |
|
445 JSObject *Interpreter::builtinDate() const |
|
446 { |
|
447 return m_Date; |
|
448 } |
|
449 |
|
450 JSObject *Interpreter::builtinRegExp() const |
|
451 { |
|
452 return m_RegExp; |
|
453 } |
|
454 |
|
455 JSObject *Interpreter::builtinError() const |
|
456 { |
|
457 return m_Error; |
|
458 } |
|
459 |
|
460 EXPORT |
|
461 JSObject *Interpreter::builtinObjectPrototype() const |
|
462 { |
|
463 return m_ObjectPrototype; |
|
464 } |
|
465 |
|
466 EXPORT |
|
467 JSObject *Interpreter::builtinFunctionPrototype() const |
|
468 { |
|
469 return m_FunctionPrototype; |
|
470 } |
|
471 |
|
472 JSObject *Interpreter::builtinArrayPrototype() const |
|
473 { |
|
474 return m_ArrayPrototype; |
|
475 } |
|
476 |
|
477 JSObject *Interpreter::builtinBooleanPrototype() const |
|
478 { |
|
479 return m_BooleanPrototype; |
|
480 } |
|
481 |
|
482 EXPORT |
|
483 JSObject *Interpreter::builtinStringPrototype() const |
|
484 { |
|
485 return m_StringPrototype; |
|
486 } |
|
487 |
|
488 JSObject *Interpreter::builtinNumberPrototype() const |
|
489 { |
|
490 return m_NumberPrototype; |
|
491 } |
|
492 |
|
493 JSObject *Interpreter::builtinDatePrototype() const |
|
494 { |
|
495 return m_DatePrototype; |
|
496 } |
|
497 |
|
498 JSObject *Interpreter::builtinRegExpPrototype() const |
|
499 { |
|
500 return m_RegExpPrototype; |
|
501 } |
|
502 |
|
503 JSObject *Interpreter::builtinErrorPrototype() const |
|
504 { |
|
505 return m_ErrorPrototype; |
|
506 } |
|
507 |
|
508 JSObject *Interpreter::builtinEvalError() const |
|
509 { |
|
510 return m_EvalError; |
|
511 } |
|
512 |
|
513 JSObject *Interpreter::builtinRangeError() const |
|
514 { |
|
515 return m_RangeError; |
|
516 } |
|
517 |
|
518 JSObject *Interpreter::builtinReferenceError() const |
|
519 { |
|
520 return m_ReferenceError; |
|
521 } |
|
522 |
|
523 JSObject *Interpreter::builtinSyntaxError() const |
|
524 { |
|
525 return m_SyntaxError; |
|
526 } |
|
527 |
|
528 JSObject *Interpreter::builtinTypeError() const |
|
529 { |
|
530 return m_TypeError; |
|
531 } |
|
532 |
|
533 JSObject *Interpreter::builtinURIError() const |
|
534 { |
|
535 return m_UriError; |
|
536 } |
|
537 |
|
538 JSObject *Interpreter::builtinEvalErrorPrototype() const |
|
539 { |
|
540 return m_EvalErrorPrototype; |
|
541 } |
|
542 |
|
543 JSObject *Interpreter::builtinRangeErrorPrototype() const |
|
544 { |
|
545 return m_RangeErrorPrototype; |
|
546 } |
|
547 |
|
548 JSObject *Interpreter::builtinReferenceErrorPrototype() const |
|
549 { |
|
550 return m_ReferenceErrorPrototype; |
|
551 } |
|
552 |
|
553 JSObject *Interpreter::builtinSyntaxErrorPrototype() const |
|
554 { |
|
555 return m_SyntaxErrorPrototype; |
|
556 } |
|
557 |
|
558 JSObject *Interpreter::builtinTypeErrorPrototype() const |
|
559 { |
|
560 return m_TypeErrorPrototype; |
|
561 } |
|
562 |
|
563 JSObject *Interpreter::builtinURIErrorPrototype() const |
|
564 { |
|
565 return m_UriErrorPrototype; |
|
566 } |
|
567 |
|
568 EXPORT |
|
569 void Interpreter::mark() |
|
570 { |
|
571 if (m_context) |
|
572 m_context->mark(); |
|
573 |
|
574 if (m_globalExec.exception() && !m_globalExec.exception()->marked()) |
|
575 m_globalExec.exception()->mark(); |
|
576 |
|
577 if (m_globalObject && !m_globalObject->marked()) |
|
578 m_globalObject->mark(); |
|
579 |
|
580 if (m_Object && !m_Object->marked()) |
|
581 m_Object->mark(); |
|
582 if (m_Function && !m_Function->marked()) |
|
583 m_Function->mark(); |
|
584 if (m_Array && !m_Array->marked()) |
|
585 m_Array->mark(); |
|
586 if (m_Boolean && !m_Boolean->marked()) |
|
587 m_Boolean->mark(); |
|
588 if (m_String && !m_String->marked()) |
|
589 m_String->mark(); |
|
590 if (m_Number && !m_Number->marked()) |
|
591 m_Number->mark(); |
|
592 if (m_Date && !m_Date->marked()) |
|
593 m_Date->mark(); |
|
594 if (m_RegExp && !m_RegExp->marked()) |
|
595 m_RegExp->mark(); |
|
596 if (m_Error && !m_Error->marked()) |
|
597 m_Error->mark(); |
|
598 |
|
599 if (m_ObjectPrototype && !m_ObjectPrototype->marked()) |
|
600 m_ObjectPrototype->mark(); |
|
601 if (m_FunctionPrototype && !m_FunctionPrototype->marked()) |
|
602 m_FunctionPrototype->mark(); |
|
603 if (m_ArrayPrototype && !m_ArrayPrototype->marked()) |
|
604 m_ArrayPrototype->mark(); |
|
605 if (m_BooleanPrototype && !m_BooleanPrototype->marked()) |
|
606 m_BooleanPrototype->mark(); |
|
607 if (m_StringPrototype && !m_StringPrototype->marked()) |
|
608 m_StringPrototype->mark(); |
|
609 if (m_NumberPrototype && !m_NumberPrototype->marked()) |
|
610 m_NumberPrototype->mark(); |
|
611 if (m_DatePrototype && !m_DatePrototype->marked()) |
|
612 m_DatePrototype->mark(); |
|
613 if (m_RegExpPrototype && !m_RegExpPrototype->marked()) |
|
614 m_RegExpPrototype->mark(); |
|
615 if (m_ErrorPrototype && !m_ErrorPrototype->marked()) |
|
616 m_ErrorPrototype->mark(); |
|
617 |
|
618 if (m_EvalError && !m_EvalError->marked()) |
|
619 m_EvalError->mark(); |
|
620 if (m_RangeError && !m_RangeError->marked()) |
|
621 m_RangeError->mark(); |
|
622 if (m_ReferenceError && !m_ReferenceError->marked()) |
|
623 m_ReferenceError->mark(); |
|
624 if (m_SyntaxError && !m_SyntaxError->marked()) |
|
625 m_SyntaxError->mark(); |
|
626 if (m_TypeError && !m_TypeError->marked()) |
|
627 m_TypeError->mark(); |
|
628 if (m_UriError && !m_UriError->marked()) |
|
629 m_UriError->mark(); |
|
630 |
|
631 if (m_EvalErrorPrototype && !m_EvalErrorPrototype->marked()) |
|
632 m_EvalErrorPrototype->mark(); |
|
633 if (m_RangeErrorPrototype && !m_RangeErrorPrototype->marked()) |
|
634 m_RangeErrorPrototype->mark(); |
|
635 if (m_ReferenceErrorPrototype && !m_ReferenceErrorPrototype->marked()) |
|
636 m_ReferenceErrorPrototype->mark(); |
|
637 if (m_SyntaxErrorPrototype && !m_SyntaxErrorPrototype->marked()) |
|
638 m_SyntaxErrorPrototype->mark(); |
|
639 if (m_TypeErrorPrototype && !m_TypeErrorPrototype->marked()) |
|
640 m_TypeErrorPrototype->mark(); |
|
641 if (m_UriErrorPrototype && !m_UriErrorPrototype->marked()) |
|
642 m_UriErrorPrototype->mark(); |
|
643 } |
|
644 |
|
645 Interpreter* Interpreter::interpreterWithGlobalObject(JSObject* globalObject) |
|
646 { |
|
647 return interpreterMap().get(globalObject); |
|
648 } |
|
649 |
|
650 #ifdef KJS_DEBUG_MEM |
|
651 #include "lexer.h" |
|
652 void Interpreter::finalCheck() |
|
653 { |
|
654 fprintf(stderr,"Interpreter::finalCheck()\n"); |
|
655 Collector::collect(); |
|
656 |
|
657 Node::finalCheck(); |
|
658 Collector::finalCheck(); |
|
659 Lexer::globalClear(); |
|
660 UString::globalClear(); |
|
661 } |
|
662 #endif |
|
663 |
|
664 static bool printExceptions = false; |
|
665 |
|
666 EXPORT |
|
667 bool Interpreter::shouldPrintExceptions() |
|
668 { |
|
669 return printExceptions; |
|
670 } |
|
671 |
|
672 EXPORT |
|
673 void Interpreter::setShouldPrintExceptions(bool print) |
|
674 { |
|
675 printExceptions = print; |
|
676 } |
|
677 |
|
678 EXPORT |
|
679 void Interpreter::saveBuiltins (SavedBuiltins& builtins) const |
|
680 { |
|
681 if (!builtins._internal) |
|
682 builtins._internal = new SavedBuiltinsInternal; |
|
683 |
|
684 builtins._internal->m_Object = m_Object; |
|
685 builtins._internal->m_Function = m_Function; |
|
686 builtins._internal->m_Array = m_Array; |
|
687 builtins._internal->m_Boolean = m_Boolean; |
|
688 builtins._internal->m_String = m_String; |
|
689 builtins._internal->m_Number = m_Number; |
|
690 builtins._internal->m_Date = m_Date; |
|
691 builtins._internal->m_RegExp = m_RegExp; |
|
692 builtins._internal->m_Error = m_Error; |
|
693 |
|
694 builtins._internal->m_ObjectPrototype = m_ObjectPrototype; |
|
695 builtins._internal->m_FunctionPrototype = m_FunctionPrototype; |
|
696 builtins._internal->m_ArrayPrototype = m_ArrayPrototype; |
|
697 builtins._internal->m_BooleanPrototype = m_BooleanPrototype; |
|
698 builtins._internal->m_StringPrototype = m_StringPrototype; |
|
699 builtins._internal->m_NumberPrototype = m_NumberPrototype; |
|
700 builtins._internal->m_DatePrototype = m_DatePrototype; |
|
701 builtins._internal->m_RegExpPrototype = m_RegExpPrototype; |
|
702 builtins._internal->m_ErrorPrototype = m_ErrorPrototype; |
|
703 |
|
704 builtins._internal->m_EvalError = m_EvalError; |
|
705 builtins._internal->m_RangeError = m_RangeError; |
|
706 builtins._internal->m_ReferenceError = m_ReferenceError; |
|
707 builtins._internal->m_SyntaxError = m_SyntaxError; |
|
708 builtins._internal->m_TypeError = m_TypeError; |
|
709 builtins._internal->m_UriError = m_UriError; |
|
710 |
|
711 builtins._internal->m_EvalErrorPrototype = m_EvalErrorPrototype; |
|
712 builtins._internal->m_RangeErrorPrototype = m_RangeErrorPrototype; |
|
713 builtins._internal->m_ReferenceErrorPrototype = m_ReferenceErrorPrototype; |
|
714 builtins._internal->m_SyntaxErrorPrototype = m_SyntaxErrorPrototype; |
|
715 builtins._internal->m_TypeErrorPrototype = m_TypeErrorPrototype; |
|
716 builtins._internal->m_UriErrorPrototype = m_UriErrorPrototype; |
|
717 } |
|
718 |
|
719 EXPORT |
|
720 void Interpreter::restoreBuiltins (const SavedBuiltins& builtins) |
|
721 { |
|
722 if (!builtins._internal) |
|
723 return; |
|
724 |
|
725 m_Object = builtins._internal->m_Object; |
|
726 m_Function = builtins._internal->m_Function; |
|
727 m_Array = builtins._internal->m_Array; |
|
728 m_Boolean = builtins._internal->m_Boolean; |
|
729 m_String = builtins._internal->m_String; |
|
730 m_Number = builtins._internal->m_Number; |
|
731 m_Date = builtins._internal->m_Date; |
|
732 m_RegExp = builtins._internal->m_RegExp; |
|
733 m_Error = builtins._internal->m_Error; |
|
734 |
|
735 m_ObjectPrototype = builtins._internal->m_ObjectPrototype; |
|
736 m_FunctionPrototype = builtins._internal->m_FunctionPrototype; |
|
737 m_ArrayPrototype = builtins._internal->m_ArrayPrototype; |
|
738 m_BooleanPrototype = builtins._internal->m_BooleanPrototype; |
|
739 m_StringPrototype = builtins._internal->m_StringPrototype; |
|
740 m_NumberPrototype = builtins._internal->m_NumberPrototype; |
|
741 m_DatePrototype = builtins._internal->m_DatePrototype; |
|
742 m_RegExpPrototype = builtins._internal->m_RegExpPrototype; |
|
743 m_ErrorPrototype = builtins._internal->m_ErrorPrototype; |
|
744 |
|
745 m_EvalError = builtins._internal->m_EvalError; |
|
746 m_RangeError = builtins._internal->m_RangeError; |
|
747 m_ReferenceError = builtins._internal->m_ReferenceError; |
|
748 m_SyntaxError = builtins._internal->m_SyntaxError; |
|
749 m_TypeError = builtins._internal->m_TypeError; |
|
750 m_UriError = builtins._internal->m_UriError; |
|
751 |
|
752 m_EvalErrorPrototype = builtins._internal->m_EvalErrorPrototype; |
|
753 m_RangeErrorPrototype = builtins._internal->m_RangeErrorPrototype; |
|
754 m_ReferenceErrorPrototype = builtins._internal->m_ReferenceErrorPrototype; |
|
755 m_SyntaxErrorPrototype = builtins._internal->m_SyntaxErrorPrototype; |
|
756 m_TypeErrorPrototype = builtins._internal->m_TypeErrorPrototype; |
|
757 m_UriErrorPrototype = builtins._internal->m_UriErrorPrototype; |
|
758 } |
|
759 |
|
760 EXPORT |
|
761 void Interpreter::startTimeoutCheck() |
|
762 { |
|
763 if (m_timeoutCheckCount == 0) |
|
764 resetTimeoutCheck(); |
|
765 |
|
766 m_timeoutCheckCount++; |
|
767 } |
|
768 |
|
769 EXPORT |
|
770 void Interpreter::stopTimeoutCheck() |
|
771 { |
|
772 m_timeoutCheckCount--; |
|
773 } |
|
774 |
|
775 void Interpreter::resetTimeoutCheck() |
|
776 { |
|
777 m_tickCount = 0; |
|
778 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold; |
|
779 m_timeAtLastCheckTimeout = 0; |
|
780 m_timeExecuting = 0; |
|
781 } |
|
782 |
|
783 // Returns the current time in milliseconds |
|
784 // It doesn't matter what "current time" is here, just as long as |
|
785 // it's possible to measure the time difference correctly. |
|
786 static inline unsigned getCurrentTime() { |
|
787 #if HAVE(SYS_TIME_H) |
|
788 struct timeval tv; |
|
789 gettimeofday(&tv, 0); |
|
790 return tv.tv_sec * 1000 + tv.tv_usec / 1000; |
|
791 #elif PLATFORM(QT) |
|
792 QDateTime t = QDateTime::currentDateTime(); |
|
793 return t.toTime_t() * 1000 + t.time().msec(); |
|
794 #elif PLATFORM(WIN_OS) |
|
795 return timeGetTime(); |
|
796 #else |
|
797 #error Platform does not have getCurrentTime function |
|
798 #endif |
|
799 } |
|
800 |
|
801 bool Interpreter::checkTimeout() |
|
802 { |
|
803 m_tickCount = 0; |
|
804 |
|
805 unsigned currentTime = getCurrentTime(); |
|
806 |
|
807 if (!m_timeAtLastCheckTimeout) { |
|
808 // Suspicious amount of looping in a script -- start timing it |
|
809 m_timeAtLastCheckTimeout = currentTime; |
|
810 return false; |
|
811 } |
|
812 |
|
813 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout; |
|
814 |
|
815 if (timeDiff == 0) |
|
816 timeDiff = 1; |
|
817 |
|
818 m_timeExecuting += timeDiff; |
|
819 m_timeAtLastCheckTimeout = currentTime; |
|
820 |
|
821 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in |
|
822 // preferredScriptCheckTimeInterval |
|
823 m_ticksUntilNextTimeoutCheck = (unsigned)((float)preferredScriptCheckTimeInterval / timeDiff) * m_ticksUntilNextTimeoutCheck; |
|
824 |
|
825 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the |
|
826 // preferred script check time interval. |
|
827 if (m_ticksUntilNextTimeoutCheck == 0) |
|
828 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold; |
|
829 |
|
830 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) { |
|
831 if (shouldInterruptScript()) |
|
832 return true; |
|
833 |
|
834 resetTimeoutCheck(); |
|
835 } |
|
836 |
|
837 return false; |
|
838 } |
|
839 |
|
840 |
|
841 EXPORT |
|
842 SavedBuiltins::SavedBuiltins() : |
|
843 _internal(0) |
|
844 { |
|
845 } |
|
846 |
|
847 EXPORT |
|
848 SavedBuiltins::~SavedBuiltins() |
|
849 { |
|
850 delete _internal; |
|
851 } |
|
852 |
|
853 } |