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

Last change on this file since 12908 was 12728, checked in by ggaren, 19 years ago

Reviewed by mjs.

  • Fixed <rdar://problem/4343730> Should switch ConstantValues (null, undefined, true, false) from JS objects to immediate values similar to SimpleNumber

2.0% performance gain on my new super-accurate version of JS iBench.
(I promise to land a version of it soon.)

The gist of the change:
(1) The SimpleNumber class (simple_number.h) is now the JSImmediate
class (JSImmediate.h/.cpp), and it handles not only numbers but also
null, undefined, true, and false.
(2) JSImmediate provides convenience methods for the bit masking
necessary to encode and decode immediate values.
(3) ConstantValues, BooleanImp, NullImp, and UndefinedImp are gone.
(4) JSCell no longer implements functions like getBoolean, because
only a JSImmediate can be a boolean.
(5) JSImmediate no longer uses ALWAYS_INLINE because there's no need,
and ALWAYS_INLINE is a non-portable option of last resort.
(6) Type is now JSType, and it resides in its own file, JSType.h.
Since I was there, I did some header include sorting as part of this
change.

The rest pretty much explains itself.

  • JavaScriptCore.xcodeproj/project.pbxproj: Removed simple_number.h, added JSImmediate.h/.cpp.
  • bindings/c/c_instance.cpp: (KJS::Bindings::CInstance::defaultValue):
  • bindings/c/c_instance.h:
  • bindings/c/c_utility.cpp: (KJS::Bindings::convertValueToNPVariant):
  • bindings/jni/jni_instance.cpp: (JavaInstance::defaultValue):
  • bindings/jni/jni_instance.h:
  • bindings/jni/jni_jsobject.cpp: (JavaJSObject::convertValueToJObject):
  • bindings/objc/WebScriptObject.mm: (+[WebScriptObject _convertValueToObjcValue:originExecutionContext:executionContext:]): Standardized calls to use getXXX instead of hand-rolling JSValue functionality.
  • bindings/objc/objc_instance.h:
  • bindings/objc/objc_instance.mm: (ObjcInstance::getValueOfUndefinedField): (ObjcInstance::defaultValue):
  • bindings/objc/objc_runtime.h:
  • bindings/objc/objc_runtime.mm: (ObjcFallbackObjectImp::type): (ObjcFallbackObjectImp::defaultValue):
  • bindings/runtime.h: (KJS::Bindings::Instance::getValueOfUndefinedField):
  • bindings/runtime_object.cpp: (RuntimeObjectImp::defaultValue):
  • bindings/runtime_object.h:
  • kjs/JSImmediate.h: Added. (KJS::JSImmediate::isImmediate): (KJS::JSImmediate::isNumber): (KJS::JSImmediate::isBoolean): (KJS::JSImmediate::isUndefinedOrNull): (KJS::JSImmediate::fromDouble): (KJS::JSImmediate::toDouble): (KJS::JSImmediate::toBoolean): (KJS::JSImmediate::trueImmediate): (KJS::JSImmediate::falseImmediate): (KJS::JSImmediate::NaNImmediate): (KJS::JSImmediate::undefinedImmediate): (KJS::JSImmediate::nullImmediate): (KJS::JSImmediate::tag): (KJS::JSImmediate::unTag): (KJS::JSImmediate::getTag): (KJS::JSImmediate::): (KJS::JSImmediate::isIEEE): (KJS::JSImmediate::is32bit): (KJS::JSImmediate::is64bit): (KJS::JSImmediate::NanAsBits): (KJS::JSImmediate::zeroAsBits): (KJS::JSImmediate::oneAsBits):
  • kjs/JSLock.cpp: (KJS::JSLock::lock): Removed hack-o-rama to initialize ConstantValues.
  • kjs/JSType.h: Added.
  • kjs/collector.cpp: (KJS::Collector::protect): (KJS::Collector::unprotect): (KJS::Collector::collect):
  • kjs/internal.cpp: (KJS::StringImp::toPrimitive): (KJS::NumberImp::toPrimitive): (KJS::NumberImp::toBoolean): (KJS::GetterSetterImp::toPrimitive):
  • kjs/internal.h: (KJS::StringImp::type): (KJS::NumberImp::type):
  • kjs/object.cpp: (KJS::JSObject::type): (KJS::tryGetAndCallProperty): Replaced "Are you one of the six things I'm looking for?" test with "Are you not the one thing I'm not looking for" test. (KJS::JSObject::defaultValue): (KJS::JSObject::toPrimitive):
  • kjs/object.h: (KJS::GetterSetterImp::type): (KJS::JSValue::isObject):
  • kjs/operations.cpp: (KJS::equal): (KJS::strictEqual): (KJS::add):
  • kjs/reference.cpp: (KJS::Reference::deleteValue):
  • kjs/simple_number.h: Removed.
  • kjs/string_object.cpp: (StringInstance::getOwnPropertySlot): fixed indentation
  • kjs/value.cpp: (KJS::JSValue::toObject): (KJS::jsNumberCell): New function to quarantine a PIC branch -- allows us to inline jsNumber without adding PIC branches to callers.
  • kjs/value.h: (KJS::jsUndefined): (KJS::jsNull): (KJS::jsNaN): (KJS::jsBoolean): (KJS::jsNumber): (KJS::JSValue::downcast): (KJS::JSValue::isUndefinedOrNull): (KJS::JSValue::isBoolean): (KJS::JSValue::isNumber): (KJS::JSValue::isString): (KJS::JSValue::isObject): (KJS::JSValue::getBoolean): (KJS::JSValue::getNumber): (KJS::JSValue::getString): (KJS::JSValue::getObject): (KJS::JSValue::getUInt32): (KJS::JSValue::mark): Replaced !JSImmediate::is() test with assertion, resulting in a slight performance gain. Callers should always check !marked() before calling mark(), so it's impossible to call mark on a JSImmediate. (KJS::JSValue::marked): (KJS::JSValue::type): (KJS::JSValue::toPrimitive): (KJS::JSValue::toBoolean): (KJS::JSValue::toNumber): (KJS::JSValue::toString):
  • Property svn:eol-style set to native
