internal.cpp

00001 // -*- c-basic-offset: 2 -*-
00002 /*
00003  *  This file is part of the KDE libraries
00004  *  Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
00005  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
00006  *  Copyright (C) 2004 Apple Computer, Inc.
00007  *
00008  *  This library is free software; you can redistribute it and/or
00009  *  modify it under the terms of the GNU Library General Public
00010  *  License as published by the Free Software Foundation; either
00011  *  version 2 of the License, or (at your option) any later version.
00012  *
00013  *  This library is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  *  Library General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU Library General Public License
00019  *  along with this library; see the file COPYING.LIB.  If not, write to
00020  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021  *  Boston, MA 02110-1301, USA.
00022  *
00023  */
00024 
00025 #include <stdio.h>
00026 #include <math.h>
00027 #include <assert.h>
00028 
00029 #include "array_object.h"
00030 #include "bool_object.h"
00031 #include "collector.h"
00032 #include "context.h"
00033 #include "date_object.h"
00034 #include "debugger.h"
00035 #include "error_object.h"
00036 #include "function_object.h"
00037 #include "internal.h"
00038 #include "lexer.h"
00039 #include "math_object.h"
00040 #include "nodes.h"
00041 #include "number_object.h"
00042 #include "object.h"
00043 #include "object_object.h"
00044 #include "operations.h"
00045 #include "regexp_object.h"
00046 #include "string_object.h"
00047 
00048 #define I18N_NOOP(s) s
00049 
00050 extern int kjsyyparse();
00051 
00052 using namespace KJS;
00053 
00054 namespace KJS {
00055   /* work around some strict alignment requirements
00056      for double variables on some architectures (e.g. PA-RISC) */
00057   typedef union { unsigned char b[8]; double d; } kjs_double_t;
00058 
00059 #ifdef WORDS_BIGENDIAN
00060   static const kjs_double_t NaN_Bytes = { { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 } };
00061   static const kjs_double_t Inf_Bytes = { { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 } };
00062 #elif defined(arm)
00063   static const kjs_double_t NaN_Bytes = { { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 } };
00064   static const kjs_double_t Inf_Bytes = { { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 } };
00065 #else
00066   static const kjs_double_t NaN_Bytes = { { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f } };
00067   static const kjs_double_t Inf_Bytes = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
00068 #endif
00069 
00070   const double NaN = NaN_Bytes.d;
00071   const double Inf = Inf_Bytes.d;
00072 }
00073 
00074 #ifdef KJS_THREADSUPPORT
00075 static pthread_once_t interpreterLockOnce = PTHREAD_ONCE_INIT;
00076 static pthread_mutex_t interpreterLock;
00077 static int interpreterLockCount = 0;
00078 
00079 static void initializeInterpreterLock()
00080 {
00081   pthread_mutexattr_t attr;
00082 
00083   pthread_mutexattr_init(&attr);
00084   pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
00085 
00086   pthread_mutex_init(&interpreterLock, &attr);
00087 }
00088 #endif
00089 
00090 static inline void lockInterpreter()
00091 {
00092 #ifdef KJS_THREADSUPPORT
00093   pthread_once(&interpreterLockOnce, initializeInterpreterLock);
00094   pthread_mutex_lock(&interpreterLock);
00095   interpreterLockCount++;
00096 #endif
00097 }
00098 
00099 static inline void unlockInterpreter()
00100 {
00101 #ifdef KJS_THREADSUPPORT
00102   interpreterLockCount--;
00103   pthread_mutex_unlock(&interpreterLock);
00104 #endif
00105 }
00106 
00107 
00108 
00109 // ------------------------------ UndefinedImp ---------------------------------
00110 
00111 UndefinedImp *UndefinedImp::staticUndefined = 0;
00112 
00113 Value UndefinedImp::toPrimitive(ExecState* /*exec*/, Type) const
00114 {
00115   return Value((ValueImp*)this);
00116 }
00117 
00118 bool UndefinedImp::toBoolean(ExecState* /*exec*/) const
00119 {
00120   return false;
00121 }
00122 
00123 double UndefinedImp::toNumber(ExecState* /*exec*/) const
00124 {
00125   return NaN;
00126 }
00127 
00128 UString UndefinedImp::toString(ExecState* /*exec*/) const
00129 {
00130   return "undefined";
00131 }
00132 
00133 Object UndefinedImp::toObject(ExecState *exec) const
00134 {
00135   Object err = Error::create(exec, TypeError, I18N_NOOP("Undefined value"));
00136   exec->setException(err);
00137   return err;
00138 }
00139 
00140 // ------------------------------ NullImp --------------------------------------
00141 
00142 NullImp *NullImp::staticNull = 0;
00143 
00144 Value NullImp::toPrimitive(ExecState* /*exec*/, Type) const
00145 {
00146   return Value((ValueImp*)this);
00147 }
00148 
00149 bool NullImp::toBoolean(ExecState* /*exec*/) const
00150 {
00151   return false;
00152 }
00153 
00154 double NullImp::toNumber(ExecState* /*exec*/) const
00155 {
00156   return 0.0;
00157 }
00158 
00159 UString NullImp::toString(ExecState* /*exec*/) const
00160 {
00161   return "null";
00162 }
00163 
00164 Object NullImp::toObject(ExecState *exec) const
00165 {
00166   Object err = Error::create(exec, TypeError, I18N_NOOP("Null value"));
00167   exec->setException(err);
00168   return err;
00169 }
00170 
00171 // ------------------------------ BooleanImp -----------------------------------
00172 
00173 BooleanImp* BooleanImp::staticTrue = 0;
00174 BooleanImp* BooleanImp::staticFalse = 0;
00175 
00176 Value BooleanImp::toPrimitive(ExecState* /*exec*/, Type) const
00177 {
00178   return Value((ValueImp*)this);
00179 }
00180 
00181 bool BooleanImp::toBoolean(ExecState* /*exec*/) const
00182 {
00183   return val;
00184 }
00185 
00186 double BooleanImp::toNumber(ExecState* /*exec*/) const
00187 {
00188   return val ? 1.0 : 0.0;
00189 }
00190 
00191 UString BooleanImp::toString(ExecState* /*exec*/) const
00192 {
00193   return val ? "true" : "false";
00194 }
00195 
00196 Object BooleanImp::toObject(ExecState *exec) const
00197 {
00198   List args;
00199   args.append(const_cast<BooleanImp*>(this));
00200   return Object::dynamicCast(exec->lexicalInterpreter()->builtinBoolean().construct(exec,args));
00201 }
00202 
00203 // ------------------------------ StringImp ------------------------------------
00204 
00205 Value StringImp::toPrimitive(ExecState* /*exec*/, Type) const
00206 {
00207   return Value((ValueImp*)this);
00208 }
00209 
00210 bool StringImp::toBoolean(ExecState* /*exec*/) const
00211 {
00212   return (val.size() > 0);
00213 }
00214 
00215 double StringImp::toNumber(ExecState* /*exec*/) const
00216 {
00217   return val.toDouble();
00218 }
00219 
00220 UString StringImp::toString(ExecState* /*exec*/) const
00221 {
00222   return val;
00223 }
00224 
00225 Object StringImp::toObject(ExecState *exec) const
00226 {
00227   List args;
00228   args.append(const_cast<StringImp*>(this));
00229   return Object(static_cast<ObjectImp *>(exec->lexicalInterpreter()->builtinString().construct(exec, args).imp()));
00230 }
00231 
00232 // ------------------------------ NumberImp ------------------------------------
00233 
00234 NumberImp *NumberImp::staticNaN;
00235 
00236 ValueImp *NumberImp::create(int i)
00237 {
00238     if (SimpleNumber::fits(i))
00239         return SimpleNumber::make(i);
00240     NumberImp *imp = new NumberImp(static_cast<double>(i));
00241     imp->setGcAllowedFast();
00242     return imp;
00243 }
00244 
00245 ValueImp *NumberImp::create(double d)
00246 {
00247     if (SimpleNumber::fits(d))
00248         return SimpleNumber::make((int)d);
00249     if (isNaN(d))
00250         return staticNaN;
00251     NumberImp *imp = new NumberImp(d);
00252     imp->setGcAllowedFast();
00253     return imp;
00254 }
00255 
00256 Value NumberImp::toPrimitive(ExecState *, Type) const
00257 {
00258   return Number((NumberImp*)this);
00259 }
00260 
00261 bool NumberImp::toBoolean(ExecState *) const
00262 {
00263   return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
00264 }
00265 
00266 double NumberImp::toNumber(ExecState *) const
00267 {
00268   return val;
00269 }
00270 
00271 UString NumberImp::toString(ExecState *) const
00272 {
00273   if (val == 0.0) // +0.0 or -0.0
00274     return "0";
00275   return UString::from(val);
00276 }
00277 
00278 Object NumberImp::toObject(ExecState *exec) const
00279 {
00280   List args;
00281   args.append(const_cast<NumberImp*>(this));
00282   return Object::dynamicCast(exec->lexicalInterpreter()->builtinNumber().construct(exec,args));
00283 }
00284 
00285 bool NumberImp::toUInt32(unsigned& uint32) const
00286 {
00287   uint32 = (unsigned)val;
00288   return (double)uint32 == val;
00289 }
00290 
00291 double SimpleNumber::negZero = -0.0;
00292 
00293 // ------------------------------ LabelStack -----------------------------------
00294 
00295 LabelStack::LabelStack(const LabelStack &other)
00296 {
00297   tos = 0;
00298   *this = other;
00299 }
00300 
00301 LabelStack &LabelStack::operator=(const LabelStack &other)
00302 {
00303   clear();
00304   tos = 0;
00305   StackElem *cur = 0;
00306   StackElem *se = other.tos;
00307   while (se) {
00308     StackElem *newPrev = new StackElem;
00309     newPrev->prev = 0;
00310     newPrev->id = se->id;
00311     if (cur)
00312       cur->prev = newPrev;
00313     else
00314       tos = newPrev;
00315     cur = newPrev;
00316     se = se->prev;
00317   }
00318   return *this;
00319 }
00320 
00321 bool LabelStack::push(const Identifier &id)
00322 {
00323   if (id.isEmpty() || contains(id))
00324     return false;
00325 
00326   StackElem *newtos = new StackElem;
00327   newtos->id = id;
00328   newtos->prev = tos;
00329   tos = newtos;
00330   return true;
00331 }
00332 
00333 bool LabelStack::contains(const Identifier &id) const
00334 {
00335   if (id.isEmpty())
00336     return true;
00337 
00338   for (StackElem *curr = tos; curr; curr = curr->prev)
00339     if (curr->id == id)
00340       return true;
00341 
00342   return false;
00343 }
00344 
00345 void LabelStack::pop()
00346 {
00347   if (tos) {
00348     StackElem *prev = tos->prev;
00349     delete tos;
00350     tos = prev;
00351   }
00352 }
00353 
00354 LabelStack::~LabelStack()
00355 {
00356   clear();
00357 }
00358 
00359 void LabelStack::clear()
00360 {
00361   StackElem *prev;
00362 
00363   while (tos) {
00364     prev = tos->prev;
00365     delete tos;
00366     tos = prev;
00367   }
00368 }
00369 
00370 // ------------------------------ ContextImp -----------------------------------
00371 
00372 
00373 // ECMA 10.2
00374 ContextImp::ContextImp(Object &glob, InterpreterImp *interpreter, Object &thisV, int _sourceId, CodeType type,
00375                        ContextImp *callingCon, FunctionImp *func, const List *args)
00376   : _interpreter(interpreter), _function(func), _arguments(args)
00377 {
00378   m_codeType = type;
00379   _callingContext = callingCon;
00380   tryCatch = 0;
00381 
00382   sourceId = _sourceId;
00383   line0 = 1;
00384   line1 = 1;
00385 
00386   if (func && func->inherits(&DeclaredFunctionImp::info))
00387     functionName = static_cast<DeclaredFunctionImp*>(func)->name();
00388   else
00389     functionName = Identifier::null();
00390 
00391   // create and initialize activation object (ECMA 10.1.6)
00392   if (type == FunctionCode) {
00393     activation = Object(new ActivationImp(func,*args));
00394     variable = activation;
00395   } else {
00396     activation = Object();
00397     variable = glob;
00398   }
00399 
00400   // ECMA 10.2
00401   switch(type) {
00402     case EvalCode:
00403       if (_callingContext) {
00404     scope = _callingContext->scopeChain();
00405 #ifndef KJS_PURE_ECMA
00406     if (thisV.imp() != glob.imp())
00407       scope.push(thisV.imp()); // for deprecated Object.prototype.eval()
00408 #endif
00409     variable = _callingContext->variableObject();
00410     thisVal = _callingContext->thisValue();
00411     break;
00412       } // else same as GlobalCode
00413     case GlobalCode:
00414       scope.clear();
00415       scope.push(glob.imp());
00416 #ifndef KJS_PURE_ECMA
00417       if (thisV.isValid())
00418           thisVal = thisV;
00419       else
00420 #endif
00421           thisVal = glob;
00422       break;
00423     case FunctionCode:
00424       scope = func->scope();
00425       scope.push(activation.imp());
00426       variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
00427       thisVal = thisV;
00428       break;
00429     }
00430 
00431   _interpreter->setContext(this);
00432 }
00433 
00434 ContextImp::~ContextImp()
00435 {
00436   _interpreter->setContext(_callingContext);
00437 }
00438 
00439 void ContextImp::mark()
00440 {
00441   for (ContextImp *context = this; context; context = context->_callingContext) {
00442     context->scope.mark();
00443   }
00444 }
00445 
00446 bool ContextImp::inTryCatch() const
00447 {
00448   const ContextImp *c = this;
00449   while (c && !c->tryCatch)
00450     c = c->_callingContext;
00451   return (c && c->tryCatch);
00452 }
00453 
00454 // ---------------------------- SourceCode -------------------------------------
00455 
00456 void SourceCode::cleanup()
00457 {
00458   if (interpreter && interpreter->debugger())
00459     interpreter->debugger()->sourceUnused(interpreter->globalExec(),sid);
00460   if (interpreter)
00461     interpreter->removeSourceCode(this);
00462   delete this;
00463 }
00464 
00465 // ------------------------------ Parser ---------------------------------------
00466 
00467 FunctionBodyNode *Parser::progNode = 0;
00468 int Parser::sid = 0;
00469 SourceCode *Parser::source = 0;
00470 
00471 FunctionBodyNode *Parser::parse(const UChar *code, unsigned int length, SourceCode **src,
00472                 int *errLine, UString *errMsg)
00473 {
00474   if (errLine)
00475     *errLine = -1;
00476   if (errMsg)
00477     *errMsg = 0;
00478 
00479   Lexer::curr()->setCode(code, length);
00480   progNode = 0;
00481   sid++;
00482 
00483   source = new SourceCode(sid);
00484   source->ref();
00485   *src = source;
00486 
00487   // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
00488   //extern int kjsyydebug;
00489   //kjsyydebug=1;
00490   int parseError = kjsyyparse();
00491   if (Lexer::curr()->hadError())
00492     parseError = 1;
00493   Lexer::curr()->doneParsing();
00494   FunctionBodyNode *prog = progNode;
00495   progNode = 0;
00496   //sid = -1;
00497   source = 0;
00498 
00499   if (parseError) {
00500     int eline = Lexer::curr()->lineNo();
00501     if (errLine)
00502       *errLine = eline;
00503     if (errMsg)
00504       *errMsg = "Parse error at line " + UString::from(eline);
00505 #ifdef KJS_VERBOSE
00506     fprintf( stderr, "%s\n", UString(code,length).ascii() );
00507 #endif
00508 #ifndef NDEBUG
00509     fprintf(stderr, "KJS: JavaScript parse error at line %d.\n", eline);
00510 #endif
00511     delete prog;
00512     return 0;
00513   }
00514 #ifdef KJS_VERBOSE
00515   fprintf( stderr, "%s\n", prog->toCode().ascii() );
00516 #endif
00517 
00518   return prog;
00519 }
00520 
00521 // ------------------------------ InterpreterImp -------------------------------
00522 
00523 InterpreterImp* InterpreterImp::s_hook = 0L;
00524 
00525 void InterpreterImp::globalInit()
00526 {
00527   //fprintf( stderr, "InterpreterImp::globalInit()\n" );
00528   UndefinedImp::staticUndefined = new UndefinedImp();
00529   UndefinedImp::staticUndefined->ref();
00530   NullImp::staticNull = new NullImp();
00531   NullImp::staticNull->ref();
00532   BooleanImp::staticTrue = new BooleanImp(true);
00533   BooleanImp::staticTrue->ref();
00534   BooleanImp::staticFalse = new BooleanImp(false);
00535   BooleanImp::staticFalse->ref();
00536   NumberImp::staticNaN = new NumberImp(NaN);
00537   NumberImp::staticNaN->ref();
00538 }
00539 
00540 void InterpreterImp::globalClear()
00541 {
00542   //fprintf( stderr, "InterpreterImp::globalClear()\n" );
00543   UndefinedImp::staticUndefined->deref();
00544   UndefinedImp::staticUndefined->setGcAllowed();
00545   UndefinedImp::staticUndefined = 0L;
00546   NullImp::staticNull->deref();
00547   NullImp::staticNull->setGcAllowed();
00548   NullImp::staticNull = 0L;
00549   BooleanImp::staticTrue->deref();
00550   BooleanImp::staticTrue->setGcAllowed();
00551   BooleanImp::staticTrue = 0L;
00552   BooleanImp::staticFalse->deref();
00553   BooleanImp::staticFalse->setGcAllowed();
00554   BooleanImp::staticFalse = 0L;
00555   NumberImp::staticNaN->deref();
00556   NumberImp::staticNaN->setGcAllowed();
00557   NumberImp::staticNaN = 0;
00558 }
00559 
00560 InterpreterImp::InterpreterImp(Interpreter *interp, const Object &glob)
00561   : m_interpreter(interp),
00562     global(glob),
00563     dbg(0),
00564     m_compatMode(Interpreter::NativeMode),
00565     _context(0),
00566     recursion(0),
00567     sources(0)
00568 {
00569   // add this interpreter to the global chain
00570   // as a root set for garbage collection
00571   lockInterpreter();
00572   if (s_hook) {
00573     prev = s_hook;
00574     next = s_hook->next;
00575     s_hook->next->prev = this;
00576     s_hook->next = this;
00577   } else {
00578     // This is the first interpreter
00579     s_hook = next = prev = this;
00580     globalInit();
00581   }
00582   unlockInterpreter();
00583 
00584   globExec = new ExecState(m_interpreter,0);
00585 
00586   // initialize properties of the global object
00587   initGlobalObject();
00588 }
00589 
00590 void InterpreterImp::lock()
00591 {
00592   lockInterpreter();
00593 }
00594 
00595 void InterpreterImp::unlock()
00596 {
00597   unlockInterpreter();
00598 }
00599 
00600 void InterpreterImp::initGlobalObject()
00601 {
00602   // Contructor prototype objects (Object.prototype, Array.prototype etc)
00603 
00604   FunctionPrototypeImp *funcProto = new FunctionPrototypeImp(globExec);
00605   b_FunctionPrototype = Object(funcProto);
00606   ObjectPrototypeImp *objProto = new ObjectPrototypeImp(globExec,funcProto);
00607   b_ObjectPrototype = Object(objProto);
00608   funcProto->setPrototype(b_ObjectPrototype);
00609 
00610   ArrayPrototypeImp *arrayProto = new ArrayPrototypeImp(globExec,objProto);
00611   b_ArrayPrototype = Object(arrayProto);
00612   StringPrototypeImp *stringProto = new StringPrototypeImp(globExec,objProto);
00613   b_StringPrototype = Object(stringProto);
00614   BooleanPrototypeImp *booleanProto = new BooleanPrototypeImp(globExec,objProto,funcProto);
00615   b_BooleanPrototype = Object(booleanProto);
00616   NumberPrototypeImp *numberProto = new NumberPrototypeImp(globExec,objProto,funcProto);
00617   b_NumberPrototype = Object(numberProto);
00618   DatePrototypeImp *dateProto = new DatePrototypeImp(globExec,objProto);
00619   b_DatePrototype = Object(dateProto);
00620   RegExpPrototypeImp *regexpProto = new RegExpPrototypeImp(globExec,objProto,funcProto);
00621   b_RegExpPrototype = Object(regexpProto);
00622   ErrorPrototypeImp *errorProto = new ErrorPrototypeImp(globExec,objProto,funcProto);
00623   b_ErrorPrototype = Object(errorProto);
00624 
00625   static_cast<ObjectImp*>(global.imp())->setPrototype(b_ObjectPrototype);
00626 
00627   // Constructors (Object, Array, etc.)
00628 
00629   b_Object = Object(new ObjectObjectImp(globExec, objProto, funcProto));
00630   b_Function = Object(new FunctionObjectImp(globExec, funcProto));
00631   b_Array = Object(new ArrayObjectImp(globExec, funcProto, arrayProto));
00632   b_String = Object(new StringObjectImp(globExec, funcProto, stringProto));
00633   b_Boolean = Object(new BooleanObjectImp(globExec, funcProto, booleanProto));
00634   b_Number = Object(new NumberObjectImp(globExec, funcProto, numberProto));
00635   b_Date = Object(new DateObjectImp(globExec, funcProto, dateProto));
00636   b_RegExp = Object(new RegExpObjectImp(globExec, funcProto, regexpProto));
00637   b_Error = Object(new ErrorObjectImp(globExec, funcProto, errorProto));
00638 
00639   // Error object prototypes
00640   b_evalErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,EvalError,
00641                                                             "EvalError","EvalError"));
00642   b_rangeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,RangeError,
00643                                                             "RangeError","RangeError"));
00644   b_referenceErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,ReferenceError,
00645                                                             "ReferenceError","ReferenceError"));
00646   b_syntaxErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,SyntaxError,
00647                                                             "SyntaxError","SyntaxError"));
00648   b_typeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,TypeError,
00649                                                             "TypeError","TypeError"));
00650   b_uriErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,URIError,
00651                                                             "URIError","URIError"));
00652 
00653   // Error objects
00654   b_evalError = Object(new NativeErrorImp(globExec,funcProto,b_evalErrorPrototype));
00655   b_rangeError = Object(new NativeErrorImp(globExec,funcProto,b_rangeErrorPrototype));
00656   b_referenceError = Object(new NativeErrorImp(globExec,funcProto,b_referenceErrorPrototype));
00657   b_syntaxError = Object(new NativeErrorImp(globExec,funcProto,b_syntaxErrorPrototype));
00658   b_typeError = Object(new NativeErrorImp(globExec,funcProto,b_typeErrorPrototype));
00659   b_uriError = Object(new NativeErrorImp(globExec,funcProto,b_uriErrorPrototype));
00660 
00661   // ECMA 15.3.4.1
00662   funcProto->put(globExec,constructorPropertyName, b_Function, DontEnum);
00663 
00664   global.put(globExec,"Object", b_Object, DontEnum);
00665   global.put(globExec,"Function", b_Function, DontEnum);
00666   global.put(globExec,"Array", b_Array, DontEnum);
00667   global.put(globExec,"Boolean", b_Boolean, DontEnum);
00668   global.put(globExec,"String", b_String, DontEnum);
00669   global.put(globExec,"Number", b_Number, DontEnum);
00670   global.put(globExec,"Date", b_Date, DontEnum);
00671   global.put(globExec,"RegExp", b_RegExp, DontEnum);
00672   global.put(globExec,"Error", b_Error, DontEnum);
00673   // Using Internal for those to have something != 0
00674   // (see kjs_window). Maybe DontEnum would be ok too ?
00675   global.put(globExec,"EvalError",b_evalError, Internal);
00676   global.put(globExec,"RangeError",b_rangeError, Internal);
00677   global.put(globExec,"ReferenceError",b_referenceError, Internal);
00678   global.put(globExec,"SyntaxError",b_syntaxError, Internal);
00679   global.put(globExec,"TypeError",b_typeError, Internal);
00680   global.put(globExec,"URIError",b_uriError, Internal);
00681 
00682   // Set the "constructor" property of all builtin constructors
00683   objProto->put(globExec, constructorPropertyName, b_Object, DontEnum | DontDelete | ReadOnly);
00684   funcProto->put(globExec, constructorPropertyName, b_Function, DontEnum | DontDelete | ReadOnly);
00685   arrayProto->put(globExec, constructorPropertyName, b_Array, DontEnum | DontDelete | ReadOnly);
00686   booleanProto->put(globExec, constructorPropertyName, b_Boolean, DontEnum | DontDelete | ReadOnly);
00687   stringProto->put(globExec, constructorPropertyName, b_String, DontEnum | DontDelete | ReadOnly);
00688   numberProto->put(globExec, constructorPropertyName, b_Number, DontEnum | DontDelete | ReadOnly);
00689   dateProto->put(globExec, constructorPropertyName, b_Date, DontEnum | DontDelete | ReadOnly);
00690   regexpProto->put(globExec, constructorPropertyName, b_RegExp, DontEnum | DontDelete | ReadOnly);
00691   errorProto->put(globExec, constructorPropertyName, b_Error, DontEnum | DontDelete | ReadOnly);
00692   b_evalErrorPrototype.put(globExec, constructorPropertyName, b_evalError, DontEnum | DontDelete | ReadOnly);
00693   b_rangeErrorPrototype.put(globExec, constructorPropertyName, b_rangeError, DontEnum | DontDelete | ReadOnly);
00694   b_referenceErrorPrototype.put(globExec, constructorPropertyName, b_referenceError, DontEnum | DontDelete | ReadOnly);
00695   b_syntaxErrorPrototype.put(globExec, constructorPropertyName, b_syntaxError, DontEnum | DontDelete | ReadOnly);
00696   b_typeErrorPrototype.put(globExec, constructorPropertyName, b_typeError, DontEnum | DontDelete | ReadOnly);
00697   b_uriErrorPrototype.put(globExec, constructorPropertyName, b_uriError, DontEnum | DontDelete | ReadOnly);
00698 
00699   // built-in values
00700   global.put(globExec, "NaN",        Number(NaN), DontEnum|DontDelete);
00701   global.put(globExec, "Infinity",   Number(Inf), DontEnum|DontDelete);
00702   global.put(globExec, "undefined",  Undefined(), DontEnum|DontDelete);
00703 
00704   // built-in functions
00705 #ifdef KJS_PURE_ECMA // otherwise as deprecated Object.prototype property
00706   global.put(globExec,"eval",
00707          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Eval,1,"eval")), DontEnum);
00708 #endif
00709   global.put(globExec,"parseInt",
00710          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseInt,2,"parseInt")), DontEnum);
00711   global.put(globExec,"parseFloat",
00712          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseFloat,1,"parseFloat")), DontEnum);
00713   global.put(globExec,"isNaN",
00714          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsNaN,1,"isNaN")), DontEnum);
00715   global.put(globExec,"isFinite",
00716          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsFinite,1,"isFinite")), DontEnum);
00717   global.put(globExec,"decodeURI",
00718          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::DecodeURI,1,"decodeURI")),
00719          DontEnum);
00720   global.put(globExec,"decodeURIComponent",
00721          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::DecodeURIComponent,1,"decodeURIComponent")),
00722          DontEnum);
00723   global.put(globExec,"encodeURI",
00724          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::EncodeURI,1,"encodeURI")),
00725          DontEnum);
00726   global.put(globExec,"encodeURIComponent",
00727          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::EncodeURIComponent,1,"encodeURIComponent")),
00728          DontEnum);
00729   global.put(globExec,"escape",
00730          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Escape,1,"escape")), DontEnum);
00731   global.put(globExec,"unescape",
00732          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::UnEscape,1,"unescape")), DontEnum);
00733 #ifndef NDEBUG
00734   global.put(globExec,"kjsprint",
00735          Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::KJSPrint,1,"kjsprint")), DontEnum);
00736 #endif
00737 
00738   // built-in objects
00739   global.put(globExec,"Math", Object(new MathObjectImp(globExec,objProto)), DontEnum);
00740 }
00741 
00742 InterpreterImp::~InterpreterImp()
00743 {
00744   if (dbg)
00745     dbg->detach(m_interpreter);
00746   for (SourceCode *s = sources; s; s = s->next)
00747     s->interpreter = 0;
00748   delete globExec;
00749   globExec = 0L;
00750   clear();
00751 }
00752 
00753 void InterpreterImp::clear()
00754 {
00755   //fprintf(stderr,"InterpreterImp::clear\n");
00756   // remove from global chain (see init())
00757   lockInterpreter();
00758   next->prev = prev;
00759   prev->next = next;
00760   s_hook = next;
00761   if (s_hook == this)
00762   {
00763     // This was the last interpreter
00764     s_hook = 0L;
00765     globalClear();
00766   }
00767   unlockInterpreter();
00768 }
00769 
00770 void InterpreterImp::mark()
00771 {
00772   //if (exVal && !exVal->marked())
00773   //  exVal->mark();
00774   //if (retVal && !retVal->marked())
00775   //  retVal->mark();
00776   if (UndefinedImp::staticUndefined && !UndefinedImp::staticUndefined->marked())
00777     UndefinedImp::staticUndefined->mark();
00778   if (NullImp::staticNull && !NullImp::staticNull->marked())
00779     NullImp::staticNull->mark();
00780   if (NumberImp::staticNaN && !NumberImp::staticNaN->marked())
00781     NumberImp::staticNaN->mark();
00782   if (BooleanImp::staticTrue && !BooleanImp::staticTrue->marked())
00783     BooleanImp::staticTrue->mark();
00784   if (BooleanImp::staticFalse && !BooleanImp::staticFalse->marked())
00785     BooleanImp::staticFalse->mark();
00786   //fprintf( stderr, "InterpreterImp::mark this=%p global.imp()=%p\n", this, global.imp() );
00787   if (global.imp())
00788     global.imp()->mark();
00789   if (m_interpreter)
00790     m_interpreter->mark();
00791   if (_context)
00792     _context->mark();
00793 }
00794 
00795 bool InterpreterImp::checkSyntax(const UString &code, int *errLine, UString *errMsg)
00796 {
00797   // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
00798   SourceCode *source;
00799   FunctionBodyNode *progNode = Parser::parse(code.data(),code.size(),&source,errLine,errMsg);
00800   source->deref();
00801   bool ok = (progNode != 0);
00802   delete progNode;
00803   return ok;
00804 }
00805 
00806 bool InterpreterImp::checkSyntax(const UString &code)
00807 {
00808   // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
00809   SourceCode *source;
00810   FunctionBodyNode *progNode = Parser::parse(code.data(),code.size(),&source,0,0);
00811   source->deref();
00812   bool ok = (progNode != 0);
00813   delete progNode;
00814   return ok;
00815 }
00816 
00817 Completion InterpreterImp::evaluate(const UString &code, const Value &thisV)
00818 {
00819   lockInterpreter();
00820 
00821   // prevent against infinite recursion
00822   if (recursion >= 20) {
00823     Completion result = Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
00824     unlockInterpreter();
00825     return result;
00826   }
00827 
00828   // parse the source code
00829   int errLine;
00830   UString errMsg;
00831   SourceCode *source;
00832   FunctionBodyNode *progNode = Parser::parse(code.data(),code.size(),&source,&errLine,&errMsg);
00833 
00834   // notify debugger that source has been parsed
00835   if (dbg) {
00836     bool cont = dbg->sourceParsed(globExec,source->sid,code,errLine);
00837     if (!cont) {
00838       source->deref();
00839       if (progNode)
00840     delete progNode;
00841       unlockInterpreter();
00842       return Completion(Break);
00843     }
00844   }
00845 
00846   addSourceCode(source);
00847 
00848   // no program node means a syntax error occurred
00849   if (!progNode) {
00850     Object err = Error::create(globExec,SyntaxError,errMsg.ascii(),errLine);
00851     err.put(globExec,"sid",Number(source->sid));
00852     globExec->setException(err); // required to notify the debugger
00853     globExec->clearException();
00854     source->deref();
00855     unlockInterpreter();
00856     return Completion(Throw,err);
00857   }
00858   source->deref();
00859 
00860   globExec->clearException();
00861 
00862   recursion++;
00863   progNode->ref();
00864 
00865   Object &globalObj = globalObject();
00866   Object thisObj = globalObject();
00867 
00868   if (thisV.isValid()) {
00869     // "this" must be an object... use same rules as Function.prototype.apply()
00870     if (thisV.isA(NullType) || thisV.isA(UndefinedType))
00871       thisObj = globalObject();
00872     else {
00873       thisObj = thisV.toObject(globExec);
00874     }
00875   }
00876 
00877   Completion res;
00878   if (globExec->hadException()) {
00879     // the thisArg.toObject() conversion above might have thrown an exception - if so,
00880     // propagate it back
00881     res = Completion(Throw,globExec->exception());
00882   }
00883   else {
00884     // execute the code
00885     ContextImp ctx(globalObj, this, thisObj, source->sid);
00886     ExecState newExec(m_interpreter,&ctx);
00887 
00888     // create variables (initialized to undefined until var statements
00889     // with optional initializers are executed)
00890     progNode->processVarDecls(&newExec);
00891 
00892     ctx.setLines(progNode->firstLine(),progNode->firstLine());
00893     bool abort = false;
00894     if (dbg) {
00895       if (!dbg->enterContext(&newExec)) {
00896     // debugger requested we stop execution
00897     dbg->imp()->abort();
00898     abort = true;
00899       }
00900     }
00901 
00902     if (!abort) {
00903       ctx.setLines(progNode->lastLine(),progNode->lastLine());
00904       res = progNode->execute(&newExec);
00905       if (dbg && !dbg->exitContext(&newExec,res)) {
00906     // debugger requested we stop execution
00907     dbg->imp()->abort();
00908     unlockInterpreter();
00909     res = Completion(ReturnValue,Undefined());
00910       }
00911     }
00912   }
00913 
00914   if (progNode->deref())
00915     delete progNode;
00916   recursion--;
00917 
00918   if (globExec->hadException()) {
00919     res = Completion(Throw,globExec->exception());
00920     globExec->clearException();
00921   }
00922 
00923   unlockInterpreter();
00924   return res;
00925 }
00926 
00927 void InterpreterImp::setDebugger(Debugger *d)
00928 {
00929   if (d == dbg)
00930     return;
00931   // avoid recursion
00932   Debugger *old = dbg;
00933   dbg = d;
00934   if ( old )
00935     old->detach(m_interpreter);
00936 }
00937 
00938 void InterpreterImp::addSourceCode(SourceCode *code)
00939 {
00940   assert(!code->next);
00941   assert(!code->interpreter);
00942   code->next = sources;
00943   code->interpreter = this;
00944   sources = code;
00945 }
00946 
00947 void InterpreterImp::removeSourceCode(SourceCode *code)
00948 {
00949   assert(code);
00950   assert(sources);
00951 
00952   if (code == sources) {
00953     sources = sources->next;
00954     return;
00955   }
00956 
00957   SourceCode *prev = sources;
00958   SourceCode *cur = sources->next;
00959   while (cur != code) {
00960     assert(cur);
00961     prev = cur;
00962     cur = cur->next;
00963   }
00964 
00965   prev->next = cur->next;
00966 }
00967 
00968 // ------------------------------ InternalFunctionImp --------------------------
00969 
00970 const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
00971 
00972 InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto)
00973   : ObjectImp(funcProto)
00974 {
00975 }
00976 
00977 InternalFunctionImp::InternalFunctionImp(ExecState *exec)
00978   : ObjectImp(static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp()))
00979 {
00980 }
00981 
00982 bool InternalFunctionImp::implementsHasInstance() const
00983 {
00984   return true;
00985 }
00986 
00987 Boolean InternalFunctionImp::hasInstance(ExecState *exec, const Value &value)
00988 {
00989   if (value.type() != ObjectType)
00990     return Boolean(false);
00991 
00992   Value prot = get(exec,prototypePropertyName);
00993   if (prot.type() != ObjectType && prot.type() != NullType) {
00994     Object err = Error::create(exec, TypeError, "Invalid prototype encountered "
00995                                "in instanceof operation.");
00996     exec->setException(err);
00997     return Boolean(false);
00998   }
00999 
01000   Object v = Object(static_cast<ObjectImp*>(value.imp()));
01001   while ((v = Object::dynamicCast(v.prototype())).imp()) {
01002     if (v.imp() == prot.imp())
01003       return Boolean(true);
01004   }
01005   return Boolean(false);
01006 }
01007 
01008 // ------------------------------ global functions -----------------------------
01009 
01010 double KJS::roundValue(ExecState *exec, const Value &v)
01011 {
01012   double n = v.toNumber(exec);
01013   if (isNaN(n) || isInf(n))
01014     return n;
01015   double an = fabs(n);
01016   if (an == 0.0)
01017     return n;
01018   double d = floor(an);
01019   if (n < 0)
01020     d *= -1;
01021 
01022   return d;
01023 }
01024 
01025 #ifndef NDEBUG
01026 #include <stdio.h>
01027 void KJS::printInfo(ExecState *exec, const char *s, const Value &o, int lineno)
01028 {
01029   if (!o.isValid())
01030     fprintf(stderr, "KJS: %s: (null)", s);
01031   else {
01032     Value v = o;
01033     unsigned int arrayLength = 0;
01034     bool hadExcep = exec->hadException();
01035 
01036     UString name;
01037     switch ( v.type() ) {
01038     case UnspecifiedType:
01039       name = "Unspecified";
01040       break;
01041     case UndefinedType:
01042       name = "Undefined";
01043       break;
01044     case NullType:
01045       name = "Null";
01046       break;
01047     case BooleanType:
01048       name = "Boolean";
01049       break;
01050     case StringType:
01051       name = "String";
01052       break;
01053     case NumberType:
01054       name = "Number";
01055       break;
01056     case ObjectType: {
01057       Object obj = Object::dynamicCast(v);
01058       name = obj.className();
01059       if (name.isNull())
01060         name = "(unknown class)";
01061       if ( obj.inherits(&ArrayInstanceImp::info) )
01062         arrayLength = obj.get(exec,lengthPropertyName).toUInt32(exec);
01063       }
01064       break;
01065     }
01066     UString vString;
01067     // Avoid calling toString on a huge array (e.g. 4 billion elements, in mozilla/js/js1_5/Array/array-001.js)
01068     if ( arrayLength > 100 )
01069       vString = UString( "[ Array with " ) + UString::from( arrayLength ) + " elements ]";
01070     else
01071       vString = v.toString(exec);
01072     if ( !hadExcep )
01073       exec->clearException();
01074     if ( vString.size() > 50 )
01075       vString = vString.substr( 0, 50 ) + "...";
01076     // Can't use two UString::ascii() in the same fprintf call
01077     CString tempString( vString.cstring() );
01078 
01079     fprintf(stderr, "KJS: %s: %s : %s (%p)",
01080             s, tempString.c_str(), name.ascii(), (void*)v.imp());
01081 
01082     if (lineno >= 0)
01083       fprintf(stderr, ", line %d\n",lineno);
01084     else
01085       fprintf(stderr, "\n");
01086   }
01087 }
01088 #endif
KDE Home | KDE Accessibility Home | Description of Access Keys