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

Last change on this file since 4087 was 4087, checked in by mjs, 22 years ago

Reviewed by Don.

  • JavaScriptCore part of fix for 3158769 - JavaScript triggers not as async as they used to be

Added a way to get the current interpreter lock count, so Sherlock
can unlock the interpreter inside JS method implementations that
spend a long time waiting for I/O, allowing more efficient
multi-threaded operation.

  • kjs/internal.cpp: (lockInterpreter): (unlockInterpreter): (InterpreterImp::lock): (InterpreterImp::lockCount):
  • kjs/internal.h:
  • kjs/interpreter.cpp: (Interpreter::lockCount):
  • kjs/interpreter.h:
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.1 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 "lexer.h"
42#include "math_object.h"
43#include "nodes.h"
44#include "number_object.h"
45#include "object.h"
46#include "object_object.h"
47#include "operations.h"
48#include "regexp_object.h"
49#include "string_object.h"
50
51#define I18N_NOOP(s) s
52
53extern int kjsyyparse();
54
55using namespace KJS;
56
57namespace KJS {
58#ifdef WORDS_BIGENDIAN
59 const unsigned char NaN_Bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
60 const unsigned char Inf_Bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
61#elif defined(arm)
62 const unsigned char NaN_Bytes[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 };
63 const unsigned char Inf_Bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 };
64#else
65 const unsigned char NaN_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
66 const unsigned char Inf_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
67#endif
68
69 const double NaN = *(const double*) NaN_Bytes;
70 const double Inf = *(const double*) Inf_Bytes;
71};
72
73static pthread_once_t interpreterLockOnce = PTHREAD_ONCE_INIT;
74static pthread_mutex_t interpreterLock;
75static int interpreterLockCount = 0;
76
77static void initializeInterpreterLock()
78{
79 pthread_mutexattr_t attr;
80
81 pthread_mutexattr_init(&attr);
82 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
83
84 pthread_mutex_init(&interpreterLock, &attr);
85}
86
87static inline void lockInterpreter()
88{
89 pthread_once(&interpreterLockOnce, initializeInterpreterLock);
90 pthread_mutex_lock(&interpreterLock);
91 interpreterLockCount++;
92}
93
94static inline void unlockInterpreter()
95{
96 interpreterLockCount--;
97 pthread_mutex_unlock(&interpreterLock);
98}
99
100
101
102// ------------------------------ UndefinedImp ---------------------------------
103
104UndefinedImp *UndefinedImp::staticUndefined = 0;
105
106Value UndefinedImp::toPrimitive(ExecState */*exec*/, Type) const
107{
108 return Value((ValueImp*)this);
109}
110
111bool UndefinedImp::toBoolean(ExecState */*exec*/) const
112{
113 return false;
114}
115
116double UndefinedImp::toNumber(ExecState */*exec*/) const
117{
118 return NaN;
119}
120
121UString UndefinedImp::toString(ExecState */*exec*/) const
122{
123 return "undefined";
124}
125
126Object UndefinedImp::toObject(ExecState *exec) const
127{
128 Object err = Error::create(exec, TypeError, I18N_NOOP("Undefined value"));
129 exec->setException(err);
130 return err;
131}
132
133// ------------------------------ NullImp --------------------------------------
134
135NullImp *NullImp::staticNull = 0;
136
137Value NullImp::toPrimitive(ExecState */*exec*/, Type) const
138{
139 return Value((ValueImp*)this);
140}
141
142bool NullImp::toBoolean(ExecState */*exec*/) const
143{
144 return false;
145}
146
147double NullImp::toNumber(ExecState */*exec*/) const
148{
149 return 0.0;
150}
151
152UString NullImp::toString(ExecState */*exec*/) const
153{
154 return "null";
155}
156
157Object NullImp::toObject(ExecState *exec) const
158{
159 Object err = Error::create(exec, TypeError, I18N_NOOP("Null value"));
160 exec->setException(err);
161 return err;
162}
163
164// ------------------------------ BooleanImp -----------------------------------
165
166BooleanImp* BooleanImp::staticTrue = 0;
167BooleanImp* BooleanImp::staticFalse = 0;
168
169Value BooleanImp::toPrimitive(ExecState */*exec*/, Type) const
170{
171 return Value((ValueImp*)this);
172}
173
174bool BooleanImp::toBoolean(ExecState */*exec*/) const
175{
176 return val;
177}
178
179double BooleanImp::toNumber(ExecState */*exec*/) const
180{
181 return val ? 1.0 : 0.0;
182}
183
184UString BooleanImp::toString(ExecState */*exec*/) const
185{
186 return val ? "true" : "false";
187}
188
189Object BooleanImp::toObject(ExecState *exec) const
190{
191 List args;
192 args.append(const_cast<BooleanImp*>(this));
193 return Object::dynamicCast(exec->interpreter()->builtinBoolean().construct(exec,args));
194}
195
196// ------------------------------ StringImp ------------------------------------
197
198Value StringImp::toPrimitive(ExecState */*exec*/, Type) const
199{
200 return Value((ValueImp*)this);
201}
202
203bool StringImp::toBoolean(ExecState */*exec*/) const
204{
205 return (val.size() > 0);
206}
207
208double StringImp::toNumber(ExecState */*exec*/) const
209{
210 return val.toDouble();
211}
212
213UString StringImp::toString(ExecState */*exec*/) const
214{
215 return val;
216}
217
218Object StringImp::toObject(ExecState *exec) const
219{
220 List args;
221 args.append(const_cast<StringImp*>(this));
222 return Object::dynamicCast(exec->interpreter()->builtinString().construct(exec,args));
223}
224
225// ------------------------------ NumberImp ------------------------------------
226
227NumberImp *NumberImp::staticNaN;
228
229ValueImp *NumberImp::create(int i)
230{
231 if (SimpleNumber::fits(i))
232 return SimpleNumber::make(i);
233 NumberImp *imp = new NumberImp(static_cast<double>(i));
234 imp->setGcAllowedFast();
235 return imp;
236}
237
238ValueImp *NumberImp::create(double d)
239{
240 if (SimpleNumber::fits(d))
241 return SimpleNumber::make((int)d);
242 if (isNaN(d))
243 return staticNaN;
244 NumberImp *imp = new NumberImp(d);
245 imp->setGcAllowedFast();
246 return imp;
247}
248
249Value NumberImp::toPrimitive(ExecState *, Type) const
250{
251 return Number((NumberImp*)this);
252}
253
254bool NumberImp::toBoolean(ExecState *) const
255{
256 return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
257}
258
259double NumberImp::toNumber(ExecState *) const
260{
261 return val;
262}
263
264UString NumberImp::toString(ExecState *) const
265{
266 return UString::from(val);
267}
268
269Object NumberImp::toObject(ExecState *exec) const
270{
271 List args;
272 args.append(const_cast<NumberImp*>(this));
273 return Object::dynamicCast(exec->interpreter()->builtinNumber().construct(exec,args));
274}
275
276bool NumberImp::toUInt32(unsigned& uint32) const
277{
278 uint32 = (unsigned)val;
279 return (double)uint32 == val;
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 Identifier &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 Identifier &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// ------------------------------ ContextImp -----------------------------------
360
361// ECMA 10.2
362ContextImp::ContextImp(Object &glob, InterpreterImp *interpreter, Object &thisV, CodeType type,
363 ContextImp *callingCon, FunctionImp *func, const List *args)
364 : _interpreter(interpreter), _function(func), _arguments(args)
365{
366 codeType = type;
367 _callingContext = callingCon;
368
369 // create and initialize activation object (ECMA 10.1.6)
370 if (type == FunctionCode || type == AnonymousCode ) {
371 activation = Object(new ActivationImp(func, *args));
372 variable = activation;
373 } else {
374 activation = Object();
375 variable = glob;
376 }
377
378 // ECMA 10.2
379 switch(type) {
380 case EvalCode:
381 if (_callingContext) {
382 scope = _callingContext->scopeChain();
383 variable = _callingContext->variableObject();
384 thisVal = _callingContext->thisValue();
385 break;
386 } // else same as GlobalCode
387 case GlobalCode:
388 scope.clear();
389 scope.push(glob.imp());
390 thisVal = Object(static_cast<ObjectImp*>(glob.imp()));
391 break;
392 case FunctionCode:
393 case AnonymousCode:
394 if (type == FunctionCode) {
395 scope = func->scope();
396 scope.push(activation.imp());
397 } else {
398 scope.clear();
399 scope.push(glob.imp());
400 scope.push(activation.imp());
401 }
402 variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
403 thisVal = thisV;
404 break;
405 }
406
407 _interpreter->setContext(this);
408}
409
410ContextImp::~ContextImp()
411{
412 _interpreter->setContext(_callingContext);
413}
414
415void ContextImp::mark()
416{
417 for (ContextImp *context = this; context; context = context->_callingContext) {
418 context->scope.mark();
419 }
420}
421
422// ------------------------------ Parser ---------------------------------------
423
424ProgramNode *Parser::progNode = 0;
425int Parser::sid = 0;
426
427ProgramNode *Parser::parse(const UChar *code, unsigned int length, int *sourceId,
428 int *errLine, UString *errMsg)
429{
430 if (errLine)
431 *errLine = -1;
432 if (errMsg)
433 *errMsg = 0;
434
435 Lexer::curr()->setCode(code, length);
436 progNode = 0;
437 sid++;
438 if (sourceId)
439 *sourceId = sid;
440 // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
441 //extern int kjsyydebug;
442 //kjsyydebug=1;
443 int parseError = kjsyyparse();
444 ProgramNode *prog = progNode;
445 progNode = 0;
446 sid = -1;
447
448 if (parseError) {
449 int eline = Lexer::curr()->lineNo();
450 if (errLine)
451 *errLine = eline;
452 if (errMsg)
453 *errMsg = "Parse error at line " + UString::from(eline);
454#ifndef NDEBUG
455 fprintf(stderr, "KJS: JavaScript parse error at line %d.\n", eline);
456#endif
457 delete prog;
458 return 0;
459 }
460
461 return prog;
462}
463
464// ------------------------------ InterpreterImp -------------------------------
465
466InterpreterImp* InterpreterImp::s_hook = 0L;
467
468void InterpreterImp::globalInit()
469{
470 //fprintf( stderr, "InterpreterImp::globalInit()\n" );
471 UndefinedImp::staticUndefined = new UndefinedImp();
472 UndefinedImp::staticUndefined->ref();
473 NullImp::staticNull = new NullImp();
474 NullImp::staticNull->ref();
475 BooleanImp::staticTrue = new BooleanImp(true);
476 BooleanImp::staticTrue->ref();
477 BooleanImp::staticFalse = new BooleanImp(false);
478 BooleanImp::staticFalse->ref();
479 NumberImp::staticNaN = new NumberImp(NaN);
480 NumberImp::staticNaN->ref();
481}
482
483void InterpreterImp::globalClear()
484{
485 //fprintf( stderr, "InterpreterImp::globalClear()\n" );
486 UndefinedImp::staticUndefined->deref();
487 UndefinedImp::staticUndefined->setGcAllowed();
488 UndefinedImp::staticUndefined = 0L;
489 NullImp::staticNull->deref();
490 NullImp::staticNull->setGcAllowed();
491 NullImp::staticNull = 0L;
492 BooleanImp::staticTrue->deref();
493 BooleanImp::staticTrue->setGcAllowed();
494 BooleanImp::staticTrue = 0L;
495 BooleanImp::staticFalse->deref();
496 BooleanImp::staticFalse->setGcAllowed();
497 BooleanImp::staticFalse = 0L;
498 NumberImp::staticNaN->deref();
499 NumberImp::staticNaN->setGcAllowed();
500 NumberImp::staticNaN = 0;
501}
502
503InterpreterImp::InterpreterImp(Interpreter *interp, const Object &glob)
504 : _context(0)
505{
506 // add this interpreter to the global chain
507 // as a root set for garbage collection
508 lockInterpreter();
509 m_interpreter = interp;
510 if (s_hook) {
511 prev = s_hook;
512 next = s_hook->next;
513 s_hook->next->prev = this;
514 s_hook->next = this;
515 } else {
516 // This is the first interpreter
517 s_hook = next = prev = this;
518 globalInit();
519 }
520 unlockInterpreter();
521
522 global = glob;
523 globExec = new ExecState(m_interpreter,0);
524 dbg = 0;
525 m_compatMode = Interpreter::NativeMode;
526
527 // initialize properties of the global object
528 initGlobalObject();
529
530 recursion = 0;
531}
532
533void InterpreterImp::lock()
534{
535 lockInterpreter();
536}
537
538int InterpreterImp::lockCount()
539{
540 return interpreterLockCount;
541}
542
543void InterpreterImp::unlock()
544{
545 unlockInterpreter();
546}
547
548void InterpreterImp::initGlobalObject()
549{
550 // Contructor prototype objects (Object.prototype, Array.prototype etc)
551
552 FunctionPrototypeImp *funcProto = new FunctionPrototypeImp(globExec);
553 b_FunctionPrototype = Object(funcProto);
554 ObjectPrototypeImp *objProto = new ObjectPrototypeImp(globExec,funcProto);
555 b_ObjectPrototype = Object(objProto);
556 funcProto->setPrototype(b_ObjectPrototype);
557
558 ArrayPrototypeImp *arrayProto = new ArrayPrototypeImp(globExec,objProto);
559 b_ArrayPrototype = Object(arrayProto);
560 StringPrototypeImp *stringProto = new StringPrototypeImp(globExec,objProto);
561 b_StringPrototype = Object(stringProto);
562 BooleanPrototypeImp *booleanProto = new BooleanPrototypeImp(globExec,objProto,funcProto);
563 b_BooleanPrototype = Object(booleanProto);
564 NumberPrototypeImp *numberProto = new NumberPrototypeImp(globExec,objProto,funcProto);
565 b_NumberPrototype = Object(numberProto);
566 DatePrototypeImp *dateProto = new DatePrototypeImp(globExec,objProto);
567 b_DatePrototype = Object(dateProto);
568 RegExpPrototypeImp *regexpProto = new RegExpPrototypeImp(globExec,objProto,funcProto);
569 b_RegExpPrototype = Object(regexpProto);
570 ErrorPrototypeImp *errorProto = new ErrorPrototypeImp(globExec,objProto,funcProto);
571 b_ErrorPrototype = Object(errorProto);
572
573 static_cast<ObjectImp*>(global.imp())->setPrototype(b_ObjectPrototype);
574
575 // Constructors (Object, Array, etc.)
576 b_Object = Object(new ObjectObjectImp(globExec, objProto, funcProto));
577 b_Function = Object(new FunctionObjectImp(globExec, funcProto));
578 b_Array = Object(new ArrayObjectImp(globExec, funcProto, arrayProto));
579 b_String = Object(new StringObjectImp(globExec, funcProto, stringProto));
580 b_Boolean = Object(new BooleanObjectImp(globExec, funcProto, booleanProto));
581 b_Number = Object(new NumberObjectImp(globExec, funcProto, numberProto));
582 b_Date = Object(new DateObjectImp(globExec, funcProto, dateProto));
583 b_RegExp = Object(new RegExpObjectImp(globExec, funcProto, regexpProto));
584 b_Error = Object(new ErrorObjectImp(globExec, funcProto, errorProto));
585
586 // Error object prototypes
587 b_evalErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,EvalError,
588 "EvalError","EvalError"));
589 b_rangeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,RangeError,
590 "RangeError","RangeError"));
591 b_referenceErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,ReferenceError,
592 "ReferenceError","ReferenceError"));
593 b_syntaxErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,SyntaxError,
594 "SyntaxError","SyntaxError"));
595 b_typeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,TypeError,
596 "TypeError","TypeError"));
597 b_uriErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,URIError,
598 "URIError","URIError"));
599
600 // Error objects
601 b_evalError = Object(new NativeErrorImp(globExec,funcProto,b_evalErrorPrototype));
602 b_rangeError = Object(new NativeErrorImp(globExec,funcProto,b_rangeErrorPrototype));
603 b_referenceError = Object(new NativeErrorImp(globExec,funcProto,b_referenceErrorPrototype));
604 b_syntaxError = Object(new NativeErrorImp(globExec,funcProto,b_syntaxErrorPrototype));
605 b_typeError = Object(new NativeErrorImp(globExec,funcProto,b_typeErrorPrototype));
606 b_uriError = Object(new NativeErrorImp(globExec,funcProto,b_uriErrorPrototype));
607
608 // ECMA 15.3.4.1
609 funcProto->put(globExec,"constructor", b_Function, DontEnum);
610
611 global.put(globExec,"Object", b_Object, DontEnum);
612 global.put(globExec,"Function", b_Function, DontEnum);
613 global.put(globExec,"Array", b_Array, DontEnum);
614 global.put(globExec,"Boolean", b_Boolean, DontEnum);
615 global.put(globExec,"String", b_String, DontEnum);
616 global.put(globExec,"Number", b_Number, DontEnum);
617 global.put(globExec,"Date", b_Date, DontEnum);
618 global.put(globExec,"RegExp", b_RegExp, DontEnum);
619 global.put(globExec,"Error", b_Error, DontEnum);
620 // Using Internal for those to have something != 0
621 // (see kjs_window). Maybe DontEnum would be ok too ?
622 global.put(globExec,"EvalError",b_evalError, Internal);
623 global.put(globExec,"RangeError",b_rangeError, Internal);
624 global.put(globExec,"ReferenceError",b_referenceError, Internal);
625 global.put(globExec,"SyntaxError",b_syntaxError, Internal);
626 global.put(globExec,"TypeError",b_typeError, Internal);
627 global.put(globExec,"URIError",b_uriError, Internal);
628
629 // Set the "constructor" property of all builtin constructors
630 objProto->put(globExec, "constructor", b_Object, DontEnum | DontDelete | ReadOnly);
631 funcProto->put(globExec, "constructor", b_Function, DontEnum | DontDelete | ReadOnly);
632 arrayProto->put(globExec, "constructor", b_Array, DontEnum | DontDelete | ReadOnly);
633 booleanProto->put(globExec, "constructor", b_Boolean, DontEnum | DontDelete | ReadOnly);
634 stringProto->put(globExec, "constructor", b_String, DontEnum | DontDelete | ReadOnly);
635 numberProto->put(globExec, "constructor", b_Number, DontEnum | DontDelete | ReadOnly);
636 dateProto->put(globExec, "constructor", b_Date, DontEnum | DontDelete | ReadOnly);
637 regexpProto->put(globExec, "constructor", b_RegExp, DontEnum | DontDelete | ReadOnly);
638 errorProto->put(globExec, "constructor", b_Error, DontEnum | DontDelete | ReadOnly);
639 b_evalErrorPrototype.put(globExec, "constructor", b_evalError, DontEnum | DontDelete | ReadOnly);
640 b_rangeErrorPrototype.put(globExec, "constructor", b_rangeError, DontEnum | DontDelete | ReadOnly);
641 b_referenceErrorPrototype.put(globExec, "constructor", b_referenceError, DontEnum | DontDelete | ReadOnly);
642 b_syntaxErrorPrototype.put(globExec, "constructor", b_syntaxError, DontEnum | DontDelete | ReadOnly);
643 b_typeErrorPrototype.put(globExec, "constructor", b_typeError, DontEnum | DontDelete | ReadOnly);
644 b_uriErrorPrototype.put(globExec, "constructor", b_uriError, DontEnum | DontDelete | ReadOnly);
645
646 // built-in values
647 global.put(globExec, "NaN", Number(NaN), DontEnum|DontDelete);
648 global.put(globExec, "Infinity", Number(Inf), DontEnum|DontDelete);
649 global.put(globExec, "undefined", Undefined(), DontEnum|DontDelete);
650
651 // built-in functions
652 global.put(globExec,"eval", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Eval, 1)), DontEnum);
653 global.put(globExec,"parseInt", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseInt, 2)), DontEnum);
654 global.put(globExec,"parseFloat", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseFloat, 1)), DontEnum);
655 global.put(globExec,"isNaN", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsNaN, 1)), DontEnum);
656 global.put(globExec,"isFinite", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsFinite, 1)), DontEnum);
657 global.put(globExec,"escape", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Escape, 1)), DontEnum);
658 global.put(globExec,"unescape", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::UnEscape, 1)), DontEnum);
659#ifndef NDEBUG
660 global.put(globExec,"kjsprint", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::KJSPrint, 1)), DontEnum);
661#endif
662
663 // built-in objects
664 global.put(globExec,"Math", Object(new MathObjectImp(globExec,objProto)), DontEnum);
665}
666
667InterpreterImp::~InterpreterImp()
668{
669 if (dbg)
670 dbg->detach(m_interpreter);
671 delete globExec;
672 globExec = 0L;
673 clear();
674}
675
676void InterpreterImp::clear()
677{
678 //fprintf(stderr,"InterpreterImp::clear\n");
679 // remove from global chain (see init())
680#if APPLE_CHANGES
681 lockInterpreter();
682#endif
683 next->prev = prev;
684 prev->next = next;
685 s_hook = next;
686 if (s_hook == this)
687 {
688 // This was the last interpreter
689 s_hook = 0L;
690 globalClear();
691 }
692#if APPLE_CHANGES
693 unlockInterpreter();
694#endif
695}
696
697void InterpreterImp::mark()
698{
699 //if (exVal && !exVal->marked())
700 // exVal->mark();
701 //if (retVal && !retVal->marked())
702 // retVal->mark();
703 if (UndefinedImp::staticUndefined && !UndefinedImp::staticUndefined->marked())
704 UndefinedImp::staticUndefined->mark();
705 if (NullImp::staticNull && !NullImp::staticNull->marked())
706 NullImp::staticNull->mark();
707 if (BooleanImp::staticTrue && !BooleanImp::staticTrue->marked())
708 BooleanImp::staticTrue->mark();
709 if (BooleanImp::staticFalse && !BooleanImp::staticFalse->marked())
710 BooleanImp::staticFalse->mark();
711 //fprintf( stderr, "InterpreterImp::mark this=%p global.imp()=%p\n", this, global.imp() );
712 if (global.imp())
713 global.imp()->mark();
714 if (m_interpreter)
715 m_interpreter->mark();
716 if (_context)
717 _context->mark();
718}
719
720bool InterpreterImp::checkSyntax(const UString &code)
721{
722 // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
723 ProgramNode *progNode = Parser::parse(code.data(),code.size(),0,0,0);
724 bool ok = (progNode != 0);
725 delete progNode;
726 return ok;
727}
728
729Completion InterpreterImp::evaluate(const UString &code, const Value &thisV)
730{
731#if APPLE_CHANGES
732 lockInterpreter();
733#endif
734 // prevent against infinite recursion
735 if (recursion >= 20) {
736#if APPLE_CHANGES
737 Completion result = Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
738 unlockInterpreter();
739 return result;
740#else
741 return Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
742#endif
743 }
744
745 // parse the source code
746 int sid;
747 int errLine;
748 UString errMsg;
749 ProgramNode *progNode = Parser::parse(code.data(),code.size(),&sid,&errLine,&errMsg);
750
751 // notify debugger that source has been parsed
752 if (dbg) {
753 bool cont = dbg->sourceParsed(globExec,sid,code,errLine);
754 if (!cont)
755#if APPLE_CHANGES
756 {
757 unlockInterpreter();
758 return Completion(Break);
759 }
760#else
761 return Completion(Break);
762#endif
763 }
764
765 // no program node means a syntax error occurred
766 if (!progNode) {
767 Object err = Error::create(globExec,SyntaxError,errMsg.ascii(),errLine);
768 err.put(globExec,"sid",Number(sid));
769#if APPLE_CHANGES
770 unlockInterpreter();
771#endif
772 return Completion(Throw,err);
773 }
774
775 globExec->clearException();
776
777 recursion++;
778 progNode->ref();
779
780 Object &globalObj = globalObject();
781 Object thisObj = globalObject();
782
783 if (!thisV.isNull()) {
784 // "this" must be an object... use same rules as Function.prototype.apply()
785 if (thisV.isA(NullType) || thisV.isA(UndefinedType))
786 thisObj = globalObject();
787 else {
788 thisObj = thisV.toObject(globExec);
789 }
790 }
791
792 Completion res;
793 if (globExec->hadException()) {
794 // the thisArg.toObject() conversion above might have thrown an exception - if so,
795 // propagate it back
796 res = Completion(Throw,globExec->exception());
797 }
798 else {
799 // execute the code
800 ContextImp ctx(globalObj, this, thisObj);
801 ExecState newExec(m_interpreter,&ctx);
802 res = progNode->execute(&newExec);
803 }
804
805 if (progNode->deref())
806 delete progNode;
807 recursion--;
808
809#if APPLE_CHANGES
810 unlockInterpreter();
811#endif
812 return res;
813}
814
815void InterpreterImp::setDebugger(Debugger *d)
816{
817 if (d)
818 d->detach(m_interpreter);
819 dbg = d;
820}
821
822// ------------------------------ InternalFunctionImp --------------------------
823
824const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
825
826InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto)
827 : ObjectImp(funcProto)
828{
829}
830
831bool InternalFunctionImp::implementsHasInstance() const
832{
833 return true;
834}
835
836Boolean InternalFunctionImp::hasInstance(ExecState *exec, const Value &value)
837{
838 if (value.type() != ObjectType)
839 return Boolean(false);
840
841 Value prot = get(exec,prototypePropertyName);
842 if (prot.type() != ObjectType && prot.type() != NullType) {
843 Object err = Error::create(exec, TypeError, "Invalid prototype encountered "
844 "in instanceof operation.");
845 exec->setException(err);
846 return Boolean(false);
847 }
848
849 Object v = Object(static_cast<ObjectImp*>(value.imp()));
850 while ((v = Object::dynamicCast(v.prototype())).imp()) {
851 if (v.imp() == prot.imp())
852 return Boolean(true);
853 }
854 return Boolean(false);
855}
856
857// ------------------------------ global functions -----------------------------
858
859double KJS::roundValue(ExecState *exec, const Value &v)
860{
861 if (v.type() == UndefinedType) /* TODO: see below */
862 return 0.0;
863 Number n = v.toNumber(exec);
864 if (n.value() == 0.0) /* TODO: -0, NaN, Inf */
865 return 0.0;
866 double d = floor(fabs(n.value()));
867 if (n.value() < 0)
868 d *= -1;
869
870 return d;
871}
872
873#ifndef NDEBUG
874#include <stdio.h>
875void KJS::printInfo(ExecState *exec, const char *s, const Value &o, int lineno)
876{
877 if (o.isNull())
878 fprintf(stderr, "KJS: %s: (null)", s);
879 else {
880 Value v = o;
881
882 UString name;
883 switch ( v.type() ) {
884 case UnspecifiedType:
885 name = "Unspecified";
886 break;
887 case UndefinedType:
888 name = "Undefined";
889 break;
890 case NullType:
891 name = "Null";
892 break;
893 case BooleanType:
894 name = "Boolean";
895 break;
896 case StringType:
897 name = "String";
898 break;
899 case NumberType:
900 name = "Number";
901 break;
902 case ObjectType:
903 name = Object::dynamicCast(v).className();
904 if (name.isNull())
905 name = "(unknown class)";
906 break;
907 }
908 UString vString = v.toString(exec);
909 if ( vString.size() > 50 )
910 vString = vString.substr( 0, 50 ) + "...";
911 // Can't use two UString::ascii() in the same fprintf call
912 CString tempString( vString.cstring() );
913
914 fprintf(stderr, "KJS: %s: %s : %s (%p)",
915 s, tempString.c_str(), name.ascii(), (void*)v.imp());
916
917 if (lineno >= 0)
918 fprintf(stderr, ", line %d\n",lineno);
919 else
920 fprintf(stderr, "\n");
921 }
922}
923#endif
Note: See TracBrowser for help on using the repository browser.