File size: 25.2 KB
Line 
1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2002 Harri Porten ([email protected])
4 * Copyright (C) 2001 Peter Kelly ([email protected])
5 * Copyright (C) 2004 Apple Computer, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "config.h"
25#include "internal.h"
26
27#include "array_object.h"
28#include "bool_object.h"
29#include "collector.h"
30#include "context.h"
31#include "date_object.h"
32#include "debugger.h"
33#include "error_object.h"
34#include "function_object.h"
35#include "lexer.h"
36#include "math_object.h"
37#include "nodes.h"
38#include "number_object.h"
39#include "object.h"
40#include "object_object.h"
41#include "operations.h"
42#include "regexp_object.h"
43#include "string_object.h"
44#include <assert.h>
45#include <kxmlcore/HashMap.h>
46#include <kxmlcore/HashSet.h>
47#include <kxmlcore/Vector.h>
48#include <math.h>
49#include <stdio.h>
50
51extern int kjsyyparse();
52
53namespace KJS {
54
55#if !__APPLE__
56
57#ifdef WORDS_BIGENDIAN
58 const unsigned char NaN_Bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
59 const unsigned char Inf_Bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
60#elif defined(arm)
61 const unsigned char NaN_Bytes[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 };
62 const unsigned char Inf_Bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 };
63#else
64 const unsigned char NaN_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
65 const unsigned char Inf_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
66#endif
67
68 const double NaN = *(const double*) NaN_Bytes;
69 const double Inf = *(const double*) Inf_Bytes;
70
71#endif
72
73#if WIN32
74#define copysign _copysign
75#endif
76
77// ------------------------------ StringImp ------------------------------------
78
79JSValue *StringImp::toPrimitive(ExecState *, JSType) const
80{
81 return const_cast<StringImp *>(this);
82}
83
84bool StringImp::toBoolean(ExecState *) const
85{
86 return (val.size() > 0);
87}
88
89double StringImp::toNumber(ExecState *) const
90{
91 return val.toDouble();
92}
93
94UString StringImp::toString(ExecState *) const
95{
96 return val;
97}
98
99JSObject *StringImp::toObject(ExecState *exec) const
100{
101 return new StringInstance(exec->lexicalInterpreter()->builtinStringPrototype(), val);
102}
103
104// ------------------------------ NumberImp ------------------------------------
105
106JSValue *NumberImp::toPrimitive(ExecState *, JSType) const
107{
108 return const_cast<NumberImp *>(this);
109}
110
111bool NumberImp::toBoolean(ExecState *) const
112{
113 return val < 0.0 || val > 0.0; // false for NaN
114}
115
116double NumberImp::toNumber(ExecState *) const
117{
118 return val;
119}
120
121UString NumberImp::toString(ExecState *) const
122{
123 if (val == 0.0) // +0.0 or -0.0
124 return "0";
125 return UString::from(val);
126}
127
128JSObject *NumberImp::toObject(ExecState *exec) const
129{
130 List args;
131 args.append(const_cast<NumberImp*>(this));
132 return static_cast<JSObject *>(exec->lexicalInterpreter()->builtinNumber()->construct(exec,args));
133}
134
135// FIXME: We can optimize this to work like JSValue::getUInt32. I'm ignoring it for now
136// because it never shows up on profiles.
137bool NumberImp::getUInt32(uint32_t& uint32) const
138{
139 uint32 = (uint32_t)val;
140 return (double)uint32 == val;
141}
142
143// --------------------------- GetterSetterImp ---------------------------------
144void GetterSetterImp::mark()
145{
146 if (getter && !getter->marked())
147 getter->mark();
148 if (setter && !setter->marked())
149 setter->mark();
150}
151
152JSValue *GetterSetterImp::toPrimitive(ExecState *exec, JSType) const
153{
154 assert(false);
155 return jsNull();
156}
157
158bool GetterSetterImp::toBoolean(ExecState *) const
159{
160 assert(false);
161 return false;
162}
163
164double GetterSetterImp::toNumber(ExecState *) const
165{
166 assert(false);
167 return 0.0;
168}
169
170UString GetterSetterImp::toString(ExecState *) const
171{
172 assert(false);
173 return UString::null();
174}
175
176JSObject *GetterSetterImp::toObject(ExecState *exec) const
177{
178 assert(false);
179 return jsNull()->toObject(exec);
180}
181
182// ------------------------------ LabelStack -----------------------------------
183
184bool LabelStack::push(const Identifier &id)
185{
186 if (contains(id))
187 return false;
188
189 StackElem *newtos = new StackElem;
190 newtos->id = id;
191 newtos->prev = tos;
192 tos = newtos;
193 return true;
194}
195
196bool LabelStack::contains(const Identifier &id) const
197{
198 if (id.isEmpty())
199 return true;
200
201 for (StackElem *curr = tos; curr; curr = curr->prev)
202 if (curr->id == id)
203 return true;
204
205 return false;
206}
207
208// ------------------------------ ContextImp -----------------------------------
209
210// ECMA 10.2
211ContextImp::ContextImp(JSObject *glob, InterpreterImp *interpreter, JSObject *thisV, CodeType type,
212 ContextImp *callingCon, FunctionImp *func, const List *args)
213 : _interpreter(interpreter), _function(func), _arguments(args)
214{
215 m_codeType = type;
216 _callingContext = callingCon;
217
218 // create and initialize activation object (ECMA 10.1.6)
219 if (type == FunctionCode || type == AnonymousCode ) {
220 activation = new ActivationImp(func, *args);
221 variable = activation;
222 } else {
223 activation = NULL;
224 variable = glob;
225 }
226
227 // ECMA 10.2
228 switch(type) {
229 case EvalCode:
230 if (_callingContext) {
231 scope = _callingContext->scopeChain();
232 variable = _callingContext->variableObject();
233 thisVal = _callingContext->thisValue();
234 break;
235 } // else same as GlobalCode
236 case GlobalCode:
237 scope.clear();
238 scope.push(glob);
239 thisVal = static_cast<JSObject*>(glob);
240 break;
241 case FunctionCode:
242 case AnonymousCode:
243 if (type == FunctionCode) {
244 scope = func->scope();
245 scope.push(activation);
246 } else {
247 scope.clear();
248 scope.push(glob);
249 scope.push(activation);
250 }
251 variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
252 thisVal = thisV;
253 break;
254 }
255
256 _interpreter->setContext(this);
257}
258
259ContextImp::~ContextImp()
260{
261 _interpreter->setContext(_callingContext);
262}
263
264void ContextImp::mark()
265{
266 for (ContextImp *context = this; context; context = context->_callingContext) {
267 context->scope.mark();
268 }
269}
270
271// ------------------------------ Parser ---------------------------------------
272
273static RefPtr<ProgramNode> *progNode;
274int Parser::sid = 0;
275
276static Vector<RefPtr<Node> >* newNodes;
277static HashSet<Node*>* nodeCycles;
278
279void Parser::saveNewNode(Node *node)
280{
281 if (!newNodes)
282 newNodes = new Vector<RefPtr<Node> >;
283
284 newNodes->append(node);
285}
286
287void Parser::noteNodeCycle(Node *node)
288{
289 if (!nodeCycles)
290 nodeCycles = new HashSet<Node*>;
291 nodeCycles->add(node);
292}
293
294void Parser::removeNodeCycle(Node *node)
295{
296 ASSERT(nodeCycles);
297 nodeCycles->remove(node);
298}
299
300static void clearNewNodes()
301{
302 if (nodeCycles) {
303 for (HashSet<Node*>::iterator it = nodeCycles->begin(); it != nodeCycles->end(); ++it)
304 (*it)->breakCycle();
305 delete nodeCycles;
306 nodeCycles = 0;
307 }
308
309 delete newNodes;
310 newNodes = 0;
311}
312
313RefPtr<ProgramNode> Parser::parse(const UString &sourceURL, int startingLineNumber,
314 const UChar *code, unsigned int length, int *sourceId,
315 int *errLine, UString *errMsg)
316{
317 if (errLine)
318 *errLine = -1;
319 if (errMsg)
320 *errMsg = 0;
321 if (!progNode)
322 progNode = new RefPtr<ProgramNode>;
323
324 Lexer::curr()->setCode(sourceURL, startingLineNumber, code, length);
325 *progNode = 0;
326 sid++;
327 if (sourceId)
328 *sourceId = sid;
329 // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
330 //extern int kjsyydebug;
331 //kjsyydebug=1;
332 int parseError = kjsyyparse();
333 bool lexError = Lexer::curr()->sawError();
334 Lexer::curr()->doneParsing();
335 RefPtr<ProgramNode> prog = *progNode;
336 *progNode = 0;
337
338 clearNewNodes();
339
340 if (parseError || lexError) {
341 int eline = Lexer::curr()->lineNo();
342 if (errLine)
343 *errLine = eline;
344 if (errMsg)
345 *errMsg = "Parse error";
346 return RefPtr<ProgramNode>();
347 }
348
349 return prog;
350}
351
352void Parser::accept(ProgramNode *prog)
353{
354 *progNode = prog;
355}
356
357// ------------------------------ InterpreterImp -------------------------------
358
359InterpreterImp* InterpreterImp::s_hook = 0L;
360
361typedef HashMap<JSObject *, InterpreterImp *> InterpreterMap;
362
363static inline InterpreterMap &interpreterMap()
364{
365 static InterpreterMap *map = new InterpreterMap;
366 return *map;
367}
368
369InterpreterImp::InterpreterImp(Interpreter *interp, JSObject *glob)
370 : globExec(interp, 0)
371 , _context(0)
372{
373 // add this interpreter to the global chain
374 // as a root set for garbage collection
375 JSLock lock;
376
377 m_interpreter = interp;
378 if (s_hook) {
379 prev = s_hook;
380 next = s_hook->next;
381 s_hook->next->prev = this;
382 s_hook->next = this;
383 } else {
384 // This is the first interpreter
385 s_hook = next = prev = this;
386 }
387
388 interpreterMap().set(glob, this);
389
390 global = glob;
391 dbg = 0;
392 m_compatMode = Interpreter::NativeMode;
393
394 // initialize properties of the global object
395 initGlobalObject();
396
397 recursion = 0;
398}
399
400void InterpreterImp::initGlobalObject()
401{
402 Identifier::init();
403
404 // Contructor prototype objects (Object.prototype, Array.prototype etc)
405
406 FunctionPrototype *funcProto = new FunctionPrototype(&globExec);
407 b_FunctionPrototype = funcProto;
408 ObjectPrototype *objProto = new ObjectPrototype(&globExec, funcProto);
409 b_ObjectPrototype = objProto;
410 funcProto->setPrototype(b_ObjectPrototype);
411
412 ArrayPrototype *arrayProto = new ArrayPrototype(&globExec, objProto);
413 b_ArrayPrototype = arrayProto;
414 StringPrototype *stringProto = new StringPrototype(&globExec, objProto);
415 b_StringPrototype = stringProto;
416 BooleanPrototype *booleanProto = new BooleanPrototype(&globExec, objProto, funcProto);
417 b_BooleanPrototype = booleanProto;
418 NumberPrototype *numberProto = new NumberPrototype(&globExec, objProto, funcProto);
419 b_NumberPrototype = numberProto;
420 DatePrototype *dateProto = new DatePrototype(&globExec, objProto);
421 b_DatePrototype = dateProto;
422 RegExpPrototype *regexpProto = new RegExpPrototype(&globExec, objProto, funcProto);
423 b_RegExpPrototype = regexpProto;
424 ErrorPrototype *errorProto = new ErrorPrototype(&globExec, objProto, funcProto);
425 b_ErrorPrototype = errorProto;
426
427 static_cast<JSObject*>(global)->setPrototype(b_ObjectPrototype);
428
429 // Constructors (Object, Array, etc.)
430 b_Object = new ObjectObjectImp(&globExec, objProto, funcProto);
431 b_Function = new FunctionObjectImp(&globExec, funcProto);
432 b_Array = new ArrayObjectImp(&globExec, funcProto, arrayProto);
433 b_String = new StringObjectImp(&globExec, funcProto, stringProto);
434 b_Boolean = new BooleanObjectImp(&globExec, funcProto, booleanProto);
435 b_Number = new NumberObjectImp(&globExec, funcProto, numberProto);
436 b_Date = new DateObjectImp(&globExec, funcProto, dateProto);
437 b_RegExp = new RegExpObjectImp(&globExec, funcProto, regexpProto);
438 b_Error = new ErrorObjectImp(&globExec, funcProto, errorProto);
439
440 // Error object prototypes
441 b_evalErrorPrototype = new NativeErrorPrototype(&globExec, errorProto, EvalError, "EvalError", "EvalError");
442 b_rangeErrorPrototype = new NativeErrorPrototype(&globExec, errorProto, RangeError, "RangeError", "RangeError");
443 b_referenceErrorPrototype = new NativeErrorPrototype(&globExec, errorProto, ReferenceError, "ReferenceError", "ReferenceError");
444 b_syntaxErrorPrototype = new NativeErrorPrototype(&globExec, errorProto, SyntaxError, "SyntaxError", "SyntaxError");
445 b_typeErrorPrototype = new NativeErrorPrototype(&globExec, errorProto, TypeError, "TypeError", "TypeError");
446 b_uriErrorPrototype = new NativeErrorPrototype(&globExec, errorProto, URIError, "URIError", "URIError");
447
448 // Error objects
449 b_evalError = new NativeErrorImp(&globExec, funcProto, b_evalErrorPrototype);
450 b_rangeError = new NativeErrorImp(&globExec, funcProto, b_rangeErrorPrototype);
451 b_referenceError = new NativeErrorImp(&globExec, funcProto, b_referenceErrorPrototype);
452 b_syntaxError = new NativeErrorImp(&globExec, funcProto, b_syntaxErrorPrototype);
453 b_typeError = new NativeErrorImp(&globExec, funcProto, b_typeErrorPrototype);
454 b_uriError = new NativeErrorImp(&globExec, funcProto, b_uriErrorPrototype);
455
456 // ECMA 15.3.4.1
457 funcProto->put(&globExec, "constructor", b_Function, DontEnum);
458
459 global->put(&globExec, "Object", b_Object, DontEnum);
460 global->put(&globExec, "Function", b_Function, DontEnum);
461 global->put(&globExec, "Array", b_Array, DontEnum);
462 global->put(&globExec, "Boolean", b_Boolean, DontEnum);
463 global->put(&globExec, "String", b_String, DontEnum);
464 global->put(&globExec, "Number", b_Number, DontEnum);
465 global->put(&globExec, "Date", b_Date, DontEnum);
466 global->put(&globExec, "RegExp", b_RegExp, DontEnum);
467 global->put(&globExec, "Error", b_Error, DontEnum);
468 // Using Internal for those to have something != 0
469 // (see kjs_window). Maybe DontEnum would be ok too ?
470 global->put(&globExec, "EvalError",b_evalError, Internal);
471 global->put(&globExec, "RangeError",b_rangeError, Internal);
472 global->put(&globExec, "ReferenceError",b_referenceError, Internal);
473 global->put(&globExec, "SyntaxError",b_syntaxError, Internal);
474 global->put(&globExec, "TypeError",b_typeError, Internal);
475 global->put(&globExec, "URIError",b_uriError, Internal);
476
477 // Set the "constructor" property of all builtin constructors
478 objProto->put(&globExec, "constructor", b_Object, DontEnum | DontDelete | ReadOnly);
479 funcProto->put(&globExec, "constructor", b_Function, DontEnum | DontDelete | ReadOnly);
480 arrayProto->put(&globExec, "constructor", b_Array, DontEnum | DontDelete | ReadOnly);
481 booleanProto->put(&globExec, "constructor", b_Boolean, DontEnum | DontDelete | ReadOnly);
482 stringProto->put(&globExec, "constructor", b_String, DontEnum | DontDelete | ReadOnly);
483 numberProto->put(&globExec, "constructor", b_Number, DontEnum | DontDelete | ReadOnly);
484 dateProto->put(&globExec, "constructor", b_Date, DontEnum | DontDelete | ReadOnly);
485 regexpProto->put(&globExec, "constructor", b_RegExp, DontEnum | DontDelete | ReadOnly);
486 errorProto->put(&globExec, "constructor", b_Error, DontEnum | DontDelete | ReadOnly);
487 b_evalErrorPrototype->put(&globExec, "constructor", b_evalError, DontEnum | DontDelete | ReadOnly);
488 b_rangeErrorPrototype->put(&globExec, "constructor", b_rangeError, DontEnum | DontDelete | ReadOnly);
489 b_referenceErrorPrototype->put(&globExec, "constructor", b_referenceError, DontEnum | DontDelete | ReadOnly);
490 b_syntaxErrorPrototype->put(&globExec, "constructor", b_syntaxError, DontEnum | DontDelete | ReadOnly);
491 b_typeErrorPrototype->put(&globExec, "constructor", b_typeError, DontEnum | DontDelete | ReadOnly);
492 b_uriErrorPrototype->put(&globExec, "constructor", b_uriError, DontEnum | DontDelete | ReadOnly);
493
494 // built-in values
495 global->put(&globExec, "NaN", jsNaN(), DontEnum|DontDelete);
496 global->put(&globExec, "Infinity", jsNumber(Inf), DontEnum|DontDelete);
497 global->put(&globExec, "undefined", jsUndefined(), DontEnum|DontDelete);
498
499 // built-in functions
500 global->put(&globExec, "eval", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::Eval, 1), DontEnum);
501 global->put(&globExec, "parseInt", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::ParseInt, 2), DontEnum);
502 global->put(&globExec, "parseFloat", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::ParseFloat, 1), DontEnum);
503 global->put(&globExec, "isNaN", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::IsNaN, 1), DontEnum);
504 global->put(&globExec, "isFinite", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::IsFinite, 1), DontEnum);
505 global->put(&globExec, "escape", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::Escape, 1), DontEnum);
506 global->put(&globExec, "unescape", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::UnEscape, 1), DontEnum);
507 global->put(&globExec, "decodeURI", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::DecodeURI, 1), DontEnum);
508 global->put(&globExec, "decodeURIComponent", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::DecodeURIComponent, 1), DontEnum);
509 global->put(&globExec, "encodeURI", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::EncodeURI, 1), DontEnum);
510 global->put(&globExec, "encodeURIComponent", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::EncodeURIComponent, 1), DontEnum);
511#ifndef NDEBUG
512 global->put(&globExec, "kjsprint", new GlobalFuncImp(&globExec, funcProto, GlobalFuncImp::KJSPrint, 1), DontEnum);
513#endif
514
515 // built-in objects
516 global->put(&globExec, "Math", new MathObjectImp(&globExec, objProto), DontEnum);
517}
518
519InterpreterImp::~InterpreterImp()
520{
521 if (dbg)
522 dbg->detach(m_interpreter);
523 clear();
524}
525
526void InterpreterImp::clear()
527{
528 //fprintf(stderr,"InterpreterImp::clear\n");
529 // remove from global chain (see init())
530 JSLock lock;
531
532 next->prev = prev;
533 prev->next = next;
534 s_hook = next;
535 if (s_hook == this)
536 {
537 // This was the last interpreter
538 s_hook = 0L;
539 }
540 interpreterMap().remove(global);
541}
542
543void InterpreterImp::mark()
544{
545 if (m_interpreter)
546 m_interpreter->mark();
547 if (_context)
548 _context->mark();
549 if (global)
550 global->mark();
551 if (globExec._exception)
552 globExec._exception->mark();
553}
554
555bool InterpreterImp::checkSyntax(const UString &code)
556{
557 JSLock lock;
558
559 // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
560 RefPtr<ProgramNode> progNode = Parser::parse(UString(), 0, code.data(), code.size(), 0, 0, 0);
561 return progNode;
562}
563
564Completion InterpreterImp::evaluate(const UChar* code, int codeLength, JSValue* thisV, const UString& sourceURL, int startingLineNumber)
565{
566 JSLock lock;
567
568 // prevent against infinite recursion
569 if (recursion >= 20)
570 return Completion(Throw, Error::create(&globExec, GeneralError, "Recursion too deep"));
571
572 // parse the source code
573 int sid;
574 int errLine;
575 UString errMsg;
576 RefPtr<ProgramNode> progNode = Parser::parse(sourceURL, startingLineNumber, code, codeLength, &sid, &errLine, &errMsg);
577
578 // notify debugger that source has been parsed
579 if (dbg) {
580 bool cont = dbg->sourceParsed(&globExec, sid, sourceURL, UString(code, codeLength), errLine);
581 if (!cont)
582 return Completion(Break);
583 }
584
585 // no program node means a syntax error occurred
586 if (!progNode)
587 return Completion(Throw, Error::create(&globExec, SyntaxError, errMsg, errLine, sid, &sourceURL));
588
589 globExec.clearException();
590
591 recursion++;
592
593 JSObject* globalObj = globalObject();
594 JSObject* thisObj = globalObj;
595
596 // "this" must be an object... use same rules as Function.prototype.apply()
597 if (thisV && !thisV->isUndefinedOrNull())
598 thisObj = thisV->toObject(&globExec);
599
600 Completion res;
601 if (globExec.hadException())
602 // the thisV->toObject() conversion above might have thrown an exception - if so, propagate it
603 res = Completion(Throw, globExec.exception());
604 else {
605 // execute the code
606 ContextImp ctx(globalObj, this, thisObj);
607 ExecState newExec(m_interpreter, &ctx);
608 progNode->processVarDecls(&newExec);
609 res = progNode->execute(&newExec);
610 }
611
612 recursion--;
613
614 return res;
615}
616
617void InterpreterImp::saveBuiltins (SavedBuiltins &builtins) const
618{
619 if (!builtins._internal) {
620 builtins._internal = new SavedBuiltinsInternal;
621 }
622
623 builtins._internal->b_Object = b_Object;
624 builtins._internal->b_Function = b_Function;
625 builtins._internal->b_Array = b_Array;
626 builtins._internal->b_Boolean = b_Boolean;
627 builtins._internal->b_String = b_String;
628 builtins._internal->b_Number = b_Number;
629 builtins._internal->b_Date = b_Date;
630 builtins._internal->b_RegExp = b_RegExp;
631 builtins._internal->b_Error = b_Error;
632
633 builtins._internal->b_ObjectPrototype = b_ObjectPrototype;
634 builtins._internal->b_FunctionPrototype = b_FunctionPrototype;
635 builtins._internal->b_ArrayPrototype = b_ArrayPrototype;
636 builtins._internal->b_BooleanPrototype = b_BooleanPrototype;
637 builtins._internal->b_StringPrototype = b_StringPrototype;
638 builtins._internal->b_NumberPrototype = b_NumberPrototype;
639 builtins._internal->b_DatePrototype = b_DatePrototype;
640 builtins._internal->b_RegExpPrototype = b_RegExpPrototype;
641 builtins._internal->b_ErrorPrototype = b_ErrorPrototype;
642
643 builtins._internal->b_evalError = b_evalError;
644 builtins._internal->b_rangeError = b_rangeError;
645 builtins._internal->b_referenceError = b_referenceError;
646 builtins._internal->b_syntaxError = b_syntaxError;
647 builtins._internal->b_typeError = b_typeError;
648 builtins._internal->b_uriError = b_uriError;
649
650 builtins._internal->b_evalErrorPrototype = b_evalErrorPrototype;
651 builtins._internal->b_rangeErrorPrototype = b_rangeErrorPrototype;
652 builtins._internal->b_referenceErrorPrototype = b_referenceErrorPrototype;
653 builtins._internal->b_syntaxErrorPrototype = b_syntaxErrorPrototype;
654 builtins._internal->b_typeErrorPrototype = b_typeErrorPrototype;
655 builtins._internal->b_uriErrorPrototype = b_uriErrorPrototype;
656}
657
658void InterpreterImp::restoreBuiltins (const SavedBuiltins &builtins)
659{
660 if (!builtins._internal) {
661 return;
662 }
663
664 b_Object = builtins._internal->b_Object;
665 b_Function = builtins._internal->b_Function;
666 b_Array = builtins._internal->b_Array;
667 b_Boolean = builtins._internal->b_Boolean;
668 b_String = builtins._internal->b_String;
669 b_Number = builtins._internal->b_Number;
670 b_Date = builtins._internal->b_Date;
671 b_RegExp = builtins._internal->b_RegExp;
672 b_Error = builtins._internal->b_Error;
673
674 b_ObjectPrototype = builtins._internal->b_ObjectPrototype;
675 b_FunctionPrototype = builtins._internal->b_FunctionPrototype;
676 b_ArrayPrototype = builtins._internal->b_ArrayPrototype;
677 b_BooleanPrototype = builtins._internal->b_BooleanPrototype;
678 b_StringPrototype = builtins._internal->b_StringPrototype;
679 b_NumberPrototype = builtins._internal->b_NumberPrototype;
680 b_DatePrototype = builtins._internal->b_DatePrototype;
681 b_RegExpPrototype = builtins._internal->b_RegExpPrototype;
682 b_ErrorPrototype = builtins._internal->b_ErrorPrototype;
683
684 b_evalError = builtins._internal->b_evalError;
685 b_rangeError = builtins._internal->b_rangeError;
686 b_referenceError = builtins._internal->b_referenceError;
687 b_syntaxError = builtins._internal->b_syntaxError;
688 b_typeError = builtins._internal->b_typeError;
689 b_uriError = builtins._internal->b_uriError;
690
691 b_evalErrorPrototype = builtins._internal->b_evalErrorPrototype;
692 b_rangeErrorPrototype = builtins._internal->b_rangeErrorPrototype;
693 b_referenceErrorPrototype = builtins._internal->b_referenceErrorPrototype;
694 b_syntaxErrorPrototype = builtins._internal->b_syntaxErrorPrototype;
695 b_typeErrorPrototype = builtins._internal->b_typeErrorPrototype;
696 b_uriErrorPrototype = builtins._internal->b_uriErrorPrototype;
697}
698
699InterpreterImp *InterpreterImp::interpreterWithGlobalObject(JSObject *global)
700{
701 return interpreterMap().get(global);
702}
703
704
705// ------------------------------ InternalFunctionImp --------------------------
706
707const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
708
709InternalFunctionImp::InternalFunctionImp()
710{
711}
712
713InternalFunctionImp::InternalFunctionImp(FunctionPrototype *funcProto)
714 : JSObject(funcProto)
715{
716}
717
718bool InternalFunctionImp::implementsHasInstance() const
719{
720 return true;
721}
722
723bool InternalFunctionImp::hasInstance(ExecState *exec, JSValue *value)
724{
725 if (!value->isObject())
726 return false;
727
728 JSValue *prot = get(exec,prototypePropertyName);
729 if (!prot->isObject() && !prot->isNull()) {
730 throwError(exec, TypeError, "Invalid prototype encountered in instanceof operation.");
731 return false;
732 }
733
734 JSObject *v = static_cast<JSObject *>(value);
735 while ((v = v->prototype()->getObject())) {
736 if (v == prot)
737 return true;
738 }
739 return false;
740}
741
742// ------------------------------ global functions -----------------------------
743
744double roundValue(ExecState *exec, JSValue *v)
745{
746 double d = v->toNumber(exec);
747 double ad = fabs(d);
748 if (ad == 0 || isNaN(d) || isInf(d))
749 return d;
750 return copysign(floor(ad), d);
751}
752
753#ifndef NDEBUG
754#include <stdio.h>
755void printInfo(ExecState *exec, const char *s, JSValue *o, int lineno)
756{
757 if (!o)
758 fprintf(stderr, "KJS: %s: (null)", s);
759 else {
760 JSValue *v = o;
761
762 UString name;
763 switch (v->type()) {
764 case UnspecifiedType:
765 name = "Unspecified";
766 break;
767 case UndefinedType:
768 name = "Undefined";
769 break;
770 case NullType:
771 name = "Null";
772 break;
773 case BooleanType:
774 name = "Boolean";
775 break;
776 case StringType:
777 name = "String";
778 break;
779 case NumberType:
780 name = "Number";
781 break;
782 case ObjectType:
783 name = static_cast<JSObject *>(v)->className();
784 if (name.isNull())
785 name = "(unknown class)";
786 break;
787 case GetterSetterType:
788 name = "GetterSetter";
789 break;
790 }
791 UString vString = v->toString(exec);
792 if ( vString.size() > 50 )
793 vString = vString.substr( 0, 50 ) + "...";
794 // Can't use two UString::ascii() in the same fprintf call
795 CString tempString( vString.cstring() );
796
797 fprintf(stderr, "KJS: %s: %s : %s (%p)",
798 s, tempString.c_str(), name.ascii(), (void*)v);
799
800 if (lineno >= 0)
801 fprintf(stderr, ", line %d\n",lineno);
802 else
803 fprintf(stderr, "\n");
804 }
805}
806#endif
807
808}
Note: See TracBrowser for help on using the repository browser.