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

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

JavaScriptCore:

Reviewed by John.

Changed things so that newly created objects get a prototype based
on the scope chain of the current function, rather than the
interpreter that started execution. This fixes the following bugs:

<rdar://problem/3368523>: ARCH: wrong prototype used to create new objects (hang on lookup.atomica.com)
<rdar://problem/3559173>: ARCH: Cannot scan using a HP Jetdirect product (JS object prototypes bind incorrectly)

  • JavaScriptCore.pbproj/project.pbxproj:
  • kjs/array_object.cpp: (CompareWithCompareFunctionArguments::CompareWithCompareFunctionArguments): (ArrayProtoFuncImp::ArrayProtoFuncImp): (ArrayProtoFuncImp::call): (ArrayObjectImp::construct):
  • kjs/bool_object.cpp: (BooleanObjectImp::construct):
  • kjs/date_object.cpp: (DateProtoFuncImp::DateProtoFuncImp): (DateProtoFuncImp::call): (DateObjectImp::construct):
  • kjs/error_object.cpp: (ErrorObjectImp::construct):
  • kjs/function.cpp: (FunctionImp::FunctionImp): (FunctionImp::call): (DeclaredFunctionImp::construct): (ArgumentsImp::ArgumentsImp): (GlobalFuncImp::call):
  • kjs/function_object.cpp: (FunctionProtoFuncImp::call): (FunctionObjectImp::construct):
  • kjs/internal.cpp: (BooleanImp::toObject): (StringImp::toObject): (NumberImp::toObject): (InterpreterImp::InterpreterImp): (InterpreterImp::clear): (InterpreterImp::interpreterWithGlobalObject):
  • kjs/internal.h:
  • kjs/interpreter.cpp: (ExecState::lexicalInterpreter):
  • kjs/interpreter.h: (KJS::ExecState::dynamicInterpreter): (KJS::ExecState::interpreter):
  • kjs/math_object.cpp: (MathFuncImp::MathFuncImp):
  • kjs/nodes.cpp: (StatementNode::hitStatement): (StatementNode::abortStatement): (RegExpNode::evaluate): (ElementNode::evaluate): (ArrayNode::evaluate): (ObjectLiteralNode::evaluate): (PropertyValueNode::evaluate): (FunctionCallNode::evaluate): (FuncDeclNode::processFuncDecl): (FuncExprNode::evaluate):
  • kjs/number_object.cpp: (NumberObjectImp::construct):
  • kjs/object.cpp: (KJS::ObjectImp::defaultValue): (KJS::Error::create):
  • kjs/object_object.cpp: (ObjectObjectImp::construct):
  • kjs/reference.cpp: (Reference::putValue):
  • kjs/regexp_object.cpp: (RegExpProtoFuncImp::call): (RegExpObjectImp::arrayOfMatches): (RegExpObjectImp::construct):
  • kjs/scope_chain.cpp: (KJS::ScopeChain::bottom):
  • kjs/scope_chain.h:
  • kjs/string_object.cpp: (StringProtoFuncImp::StringProtoFuncImp): (StringProtoFuncImp::call): (StringObjectImp::construct):

WebCore:

Reviewed by John.

Changed things so that newly created objects get a prototype based
on the scope chain of the current function, rather than the
interpreter that started execution. This fixes the following bugs:

<rdar://problem/3368523>: ARCH: wrong prototype used to create new objects (hang on lookup.atomica.com)
<rdar://problem/3559173>: ARCH: Cannot scan using a HP Jetdirect product (JS object prototypes bind incorrectly)

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