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

Last change on this file since 6549 was 6549, checked in by mjs, 21 years ago

JavaScriptCore:

Reviewed by Darin.

Enable full conservative GC mode in addition to test mode. When
conservative GC is enabled, we now get an 11% speed improvement on
the iBench. Also fix some spots I missed before.

Specific noteworth changes:

  • kjs/collector.cpp: (KJS::Collector::markStackObjectsConservatively): Check possible cell pointers for 8-byte aligment and verify they are not 0.
  • kjs/protected_values.cpp: (KJS::ProtectedValues::increaseProtectCount): Move null-tolerance from here... (KJS::ProtectedValues::decreaseProtectCount): ...and here...
  • kjs/protect.h: (KJS::gcProtectNullTolerant): ...to here... (KJS::gcUnprotectNullTolerant): ...and here, because not all callers need the null tolerance, and doing the check is expensive.
  • kjs/protected_values.cpp: (KJS::ProtectedValues::computeHash): Replace hash function with a much faster one that is still very good.
  • kjs/protect.h: (KJS::gcProtect): (KJS::gcUnprotect): (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_values.cpp: (KJS::ProtectedValues::getProtectCount): (KJS::ProtectedValues::increaseProtectCount): (KJS::ProtectedValues::decreaseProtectCount): (KJS::ProtectedValues::computeHash):
  • bindings/runtime_root.cpp: (KJS::Bindings::addNativeReference): (KJS::Bindings::removeNativeReference): (RootObject::removeAllNativeReferences):
  • bindings/runtime_root.h: (KJS::Bindings::RootObject::~RootObject): (KJS::Bindings::RootObject::setRootObjectImp):
  • kjs/collector.cpp: (KJS::Collector::allocate): (KJS::Collector::collect):
  • kjs/collector.h:
  • kjs/internal.cpp: (NumberImp::create): (InterpreterImp::globalInit): (InterpreterImp::globalClear): (InterpreterImp::mark):
  • kjs/list.cpp: (KJS::List::derefValues): (KJS::List::refValues): (KJS::List::append):
  • kjs/object.cpp: (KJS::ObjectImp::setInternalValue): (KJS::ObjectImp::putDirect):
  • kjs/value.cpp: (ValueImp::mark): (ValueImp::marked):
  • kjs/value.h: (KJS::ValueImp::ValueImp): (KJS::ValueImp::~ValueImp): (KJS::ValueImp::): (KJS::Value::Value): (KJS::Value::~Value): (KJS::Value::operator=):

WebCore:

Reviewed by Darin.

  • khtml/ecma/kjs_events.cpp: (JSLazyEventListener::parseCode): Make sure to protect the permanent "event" string object.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.9 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2002 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., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 *
23 */
24
25#include <stdio.h>
26#include <math.h>
27#include <assert.h>
28#ifndef NDEBUG
29#include <strings.h> // for strdup
30#endif
31
32#include "array_object.h"
33#include "bool_object.h"
34#include "collector.h"
35#include "context.h"
36#include "date_object.h"
37#include "debugger.h"
38#include "error_object.h"
39#include "function_object.h"
40#include "internal.h"
41#include "interpreter_map.h"
42#include "lexer.h"
43#include "math_object.h"
44#include "nodes.h"
45#include "number_object.h"
46#include "object.h"
47#include "object_object.h"
48#include "operations.h"
49#include "regexp_object.h"
50#include "string_object.h"
51
52#define I18N_NOOP(s) s
53
54extern int kjsyyparse();
55
56using namespace KJS;
57
58#if !APPLE_CHANGES
59
60namespace KJS {
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
76#endif // APPLE_CHANGES
77
78static pthread_once_t interpreterLockOnce = PTHREAD_ONCE_INIT;
79static pthread_mutex_t interpreterLock;
80static int interpreterLockCount = 0;
81
82static void initializeInterpreterLock()
83{
84 pthread_mutexattr_t attr;
85
86 pthread_mutexattr_init(&attr);
87 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
88
89 pthread_mutex_init(&interpreterLock, &attr);
90}
91
92static inline void lockInterpreter()
93{
94 pthread_once(&interpreterLockOnce, initializeInterpreterLock);
95 pthread_mutex_lock(&interpreterLock);
96 interpreterLockCount++;
97}
98
99static inline void unlockInterpreter()
100{
101 interpreterLockCount--;
102 pthread_mutex_unlock(&interpreterLock);
103}
104
105
106
107// ------------------------------ UndefinedImp ---------------------------------
108
109UndefinedImp *UndefinedImp::staticUndefined = 0;
110
111Value UndefinedImp::toPrimitive(ExecState */*exec*/, Type) const
112{
113 return Value((ValueImp*)this);
114}
115
116bool UndefinedImp::toBoolean(ExecState */*exec*/) const
117{
118 return false;
119}
120
121double UndefinedImp::toNumber(ExecState */*exec*/) const
122{
123 return NaN;
124}
125
126UString UndefinedImp::toString(ExecState */*exec*/) const
127{
128 return "undefined";
129}
130
131Object UndefinedImp::toObject(ExecState *exec) const
132{
133 Object err = Error::create(exec, TypeError, I18N_NOOP("Undefined value"));
134 exec->setException(err);
135 return err;
136}
137
138// ------------------------------ NullImp --------------------------------------
139
140NullImp *NullImp::staticNull = 0;
141
142Value NullImp::toPrimitive(ExecState */*exec*/, Type) const
143{
144 return Value((ValueImp*)this);
145}
146
147bool NullImp::toBoolean(ExecState */*exec*/) const
148{
149 return false;
150}
151
152double NullImp::toNumber(ExecState */*exec*/) const
153{
154 return 0.0;
155}
156
157UString NullImp::toString(ExecState */*exec*/) const
158{
159 return "null";
160}
161
162Object NullImp::toObject(ExecState *exec) const
163{
164 Object err = Error::create(exec, TypeError, I18N_NOOP("Null value"));
165 exec->setException(err);
166 return err;
167}
168
169// ------------------------------ BooleanImp -----------------------------------
170
171BooleanImp* BooleanImp::staticTrue = 0;
172BooleanImp* BooleanImp::staticFalse = 0;
173
174Value BooleanImp::toPrimitive(ExecState */*exec*/, Type) const
175{
176 return Value((ValueImp*)this);
177}
178
179bool BooleanImp::toBoolean(ExecState */*exec*/) const
180{
181 return val;
182}
183
184double BooleanImp::toNumber(ExecState */*exec*/) const
185{
186 return val ? 1.0 : 0.0;
187}
188
189UString BooleanImp::toString(ExecState */*exec*/) const
190{
191 return val ? "true" : "false";
192}
193
194Object BooleanImp::toObject(ExecState *exec) const
195{
196 List args;
197 args.append(const_cast<BooleanImp*>(this));
198 return Object::dynamicCast(exec->lexicalInterpreter()->builtinBoolean().construct(exec,args));
199}
200
201// ------------------------------ StringImp ------------------------------------
202
203Value StringImp::toPrimitive(ExecState */*exec*/, Type) const
204{
205 return Value((ValueImp*)this);
206}
207
208bool StringImp::toBoolean(ExecState */*exec*/) const
209{
210 return (val.size() > 0);
211}
212
213double StringImp::toNumber(ExecState */*exec*/) const
214{
215 return val.toDouble();
216}
217
218UString StringImp::toString(ExecState */*exec*/) const
219{
220 return val;
221}
222
223Object StringImp::toObject(ExecState *exec) const
224{
225 List args;
226 args.append(const_cast<StringImp*>(this));
227 return Object::dynamicCast(exec->lexicalInterpreter()->builtinString().construct(exec,args));
228}
229
230// ------------------------------ NumberImp ------------------------------------
231
232NumberImp *NumberImp::staticNaN;
233
234ValueImp *NumberImp::create(int i)
235{
236 if (SimpleNumber::fits(i))
237 return SimpleNumber::make(i);
238 NumberImp *imp = new NumberImp(static_cast<double>(i));
239#if !USE_CONSERVATIVE_GC
240 imp->setGcAllowedFast();
241#endif
242 return imp;
243}
244
245ValueImp *NumberImp::create(double d)
246{
247 if (SimpleNumber::fits(d))
248 return SimpleNumber::make((int)d);
249 if (isNaN(d))
250 return staticNaN;
251 NumberImp *imp = new NumberImp(d);
252#if !USE_CONSERVATIVE_GC
253 imp->setGcAllowedFast();
254#endif
255 return imp;
256}
257
258Value NumberImp::toPrimitive(ExecState *, Type) const
259{
260 return Number((NumberImp*)this);
261}
262
263bool NumberImp::toBoolean(ExecState *) const
264{
265 return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
266}
267
268double NumberImp::toNumber(ExecState *) const
269{
270 return val;
271}
272
273UString NumberImp::toString(ExecState *) const
274{
275 return UString::from(val);
276}
277
278Object NumberImp::toObject(ExecState *exec) const
279{
280 List args;
281 args.append(const_cast<NumberImp*>(this));
282 return Object::dynamicCast(exec->lexicalInterpreter()->builtinNumber().construct(exec,args));
283}
284
285bool NumberImp::toUInt32(unsigned& uint32) const
286{
287 uint32 = (unsigned)val;
288 return (double)uint32 == val;
289}
290
291double SimpleNumber::negZero = -0.0;
292
293// ------------------------------ LabelStack -----------------------------------
294
295LabelStack::LabelStack(const LabelStack &other)
296{
297 tos = 0;
298 *this = other;
299}
300
301LabelStack &LabelStack::operator=(const LabelStack &other)
302{
303 clear();
304 tos = 0;
305 StackElem *cur = 0;
306 StackElem *se = other.tos;
307 while (se) {
308 StackElem *newPrev = new StackElem;
309 newPrev->prev = 0;
310 newPrev->id = se->id;
311 if (cur)
312 cur->prev = newPrev;
313 else
314 tos = newPrev;
315 cur = newPrev;
316 se = se->prev;
317 }
318 return *this;
319}
320
321bool LabelStack::push(const Identifier &id)
322{
323 if (id.isEmpty() || contains(id))
324 return false;
325
326 StackElem *newtos = new StackElem;
327 newtos->id = id;
328 newtos->prev = tos;
329 tos = newtos;
330 return true;
331}
332
333bool LabelStack::contains(const Identifier &id) const
334{
335 if (id.isEmpty())
336 return true;
337
338 for (StackElem *curr = tos; curr; curr = curr->prev)
339 if (curr->id == id)
340 return true;
341
342 return false;
343}
344
345void LabelStack::pop()
346{
347 if (tos) {
348 StackElem *prev = tos->prev;
349 delete tos;
350 tos = prev;
351 }
352}
353
354LabelStack::~LabelStack()
355{
356 clear();
357}
358
359void LabelStack::clear()
360{
361 StackElem *prev;
362
363 while (tos) {
364 prev = tos->prev;
365 delete tos;
366 tos = prev;
367 }
368}
369
370// ------------------------------ ContextImp -----------------------------------
371
372// ECMA 10.2
373ContextImp::ContextImp(Object &glob, InterpreterImp *interpreter, Object &thisV, CodeType type,
374 ContextImp *callingCon, FunctionImp *func, const List *args)
375 : _interpreter(interpreter), _function(func), _arguments(args)
376{
377 codeType = type;
378 _callingContext = callingCon;
379
380 // create and initialize activation object (ECMA 10.1.6)
381 if (type == FunctionCode || type == AnonymousCode ) {
382 activation = Object(new ActivationImp(func, *args));
383 variable = activation;
384 } else {
385 activation = Object();
386 variable = glob;
387 }
388
389 // ECMA 10.2
390 switch(type) {
391 case EvalCode:
392 if (_callingContext) {
393 scope = _callingContext->scopeChain();
394 variable = _callingContext->variableObject();
395 thisVal = _callingContext->thisValue();
396 break;
397 } // else same as GlobalCode
398 case GlobalCode:
399 scope.clear();
400 scope.push(glob.imp());
401 thisVal = Object(static_cast<ObjectImp*>(glob.imp()));
402 break;
403 case FunctionCode:
404 case AnonymousCode:
405 if (type == FunctionCode) {
406 scope = func->scope();
407 scope.push(activation.imp());
408 } else {
409 scope.clear();
410 scope.push(glob.imp());
411 scope.push(activation.imp());
412 }
413 variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
414 thisVal = thisV;
415 break;
416 }
417
418 _interpreter->setContext(this);
419}
420
421ContextImp::~ContextImp()
422{
423 _interpreter->setContext(_callingContext);
424}
425
426void ContextImp::mark()
427{
428 for (ContextImp *context = this; context; context = context->_callingContext) {
429 context->scope.mark();
430 }
431}
432
433// ------------------------------ Parser ---------------------------------------
434
435ProgramNode *Parser::progNode = 0;
436int Parser::sid = 0;
437
438ProgramNode *Parser::parse(const UChar *code, unsigned int length, int *sourceId,
439 int *errLine, UString *errMsg)
440{
441 if (errLine)
442 *errLine = -1;
443 if (errMsg)
444 *errMsg = 0;
445
446 Lexer::curr()->setCode(code, length);
447 progNode = 0;
448 sid++;
449 if (sourceId)
450 *sourceId = sid;
451 // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
452 //extern int kjsyydebug;
453 //kjsyydebug=1;
454 int parseError = kjsyyparse();
455 Lexer::curr()->doneParsing();
456 ProgramNode *prog = progNode;
457 progNode = 0;
458 sid = -1;
459
460 if (parseError) {
461 int eline = Lexer::curr()->lineNo();
462 if (errLine)
463 *errLine = eline;
464 if (errMsg)
465 *errMsg = "Parse error at line " + UString::from(eline);
466 if (prog) {
467 // must ref and deref to clean up properly
468 prog->ref();
469 prog->deref();
470 delete prog;
471 }
472 return 0;
473 }
474
475 return prog;
476}
477
478// ------------------------------ InterpreterImp -------------------------------
479
480InterpreterImp* InterpreterImp::s_hook = 0L;
481
482void InterpreterImp::globalInit()
483{
484 //fprintf( stderr, "InterpreterImp::globalInit()\n" );
485 UndefinedImp::staticUndefined = new UndefinedImp();
486#if !USE_CONSERVATIVE_GC
487 UndefinedImp::staticUndefined->ref();
488#endif
489 NullImp::staticNull = new NullImp();
490#if !USE_CONSERVATIVE_GC
491 NullImp::staticNull->ref();
492#endif
493 BooleanImp::staticTrue = new BooleanImp(true);
494#if !USE_CONSERVATIVE_GC
495 BooleanImp::staticTrue->ref();
496#endif
497 BooleanImp::staticFalse = new BooleanImp(false);
498#if !USE_CONSERVATIVE_GC
499 BooleanImp::staticFalse->ref();
500#endif
501 NumberImp::staticNaN = new NumberImp(NaN);
502#if !USE_CONSERVATIVE_GC
503 NumberImp::staticNaN->ref();
504#endif
505}
506
507void InterpreterImp::globalClear()
508{
509 //fprintf( stderr, "InterpreterImp::globalClear()\n" );
510#if !USE_CONSERVATIVE_GC
511 UndefinedImp::staticUndefined->deref();
512 UndefinedImp::staticUndefined->setGcAllowed();
513#endif
514 UndefinedImp::staticUndefined = 0L;
515#if !USE_CONSERVATIVE_GC
516 NullImp::staticNull->deref();
517 NullImp::staticNull->setGcAllowed();
518#endif
519 NullImp::staticNull = 0L;
520#if !USE_CONSERVATIVE_GC
521 BooleanImp::staticTrue->deref();
522 BooleanImp::staticTrue->setGcAllowed();
523#endif
524 BooleanImp::staticTrue = 0L;
525#if !USE_CONSERVATIVE_GC
526 BooleanImp::staticFalse->deref();
527 BooleanImp::staticFalse->setGcAllowed();
528#endif
529 BooleanImp::staticFalse = 0L;
530#if !USE_CONSERVATIVE_GC
531 NumberImp::staticNaN->deref();
532 NumberImp::staticNaN->setGcAllowed();
533#endif
534 NumberImp::staticNaN = 0;
535}
536
537InterpreterImp::InterpreterImp(Interpreter *interp, const Object &glob)
538 : _context(0)
539{
540 // add this interpreter to the global chain
541 // as a root set for garbage collection
542 lockInterpreter();
543 m_interpreter = interp;
544 if (s_hook) {
545 prev = s_hook;
546 next = s_hook->next;
547 s_hook->next->prev = this;
548 s_hook->next = this;
549 } else {
550 // This is the first interpreter
551 s_hook = next = prev = this;
552 globalInit();
553 }
554
555 InterpreterMap::setInterpreterForGlobalObject(this, glob.imp());
556
557 global = glob;
558 globExec = new ExecState(m_interpreter,0);
559 dbg = 0;
560 m_compatMode = Interpreter::NativeMode;
561
562 // initialize properties of the global object
563 initGlobalObject();
564
565 recursion = 0;
566 unlockInterpreter();
567}
568
569void InterpreterImp::lock()
570{
571 lockInterpreter();
572}
573
574int InterpreterImp::lockCount()
575{
576 return interpreterLockCount;
577}
578
579void InterpreterImp::unlock()
580{
581 unlockInterpreter();
582}
583
584 void InterpreterImp::initGlobalObject()
585{
586 Identifier::init();
587
588 // Contructor prototype objects (Object.prototype, Array.prototype etc)
589
590 FunctionPrototypeImp *funcProto = new FunctionPrototypeImp(globExec);
591 b_FunctionPrototype = Object(funcProto);
592 ObjectPrototypeImp *objProto = new ObjectPrototypeImp(globExec,funcProto);
593 b_ObjectPrototype = Object(objProto);
594 funcProto->setPrototype(b_ObjectPrototype);
595
596 ArrayPrototypeImp *arrayProto = new ArrayPrototypeImp(globExec,objProto);
597 b_ArrayPrototype = Object(arrayProto);
598 StringPrototypeImp *stringProto = new StringPrototypeImp(globExec,objProto);
599 b_StringPrototype = Object(stringProto);
600 BooleanPrototypeImp *booleanProto = new BooleanPrototypeImp(globExec,objProto,funcProto);
601 b_BooleanPrototype = Object(booleanProto);
602 NumberPrototypeImp *numberProto = new NumberPrototypeImp(globExec,objProto,funcProto);
603 b_NumberPrototype = Object(numberProto);
604 DatePrototypeImp *dateProto = new DatePrototypeImp(globExec,objProto);
605 b_DatePrototype = Object(dateProto);
606 RegExpPrototypeImp *regexpProto = new RegExpPrototypeImp(globExec,objProto,funcProto);
607 b_RegExpPrototype = Object(regexpProto);
608 ErrorPrototypeImp *errorProto = new ErrorPrototypeImp(globExec,objProto,funcProto);
609 b_ErrorPrototype = Object(errorProto);
610
611 static_cast<ObjectImp*>(global.imp())->setPrototype(b_ObjectPrototype);
612
613 // Constructors (Object, Array, etc.)
614 b_Object = Object(new ObjectObjectImp(globExec, objProto, funcProto));
615 b_Function = Object(new FunctionObjectImp(globExec, funcProto));
616 b_Array = Object(new ArrayObjectImp(globExec, funcProto, arrayProto));
617 b_String = Object(new StringObjectImp(globExec, funcProto, stringProto));
618 b_Boolean = Object(new BooleanObjectImp(globExec, funcProto, booleanProto));
619 b_Number = Object(new NumberObjectImp(globExec, funcProto, numberProto));
620 b_Date = Object(new DateObjectImp(globExec, funcProto, dateProto));
621 b_RegExp = Object(new RegExpObjectImp(globExec, funcProto, regexpProto));
622 b_Error = Object(new ErrorObjectImp(globExec, funcProto, errorProto));
623
624 // Error object prototypes
625 b_evalErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,EvalError,
626 "EvalError","EvalError"));
627 b_rangeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,RangeError,
628 "RangeError","RangeError"));
629 b_referenceErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,ReferenceError,
630 "ReferenceError","ReferenceError"));
631 b_syntaxErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,SyntaxError,
632 "SyntaxError","SyntaxError"));
633 b_typeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,TypeError,
634 "TypeError","TypeError"));
635 b_uriErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,URIError,
636 "URIError","URIError"));
637
638 // Error objects
639 b_evalError = Object(new NativeErrorImp(globExec,funcProto,b_evalErrorPrototype));
640 b_rangeError = Object(new NativeErrorImp(globExec,funcProto,b_rangeErrorPrototype));
641 b_referenceError = Object(new NativeErrorImp(globExec,funcProto,b_referenceErrorPrototype));
642 b_syntaxError = Object(new NativeErrorImp(globExec,funcProto,b_syntaxErrorPrototype));
643 b_typeError = Object(new NativeErrorImp(globExec,funcProto,b_typeErrorPrototype));
644 b_uriError = Object(new NativeErrorImp(globExec,funcProto,b_uriErrorPrototype));
645
646 // ECMA 15.3.4.1
647 funcProto->put(globExec,"constructor", b_Function, DontEnum);
648
649 global.put(globExec,"Object", b_Object, DontEnum);
650 global.put(globExec,"Function", b_Function, DontEnum);
651 global.put(globExec,"Array", b_Array, DontEnum);
652 global.put(globExec,"Boolean", b_Boolean, DontEnum);
653 global.put(globExec,"String", b_String, DontEnum);
654 global.put(globExec,"Number", b_Number, DontEnum);
655 global.put(globExec,"Date", b_Date, DontEnum);
656 global.put(globExec,"RegExp", b_RegExp, DontEnum);
657 global.put(globExec,"Error", b_Error, DontEnum);
658 // Using Internal for those to have something != 0
659 // (see kjs_window). Maybe DontEnum would be ok too ?
660 global.put(globExec,"EvalError",b_evalError, Internal);
661 global.put(globExec,"RangeError",b_rangeError, Internal);
662 global.put(globExec,"ReferenceError",b_referenceError, Internal);
663 global.put(globExec,"SyntaxError",b_syntaxError, Internal);
664 global.put(globExec,"TypeError",b_typeError, Internal);
665 global.put(globExec,"URIError",b_uriError, Internal);
666
667 // Set the "constructor" property of all builtin constructors
668 objProto->put(globExec, "constructor", b_Object, DontEnum | DontDelete | ReadOnly);
669 funcProto->put(globExec, "constructor", b_Function, DontEnum | DontDelete | ReadOnly);
670 arrayProto->put(globExec, "constructor", b_Array, DontEnum | DontDelete | ReadOnly);
671 booleanProto->put(globExec, "constructor", b_Boolean, DontEnum | DontDelete | ReadOnly);
672 stringProto->put(globExec, "constructor", b_String, DontEnum | DontDelete | ReadOnly);
673 numberProto->put(globExec, "constructor", b_Number, DontEnum | DontDelete | ReadOnly);
674 dateProto->put(globExec, "constructor", b_Date, DontEnum | DontDelete | ReadOnly);
675 regexpProto->put(globExec, "constructor", b_RegExp, DontEnum | DontDelete | ReadOnly);
676 errorProto->put(globExec, "constructor", b_Error, DontEnum | DontDelete | ReadOnly);
677 b_evalErrorPrototype.put(globExec, "constructor", b_evalError, DontEnum | DontDelete | ReadOnly);
678 b_rangeErrorPrototype.put(globExec, "constructor", b_rangeError, DontEnum | DontDelete | ReadOnly);
679 b_referenceErrorPrototype.put(globExec, "constructor", b_referenceError, DontEnum | DontDelete | ReadOnly);
680 b_syntaxErrorPrototype.put(globExec, "constructor", b_syntaxError, DontEnum | DontDelete | ReadOnly);
681 b_typeErrorPrototype.put(globExec, "constructor", b_typeError, DontEnum | DontDelete | ReadOnly);
682 b_uriErrorPrototype.put(globExec, "constructor", b_uriError, DontEnum | DontDelete | ReadOnly);
683
684 // built-in values
685 global.put(globExec, "NaN", Number(NaN), DontEnum|DontDelete);
686 global.put(globExec, "Infinity", Number(Inf), DontEnum|DontDelete);
687 global.put(globExec, "undefined", Undefined(), DontEnum|DontDelete);
688
689 // built-in functions
690 global.put(globExec,"eval", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Eval, 1)), DontEnum);
691 global.put(globExec,"parseInt", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseInt, 2)), DontEnum);
692 global.put(globExec,"parseFloat", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseFloat, 1)), DontEnum);
693 global.put(globExec,"isNaN", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsNaN, 1)), DontEnum);
694 global.put(globExec,"isFinite", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsFinite, 1)), DontEnum);
695 global.put(globExec,"escape", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Escape, 1)), DontEnum);
696 global.put(globExec,"unescape", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::UnEscape, 1)), DontEnum);
697 global.put(globExec,"decodeURI", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::DecodeURI, 1)), DontEnum);
698 global.put(globExec,"decodeURIComponent", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::DecodeURIComponent, 1)), DontEnum);
699 global.put(globExec,"encodeURI", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::EncodeURI, 1)), DontEnum);
700 global.put(globExec,"encodeURIComponent", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::EncodeURIComponent, 1)), DontEnum);
701#ifndef NDEBUG
702 global.put(globExec,"kjsprint", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::KJSPrint, 1)), DontEnum);
703#endif
704
705 // built-in objects
706 global.put(globExec,"Math", Object(new MathObjectImp(globExec,objProto)), DontEnum);
707}
708
709InterpreterImp::~InterpreterImp()
710{
711 if (dbg)
712 dbg->detach(m_interpreter);
713 delete globExec;
714 globExec = 0L;
715 clear();
716}
717
718void InterpreterImp::clear()
719{
720 //fprintf(stderr,"InterpreterImp::clear\n");
721 // remove from global chain (see init())
722#if APPLE_CHANGES
723 lockInterpreter();
724#endif
725 next->prev = prev;
726 prev->next = next;
727 s_hook = next;
728 if (s_hook == this)
729 {
730 // This was the last interpreter
731 s_hook = 0L;
732 globalClear();
733 }
734 InterpreterMap::removeInterpreterForGlobalObject(global.imp());
735
736#if APPLE_CHANGES
737 unlockInterpreter();
738#endif
739}
740
741void InterpreterImp::mark()
742{
743 //if (exVal && !exVal->marked())
744 // exVal->mark();
745 //if (retVal && !retVal->marked())
746 // retVal->mark();
747 if (UndefinedImp::staticUndefined && !UndefinedImp::staticUndefined->marked())
748 UndefinedImp::staticUndefined->mark();
749 if (NullImp::staticNull && !NullImp::staticNull->marked())
750 NullImp::staticNull->mark();
751 if (BooleanImp::staticTrue && !BooleanImp::staticTrue->marked())
752 BooleanImp::staticTrue->mark();
753 if (BooleanImp::staticFalse && !BooleanImp::staticFalse->marked())
754 BooleanImp::staticFalse->mark();
755 //fprintf( stderr, "InterpreterImp::mark this=%p global.imp()=%p\n", this, global.imp() );
756 if (m_interpreter)
757 m_interpreter->mark();
758 if (_context)
759 _context->mark();
760}
761
762bool InterpreterImp::checkSyntax(const UString &code)
763{
764 // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
765 ProgramNode *progNode = Parser::parse(code.data(),code.size(),0,0,0);
766 bool ok = (progNode != 0);
767 if (progNode) {
768 // must ref and deref to clean up properly
769 progNode->ref();
770 progNode->deref();
771 delete progNode;
772 }
773 return ok;
774}
775
776Completion InterpreterImp::evaluate(const UString &code, const Value &thisV)
777{
778#if APPLE_CHANGES
779 lockInterpreter();
780#endif
781 // prevent against infinite recursion
782 if (recursion >= 20) {
783#if APPLE_CHANGES
784 Completion result = Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
785 unlockInterpreter();
786 return result;
787#else
788 return Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
789#endif
790 }
791
792 // parse the source code
793 int sid;
794 int errLine;
795 UString errMsg;
796 ProgramNode *progNode = Parser::parse(code.data(),code.size(),&sid,&errLine,&errMsg);
797
798 // notify debugger that source has been parsed
799 if (dbg) {
800 bool cont = dbg->sourceParsed(globExec,sid,code,errLine);
801 if (!cont)
802#if APPLE_CHANGES
803 {
804 unlockInterpreter();
805 return Completion(Break);
806 }
807#else
808 return Completion(Break);
809#endif
810 }
811
812 // no program node means a syntax error occurred
813 if (!progNode) {
814 Object err = Error::create(globExec,SyntaxError,errMsg.ascii(),errLine);
815 err.put(globExec,"sid",Number(sid));
816#if APPLE_CHANGES
817 unlockInterpreter();
818#endif
819 return Completion(Throw,err);
820 }
821
822 globExec->clearException();
823
824 recursion++;
825 progNode->ref();
826
827 Object &globalObj = globalObject();
828 Object thisObj = globalObject();
829
830 if (!thisV.isNull()) {
831 // "this" must be an object... use same rules as Function.prototype.apply()
832 if (thisV.isA(NullType) || thisV.isA(UndefinedType))
833 thisObj = globalObject();
834 else {
835 thisObj = thisV.toObject(globExec);
836 }
837 }
838
839 Completion res;
840 if (globExec->hadException()) {
841 // the thisArg.toObject() conversion above might have thrown an exception - if so,
842 // propagate it back
843 res = Completion(Throw,globExec->exception());
844 }
845 else {
846 // execute the code
847 ContextImp ctx(globalObj, this, thisObj);
848 ExecState newExec(m_interpreter,&ctx);
849 res = progNode->execute(&newExec);
850 }
851
852 if (progNode->deref())
853 delete progNode;
854 recursion--;
855
856#if APPLE_CHANGES
857 unlockInterpreter();
858#endif
859 return res;
860}
861
862void InterpreterImp::setDebugger(Debugger *d)
863{
864 if (d)
865 d->detach(m_interpreter);
866 dbg = d;
867}
868
869void InterpreterImp::saveBuiltins (SavedBuiltins &builtins) const
870{
871 if (!builtins._internal) {
872 builtins._internal = new SavedBuiltinsInternal;
873 }
874
875 builtins._internal->b_Object = b_Object;
876 builtins._internal->b_Function = b_Function;
877 builtins._internal->b_Array = b_Array;
878 builtins._internal->b_Boolean = b_Boolean;
879 builtins._internal->b_String = b_String;
880 builtins._internal->b_Number = b_Number;
881 builtins._internal->b_Date = b_Date;
882 builtins._internal->b_RegExp = b_RegExp;
883 builtins._internal->b_Error = b_Error;
884
885 builtins._internal->b_ObjectPrototype = b_ObjectPrototype;
886 builtins._internal->b_FunctionPrototype = b_FunctionPrototype;
887 builtins._internal->b_ArrayPrototype = b_ArrayPrototype;
888 builtins._internal->b_BooleanPrototype = b_BooleanPrototype;
889 builtins._internal->b_StringPrototype = b_StringPrototype;
890 builtins._internal->b_NumberPrototype = b_NumberPrototype;
891 builtins._internal->b_DatePrototype = b_DatePrototype;
892 builtins._internal->b_RegExpPrototype = b_RegExpPrototype;
893 builtins._internal->b_ErrorPrototype = b_ErrorPrototype;
894
895 builtins._internal->b_evalError = b_evalError;
896 builtins._internal->b_rangeError = b_rangeError;
897 builtins._internal->b_referenceError = b_referenceError;
898 builtins._internal->b_syntaxError = b_syntaxError;
899 builtins._internal->b_typeError = b_typeError;
900 builtins._internal->b_uriError = b_uriError;
901
902 builtins._internal->b_evalErrorPrototype = b_evalErrorPrototype;
903 builtins._internal->b_rangeErrorPrototype = b_rangeErrorPrototype;
904 builtins._internal->b_referenceErrorPrototype = b_referenceErrorPrototype;
905 builtins._internal->b_syntaxErrorPrototype = b_syntaxErrorPrototype;
906 builtins._internal->b_typeErrorPrototype = b_typeErrorPrototype;
907 builtins._internal->b_uriErrorPrototype = b_uriErrorPrototype;
908}
909
910void InterpreterImp::restoreBuiltins (const SavedBuiltins &builtins)
911{
912 if (!builtins._internal) {
913 return;
914 }
915
916 b_Object = builtins._internal->b_Object;
917 b_Function = builtins._internal->b_Function;
918 b_Array = builtins._internal->b_Array;
919 b_Boolean = builtins._internal->b_Boolean;
920 b_String = builtins._internal->b_String;
921 b_Number = builtins._internal->b_Number;
922 b_Date = builtins._internal->b_Date;
923 b_RegExp = builtins._internal->b_RegExp;
924 b_Error = builtins._internal->b_Error;
925
926 b_ObjectPrototype = builtins._internal->b_ObjectPrototype;
927 b_FunctionPrototype = builtins._internal->b_FunctionPrototype;
928 b_ArrayPrototype = builtins._internal->b_ArrayPrototype;
929 b_BooleanPrototype = builtins._internal->b_BooleanPrototype;
930 b_StringPrototype = builtins._internal->b_StringPrototype;
931 b_NumberPrototype = builtins._internal->b_NumberPrototype;
932 b_DatePrototype = builtins._internal->b_DatePrototype;
933 b_RegExpPrototype = builtins._internal->b_RegExpPrototype;
934 b_ErrorPrototype = builtins._internal->b_ErrorPrototype;
935
936 b_evalError = builtins._internal->b_evalError;
937 b_rangeError = builtins._internal->b_rangeError;
938 b_referenceError = builtins._internal->b_referenceError;
939 b_syntaxError = builtins._internal->b_syntaxError;
940 b_typeError = builtins._internal->b_typeError;
941 b_uriError = builtins._internal->b_uriError;
942
943 b_evalErrorPrototype = builtins._internal->b_evalErrorPrototype;
944 b_rangeErrorPrototype = builtins._internal->b_rangeErrorPrototype;
945 b_referenceErrorPrototype = builtins._internal->b_referenceErrorPrototype;
946 b_syntaxErrorPrototype = builtins._internal->b_syntaxErrorPrototype;
947 b_typeErrorPrototype = builtins._internal->b_typeErrorPrototype;
948 b_uriErrorPrototype = builtins._internal->b_uriErrorPrototype;
949}
950
951InterpreterImp *InterpreterImp::interpreterWithGlobalObject(ObjectImp *global)
952{
953 return InterpreterMap::getInterpreterForGlobalObject(global);
954}
955
956
957// ------------------------------ InternalFunctionImp --------------------------
958
959const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
960
961InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto)
962 : ObjectImp(funcProto)
963{
964}
965
966bool InternalFunctionImp::implementsHasInstance() const
967{
968 return true;
969}
970
971Boolean InternalFunctionImp::hasInstance(ExecState *exec, const Value &value)
972{
973 if (value.type() != ObjectType)
974 return Boolean(false);
975
976 Value prot = get(exec,prototypePropertyName);
977 if (prot.type() != ObjectType && prot.type() != NullType) {
978 Object err = Error::create(exec, TypeError, "Invalid prototype encountered "
979 "in instanceof operation.");
980 exec->setException(err);
981 return Boolean(false);
982 }
983
984 Object v = Object(static_cast<ObjectImp*>(value.imp()));
985 while ((v = Object::dynamicCast(v.prototype())).imp()) {
986 if (v.imp() == prot.imp())
987 return Boolean(true);
988 }
989 return Boolean(false);
990}
991
992// ------------------------------ global functions -----------------------------
993
994double KJS::roundValue(ExecState *exec, const Value &v)
995{
996 Number n = v.toNumber(exec);
997 double d = n.value();
998 double ad = fabs(d);
999 if (ad == 0 || isNaN(d) || isInf(d))
1000 return d;
1001 return copysign(floor(ad), d);
1002}
1003
1004#ifndef NDEBUG
1005#include <stdio.h>
1006void KJS::printInfo(ExecState *exec, const char *s, const Value &o, int lineno)
1007{
1008 if (o.isNull())
1009 fprintf(stderr, "KJS: %s: (null)", s);
1010 else {
1011 Value v = o;
1012
1013 UString name;
1014 switch ( v.type() ) {
1015 case UnspecifiedType:
1016 name = "Unspecified";
1017 break;
1018 case UndefinedType:
1019 name = "Undefined";
1020 break;
1021 case NullType:
1022 name = "Null";
1023 break;
1024 case BooleanType:
1025 name = "Boolean";
1026 break;
1027 case StringType:
1028 name = "String";
1029 break;
1030 case NumberType:
1031 name = "Number";
1032 break;
1033 case ObjectType:
1034 name = Object::dynamicCast(v).className();
1035 if (name.isNull())
1036 name = "(unknown class)";
1037 break;
1038 }
1039 UString vString = v.toString(exec);
1040 if ( vString.size() > 50 )
1041 vString = vString.substr( 0, 50 ) + "...";
1042 // Can't use two UString::ascii() in the same fprintf call
1043 CString tempString( vString.cstring() );
1044
1045 fprintf(stderr, "KJS: %s: %s : %s (%p)",
1046 s, tempString.c_str(), name.ascii(), (void*)v.imp());
1047
1048 if (lineno >= 0)
1049 fprintf(stderr, ", line %d\n",lineno);
1050 else
1051 fprintf(stderr, "\n");
1052 }
1053}
1054#endif
Note: See TracBrowser for help on using the repository browser.