source: webkit/trunk/JavaScriptCore/kjs/interpreter.cpp@ 20004

Last change on this file since 20004 was 20004, checked in by ggaren, 18 years ago

JavaScriptCore:

Reviewed by Maciej Stachowiak.


Fixed all known crashers exposed by run-webkit-tests --threaded. This covers:

<rdar://problem/4565394> | http://bugs.webkit.org/show_bug.cgi?id=12585

PAC file: after closing a window that contains macworld.com, new window
crashes (KJS::PropertyMap::mark()) (12585)

<rdar://problem/4571215> | http://bugs.webkit.org/show_bug.cgi?id=9211

PAC file: Crash occurs when clicking on the navigation tabs at http://www.businessweek.com/ (9211)

<rdar://problem/4557926>

PAC file: Crash occurs when attempting to view image in slideshow mode
at http://d.smugmug.com/gallery/581716 ( KJS::IfNode::execute (KJS::
ExecState*) + 312) if you use a PAC file

(1) Added some missing JSLocks, along with related ASSERTs.


(2) Fully implemented support for objects that can only be garbage collected
on the main thread. So far, only WebCore uses this. We can add it to API
later if we learn that it's needed.


The implementation uses a "main thread only" flag inside each object. When
collecting on a secondary thread, the Collector does an extra pass through
the heap to mark all flagged objects before sweeping. This solution makes
the common case -- flag lots of objects, but never collect on a secondary
thread -- very fast, even though the uncommon case of garbage collecting
on a secondary thread isn't as fast as it could be. I left some notes
about how to speed it up, if we ever care.


For posterity, here are some things I learned about GC while investigating:


  • Each collect must either mark or delete every heap object. "Zombie" objects, which are neither marked nor deleted, raise these issues:
  • On the next pass, the conservative marking algorithm might mark a zombie, causing it to mark freed objects.
  • The client might try to use a zombie, which would seem live because its finalizer had not yet run.
  • A collect on the main thread is free to delete any object. Presumably, objects allocated on secondary threads have thread-safe finalizers.
  • A collect on a secondary thread must not delete thread-unsafe objects.
  • The mark function must be thread-safe.


Line by line comments:

  • API/JSObjectRef.h: Added comment specifying that the finalize callback may run on any thread.
  • bindings/npruntime.cpp: (_NPN_GetStringIdentifier): Added JSLock.
  • bindings/objc/objc_instance.h:
  • bindings/objc/objc_instance.mm: (ObjcInstance::~ObjcInstance): Use an autorelease pool. The other callers to CFRelease needed one, too, but they were dead code, so I removed them instead. (This fixes a leak seen while running run-webkit-tests --threaded, although I don't think it's specifically a threading issue.)


  • kjs/collector.cpp: (KJS::Collector::collectOnMainThreadOnly): New function. Tells the collector to collect a value only if it's collecting on the main thread. (KJS::Collector::markMainThreadOnlyObjects): New function. Scans the heap for "main thread only" objects and marks them.
  • kjs/date_object.cpp: (KJS::DateObjectImp::DateObjectImp): To make the new ASSERTs happy, allocate our globals on the heap, avoiding a seemingly unsafe destructor call at program exit time.
  • kjs/function_object.cpp: (FunctionPrototype::FunctionPrototype): ditto
  • kjs/interpreter.cpp: (KJS::Interpreter::mark): Removed boolean parameter, which was an incomplete and arguably hackish way to implement markMainThreadOnlyObjects() inside WebCore.
  • kjs/interpreter.h:
  • kjs/identifier.cpp: (KJS::identifierTable): Added some ASSERTs to check for thread safety problems.
  • kjs/list.cpp: Added some ASSERTs to check for thread safety problems. (KJS::allocateListImp): (KJS::List::release): (KJS::List::append): (KJS::List::empty): Make the new ASSERTs happy.
  • kjs/object.h: (KJS::JSObject::JSObject): "m_destructorIsThreadSafe" => "m_collectOnMainThreadOnly". I removed the constructor parameter because m_collectOnMainThreadOnly, like m_marked, is a Collector bit, so only the Collector should set or get it.
  • kjs/object_object.cpp: (ObjectPrototype::ObjectPrototype): Make the ASSERTs happy.
  • kjs/regexp_object.cpp: (RegExpPrototype::RegExpPrototype): ditto
  • kjs/ustring.cpp: Added some ASSERTs to check for thread safety problems. (KJS::UCharReference::ref): (KJS::UString::Rep::createCopying): (KJS::UString::Rep::create): (KJS::UString::Rep::destroy): (KJS::UString::null): Make the new ASSERTs happy.
  • kjs/ustring.h: (KJS::UString::Rep::ref): Added some ASSERTs to check for thread safety problems. (KJS::UString::Rep::deref):
  • kjs/value.h: (KJS::JSCell::JSCell):

JavaScriptGlue:

Reviewed by Maciej Stachowiak.

Fixed all known crashers exposed by run-webkit-tests --threaded while using
a PAC file (for maximum carnage). See JavaScriptCore ChangeLog for
more details.

  • JSBase.cpp: (JSBase::Release): Lock when deleting, because we may be deleting an object (like a JSRun) that holds thread-unsafe data.
  • JSUtils.cpp: (CFStringToUString): Don't lock, because our caller locks. Also, locking inside a function that returns thread-unsafe data by copy will only mask threading problems.
  • JavaScriptGlue.cpp: (JSRunEvaluate): Added missing JSLock. (JSRunCheckSyntax): Converted to JSLock.
  • JavaScriptGlue.xcodeproj/project.pbxproj:

WebCore:

Reviewed by Maciej Stachowiak.

Fixed all known crashers exposed by run-webkit-tests --threaded [*]. See
JavaScriptCore ChangeLog for more details.

  • bindings/js/kjs_binding.cpp: (KJS::domNodesPerDocument): Added thread safety ASSERT. (KJS::ScriptInterpreter::mark): Removed obsolete logic for marking unsafe objects when collecting on a secondary thread. The Collector takes care of this now.
  • bindings/js/kjs_binding.h: (KJS::DOMObject::DOMObject): Used new API for specifying that WebCore objects should be garbage collected on the main thread only.
  • bindings/js/kjs_window.cpp: (KJS::ScheduledAction::execute): Moved JSLock to cover implementedsCall() call, which, for some subclasses, ends up allocating garbage collected objects. (This fix was speculative. I didn't actually see a crash from this.) (KJS::Window::timerFired): Added JSLock around ScheduleAction destruction, since it destroys a KJS::List.
  • bindings/objc/WebScriptObject.mm: (-[WebScriptObject setException:]): Added JSLock. (This fix was speculative. I didn't actually see a crash from this.)
  • bridge/mac/WebCoreScriptDebugger.mm: (-[WebCoreScriptCallFrame evaluateWebScript:]): Added JSLock. (This fix was speculative. I didn't actually see a crash from this.)
  • dom/Document.cpp: (WebCore::Document::~Document): Added JSLock around modification to domNodesPerDocument(), which can be accessed concurrently during garbage collection.
  • dom/Node.cpp: (WebCore::Node::setDocument): ditto.


[*] fast/js/toString-stack-overflow.html is an exception. --threaded mode
crashes this test because it causes the garbage collector to run frequently,
and this test crashes if you happen to garbage collect while it's running.
This is a known issue with stack overflow during the mark phase. It's
not related to threading.

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