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

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

Reviewed by: Ken Kocienda and Darin Adler

Fixed the following bug:

Radar 2890573 - JavaScriptCore needs to be thread-safe

Actually this is only a weak form of thread-safety - you can safely
use different interpreters from different threads at the same
time. If you try to use a single interpreter object from multiple
threads, you need to provide your own locking.

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