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