source: webkit/trunk/JavaScriptCore/kjs/internal.cpp@ 10563

Last change on this file since 10563 was 10563, checked in by mjs, 20 years ago

Reviewed by Geoff.

  • fixed <rdar://problem/4214783> REGRESSION: kjs_fast_malloc crash due to lack of locking on multiple threads (seen selecting volumes in the installer)

Make sure to lock using the InterpreterLock class in all places that need it
(including anything that uses the collector, the parser, the protect count hash table,
and anything that allocates via fast_malloc).

Also added assertions to ensure that the locking rules are followed for the relevant
resources.

  • Makefile.am:
  • bindings/NP_jsobject.cpp: (identifierFromNPIdentifier): (_NPN_Invoke): (_NPN_Evaluate): (_NPN_GetProperty): (_NPN_SetProperty): (_NPN_RemoveProperty): (_NPN_HasProperty): (_NPN_HasMethod): (_NPN_SetException):
  • bindings/jni/jni_jsobject.cpp: (JSObject::call): (JSObject::eval): (JSObject::getMember): (JSObject::setMember): (JSObject::removeMember): (JSObject::getSlot): (JSObject::setSlot): (JSObject::toString): (JSObject::convertJObjectToValue):
  • bindings/objc/WebScriptObject.mm: (-[WebScriptObject callWebScriptMethod:withArguments:]): (-[WebScriptObject evaluateWebScript:]): (-[WebScriptObject setValue:forKey:]): (-[WebScriptObject valueForKey:]): (-[WebScriptObject removeWebScriptKey:]): (-[WebScriptObject stringRepresentation]): (-[WebScriptObject webScriptValueAtIndex:]): (-[WebScriptObject setWebScriptValueAtIndex:value:]): (+[WebScriptObject _convertValueToObjcValue:KJS::originExecutionContext:Bindings::executionContext:Bindings::]):
  • bindings/runtime.cpp: (Instance::createRuntimeObject):
  • bindings/runtime_root.h:
  • bindings/testbindings.cpp: (main):
  • bindings/testbindings.mm: (main):
  • kjs/fast_malloc.cpp: (KJS::kjs_fast_malloc): (KJS::kjs_fast_calloc): (KJS::kjs_fast_free): (KJS::kjs_fast_realloc):
  • kjs/fast_malloc.h:
  • kjs/identifier.h:
  • kjs/internal.cpp: (InterpreterImp::InterpreterImp): (InterpreterImp::clear): (InterpreterImp::mark): (InterpreterImp::checkSyntax): (InterpreterImp::evaluate):
  • kjs/internal.h: (KJS::InterpreterImp::globalObject):
  • kjs/interpreter.cpp: (Interpreter::evaluate):
  • kjs/interpreter.h: (KJS::InterpreterLock::InterpreterLock): (KJS::InterpreterLock::~InterpreterLock):
  • kjs/nodes.h:
  • kjs/protect.h: (KJS::ProtectedValue::ProtectedValue): (KJS::ProtectedValue::~ProtectedValue): (KJS::ProtectedValue::operator=): (KJS::ProtectedObject::ProtectedObject): (KJS::ProtectedObject::~ProtectedObject): (KJS::ProtectedObject::operator=): (KJS::ProtectedReference::ProtectedReference): (KJS::ProtectedReference::~ProtectedReference): (KJS::ProtectedReference::operator=):
  • kjs/protected_object.h:
  • kjs/protected_values.cpp: (KJS::ProtectedValues::getProtectCount): (KJS::ProtectedValues::increaseProtectCount): (KJS::ProtectedValues::decreaseProtectCount):
  • kjs/string_object.cpp: (StringObjectImp::StringObjectImp):
  • kjs/testkjs.cpp: (main):
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.5 KB
Line 
1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2002 Harri Porten ([email protected])
4 * Copyright (C) 2001 Peter Kelly ([email protected])
5 * Copyright (C) 2004 Apple Computer, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include <stdio.h>
25#include <math.h>
26#include <assert.h>
27
28#include "array_object.h"
29#include "bool_object.h"
30#include "collector.h"
31#include "context.h"
32#include "date_object.h"
33#include "debugger.h"
34#include "error_object.h"
35#include "function_object.h"
36#include "internal.h"
37#include "interpreter_map.h"
38#include "lexer.h"
39#include "math_object.h"
40#include "nodes.h"
41#include "number_object.h"
42#include "object.h"
43#include "object_object.h"
44#include "operations.h"
45#include "regexp_object.h"
46#include "string_object.h"
47
48#if WIN32
49#include <float.h>
50#define copysign(a, b) _copysign(a, b)
51#endif
52
53extern int kjsyyparse();
54
55using namespace KXMLCore;
56
57namespace KJS {
58
59#if !APPLE_CHANGES
60
61#ifdef WORDS_BIGENDIAN
62 const unsigned char NaN_Bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
63 const unsigned char Inf_Bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
64#elif defined(arm)
65 const unsigned char NaN_Bytes[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 };
66 const unsigned char Inf_Bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 };
67#else
68 const unsigned char NaN_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
69 const unsigned char Inf_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
70#endif
71
72 const double NaN = *(const double*) NaN_Bytes;
73 const double Inf = *(const double*) Inf_Bytes;
74
75#endif // APPLE_CHANGES
76
77#if !KJS_MULTIPLE_THREADS
78
79static inline void initializeInterpreterLock() { }
80static inline void lockInterpreter() { }
81static inline void unlockInterpreter() { }
82
83const int interpreterLockCount = 1;
84
85#else
86
87static pthread_once_t interpreterLockOnce = PTHREAD_ONCE_INIT;
88static pthread_mutex_t interpreterLock;
89static int interpreterLockCount = 0;
90
91static void initializeInterpreterLock()
92{
93 pthread_mutexattr_t attr;
94
95 pthread_mutexattr_init(&attr);
96 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
97
98 pthread_mutex_init(&interpreterLock, &attr);
99}
100
101static inline void lockInterpreter()
102{
103 pthread_once(&interpreterLockOnce, initializeInterpreterLock);
104 pthread_mutex_lock(&interpreterLock);
105 interpreterLockCount++;
106 Collector::registerThread();
107}
108
109static inline void unlockInterpreter()
110{
111 interpreterLockCount--;
112 pthread_mutex_unlock(&interpreterLock);
113}
114
115#endif
116
117// ------------------------------ UndefinedImp ---------------------------------
118
119ValueImp *UndefinedImp::toPrimitive(ExecState */*exec*/, Type) const
120{
121 return const_cast<UndefinedImp *>(this);
122}
123
124bool UndefinedImp::toBoolean(ExecState */*exec*/) const
125{
126 return false;
127}
128
129double UndefinedImp::toNumber(ExecState */*exec*/) const
130{
131 return NaN;
132}
133
134UString UndefinedImp::toString(ExecState */*exec*/) const
135{
136 return "undefined";
137}
138
139ObjectImp *UndefinedImp::toObject(ExecState *exec) const
140{
141 return throwError(exec, TypeError, "Undefined value");
142}
143
144// ------------------------------ NullImp --------------------------------------
145
146ValueImp *NullImp::toPrimitive(ExecState */*exec*/, Type) const
147{
148 return const_cast<NullImp *>(this);
149}
150
151bool NullImp::toBoolean(ExecState */*exec*/) const
152{
153 return false;
154}
155
156double NullImp::toNumber(ExecState */*exec*/) const
157{
158 return 0.0;
159}
160
161UString NullImp::toString(ExecState */*exec*/) const
162{
163 return "null";
164}
165
166ObjectImp *NullImp::toObject(ExecState *exec) const
167{
168 return throwError(exec, TypeError, "Null value");
169}
170
171// ------------------------------ BooleanImp -----------------------------------
172
173ValueImp *BooleanImp::toPrimitive(ExecState */*exec*/, Type) const
174{
175 return const_cast<BooleanImp *>(this);
176}
177
178bool BooleanImp::toBoolean(ExecState */*exec*/) const
179{
180 return val;
181}
182
183double BooleanImp::toNumber(ExecState */*exec*/) const
184{
185 return val ? 1.0 : 0.0;
186}
187
188UString BooleanImp::toString(ExecState */*exec*/) const
189{
190 return val ? "true" : "false";
191}
192
193ObjectImp *BooleanImp::toObject(ExecState *exec) const
194{
195 List args;
196 args.append(const_cast<BooleanImp*>(this));
197 return static_cast<ObjectImp *>(exec->lexicalInterpreter()->builtinBoolean()->construct(exec,args));
198}
199
200// ------------------------------ StringImp ------------------------------------
201
202ValueImp *StringImp::toPrimitive(ExecState */*exec*/, Type) const
203{
204 return const_cast<StringImp *>(this);
205}
206
207bool StringImp::toBoolean(ExecState */*exec*/) const
208{
209 return (val.size() > 0);
210}
211
212double StringImp::toNumber(ExecState */*exec*/) const
213{
214 return val.toDouble();
215}
216
217UString StringImp::toString(ExecState */*exec*/) const
218{
219 return val;
220}
221
222ObjectImp *StringImp::toObject(ExecState *exec) const
223{
224 List args;
225 args.append(const_cast<StringImp*>(this));
226 return static_cast<ObjectImp *>(exec->lexicalInterpreter()->builtinString()->construct(exec, args));
227}
228
229// ------------------------------ NumberImp ------------------------------------
230
231ValueImp *NumberImp::toPrimitive(ExecState *, Type) const
232{
233 return const_cast<NumberImp *>(this);
234}
235
236bool NumberImp::toBoolean(ExecState *) const
237{
238 return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
239}
240
241double NumberImp::toNumber(ExecState *) const
242{
243 return val;
244}
245
246UString NumberImp::toString(ExecState *) const
247{
248 if (val == 0.0) // +0.0 or -0.0
249 return "0";
250 return UString::from(val);
251}
252
253ObjectImp *NumberImp::toObject(ExecState *exec) const
254{
255 List args;
256 args.append(const_cast<NumberImp*>(this));
257 return static_cast<ObjectImp *>(exec->lexicalInterpreter()->builtinNumber()->construct(exec,args));
258}
259
260bool NumberImp::getUInt32(uint32_t& uint32) const
261{
262 uint32 = (uint32_t)val;
263 return (double)uint32 == val;
264}
265
266// ------------------------------ LabelStack -----------------------------------
267
268bool LabelStack::push(const Identifier &id)
269{
270 if (contains(id))
271 return false;
272
273 StackElem *newtos = new StackElem;
274 newtos->id = id;
275 newtos->prev = tos;
276 tos = newtos;
277 return true;
278}
279
280bool LabelStack::contains(const Identifier &id) const
281{
282 if (id.isEmpty())
283 return true;
284
285 for (StackElem *curr = tos; curr; curr = curr->prev)
286 if (curr->id == id)
287 return true;
288
289 return false;
290}
291
292// ------------------------------ ContextImp -----------------------------------
293
294// ECMA 10.2
295ContextImp::ContextImp(ObjectImp *glob, InterpreterImp *interpreter, ObjectImp *thisV, CodeType type,
296 ContextImp *callingCon, FunctionImp *func, const List *args)
297 : _interpreter(interpreter), _function(func), _arguments(args)
298{
299 m_codeType = type;
300 _callingContext = callingCon;
301
302 // create and initialize activation object (ECMA 10.1.6)
303 if (type == FunctionCode || type == AnonymousCode ) {
304 activation = new ActivationImp(func, *args);
305 variable = activation;
306 } else {
307 activation = NULL;
308 variable = glob;
309 }
310
311 // ECMA 10.2
312 switch(type) {
313 case EvalCode:
314 if (_callingContext) {
315 scope = _callingContext->scopeChain();
316 variable = _callingContext->variableObject();
317 thisVal = _callingContext->thisValue();
318 break;
319 } // else same as GlobalCode
320 case GlobalCode:
321 scope.clear();
322 scope.push(glob);
323 thisVal = static_cast<ObjectImp*>(glob);
324 break;
325 case FunctionCode:
326 case AnonymousCode:
327 if (type == FunctionCode) {
328 scope = func->scope();
329 scope.push(activation);
330 } else {
331 scope.clear();
332 scope.push(glob);
333 scope.push(activation);
334 }
335 variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
336 thisVal = thisV;
337 break;
338 }
339
340 _interpreter->setContext(this);
341}
342
343ContextImp::~ContextImp()
344{
345 _interpreter->setContext(_callingContext);
346}
347
348void ContextImp::mark()
349{
350 for (ContextImp *context = this; context; context = context->_callingContext) {
351 context->scope.mark();
352 }
353}
354
355// ------------------------------ Parser ---------------------------------------
356
357static SharedPtr<ProgramNode> *progNode;
358int Parser::sid = 0;
359
360const int initialCapacity = 64;
361const int growthFactor = 2;
362
363static int numNewNodes;
364static int newNodesCapacity;
365static Node **newNodes;
366
367void Parser::saveNewNode(Node *node)
368{
369 if (numNewNodes == newNodesCapacity) {
370 newNodesCapacity = (newNodesCapacity == 0) ? initialCapacity : newNodesCapacity * growthFactor;
371 newNodes = (Node **)realloc(newNodes, sizeof(Node *) * newNodesCapacity);
372 }
373
374 newNodes[numNewNodes++] = node;
375}
376
377static void clearNewNodes()
378{
379 for (int i = 0; i < numNewNodes; i++) {
380 if (newNodes[i]->refcount() == 0)
381 delete newNodes[i];
382 }
383 delete newNodes;
384 newNodes = 0;
385 numNewNodes = 0;
386 newNodesCapacity = 0;
387}
388
389SharedPtr<ProgramNode> Parser::parse(const UString &sourceURL, int startingLineNumber,
390 const UChar *code, unsigned int length, int *sourceId,
391 int *errLine, UString *errMsg)
392{
393 if (errLine)
394 *errLine = -1;
395 if (errMsg)
396 *errMsg = 0;
397 if (!progNode)
398 progNode = new SharedPtr<ProgramNode>;
399
400 Lexer::curr()->setCode(sourceURL, startingLineNumber, code, length);
401 *progNode = 0;
402 sid++;
403 if (sourceId)
404 *sourceId = sid;
405 // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
406 //extern int kjsyydebug;
407 //kjsyydebug=1;
408 int parseError = kjsyyparse();
409 bool lexError = Lexer::curr()->sawError();
410 Lexer::curr()->doneParsing();
411 SharedPtr<ProgramNode> prog = *progNode;
412 *progNode = 0;
413
414 clearNewNodes();
415
416 if (parseError || lexError) {
417 int eline = Lexer::curr()->lineNo();
418 if (errLine)
419 *errLine = eline;
420 if (errMsg)
421 *errMsg = "Parse error";
422 return SharedPtr<ProgramNode>();
423 }
424
425 return prog;
426}
427
428void Parser::accept(ProgramNode *prog)
429{
430 *progNode = prog;
431}
432
433// ------------------------------ InterpreterImp -------------------------------
434
435InterpreterImp* InterpreterImp::s_hook = 0L;
436
437void InterpreterImp::globalInit()
438{
439 ConstantValues::init();
440}
441
442void InterpreterImp::globalClear()
443{
444 ConstantValues::clear();
445}
446
447InterpreterImp::InterpreterImp(Interpreter *interp, ObjectImp *glob)
448 : globExec(interp, 0)
449 , _context(0)
450{
451 // add this interpreter to the global chain
452 // as a root set for garbage collection
453 InterpreterLock lock;
454
455 m_interpreter = interp;
456 if (s_hook) {
457 prev = s_hook;
458 next = s_hook->next;
459 s_hook->next->prev = this;
460 s_hook->next = this;
461 } else {
462 // This is the first interpreter
463 s_hook = next = prev = this;
464 globalInit();
465 }
466
467 InterpreterMap::setInterpreterForGlobalObject(this, glob);
468
469 global = glob;
470 dbg = 0;
471 m_compatMode = Interpreter::NativeMode;
472
473 // initialize properties of the global object
474 initGlobalObject();
475
476 recursion = 0;
477}
478
479void InterpreterImp::lock()
480{
481 lockInterpreter();
482}
483
484int InterpreterImp::lockCount()
485{
486 return interpreterLockCount;
487}
488
489void InterpreterImp::unlock()
490{
491 unlockInterpreter();
492}
493
494 void InterpreterImp::initGlobalObject()
495{
496 Identifier::init();
497
498 // Contructor prototype objects (Object.prototype, Array.prototype etc)
499
500 FunctionPrototypeImp *funcProto = new FunctionPrototypeImp(&globExec);
501 b_FunctionPrototype = funcProto;
502 ObjectPrototypeImp *objProto = new ObjectPrototypeImp(&globExec, funcProto);
503 b_ObjectPrototype = objProto;
504 funcProto->setPrototype(b_ObjectPrototype);
505
506 ArrayPrototypeImp *arrayProto = new ArrayPrototypeImp(&globExec, objProto);
507 b_ArrayPrototype = arrayProto;
508 StringPrototypeImp *stringProto = new StringPrototypeImp(&globExec, objProto);
509 b_StringPrototype = stringProto;
510 BooleanPrototypeImp *booleanProto = new BooleanPrototypeImp(&globExec, objProto, funcProto);
511 b_BooleanPrototype = booleanProto;
512 NumberPrototypeImp *numberProto = new NumberPrototypeImp(&globExec, objProto, funcProto);
513 b_NumberPrototype = numberProto;
514 DatePrototypeImp *dateProto = new DatePrototypeImp(&globExec, objProto);
515 b_DatePrototype = dateProto;
516 RegExpPrototypeImp *regexpProto = new RegExpPrototypeImp(&globExec, objProto, funcProto);
517 b_RegExpPrototype = regexpProto;
518 ErrorPrototypeImp *errorProto = new ErrorPrototypeImp(&globExec, objProto, funcProto);
519 b_ErrorPrototype = errorProto;
520
521 static_cast<ObjectImp*>(global)->setPrototype(b_ObjectPrototype);
522
523 // Constructors (Object, Array, etc.)
524 b_Object = new ObjectObjectImp(&globExec, objProto, funcProto);
525 b_Function = new FunctionObjectImp(&globExec, funcProto);
526 b_Array = new ArrayObjectImp(&globExec, funcProto, arrayProto);
527 b_String = new StringObjectImp(&globExec, funcProto, stringProto);
528 b_Boolean = new BooleanObjectImp(&globExec, funcProto, booleanProto);
529 b_Number = new NumberObjectImp(&globExec, funcProto, numberProto);
530 b_Date = new DateObjectImp(&globExec, funcProto, dateProto);
531 b_RegExp = new RegExpObjectImp(&globExec, funcProto, regexpProto);
532 b_Error = new ErrorObjectImp(&globExec, funcProto, errorProto);
533
534 // Error object prototypes
535 b_evalErrorPrototype = new NativeErrorPrototypeImp(&globExec, errorProto, EvalError, "EvalError", "EvalError");
536 b_rangeErrorPrototype = new NativeErrorPrototypeImp(&globExec, errorProto, RangeError, "RangeError", "RangeError");
537 b_referenceErrorPrototype = new NativeErrorPrototypeImp(&globExec, errorProto, ReferenceError, "ReferenceError", "ReferenceError");
538 b_syntaxErrorPrototype = new NativeErrorPrototypeImp(&globExec, errorProto, SyntaxError, "SyntaxError", "SyntaxError");
539 b_typeErrorPrototype = new NativeErrorPrototypeImp(&globExec, errorProto, TypeError, "TypeError", "TypeError");
540 b_uriErrorPrototype = new NativeErrorPrototypeImp(&globExec, errorProto, URIError, "URIError", "URIError");
541
542 // Error objects
543 b_evalError = new NativeErrorImp(&globExec, funcProto, b_evalErrorPrototype);
544 b_rangeError = new NativeErrorImp(&globExec, funcProto, b_rangeErrorPrototype);
545 b_referenceError = new NativeErrorImp(&globExec, funcProto, b_referenceErrorPrototype);
546 b_syntaxError = new NativeErrorImp(&globExec, funcProto, b_syntaxErrorPrototype);
547 b_typeError = new NativeErrorImp(&globExec, funcProto, b_typeErrorPrototype);
548 b_uriError = new NativeErrorImp(&globExec, funcProto, b_uriErrorPrototype);
549
550 // ECMA 15.3.4.1
551 funcProto->put(&globExec, "constructor", b_Function, DontEnum);
552
553 global->put(&globExec, "Object", b_Object, DontEnum);
554 global->put(&globExec, "Function", b_Function, DontEnum);
555 global->put(&globExec, "Array", b_Array, DontEnum);
556 global->put(&globExec, "Boolean", b_Boolean, DontEnum);
557 global->put(&globExec, "String", b_String, DontEnum);
558 global->put(&globExec, "Number", b_Number, DontEnum);
559 global->put(&globExec, "Date", b_Date, DontEnum);
560 global->put(&globExec, "RegExp", b_RegExp, DontEnum);
561 global->put(&globExec, "Error", b_Error, DontEnum);
562 // Using Internal for those to have something != 0
563 // (see kjs_window). Maybe DontEnum would be ok too ?
564 global->put(&globExec, "EvalError",b_evalError, Internal);
565 global->put(&globExec, "RangeError",b_rangeError, Internal);
566 global->put(&globExec, "ReferenceError",b_referenceError, Internal);
567 global->put(&globExec, "SyntaxError",b_syntaxError, Internal);
568 global->put(&globExec, "TypeError",b_typeError, Internal);
569 global->put(&globExec, "URIError",b_uriError, Internal);
570
571 // Set the "constructor" property of all builtin constructors
572 objProto->put(&globExec, "constructor", b_Object, DontEnum | DontDelete | ReadOnly);
573 funcProto->put(&globExec, "constructor", b_Function, DontEnum | DontDelete | ReadOnly);
574 arrayProto->put(&globExec, "constructor", b_Array, DontEnum | DontDelete | ReadOnly);
575 booleanProto->put(&globExec, "constructor", b_Boolean, DontEnum | DontDelete | ReadOnly);
576 stringProto->put(&globExec, "constructor", b_String, DontEnum | DontDelete | ReadOnly);
577 numberProto->put(&globExec, "constructor", b_Number, DontEnum | DontDelete | ReadOnly);
578 dateProto->put(&globExec, "constructor", b_Date, DontEnum | DontDelete | ReadOnly);
579 regexpProto->put(&globExec, "constructor", b_RegExp, DontEnum | DontDelete | ReadOnly);
580 errorProto->put(&globExec, "constructor", b_Error, DontEnum | DontDelete | ReadOnly);
581 b_evalErrorPrototype->put(&globExec, "constructor", b_evalError, DontEnum | DontDelete | ReadOnly);
582 b_rangeErrorPrototype->put(&globExec, "constructor", b_rangeError, DontEnum | DontDelete | ReadOnly);
583 b_referenceErrorPrototype->put(&globExec, "constructor", b_referenceError, DontEnum | DontDelete | ReadOnly);
584 b_syntaxErrorPrototype->put(&globExec, "constructor", b_syntaxError, DontEnum | DontDelete | ReadOnly);
585 b_typeErrorPrototype->put(&globExec, "constructor", b_typeError, DontEnum | DontDelete | ReadOnly);
586 b_uriErrorPrototype->put(&globExec, "constructor", b_uriError, DontEnum | DontDelete | ReadOnly);
587
588 // built-in values
589 global->put(&globExec, "NaN", jsNaN(), DontEnum|DontDelete);
590 global->put(&globExec, "Infinity", Number(Inf), DontEnum|DontDelete);
591 global->put(&globExec, "undefined", Undefined(), DontEnum|DontDelete);
592
593 // built-in functions
594 global->put(&globExec, "eval", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::Eval, 1), DontEnum);
595 global->put(&globExec, "parseInt", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::ParseInt, 2), DontEnum);
596 global->put(&globExec, "parseFloat", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::ParseFloat, 1), DontEnum);
597 global->put(&globExec, "isNaN", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::IsNaN, 1), DontEnum);
598 global->put(&globExec, "isFinite", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::IsFinite, 1), DontEnum);
599 global->put(&globExec, "escape", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::Escape, 1), DontEnum);
600 global->put(&globExec, "unescape", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::UnEscape, 1), DontEnum);
601 global->put(&globExec, "decodeURI", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::DecodeURI, 1), DontEnum);
602 global->put(&globExec, "decodeURIComponent", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::DecodeURIComponent, 1), DontEnum);
603 global->put(&globExec, "encodeURI", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::EncodeURI, 1), DontEnum);
604 global->put(&globExec, "encodeURIComponent", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::EncodeURIComponent, 1), DontEnum);
605#ifndef NDEBUG
606 global->put(&globExec, "kjsprint", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::KJSPrint, 1), DontEnum);
607#endif
608
609 // built-in objects
610 global->put(&globExec, "Math", new MathObjectImp(&globExec, objProto), DontEnum);
611}
612
613InterpreterImp::~InterpreterImp()
614{
615 if (dbg)
616 dbg->detach(m_interpreter);
617 clear();
618}
619
620void InterpreterImp::clear()
621{
622 //fprintf(stderr,"InterpreterImp::clear\n");
623 // remove from global chain (see init())
624 InterpreterLock lock;
625
626 next->prev = prev;
627 prev->next = next;
628 s_hook = next;
629 if (s_hook == this)
630 {
631 // This was the last interpreter
632 s_hook = 0L;
633 globalClear();
634 }
635 InterpreterMap::removeInterpreterForGlobalObject(global);
636}
637
638void InterpreterImp::mark()
639{
640 ConstantValues::mark();
641 if (m_interpreter)
642 m_interpreter->mark();
643 if (_context)
644 _context->mark();
645 if (global)
646 global->mark();
647 if (globExec._exception)
648 globExec._exception->mark();
649}
650
651bool InterpreterImp::checkSyntax(const UString &code)
652{
653 InterpreterLock lock;
654
655 // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
656 SharedPtr<ProgramNode> progNode = Parser::parse(UString(), 0, code.data(),code.size(),0,0,0);
657 return progNode;
658}
659
660Completion InterpreterImp::evaluate(const UString &code, ValueImp *thisV, const UString &sourceURL, int startingLineNumber)
661{
662 InterpreterLock lock;
663
664 // prevent against infinite recursion
665 if (recursion >= 20) {
666#if APPLE_CHANGES
667 Completion result = Completion(Throw, Error::create(&globExec, GeneralError, "Recursion too deep"));
668 return result;
669#else
670 return Completion(Throw,Error::create(&globExec, GeneralError, "Recursion too deep"));
671#endif
672 }
673
674 // parse the source code
675 int sid;
676 int errLine;
677 UString errMsg;
678 SharedPtr<ProgramNode> progNode = Parser::parse(sourceURL, startingLineNumber, code.data(),code.size(),&sid,&errLine,&errMsg);
679
680 // notify debugger that source has been parsed
681 if (dbg) {
682 bool cont = dbg->sourceParsed(&globExec, sid, sourceURL, code, errLine);
683 if (!cont)
684 return Completion(Break);
685 }
686
687 // no program node means a syntax error occurred
688 if (!progNode) {
689 ObjectImp *err = Error::create(&globExec, SyntaxError, errMsg, errLine, sid, &sourceURL);
690 return Completion(Throw,err);
691 }
692
693 globExec.clearException();
694
695 recursion++;
696
697 ObjectImp *globalObj = globalObject();
698 ObjectImp *thisObj = globalObject();
699
700 if (thisV) {
701 // "this" must be an object... use same rules as Function.prototype.apply()
702 if (thisV->isUndefinedOrNull())
703 thisObj = globalObject();
704 else {
705 thisObj = thisV->toObject(&globExec);
706 }
707 }
708
709 Completion res;
710 if (globExec.hadException()) {
711 // the thisArg->toObject() conversion above might have thrown an exception - if so,
712 // propagate it back
713 res = Completion(Throw, globExec.exception());
714 }
715 else {
716 // execute the code
717 ContextImp ctx(globalObj, this, thisObj);
718 ExecState newExec(m_interpreter, &ctx);
719 progNode->processVarDecls(&newExec);
720 res = progNode->execute(&newExec);
721 }
722
723 recursion--;
724
725 return res;
726}
727
728void InterpreterImp::saveBuiltins (SavedBuiltins &builtins) const
729{
730 if (!builtins._internal) {
731 builtins._internal = new SavedBuiltinsInternal;
732 }
733
734 builtins._internal->b_Object = b_Object;
735 builtins._internal->b_Function = b_Function;
736 builtins._internal->b_Array = b_Array;
737 builtins._internal->b_Boolean = b_Boolean;
738 builtins._internal->b_String = b_String;
739 builtins._internal->b_Number = b_Number;
740 builtins._internal->b_Date = b_Date;
741 builtins._internal->b_RegExp = b_RegExp;
742 builtins._internal->b_Error = b_Error;
743
744 builtins._internal->b_ObjectPrototype = b_ObjectPrototype;
745 builtins._internal->b_FunctionPrototype = b_FunctionPrototype;
746 builtins._internal->b_ArrayPrototype = b_ArrayPrototype;
747 builtins._internal->b_BooleanPrototype = b_BooleanPrototype;
748 builtins._internal->b_StringPrototype = b_StringPrototype;
749 builtins._internal->b_NumberPrototype = b_NumberPrototype;
750 builtins._internal->b_DatePrototype = b_DatePrototype;
751 builtins._internal->b_RegExpPrototype = b_RegExpPrototype;
752 builtins._internal->b_ErrorPrototype = b_ErrorPrototype;
753
754 builtins._internal->b_evalError = b_evalError;
755 builtins._internal->b_rangeError = b_rangeError;
756 builtins._internal->b_referenceError = b_referenceError;
757 builtins._internal->b_syntaxError = b_syntaxError;
758 builtins._internal->b_typeError = b_typeError;
759 builtins._internal->b_uriError = b_uriError;
760
761 builtins._internal->b_evalErrorPrototype = b_evalErrorPrototype;
762 builtins._internal->b_rangeErrorPrototype = b_rangeErrorPrototype;
763 builtins._internal->b_referenceErrorPrototype = b_referenceErrorPrototype;
764 builtins._internal->b_syntaxErrorPrototype = b_syntaxErrorPrototype;
765 builtins._internal->b_typeErrorPrototype = b_typeErrorPrototype;
766 builtins._internal->b_uriErrorPrototype = b_uriErrorPrototype;
767}
768
769void InterpreterImp::restoreBuiltins (const SavedBuiltins &builtins)
770{
771 if (!builtins._internal) {
772 return;
773 }
774
775 b_Object = builtins._internal->b_Object;
776 b_Function = builtins._internal->b_Function;
777 b_Array = builtins._internal->b_Array;
778 b_Boolean = builtins._internal->b_Boolean;
779 b_String = builtins._internal->b_String;
780 b_Number = builtins._internal->b_Number;
781 b_Date = builtins._internal->b_Date;
782 b_RegExp = builtins._internal->b_RegExp;
783 b_Error = builtins._internal->b_Error;
784
785 b_ObjectPrototype = builtins._internal->b_ObjectPrototype;
786 b_FunctionPrototype = builtins._internal->b_FunctionPrototype;
787 b_ArrayPrototype = builtins._internal->b_ArrayPrototype;
788 b_BooleanPrototype = builtins._internal->b_BooleanPrototype;
789 b_StringPrototype = builtins._internal->b_StringPrototype;
790 b_NumberPrototype = builtins._internal->b_NumberPrototype;
791 b_DatePrototype = builtins._internal->b_DatePrototype;
792 b_RegExpPrototype = builtins._internal->b_RegExpPrototype;
793 b_ErrorPrototype = builtins._internal->b_ErrorPrototype;
794
795 b_evalError = builtins._internal->b_evalError;
796 b_rangeError = builtins._internal->b_rangeError;
797 b_referenceError = builtins._internal->b_referenceError;
798 b_syntaxError = builtins._internal->b_syntaxError;
799 b_typeError = builtins._internal->b_typeError;
800 b_uriError = builtins._internal->b_uriError;
801
802 b_evalErrorPrototype = builtins._internal->b_evalErrorPrototype;
803 b_rangeErrorPrototype = builtins._internal->b_rangeErrorPrototype;
804 b_referenceErrorPrototype = builtins._internal->b_referenceErrorPrototype;
805 b_syntaxErrorPrototype = builtins._internal->b_syntaxErrorPrototype;
806 b_typeErrorPrototype = builtins._internal->b_typeErrorPrototype;
807 b_uriErrorPrototype = builtins._internal->b_uriErrorPrototype;
808}
809
810InterpreterImp *InterpreterImp::interpreterWithGlobalObject(ObjectImp *global)
811{
812 return InterpreterMap::getInterpreterForGlobalObject(global);
813}
814
815
816// ------------------------------ InternalFunctionImp --------------------------
817
818const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
819
820InternalFunctionImp::InternalFunctionImp()
821{
822}
823
824InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto)
825 : ObjectImp(funcProto)
826{
827}
828
829bool InternalFunctionImp::implementsHasInstance() const
830{
831 return true;
832}
833
834bool InternalFunctionImp::hasInstance(ExecState *exec, ValueImp *value)
835{
836 if (!value->isObject())
837 return false;
838
839 ValueImp *prot = get(exec,prototypePropertyName);
840 if (!prot->isObject() && !prot->isNull()) {
841 throwError(exec, TypeError, "Invalid prototype encountered in instanceof operation.");
842 return false;
843 }
844
845 ObjectImp *v = static_cast<ObjectImp *>(value);
846 while ((v = v->prototype()->getObject())) {
847 if (v == prot)
848 return true;
849 }
850 return false;
851}
852
853// ------------------------------ global functions -----------------------------
854
855double roundValue(ExecState *exec, ValueImp *v)
856{
857 double d = v->toNumber(exec);
858 double ad = fabs(d);
859 if (ad == 0 || isNaN(d) || isInf(d))
860 return d;
861 return copysign(floor(ad), d);
862}
863
864#ifndef NDEBUG
865#include <stdio.h>
866void printInfo(ExecState *exec, const char *s, ValueImp *o, int lineno)
867{
868 if (!o)
869 fprintf(stderr, "KJS: %s: (null)", s);
870 else {
871 ValueImp *v = o;
872
873 UString name;
874 switch (v->type()) {
875 case UnspecifiedType:
876 name = "Unspecified";
877 break;
878 case UndefinedType:
879 name = "Undefined";
880 break;
881 case NullType:
882 name = "Null";
883 break;
884 case BooleanType:
885 name = "Boolean";
886 break;
887 case StringType:
888 name = "String";
889 break;
890 case NumberType:
891 name = "Number";
892 break;
893 case ObjectType:
894 name = static_cast<ObjectImp *>(v)->className();
895 if (name.isNull())
896 name = "(unknown class)";
897 break;
898 }
899 UString vString = v->toString(exec);
900 if ( vString.size() > 50 )
901 vString = vString.substr( 0, 50 ) + "...";
902 // Can't use two UString::ascii() in the same fprintf call
903 CString tempString( vString.cstring() );
904
905 fprintf(stderr, "KJS: %s: %s : %s (%p)",
906 s, tempString.c_str(), name.ascii(), (void*)v);
907
908 if (lineno >= 0)
909 fprintf(stderr, ", line %d\n",lineno);
910 else
911 fprintf(stderr, "\n");
912 }
913}
914#endif
915
916}
Note: See TracBrowser for help on using the repository browser.