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