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

Last change on this file since 2824 was 2824, checked in by darin, 23 years ago

JavaScriptCore:

  • change ScopeChain to be a singly linked list shares tails, gives 11% gain on iBench
  • kjs/context.h: (ContextImp::pushScope): Make inline, use push instead of prepend, and pass imp pointer. (ContextImp::popScope): Make inline, use pop instead of removeFirst.
  • kjs/function.cpp: (DeclaredFunctionImp::DeclaredFunctionImp): No need to copy.
  • kjs/function_object.cpp: (FunctionObjectImp::construct): Use push instead of prepend, and pass imp pointer.
  • kjs/internal.cpp: (ContextImp::ContextImp): Use clear, push instead of prepend, and pass imp pointers.
  • kjs/nodes.cpp: (ResolveNode::evaluateReference): Use isEmpty, pop, and top instead of ScopeChainIterator.
  • kjs/object.h: Change _scope to be a NoRefScopeChain.
  • kjs/object.cpp: No need to initialize _scope any more, since it's not a NoRefScopeChain.
  • kjs/scope_chain.h: Rewrite, different implementation and interface.
  • kjs/scope_chain.cpp: More of the same.

WebCore:

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