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

Last change on this file since 1850 was 1850, checked in by mjs, 23 years ago

Final step of the Reference change. Completely separate Reference
from Value, and eliminate ReferenceImp.

18% speedup on cvs-js-performance test.

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