source: webkit/trunk/JavaScriptCore/kjs/nodes.cpp@ 28884

Last change on this file since 28884 was 28884, checked in by [email protected], 17 years ago

JavaScriptCore:

Reviewed by Oliver Hunt.


Optimized global access to global variables, using a symbol table.


SunSpider reports a 1.5% overall speedup, a 6.2% speedup on 3d-morph,
and a whopping 33.1% speedup on bitops-bitwise-and.

  • API/JSCallbackObjectFunctions.h: Replaced calls to JSObject:: with calls to Base::, since JSObject is not always our base class. This was always a bug, but the bug is even more apparent after some of my changes.

(KJS::::staticFunctionGetter): Replaced use of getDirect with call to
getOwnPropertySlot. Global declarations are no longer stored in the
property map, so a call to getDirect is insufficient for finding
override properties.

  • API/testapi.c:
  • API/testapi.js: Added test for the getDirect change mentioned above.
  • kjs/ExecState.cpp:
  • kjs/ExecState.h: Dialed back the optimization to store a direct pointer to the localStorage buffer. One ExecState can grow the global object's localStorage without another ExecState's knowledge, so ExecState can't store a direct pointer to the localStorage buffer unless/until we invent a way to update all the relevant ExecStates.
  • kjs/JSGlobalObject.cpp: Inserted the symbol table into get and put operations. (KJS::JSGlobalObject::reset): Reset the symbol table and local storage, too. Also, clear the property map here, removing the need for a separate call.
  • kjs/JSVariableObject.cpp:
  • kjs/JSVariableObject.h: Added support for saving localStorage and the symbol table to the back/forward cache, and restoring them.
  • kjs/function.cpp: (KJS::GlobalFuncImp::callAsFunction): Renamed progNode to evalNode because it's an EvalNode, not a ProgramNode.
  • kjs/lookup.h: (KJS::cacheGlobalObject): Replaced put with faster putDirect, since that's how the rest of lookup.h works. putDirect is safe here because cacheGlobalObject is only used for objects whose names are not valid identifiers.
  • kjs/nodes.cpp: The good stuff!

(KJS::EvalNode::processDeclarations): Replaced hasProperty with
the new hasOwnProperty, which is slightly faster.

  • kjs/object.h: Nixed clearProperties because clear() does this job now.
  • kjs/property_map.cpp:
  • kjs/property_map.h: More back/forward cache support.


  • wtf/Vector.h: (WTF::::grow): Added fast non-branching grow function. I used it in an earlier version of this patch, even though it's not used anymore.

JavaScriptGlue:

Build fix.

  • ForwardingHeaders/wtf/VectorTraits.h: Added.

WebCore:

Reviewed by Oliver Hunt.

Build support:

  • ForwardingHeaders/kjs/SymbolTable.h: Added.
  • ForwardingHeaders/wtf/VectorTraits.h: Added.
  • bindings/js/JSDOMWindowCustom.cpp: (WebCore::JSDOMWindow::customGetOwnPropertySlot): Replaced use of getDirectLocation with getOwnPropertySlot. getDirectLocation is no longer valid, since global declarations are not stored in the property map.

(WebCore::JSDOMWindow::customPut): Replaced use of JSObject::put with
JSGlobalObject::put. JSObject::put is no longer valid, since global
declarations are not stored in the property map.

  • bindings/js/kjs_window.cpp: Replaced JSObject:: calls with Base:: calls, since JSObject is not our base class. This was always a bug, but the bug is even more apparent after some of my changes.

(KJS::Window::clear): Removed call to clearProperties because
JSGlobalObject::reset takes care of that now.

  • history/CachedPage.cpp:
  • history/CachedPage.h: Added support for saving a symbol table and localStorage to the page cache, and restoring it.

WebKit/mac:

Reviewed by Oliver Hunt.

Build fix.

  • ForwardingHeaders/kjs/SymbolTable.h: Added.
  • ForwardingHeaders/wtf/VectorTraits.h: Added.

LayoutTests:

Reviewed by Oliver Hunt.


Added some tests to verify some of the changes I made while optimizing
global access to global variables.

  • fast/dom/Window/resources/window-property-clearing-iframe0.html: Added.
  • fast/dom/Window/resources/window-property-clearing-iframe1.html: Added.
  • fast/dom/Window/window-property-clearing-expected.txt: Added.
  • fast/dom/Window/window-property-clearing.html: Added.
  • fast/dom/getter-on-window-object2-expected.txt: Added.
  • fast/dom/getter-on-window-object2.html: Added.

Checked in failing results for these const tests. The symbol table
optimization broke const. (We didn't know this before because our only
tests used global variables.)

  • fast/js/const-expected.txt:
  • fast/js/kde/const-expected.txt:
  • fast/js/resources/for-in-avoid-duplicates.js: Fixed a typo I noticed. Not related to this patch.
  • fast/dom/Window/window-property-shadowing.html: Changed this test to use "this" instead of "window". The fact that "window" worked before, despite an overriding / shadowing var declaration, was a bug.
  • Property svn:eol-style set to native
File size: 123.7 KB
Line 
1/*
2 * Copyright (C) 1999-2002 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Cameron Zwarich ([email protected])
6 * Copyright (C) 2007 Maks Orlovich
7 * Copyright (C) 2007 Eric Seidel <[email protected]>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include "config.h"
27#include "nodes.h"
28
29#include "ExecState.h"
30#include "JSGlobalObject.h"
31#include "Parser.h"
32#include "PropertyNameArray.h"
33#include "array_object.h"
34#include "debugger.h"
35#include "function_object.h"
36#include "lexer.h"
37#include "operations.h"
38#include "regexp_object.h"
39#include <math.h>
40#include <wtf/Assertions.h>
41#include <wtf/HashCountedSet.h>
42#include <wtf/HashSet.h>
43#include <wtf/MathExtras.h>
44
45namespace KJS {
46
47#define KJS_BREAKPOINT \
48 if (Debugger::debuggersPresent > 0 && !hitStatement(exec)) \
49 return Completion(Normal);
50
51#define KJS_CHECKEXCEPTION \
52 if (exec->hadException()) \
53 return rethrowException(exec);
54
55#define KJS_CHECKEXCEPTIONVALUE \
56 if (exec->hadException()) { \
57 handleException(exec); \
58 return jsUndefined(); \
59 }
60
61#define KJS_CHECKEXCEPTIONNUMBER \
62 if (exec->hadException()) { \
63 handleException(exec); \
64 return 0; \
65 }
66
67#define KJS_CHECKEXCEPTIONBOOLEAN \
68 if (exec->hadException()) { \
69 handleException(exec); \
70 return false; \
71 }
72
73#define KJS_CHECKEXCEPTIONLIST \
74 if (exec->hadException()) { \
75 handleException(exec); \
76 return; \
77 }
78
79#define KJS_CHECKEXCEPTIONVOID \
80 if (exec->hadException()) { \
81 handleException(exec); \
82 return; \
83 }
84
85#if !ASSERT_DISABLED
86static inline bool canSkipLookup(ExecState* exec, const Identifier& ident)
87{
88 // Static lookup in EvalCode is impossible because variables aren't DontDelete.
89 // Static lookup in GlobalCode may be possible, but we haven't implemented support for it yet.
90 if (exec->codeType() != FunctionCode)
91 return false;
92
93 // Static lookup is impossible when something dynamic has been added to the front of the scope chain.
94 if (exec->variableObject() != exec->scopeChain().top())
95 return false;
96
97 // Static lookup is impossible if the symbol isn't statically declared.
98 if (!exec->variableObject()->symbolTable().contains(ident.ustring().rep()))
99 return false;
100
101 return true;
102}
103#endif
104
105// ------------------------------ Node -----------------------------------------
106
107#ifndef NDEBUG
108#ifndef LOG_CHANNEL_PREFIX
109#define LOG_CHANNEL_PREFIX Log
110#endif
111static WTFLogChannel LogKJSNodeLeaks = { 0x00000000, "", WTFLogChannelOn };
112
113struct ParserRefCountedCounter {
114 static unsigned count;
115 ParserRefCountedCounter()
116 {
117 if (count)
118 LOG(KJSNodeLeaks, "LEAK: %u KJS::Node\n", count);
119 }
120};
121unsigned ParserRefCountedCounter::count = 0;
122static ParserRefCountedCounter parserRefCountedCounter;
123#endif
124
125static HashSet<ParserRefCounted*>* newTrackedObjects;
126static HashCountedSet<ParserRefCounted*>* trackedObjectExtraRefCounts;
127
128ParserRefCounted::ParserRefCounted()
129{
130#ifndef NDEBUG
131 ++ParserRefCountedCounter::count;
132#endif
133 if (!newTrackedObjects)
134 newTrackedObjects = new HashSet<ParserRefCounted*>;
135 newTrackedObjects->add(this);
136 ASSERT(newTrackedObjects->contains(this));
137}
138
139ParserRefCounted::~ParserRefCounted()
140{
141#ifndef NDEBUG
142 --ParserRefCountedCounter::count;
143#endif
144}
145
146void ParserRefCounted::ref()
147{
148 // bumping from 0 to 1 is just removing from the new nodes set
149 if (newTrackedObjects) {
150 HashSet<ParserRefCounted*>::iterator it = newTrackedObjects->find(this);
151 if (it != newTrackedObjects->end()) {
152 newTrackedObjects->remove(it);
153 ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(this));
154 return;
155 }
156 }
157
158 ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
159
160 if (!trackedObjectExtraRefCounts)
161 trackedObjectExtraRefCounts = new HashCountedSet<ParserRefCounted*>;
162 trackedObjectExtraRefCounts->add(this);
163}
164
165void ParserRefCounted::deref()
166{
167 ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
168
169 if (!trackedObjectExtraRefCounts) {
170 delete this;
171 return;
172 }
173
174 HashCountedSet<ParserRefCounted*>::iterator it = trackedObjectExtraRefCounts->find(this);
175 if (it == trackedObjectExtraRefCounts->end())
176 delete this;
177 else
178 trackedObjectExtraRefCounts->remove(it);
179}
180
181unsigned ParserRefCounted::refcount()
182{
183 if (newTrackedObjects && newTrackedObjects->contains(this)) {
184 ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(this));
185 return 0;
186 }
187
188 ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
189
190 if (!trackedObjectExtraRefCounts)
191 return 1;
192
193 return 1 + trackedObjectExtraRefCounts->count(this);
194}
195
196void ParserRefCounted::deleteNewObjects()
197{
198 if (!newTrackedObjects)
199 return;
200
201#ifndef NDEBUG
202 HashSet<ParserRefCounted*>::iterator end = newTrackedObjects->end();
203 for (HashSet<ParserRefCounted*>::iterator it = newTrackedObjects->begin(); it != end; ++it)
204 ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(*it));
205#endif
206 deleteAllValues(*newTrackedObjects);
207 delete newTrackedObjects;
208 newTrackedObjects = 0;
209}
210
211Node::Node()
212 : m_expectedReturnType(ObjectType)
213{
214 m_line = lexer().lineNo();
215}
216
217Node::Node(JSType expectedReturn)
218 : m_expectedReturnType(expectedReturn)
219{
220 m_line = lexer().lineNo();
221}
222
223double ExpressionNode::evaluateToNumber(ExecState* exec)
224{
225 JSValue* value = evaluate(exec);
226 KJS_CHECKEXCEPTIONNUMBER
227 return value->toNumber(exec);
228}
229
230bool ExpressionNode::evaluateToBoolean(ExecState* exec)
231{
232 JSValue* value = evaluate(exec);
233 KJS_CHECKEXCEPTIONBOOLEAN
234 return value->toBoolean(exec);
235}
236
237int32_t ExpressionNode::evaluateToInt32(ExecState* exec)
238{
239 JSValue* value = evaluate(exec);
240 KJS_CHECKEXCEPTIONNUMBER
241 return value->toInt32(exec);
242}
243
244uint32_t ExpressionNode::evaluateToUInt32(ExecState* exec)
245{
246 JSValue* value = evaluate(exec);
247 KJS_CHECKEXCEPTIONNUMBER
248 return value->toUInt32(exec);
249}
250
251static void substitute(UString &string, const UString &substring) KJS_FAST_CALL;
252static void substitute(UString &string, const UString &substring)
253{
254 int position = string.find("%s");
255 ASSERT(position != -1);
256 UString newString = string.substr(0, position);
257 newString.append(substring);
258 newString.append(string.substr(position + 2));
259 string = newString;
260}
261
262static inline int currentSourceId(ExecState* exec) KJS_FAST_CALL;
263static inline int currentSourceId(ExecState* exec)
264{
265 return exec->scopeNode()->sourceId();
266}
267
268static inline const UString& currentSourceURL(ExecState* exec) KJS_FAST_CALL;
269static inline const UString& currentSourceURL(ExecState* exec)
270{
271 return exec->scopeNode()->sourceURL();
272}
273
274Completion Node::createErrorCompletion(ExecState* exec, ErrorType e, const char *msg)
275{
276 return Completion(Throw, Error::create(exec, e, msg, lineNo(), currentSourceId(exec), currentSourceURL(exec)));
277}
278
279Completion Node::createErrorCompletion(ExecState *exec, ErrorType e, const char *msg, const Identifier &ident)
280{
281 UString message = msg;
282 substitute(message, ident.ustring());
283 return Completion(Throw, Error::create(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec)));
284}
285
286JSValue *Node::throwError(ExecState* exec, ErrorType e, const char *msg)
287{
288 return KJS::throwError(exec, e, msg, lineNo(), currentSourceId(exec), currentSourceURL(exec));
289}
290
291JSValue *Node::throwError(ExecState* exec, ErrorType e, const char* msg, const char* string)
292{
293 UString message = msg;
294 substitute(message, string);
295 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
296}
297
298JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *expr)
299{
300 UString message = msg;
301 substitute(message, v->toString(exec));
302 substitute(message, expr->toString());
303 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
304}
305
306
307JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, const Identifier &label)
308{
309 UString message = msg;
310 substitute(message, label.ustring());
311 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
312}
313
314JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *e1, Node *e2)
315{
316 UString message = msg;
317 substitute(message, v->toString(exec));
318 substitute(message, e1->toString());
319 substitute(message, e2->toString());
320 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
321}
322
323JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *expr, const Identifier &label)
324{
325 UString message = msg;
326 substitute(message, v->toString(exec));
327 substitute(message, expr->toString());
328 substitute(message, label.ustring());
329 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
330}
331
332JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, const Identifier &label)
333{
334 UString message = msg;
335 substitute(message, v->toString(exec));
336 substitute(message, label.ustring());
337 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
338}
339
340JSValue *Node::throwUndefinedVariableError(ExecState *exec, const Identifier &ident)
341{
342 return throwError(exec, ReferenceError, "Can't find variable: %s", ident);
343}
344
345void Node::handleException(ExecState* exec)
346{
347 handleException(exec, exec->exception());
348}
349
350void Node::handleException(ExecState* exec, JSValue* exceptionValue)
351{
352 if (exceptionValue->isObject()) {
353 JSObject* exception = static_cast<JSObject*>(exceptionValue);
354 if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
355 exception->put(exec, "line", jsNumber(m_line));
356 exception->put(exec, "sourceURL", jsString(currentSourceURL(exec)));
357 }
358 }
359 Debugger* dbg = exec->dynamicGlobalObject()->debugger();
360 if (dbg && !dbg->hasHandledException(exec, exceptionValue)) {
361 bool cont = dbg->exception(exec, currentSourceId(exec), m_line, exceptionValue);
362 if (!cont)
363 dbg->imp()->abort();
364 }
365}
366
367Completion Node::rethrowException(ExecState* exec)
368{
369 JSValue* exception = exec->exception();
370 exec->clearException();
371 handleException(exec, exception);
372 return Completion(Throw, exception);
373}
374
375// ------------------------------ StatementNode --------------------------------
376
377StatementNode::StatementNode()
378 : m_lastLine(-1)
379{
380 m_line = -1;
381}
382
383void StatementNode::setLoc(int firstLine, int lastLine)
384{
385 m_line = firstLine;
386 m_lastLine = lastLine;
387}
388
389// return true if the debugger wants us to stop at this point
390bool StatementNode::hitStatement(ExecState* exec)
391{
392 Debugger *dbg = exec->dynamicGlobalObject()->debugger();
393 if (dbg)
394 return dbg->atStatement(exec, currentSourceId(exec), firstLine(), lastLine());
395 else
396 return true; // continue
397}
398
399// ------------------------------ NullNode -------------------------------------
400
401JSValue *NullNode::evaluate(ExecState *)
402{
403 return jsNull();
404}
405
406// ------------------------------ FalseNode ----------------------------------
407
408JSValue* FalseNode::evaluate(ExecState*)
409{
410 return jsBoolean(false);
411}
412
413// ------------------------------ TrueNode ----------------------------------
414
415JSValue* TrueNode::evaluate(ExecState*)
416{
417 return jsBoolean(true);
418}
419
420// ------------------------------ NumberNode -----------------------------------
421
422JSValue* NumberNode::evaluate(ExecState*)
423{
424 // Number nodes are only created when the number can't fit in a JSImmediate, so no need to check again.
425 return jsNumberCell(m_double);
426}
427
428double NumberNode::evaluateToNumber(ExecState*)
429{
430 return m_double;
431}
432
433bool NumberNode::evaluateToBoolean(ExecState*)
434{
435 return m_double < 0.0 || m_double > 0.0; // false for NaN as well as 0
436}
437
438int32_t NumberNode::evaluateToInt32(ExecState*)
439{
440 return JSValue::toInt32(m_double);
441}
442
443uint32_t NumberNode::evaluateToUInt32(ExecState*)
444{
445 return JSValue::toUInt32(m_double);
446}
447
448// ------------------------------ ImmediateNumberNode -----------------------------------
449
450JSValue* ImmediateNumberNode::evaluate(ExecState*)
451{
452 return m_value;
453}
454
455int32_t ImmediateNumberNode::evaluateToInt32(ExecState*)
456{
457 return JSImmediate::getTruncatedInt32(m_value);
458}
459
460uint32_t ImmediateNumberNode::evaluateToUInt32(ExecState*)
461{
462 uint32_t i;
463 if (JSImmediate::getTruncatedUInt32(m_value, i))
464 return i;
465 bool ok;
466 return JSValue::toUInt32SlowCase(m_double, ok);
467}
468
469// ------------------------------ StringNode -----------------------------------
470
471JSValue* StringNode::evaluate(ExecState*)
472{
473 return jsOwnedString(m_value);
474}
475
476double StringNode::evaluateToNumber(ExecState*)
477{
478 return m_value.toDouble();
479}
480
481bool StringNode::evaluateToBoolean(ExecState*)
482{
483 return !m_value.isEmpty();
484}
485
486// ------------------------------ RegExpNode -----------------------------------
487
488JSValue* RegExpNode::evaluate(ExecState* exec)
489{
490 return exec->lexicalGlobalObject()->regExpConstructor()->createRegExpImp(exec, m_regExp);
491}
492
493// ------------------------------ ThisNode -------------------------------------
494
495// ECMA 11.1.1
496JSValue *ThisNode::evaluate(ExecState *exec)
497{
498 return exec->thisValue();
499}
500
501// ------------------------------ ResolveNode ----------------------------------
502
503// ECMA 11.1.2 & 10.1.4
504JSValue* ResolveNode::inlineEvaluate(ExecState* exec)
505{
506 // Check for missed optimization opportunity.
507 ASSERT(!canSkipLookup(exec, ident));
508
509 const ScopeChain& chain = exec->scopeChain();
510 ScopeChainIterator iter = chain.begin();
511 ScopeChainIterator end = chain.end();
512
513 // we must always have something in the scope chain
514 ASSERT(iter != end);
515
516 PropertySlot slot;
517 do {
518 JSObject *o = *iter;
519
520 if (o->getPropertySlot(exec, ident, slot))
521 return slot.getValue(exec, o, ident);
522
523 ++iter;
524 } while (iter != end);
525
526 return throwUndefinedVariableError(exec, ident);
527}
528
529JSValue* ResolveNode::evaluate(ExecState* exec)
530{
531 return inlineEvaluate(exec);
532}
533
534double ResolveNode::evaluateToNumber(ExecState* exec)
535{
536 JSValue* v = inlineEvaluate(exec);
537 KJS_CHECKEXCEPTIONNUMBER
538 return v->toNumber(exec);
539}
540
541bool ResolveNode::evaluateToBoolean(ExecState* exec)
542{
543 JSValue* v = inlineEvaluate(exec);
544 KJS_CHECKEXCEPTIONBOOLEAN
545 return v->toBoolean(exec);
546}
547
548int32_t ResolveNode::evaluateToInt32(ExecState* exec)
549{
550 JSValue* v = inlineEvaluate(exec);
551 KJS_CHECKEXCEPTIONNUMBER
552 return v->toInt32(exec);
553}
554
555uint32_t ResolveNode::evaluateToUInt32(ExecState* exec)
556{
557 JSValue* v = inlineEvaluate(exec);
558 KJS_CHECKEXCEPTIONNUMBER
559 return v->toUInt32(exec);
560}
561
562void ResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
563{
564 size_t index = symbolTable.get(ident.ustring().rep());
565 if (index != missingSymbolMarker())
566 new (this) LocalVarAccessNode(index);
567}
568
569JSValue* LocalVarAccessNode::inlineEvaluate(ExecState* exec)
570{
571 ASSERT(exec->variableObject() == exec->scopeChain().top());
572 return exec->localStorage()[index].value;
573}
574
575JSValue* LocalVarAccessNode::evaluate(ExecState* exec)
576{
577 return inlineEvaluate(exec);
578}
579
580double LocalVarAccessNode::evaluateToNumber(ExecState* exec)
581{
582 return inlineEvaluate(exec)->toNumber(exec);
583}
584
585bool LocalVarAccessNode::evaluateToBoolean(ExecState* exec)
586{
587 return inlineEvaluate(exec)->toBoolean(exec);
588}
589
590int32_t LocalVarAccessNode::evaluateToInt32(ExecState* exec)
591{
592 return inlineEvaluate(exec)->toInt32(exec);
593}
594
595uint32_t LocalVarAccessNode::evaluateToUInt32(ExecState* exec)
596{
597 return inlineEvaluate(exec)->toUInt32(exec);
598}
599
600// ------------------------------ ElementNode ----------------------------------
601
602void ElementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
603{
604 if (next)
605 nodeStack.append(next.get());
606 ASSERT(node);
607 nodeStack.append(node.get());
608}
609
610// ECMA 11.1.4
611JSValue *ElementNode::evaluate(ExecState *exec)
612{
613 JSObject *array = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, List::empty());
614 int length = 0;
615 for (ElementNode *n = this; n; n = n->next.get()) {
616 JSValue *val = n->node->evaluate(exec);
617 KJS_CHECKEXCEPTIONVALUE
618 length += n->elision;
619 array->put(exec, length++, val);
620 }
621 return array;
622}
623
624// ------------------------------ ArrayNode ------------------------------------
625
626void ArrayNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
627{
628 if (element)
629 nodeStack.append(element.get());
630}
631
632
633// ECMA 11.1.4
634JSValue *ArrayNode::evaluate(ExecState *exec)
635{
636 JSObject *array;
637 int length;
638
639 if (element) {
640 array = static_cast<JSObject*>(element->evaluate(exec));
641 KJS_CHECKEXCEPTIONVALUE
642 length = opt ? array->get(exec, exec->propertyNames().length)->toInt32(exec) : 0;
643 } else {
644 JSValue *newArr = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec,List::empty());
645 array = static_cast<JSObject*>(newArr);
646 length = 0;
647 }
648
649 if (opt)
650 array->put(exec, exec->propertyNames().length, jsNumber(elision + length), DontEnum | DontDelete);
651
652 return array;
653}
654
655// ------------------------------ ObjectLiteralNode ----------------------------
656
657void ObjectLiteralNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
658{
659 if (list)
660 nodeStack.append(list.get());
661}
662
663// ECMA 11.1.5
664JSValue *ObjectLiteralNode::evaluate(ExecState *exec)
665{
666 if (list)
667 return list->evaluate(exec);
668
669 return exec->lexicalGlobalObject()->objectConstructor()->construct(exec,List::empty());
670}
671
672// ------------------------------ PropertyListNode -----------------------------
673
674void PropertyListNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
675{
676 if (next)
677 nodeStack.append(next.get());
678 nodeStack.append(node.get());
679}
680
681// ECMA 11.1.5
682JSValue *PropertyListNode::evaluate(ExecState *exec)
683{
684 JSObject *obj = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, List::empty());
685
686 for (PropertyListNode *p = this; p; p = p->next.get()) {
687 JSValue *v = p->node->assign->evaluate(exec);
688 KJS_CHECKEXCEPTIONVALUE
689
690 switch (p->node->type) {
691 case PropertyNode::Getter:
692 ASSERT(v->isObject());
693 obj->defineGetter(exec, p->node->name(), static_cast<JSObject *>(v));
694 break;
695 case PropertyNode::Setter:
696 ASSERT(v->isObject());
697 obj->defineSetter(exec, p->node->name(), static_cast<JSObject *>(v));
698 break;
699 case PropertyNode::Constant:
700 obj->put(exec, p->node->name(), v);
701 break;
702 }
703 }
704
705 return obj;
706}
707
708// ------------------------------ PropertyNode -----------------------------
709
710void PropertyNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
711{
712 nodeStack.append(assign.get());
713}
714
715// ECMA 11.1.5
716JSValue *PropertyNode::evaluate(ExecState*)
717{
718 ASSERT(false);
719 return jsNull();
720}
721
722// ------------------------------ BracketAccessorNode --------------------------------
723
724void BracketAccessorNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
725{
726 nodeStack.append(expr2.get());
727 nodeStack.append(expr1.get());
728}
729
730// ECMA 11.2.1a
731JSValue* BracketAccessorNode::inlineEvaluate(ExecState* exec)
732{
733 JSValue* v1 = expr1->evaluate(exec);
734 KJS_CHECKEXCEPTIONVALUE
735 JSValue* v2 = expr2->evaluate(exec);
736 KJS_CHECKEXCEPTIONVALUE
737 JSObject* o = v1->toObject(exec);
738 uint32_t i;
739 if (v2->getUInt32(i))
740 return o->get(exec, i);
741 return o->get(exec, Identifier(v2->toString(exec)));
742}
743
744JSValue* BracketAccessorNode::evaluate(ExecState* exec)
745{
746 return inlineEvaluate(exec);
747}
748
749double BracketAccessorNode::evaluateToNumber(ExecState* exec)
750{
751 JSValue* v = inlineEvaluate(exec);
752 KJS_CHECKEXCEPTIONNUMBER
753 return v->toNumber(exec);
754}
755
756bool BracketAccessorNode::evaluateToBoolean(ExecState* exec)
757{
758 JSValue* v = inlineEvaluate(exec);
759 KJS_CHECKEXCEPTIONBOOLEAN
760 return v->toBoolean(exec);
761}
762
763int32_t BracketAccessorNode::evaluateToInt32(ExecState* exec)
764{
765 JSValue* v = inlineEvaluate(exec);
766 KJS_CHECKEXCEPTIONNUMBER
767 return v->toInt32(exec);
768}
769
770uint32_t BracketAccessorNode::evaluateToUInt32(ExecState* exec)
771{
772 JSValue* v = inlineEvaluate(exec);
773 KJS_CHECKEXCEPTIONNUMBER
774 return v->toUInt32(exec);
775}
776
777// ------------------------------ DotAccessorNode --------------------------------
778
779void DotAccessorNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
780{
781 nodeStack.append(expr.get());
782}
783
784// ECMA 11.2.1b
785JSValue* DotAccessorNode::inlineEvaluate(ExecState* exec)
786{
787 JSValue* v = expr->evaluate(exec);
788 KJS_CHECKEXCEPTIONVALUE
789 return v->toObject(exec)->get(exec, ident);
790}
791
792JSValue* DotAccessorNode::evaluate(ExecState* exec)
793{
794 return inlineEvaluate(exec);
795}
796
797double DotAccessorNode::evaluateToNumber(ExecState* exec)
798{
799 JSValue* v = inlineEvaluate(exec);
800 KJS_CHECKEXCEPTIONNUMBER
801 return v->toNumber(exec);
802}
803
804bool DotAccessorNode::evaluateToBoolean(ExecState* exec)
805{
806 JSValue* v = inlineEvaluate(exec);
807 KJS_CHECKEXCEPTIONBOOLEAN
808 return v->toBoolean(exec);
809}
810
811int32_t DotAccessorNode::evaluateToInt32(ExecState* exec)
812{
813 JSValue* v = inlineEvaluate(exec);
814 KJS_CHECKEXCEPTIONNUMBER
815 return v->toInt32(exec);
816}
817
818uint32_t DotAccessorNode::evaluateToUInt32(ExecState* exec)
819{
820 JSValue* v = inlineEvaluate(exec);
821 KJS_CHECKEXCEPTIONNUMBER
822 return v->toUInt32(exec);
823}
824
825// ------------------------------ ArgumentListNode -----------------------------
826
827void ArgumentListNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
828{
829 if (next)
830 nodeStack.append(next.get());
831 ASSERT(expr);
832 nodeStack.append(expr.get());
833}
834
835// ECMA 11.2.4
836void ArgumentListNode::evaluateList(ExecState* exec, List& list)
837{
838 for (ArgumentListNode *n = this; n; n = n->next.get()) {
839 JSValue *v = n->expr->evaluate(exec);
840 KJS_CHECKEXCEPTIONLIST
841 list.append(v);
842 }
843}
844
845// ------------------------------ ArgumentsNode --------------------------------
846
847void ArgumentsNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
848{
849 if (listNode)
850 nodeStack.append(listNode.get());
851}
852
853// ------------------------------ NewExprNode ----------------------------------
854
855void NewExprNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
856{
857 if (args)
858 nodeStack.append(args.get());
859 nodeStack.append(expr.get());
860}
861
862// ECMA 11.2.2
863
864JSValue* NewExprNode::inlineEvaluate(ExecState* exec)
865{
866 JSValue* v = expr->evaluate(exec);
867 KJS_CHECKEXCEPTIONVALUE
868
869 List argList;
870 if (args) {
871 args->evaluateList(exec, argList);
872 KJS_CHECKEXCEPTIONVALUE
873 }
874
875 if (!v->isObject())
876 return throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with new.", v, expr.get());
877
878 JSObject *constr = static_cast<JSObject*>(v);
879 if (!constr->implementsConstruct())
880 return throwError(exec, TypeError, "Value %s (result of expression %s) is not a constructor. Cannot be used with new.", v, expr.get());
881
882 return constr->construct(exec, argList);
883}
884
885JSValue* NewExprNode::evaluate(ExecState* exec)
886{
887 return inlineEvaluate(exec);
888}
889
890double NewExprNode::evaluateToNumber(ExecState* exec)
891{
892 JSValue* v = inlineEvaluate(exec);
893 KJS_CHECKEXCEPTIONNUMBER
894 return v->toNumber(exec);
895}
896
897bool NewExprNode::evaluateToBoolean(ExecState* exec)
898{
899 JSValue* v = inlineEvaluate(exec);
900 KJS_CHECKEXCEPTIONBOOLEAN
901 return v->toBoolean(exec);
902}
903
904int32_t NewExprNode::evaluateToInt32(ExecState* exec)
905{
906 JSValue* v = inlineEvaluate(exec);
907 KJS_CHECKEXCEPTIONNUMBER
908 return v->toInt32(exec);
909}
910
911uint32_t NewExprNode::evaluateToUInt32(ExecState* exec)
912{
913 JSValue* v = inlineEvaluate(exec);
914 KJS_CHECKEXCEPTIONNUMBER
915 return v->toUInt32(exec);
916}
917
918void FunctionCallValueNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
919{
920 nodeStack.append(args.get());
921 nodeStack.append(expr.get());
922}
923
924// ECMA 11.2.3
925JSValue *FunctionCallValueNode::evaluate(ExecState *exec)
926{
927 JSValue *v = expr->evaluate(exec);
928 KJS_CHECKEXCEPTIONVALUE
929
930 if (!v->isObject()) {
931 return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, expr.get());
932 }
933
934 JSObject *func = static_cast<JSObject*>(v);
935
936 if (!func->implementsCall()) {
937 return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, expr.get());
938 }
939
940 List argList;
941 args->evaluateList(exec, argList);
942 KJS_CHECKEXCEPTIONVALUE
943
944 JSObject *thisObj = exec->dynamicGlobalObject();
945
946 return func->call(exec, thisObj, argList);
947}
948
949void FunctionCallResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack& nodeStack)
950{
951 nodeStack.append(args.get());
952
953 size_t index = symbolTable.get(ident.ustring().rep());
954 if (index != missingSymbolMarker())
955 new (this) LocalVarFunctionCallNode(index);
956}
957
958// ECMA 11.2.3
959JSValue* FunctionCallResolveNode::inlineEvaluate(ExecState* exec)
960{
961 // Check for missed optimization opportunity.
962 ASSERT(!canSkipLookup(exec, ident));
963
964 const ScopeChain& chain = exec->scopeChain();
965 ScopeChainIterator iter = chain.begin();
966 ScopeChainIterator end = chain.end();
967
968 // we must always have something in the scope chain
969 ASSERT(iter != end);
970
971 PropertySlot slot;
972 JSObject *base;
973 do {
974 base = *iter;
975 if (base->getPropertySlot(exec, ident, slot)) {
976 JSValue *v = slot.getValue(exec, base, ident);
977 KJS_CHECKEXCEPTIONVALUE
978
979 if (!v->isObject())
980 return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, ident);
981
982 JSObject *func = static_cast<JSObject*>(v);
983
984 if (!func->implementsCall())
985 return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, ident);
986
987 List argList;
988 args->evaluateList(exec, argList);
989 KJS_CHECKEXCEPTIONVALUE
990
991 JSObject *thisObj = base;
992 // ECMA 11.2.3 says that in this situation the this value should be null.
993 // However, section 10.2.3 says that in the case where the value provided
994 // by the caller is null, the global object should be used. It also says
995 // that the section does not apply to interal functions, but for simplicity
996 // of implementation we use the global object anyway here. This guarantees
997 // that in host objects you always get a valid object for this.
998 if (thisObj->isActivationObject())
999 thisObj = exec->dynamicGlobalObject();
1000
1001 return func->call(exec, thisObj, argList);
1002 }
1003 ++iter;
1004 } while (iter != end);
1005
1006 return throwUndefinedVariableError(exec, ident);
1007}
1008
1009JSValue* FunctionCallResolveNode::evaluate(ExecState* exec)
1010{
1011 return inlineEvaluate(exec);
1012}
1013
1014double FunctionCallResolveNode::evaluateToNumber(ExecState* exec)
1015{
1016 JSValue* v = inlineEvaluate(exec);
1017 KJS_CHECKEXCEPTIONNUMBER
1018 return v->toNumber(exec);
1019}
1020
1021bool FunctionCallResolveNode::evaluateToBoolean(ExecState* exec)
1022{
1023 JSValue* v = inlineEvaluate(exec);
1024 KJS_CHECKEXCEPTIONBOOLEAN
1025 return v->toBoolean(exec);
1026}
1027
1028int32_t FunctionCallResolveNode::evaluateToInt32(ExecState* exec)
1029{
1030 JSValue* v = inlineEvaluate(exec);
1031 KJS_CHECKEXCEPTIONNUMBER
1032 return v->toInt32(exec);
1033}
1034
1035uint32_t FunctionCallResolveNode::evaluateToUInt32(ExecState* exec)
1036{
1037 JSValue* v = inlineEvaluate(exec);
1038 KJS_CHECKEXCEPTIONNUMBER
1039 return v->toUInt32(exec);
1040}
1041
1042JSValue* LocalVarFunctionCallNode::inlineEvaluate(ExecState* exec)
1043{
1044 ASSERT(exec->variableObject() == exec->scopeChain().top());
1045
1046 JSValue* v = exec->localStorage()[index].value;
1047
1048 if (!v->isObject())
1049 return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, ident);
1050
1051 JSObject* func = static_cast<JSObject*>(v);
1052 if (!func->implementsCall())
1053 return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, ident);
1054
1055 List argList;
1056 args->evaluateList(exec, argList);
1057 KJS_CHECKEXCEPTIONVALUE
1058
1059 return func->call(exec, exec->dynamicGlobalObject(), argList);
1060}
1061
1062JSValue* LocalVarFunctionCallNode::evaluate(ExecState* exec)
1063{
1064 return inlineEvaluate(exec);
1065}
1066
1067double LocalVarFunctionCallNode::evaluateToNumber(ExecState* exec)
1068{
1069 JSValue* v = inlineEvaluate(exec);
1070 KJS_CHECKEXCEPTIONNUMBER
1071 return v->toNumber(exec);
1072}
1073
1074bool LocalVarFunctionCallNode::evaluateToBoolean(ExecState* exec)
1075{
1076 JSValue* v = inlineEvaluate(exec);
1077 KJS_CHECKEXCEPTIONBOOLEAN
1078 return v->toBoolean(exec);
1079}
1080
1081int32_t LocalVarFunctionCallNode::evaluateToInt32(ExecState* exec)
1082{
1083 JSValue* v = inlineEvaluate(exec);
1084 KJS_CHECKEXCEPTIONNUMBER
1085 return v->toInt32(exec);
1086}
1087
1088uint32_t LocalVarFunctionCallNode::evaluateToUInt32(ExecState* exec)
1089{
1090 JSValue* v = inlineEvaluate(exec);
1091 KJS_CHECKEXCEPTIONNUMBER
1092 return v->toUInt32(exec);
1093}
1094
1095void FunctionCallBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1096{
1097 nodeStack.append(args.get());
1098 nodeStack.append(subscript.get());
1099 nodeStack.append(base.get());
1100}
1101
1102// ECMA 11.2.3
1103JSValue *FunctionCallBracketNode::evaluate(ExecState *exec)
1104{
1105 JSValue *baseVal = base->evaluate(exec);
1106 KJS_CHECKEXCEPTIONVALUE
1107
1108 JSValue *subscriptVal = subscript->evaluate(exec);
1109
1110 JSObject *baseObj = baseVal->toObject(exec);
1111 uint32_t i;
1112 PropertySlot slot;
1113
1114 JSValue *funcVal;
1115 if (subscriptVal->getUInt32(i)) {
1116 if (baseObj->getPropertySlot(exec, i, slot))
1117 funcVal = slot.getValue(exec, baseObj, i);
1118 else
1119 funcVal = jsUndefined();
1120 } else {
1121 Identifier ident(subscriptVal->toString(exec));
1122 if (baseObj->getPropertySlot(exec, ident, slot))
1123 funcVal = baseObj->get(exec, ident);
1124 else
1125 funcVal = jsUndefined();
1126 }
1127
1128 KJS_CHECKEXCEPTIONVALUE
1129
1130 if (!funcVal->isObject()) {
1131 return throwError(exec, TypeError, "Value %s (result of expression %s[%s]) is not object.", funcVal, base.get(), subscript.get());
1132 }
1133
1134 JSObject *func = static_cast<JSObject*>(funcVal);
1135
1136 if (!func->implementsCall()) {
1137 return throwError(exec, TypeError, "Object %s (result of expression %s[%s]) does not allow calls.", funcVal, base.get(), subscript.get());
1138 }
1139
1140 List argList;
1141 args->evaluateList(exec, argList);
1142 KJS_CHECKEXCEPTIONVALUE
1143
1144 JSObject *thisObj = baseObj;
1145 ASSERT(thisObj);
1146 ASSERT(thisObj->isObject());
1147 ASSERT(!thisObj->isActivationObject());
1148
1149 return func->call(exec, thisObj, argList);
1150}
1151
1152static const char *dotExprNotAnObjectString() KJS_FAST_CALL;
1153static const char *dotExprNotAnObjectString()
1154{
1155 return "Value %s (result of expression %s.%s) is not object.";
1156}
1157
1158static const char *dotExprDoesNotAllowCallsString() KJS_FAST_CALL;
1159static const char *dotExprDoesNotAllowCallsString()
1160{
1161 return "Object %s (result of expression %s.%s) does not allow calls.";
1162}
1163
1164void FunctionCallDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1165{
1166 nodeStack.append(args.get());
1167 nodeStack.append(base.get());
1168}
1169
1170// ECMA 11.2.3
1171JSValue* FunctionCallDotNode::inlineEvaluate(ExecState* exec)
1172{
1173 JSValue *baseVal = base->evaluate(exec);
1174 KJS_CHECKEXCEPTIONVALUE
1175
1176 JSObject *baseObj = baseVal->toObject(exec);
1177 PropertySlot slot;
1178 JSValue *funcVal = baseObj->getPropertySlot(exec, ident, slot) ? slot.getValue(exec, baseObj, ident) : jsUndefined();
1179 KJS_CHECKEXCEPTIONVALUE
1180
1181 if (!funcVal->isObject())
1182 return throwError(exec, TypeError, dotExprNotAnObjectString(), funcVal, base.get(), ident);
1183
1184 JSObject *func = static_cast<JSObject*>(funcVal);
1185
1186 if (!func->implementsCall())
1187 return throwError(exec, TypeError, dotExprDoesNotAllowCallsString(), funcVal, base.get(), ident);
1188
1189 List argList;
1190 args->evaluateList(exec, argList);
1191 KJS_CHECKEXCEPTIONVALUE
1192
1193 JSObject *thisObj = baseObj;
1194 ASSERT(thisObj);
1195 ASSERT(thisObj->isObject());
1196 ASSERT(!thisObj->isActivationObject());
1197
1198 return func->call(exec, thisObj, argList);
1199}
1200
1201JSValue* FunctionCallDotNode::evaluate(ExecState* exec)
1202{
1203 return inlineEvaluate(exec);
1204}
1205
1206double FunctionCallDotNode::evaluateToNumber(ExecState* exec)
1207{
1208 JSValue* v = inlineEvaluate(exec);
1209 KJS_CHECKEXCEPTIONNUMBER
1210 return v->toNumber(exec);
1211}
1212
1213bool FunctionCallDotNode::evaluateToBoolean(ExecState* exec)
1214{
1215 JSValue* v = inlineEvaluate(exec);
1216 KJS_CHECKEXCEPTIONBOOLEAN
1217 return v->toBoolean(exec);
1218}
1219
1220int32_t FunctionCallDotNode::evaluateToInt32(ExecState* exec)
1221{
1222 JSValue* v = inlineEvaluate(exec);
1223 KJS_CHECKEXCEPTIONNUMBER
1224 return v->toInt32(exec);
1225}
1226
1227uint32_t FunctionCallDotNode::evaluateToUInt32(ExecState* exec)
1228{
1229 JSValue* v = inlineEvaluate(exec);
1230 KJS_CHECKEXCEPTIONNUMBER
1231 return v->toUInt32(exec);
1232}
1233
1234// ECMA 11.3
1235
1236// ------------------------------ PostfixResolveNode ----------------------------------
1237
1238// Increment
1239void PostIncResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
1240{
1241 size_t index = symbolTable.get(m_ident.ustring().rep());
1242 if (index != missingSymbolMarker())
1243 new (this) PostIncLocalVarNode(index);
1244}
1245
1246JSValue *PostIncResolveNode::evaluate(ExecState *exec)
1247{
1248 // Check for missed optimization opportunity.
1249 ASSERT(!canSkipLookup(exec, m_ident));
1250
1251 const ScopeChain& chain = exec->scopeChain();
1252 ScopeChainIterator iter = chain.begin();
1253 ScopeChainIterator end = chain.end();
1254
1255 // we must always have something in the scope chain
1256 ASSERT(iter != end);
1257
1258 PropertySlot slot;
1259 JSObject *base;
1260 do {
1261 base = *iter;
1262 if (base->getPropertySlot(exec, m_ident, slot)) {
1263 JSValue* v = slot.getValue(exec, base, m_ident)->toJSNumber(exec);
1264 base->put(exec, m_ident, jsNumber(v->toNumber(exec) + 1));
1265 return v;
1266 }
1267
1268 ++iter;
1269 } while (iter != end);
1270
1271 return throwUndefinedVariableError(exec, m_ident);
1272}
1273
1274void PostIncResolveNode::optimizeForUnnecessaryResult()
1275{
1276 new (this) PreIncResolveNode(PlacementNewAdopt);
1277}
1278
1279JSValue* PostIncLocalVarNode::evaluate(ExecState* exec)
1280{
1281 ASSERT(exec->variableObject() == exec->scopeChain().top());
1282
1283 JSValue** slot = &exec->localStorage()[m_index].value;
1284 JSValue* v = (*slot)->toJSNumber(exec);
1285 *slot = jsNumber(v->toNumber(exec) + 1);
1286 return v;
1287}
1288
1289void PostIncLocalVarNode::optimizeForUnnecessaryResult()
1290{
1291 new (this) PreIncLocalVarNode(m_index);
1292}
1293
1294
1295// Decrement
1296void PostDecResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
1297{
1298 size_t index = symbolTable.get(m_ident.ustring().rep());
1299 if (index != missingSymbolMarker())
1300 new (this) PostDecLocalVarNode(index);
1301}
1302
1303JSValue *PostDecResolveNode::evaluate(ExecState *exec)
1304{
1305 // Check for missed optimization opportunity.
1306 ASSERT(!canSkipLookup(exec, m_ident));
1307
1308 const ScopeChain& chain = exec->scopeChain();
1309 ScopeChainIterator iter = chain.begin();
1310 ScopeChainIterator end = chain.end();
1311
1312 // we must always have something in the scope chain
1313 ASSERT(iter != end);
1314
1315 PropertySlot slot;
1316 JSObject *base;
1317 do {
1318 base = *iter;
1319 if (base->getPropertySlot(exec, m_ident, slot)) {
1320 JSValue* v = slot.getValue(exec, base, m_ident)->toJSNumber(exec);
1321 base->put(exec, m_ident, jsNumber(v->toNumber(exec) - 1));
1322 return v;
1323 }
1324
1325 ++iter;
1326 } while (iter != end);
1327
1328 return throwUndefinedVariableError(exec, m_ident);
1329}
1330
1331void PostDecResolveNode::optimizeForUnnecessaryResult()
1332{
1333 new (this) PreDecResolveNode(PlacementNewAdopt);
1334}
1335
1336JSValue* PostDecLocalVarNode::evaluate(ExecState* exec)
1337{
1338 ASSERT(exec->variableObject() == exec->scopeChain().top());
1339
1340 JSValue** slot = &exec->localStorage()[m_index].value;
1341 JSValue* v = (*slot)->toJSNumber(exec);
1342 *slot = jsNumber(v->toNumber(exec) - 1);
1343 return v;
1344}
1345
1346double PostDecLocalVarNode::inlineEvaluateToNumber(ExecState* exec)
1347{
1348 ASSERT(exec->variableObject() == exec->scopeChain().top());
1349
1350 JSValue** slot = &exec->localStorage()[m_index].value;
1351 double n = (*slot)->toNumber(exec);
1352 *slot = jsNumber(n - 1);
1353 return n;
1354}
1355
1356double PostDecLocalVarNode::evaluateToNumber(ExecState* exec)
1357{
1358 return inlineEvaluateToNumber(exec);
1359}
1360
1361bool PostDecLocalVarNode::evaluateToBoolean(ExecState* exec)
1362{
1363 return inlineEvaluateToNumber(exec);
1364}
1365
1366int32_t PostDecLocalVarNode::evaluateToInt32(ExecState* exec)
1367{
1368 return JSValue::toInt32(inlineEvaluateToNumber(exec));
1369}
1370
1371uint32_t PostDecLocalVarNode::evaluateToUInt32(ExecState* exec)
1372{
1373 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
1374}
1375
1376void PostDecLocalVarNode::optimizeForUnnecessaryResult()
1377{
1378 new (this) PreDecLocalVarNode(m_index);
1379}
1380
1381// ------------------------------ PostfixBracketNode ----------------------------------
1382
1383void PostfixBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1384{
1385 nodeStack.append(m_subscript.get());
1386 nodeStack.append(m_base.get());
1387}
1388
1389JSValue *PostIncBracketNode::evaluate(ExecState *exec)
1390{
1391 JSValue *baseValue = m_base->evaluate(exec);
1392 KJS_CHECKEXCEPTIONVALUE
1393 JSValue *subscript = m_subscript->evaluate(exec);
1394 KJS_CHECKEXCEPTIONVALUE
1395
1396 JSObject *base = baseValue->toObject(exec);
1397
1398 uint32_t propertyIndex;
1399 if (subscript->getUInt32(propertyIndex)) {
1400 PropertySlot slot;
1401 JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1402 KJS_CHECKEXCEPTIONVALUE
1403
1404 JSValue* v2 = v->toJSNumber(exec);
1405 base->put(exec, propertyIndex, jsNumber(v2->toNumber(exec) + 1));
1406
1407 return v2;
1408 }
1409
1410 Identifier propertyName(subscript->toString(exec));
1411 PropertySlot slot;
1412 JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1413 KJS_CHECKEXCEPTIONVALUE
1414
1415 JSValue* v2 = v->toJSNumber(exec);
1416 base->put(exec, propertyName, jsNumber(v2->toNumber(exec) + 1));
1417 return v2;
1418}
1419
1420JSValue *PostDecBracketNode::evaluate(ExecState *exec)
1421{
1422 JSValue *baseValue = m_base->evaluate(exec);
1423 KJS_CHECKEXCEPTIONVALUE
1424 JSValue *subscript = m_subscript->evaluate(exec);
1425 KJS_CHECKEXCEPTIONVALUE
1426
1427 JSObject *base = baseValue->toObject(exec);
1428
1429 uint32_t propertyIndex;
1430 if (subscript->getUInt32(propertyIndex)) {
1431 PropertySlot slot;
1432 JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1433 KJS_CHECKEXCEPTIONVALUE
1434
1435 JSValue* v2 = v->toJSNumber(exec);
1436 base->put(exec, propertyIndex, jsNumber(v2->toNumber(exec) - 1));
1437 return v2;
1438 }
1439
1440 Identifier propertyName(subscript->toString(exec));
1441 PropertySlot slot;
1442 JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1443 KJS_CHECKEXCEPTIONVALUE
1444
1445 JSValue* v2 = v->toJSNumber(exec);
1446 base->put(exec, propertyName, jsNumber(v2->toNumber(exec) - 1));
1447 return v2;
1448}
1449
1450// ------------------------------ PostfixDotNode ----------------------------------
1451
1452void PostfixDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1453{
1454 nodeStack.append(m_base.get());
1455}
1456
1457JSValue *PostIncDotNode::evaluate(ExecState *exec)
1458{
1459 JSValue *baseValue = m_base->evaluate(exec);
1460 KJS_CHECKEXCEPTIONVALUE
1461 JSObject *base = baseValue->toObject(exec);
1462
1463 PropertySlot slot;
1464 JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1465 KJS_CHECKEXCEPTIONVALUE
1466
1467 JSValue* v2 = v->toJSNumber(exec);
1468 base->put(exec, m_ident, jsNumber(v2->toNumber(exec) + 1));
1469 return v2;
1470}
1471
1472JSValue *PostDecDotNode::evaluate(ExecState *exec)
1473{
1474 JSValue *baseValue = m_base->evaluate(exec);
1475 KJS_CHECKEXCEPTIONVALUE
1476 JSObject *base = baseValue->toObject(exec);
1477
1478 PropertySlot slot;
1479 JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1480 KJS_CHECKEXCEPTIONVALUE
1481
1482 JSValue* v2 = v->toJSNumber(exec);
1483 base->put(exec, m_ident, jsNumber(v2->toNumber(exec) - 1));
1484 return v2;
1485}
1486
1487// ------------------------------ PostfixErrorNode -----------------------------------
1488
1489JSValue* PostfixErrorNode::evaluate(ExecState* exec)
1490{
1491 throwError(exec, ReferenceError, "Postfix %s operator applied to value that is not a reference.",
1492 m_oper == OpPlusPlus ? "++" : "--");
1493 handleException(exec);
1494 return jsUndefined();
1495}
1496
1497// ------------------------------ DeleteResolveNode -----------------------------------
1498
1499void DeleteResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
1500{
1501 size_t index = symbolTable.get(m_ident.ustring().rep());
1502 if (index != missingSymbolMarker())
1503 new (this) LocalVarDeleteNode();
1504}
1505
1506// ECMA 11.4.1
1507
1508JSValue *DeleteResolveNode::evaluate(ExecState *exec)
1509{
1510 // Check for missed optimization opportunity.
1511 ASSERT(!canSkipLookup(exec, m_ident));
1512
1513 const ScopeChain& chain = exec->scopeChain();
1514 ScopeChainIterator iter = chain.begin();
1515 ScopeChainIterator end = chain.end();
1516
1517 // we must always have something in the scope chain
1518 ASSERT(iter != end);
1519
1520 PropertySlot slot;
1521 JSObject *base;
1522 do {
1523 base = *iter;
1524 if (base->getPropertySlot(exec, m_ident, slot)) {
1525 return jsBoolean(base->deleteProperty(exec, m_ident));
1526 }
1527
1528 ++iter;
1529 } while (iter != end);
1530
1531 return jsBoolean(true);
1532}
1533
1534JSValue* LocalVarDeleteNode::evaluate(ExecState*)
1535{
1536 return jsBoolean(false);
1537}
1538
1539// ------------------------------ DeleteBracketNode -----------------------------------
1540
1541void DeleteBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1542{
1543 nodeStack.append(m_subscript.get());
1544 nodeStack.append(m_base.get());
1545}
1546
1547JSValue *DeleteBracketNode::evaluate(ExecState *exec)
1548{
1549 JSValue *baseValue = m_base->evaluate(exec);
1550 KJS_CHECKEXCEPTIONVALUE
1551 JSValue *subscript = m_subscript->evaluate(exec);
1552 KJS_CHECKEXCEPTIONVALUE
1553
1554 JSObject *base = baseValue->toObject(exec);
1555
1556 uint32_t propertyIndex;
1557 if (subscript->getUInt32(propertyIndex))
1558 return jsBoolean(base->deleteProperty(exec, propertyIndex));
1559
1560 Identifier propertyName(subscript->toString(exec));
1561 return jsBoolean(base->deleteProperty(exec, propertyName));
1562}
1563
1564// ------------------------------ DeleteDotNode -----------------------------------
1565
1566void DeleteDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1567{
1568 nodeStack.append(m_base.get());
1569}
1570
1571JSValue *DeleteDotNode::evaluate(ExecState *exec)
1572{
1573 JSValue *baseValue = m_base->evaluate(exec);
1574 JSObject *base = baseValue->toObject(exec);
1575 KJS_CHECKEXCEPTIONVALUE
1576
1577 return jsBoolean(base->deleteProperty(exec, m_ident));
1578}
1579
1580// ------------------------------ DeleteValueNode -----------------------------------
1581
1582void DeleteValueNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1583{
1584 nodeStack.append(m_expr.get());
1585}
1586
1587JSValue *DeleteValueNode::evaluate(ExecState *exec)
1588{
1589 m_expr->evaluate(exec);
1590 KJS_CHECKEXCEPTIONVALUE
1591
1592 // delete on a non-location expression ignores the value and returns true
1593 return jsBoolean(true);
1594}
1595
1596// ------------------------------ VoidNode -------------------------------------
1597
1598void VoidNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1599{
1600 nodeStack.append(expr.get());
1601}
1602
1603// ECMA 11.4.2
1604JSValue *VoidNode::evaluate(ExecState *exec)
1605{
1606 expr->evaluate(exec);
1607 KJS_CHECKEXCEPTIONVALUE
1608
1609 return jsUndefined();
1610}
1611
1612// ECMA 11.4.3
1613
1614// ------------------------------ TypeOfValueNode -----------------------------------
1615
1616void TypeOfValueNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1617{
1618 nodeStack.append(m_expr.get());
1619}
1620
1621static JSValue *typeStringForValue(JSValue *v) KJS_FAST_CALL;
1622static JSValue *typeStringForValue(JSValue *v)
1623{
1624 switch (v->type()) {
1625 case UndefinedType:
1626 return jsString("undefined");
1627 case NullType:
1628 return jsString("object");
1629 case BooleanType:
1630 return jsString("boolean");
1631 case NumberType:
1632 return jsString("number");
1633 case StringType:
1634 return jsString("string");
1635 default:
1636 if (v->isObject()) {
1637 // Return "undefined" for objects that should be treated
1638 // as null when doing comparisons.
1639 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
1640 return jsString("undefined");
1641 else if (static_cast<JSObject*>(v)->implementsCall())
1642 return jsString("function");
1643 }
1644
1645 return jsString("object");
1646 }
1647}
1648
1649void TypeOfResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
1650{
1651 size_t index = symbolTable.get(m_ident.ustring().rep());
1652 if (index != missingSymbolMarker())
1653 new (this) LocalVarTypeOfNode(index);
1654}
1655
1656JSValue* LocalVarTypeOfNode::evaluate(ExecState* exec)
1657{
1658 ASSERT(exec->variableObject() == exec->scopeChain().top());
1659
1660 return typeStringForValue(exec->localStorage()[m_index].value);
1661}
1662
1663JSValue *TypeOfResolveNode::evaluate(ExecState *exec)
1664{
1665 const ScopeChain& chain = exec->scopeChain();
1666 ScopeChainIterator iter = chain.begin();
1667 ScopeChainIterator end = chain.end();
1668
1669 // we must always have something in the scope chain
1670 ASSERT(iter != end);
1671
1672 PropertySlot slot;
1673 JSObject *base;
1674 do {
1675 base = *iter;
1676 if (base->getPropertySlot(exec, m_ident, slot)) {
1677 JSValue *v = slot.getValue(exec, base, m_ident);
1678 return typeStringForValue(v);
1679 }
1680
1681 ++iter;
1682 } while (iter != end);
1683
1684 return jsString("undefined");
1685}
1686
1687// ------------------------------ TypeOfValueNode -----------------------------------
1688
1689JSValue *TypeOfValueNode::evaluate(ExecState *exec)
1690{
1691 JSValue *v = m_expr->evaluate(exec);
1692 KJS_CHECKEXCEPTIONVALUE
1693
1694 return typeStringForValue(v);
1695}
1696
1697// ECMA 11.4.4 and 11.4.5
1698
1699// ------------------------------ PrefixResolveNode ----------------------------------
1700
1701void PreIncResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
1702{
1703 size_t index = symbolTable.get(m_ident.ustring().rep());
1704 if (index != missingSymbolMarker())
1705 new (this) PreIncLocalVarNode(index);
1706}
1707
1708JSValue* PreIncLocalVarNode::evaluate(ExecState* exec)
1709{
1710 ASSERT(exec->variableObject() == exec->scopeChain().top());
1711 JSValue** slot = &exec->localStorage()[m_index].value;
1712
1713 double n = (*slot)->toNumber(exec);
1714 JSValue* n2 = jsNumber(n + 1);
1715 *slot = n2;
1716 return n2;
1717}
1718
1719JSValue *PreIncResolveNode::evaluate(ExecState *exec)
1720{
1721 const ScopeChain& chain = exec->scopeChain();
1722 ScopeChainIterator iter = chain.begin();
1723 ScopeChainIterator end = chain.end();
1724
1725 // we must always have something in the scope chain
1726 ASSERT(iter != end);
1727
1728 PropertySlot slot;
1729 JSObject *base;
1730 do {
1731 base = *iter;
1732 if (base->getPropertySlot(exec, m_ident, slot)) {
1733 JSValue *v = slot.getValue(exec, base, m_ident);
1734
1735 double n = v->toNumber(exec);
1736 JSValue *n2 = jsNumber(n + 1);
1737 base->put(exec, m_ident, n2);
1738
1739 return n2;
1740 }
1741
1742 ++iter;
1743 } while (iter != end);
1744
1745 return throwUndefinedVariableError(exec, m_ident);
1746}
1747
1748void PreDecResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack&)
1749{
1750 size_t index = symbolTable.get(m_ident.ustring().rep());
1751 if (index != missingSymbolMarker())
1752 new (this) PreDecLocalVarNode(index);
1753}
1754
1755JSValue* PreDecLocalVarNode::evaluate(ExecState* exec)
1756{
1757 ASSERT(exec->variableObject() == exec->scopeChain().top());
1758 JSValue** slot = &exec->localStorage()[m_index].value;
1759
1760 double n = (*slot)->toNumber(exec);
1761 JSValue* n2 = jsNumber(n - 1);
1762 *slot = n2;
1763 return n2;
1764}
1765
1766JSValue *PreDecResolveNode::evaluate(ExecState *exec)
1767{
1768 const ScopeChain& chain = exec->scopeChain();
1769 ScopeChainIterator iter = chain.begin();
1770 ScopeChainIterator end = chain.end();
1771
1772 // we must always have something in the scope chain
1773 ASSERT(iter != end);
1774
1775 PropertySlot slot;
1776 JSObject *base;
1777 do {
1778 base = *iter;
1779 if (base->getPropertySlot(exec, m_ident, slot)) {
1780 JSValue *v = slot.getValue(exec, base, m_ident);
1781
1782 double n = v->toNumber(exec);
1783 JSValue *n2 = jsNumber(n - 1);
1784 base->put(exec, m_ident, n2);
1785
1786 return n2;
1787 }
1788
1789 ++iter;
1790 } while (iter != end);
1791
1792 return throwUndefinedVariableError(exec, m_ident);
1793}
1794
1795// ------------------------------ PrefixBracketNode ----------------------------------
1796
1797void PrefixBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1798{
1799 nodeStack.append(m_subscript.get());
1800 nodeStack.append(m_base.get());
1801}
1802
1803JSValue *PreIncBracketNode::evaluate(ExecState *exec)
1804{
1805 JSValue *baseValue = m_base->evaluate(exec);
1806 KJS_CHECKEXCEPTIONVALUE
1807 JSValue *subscript = m_subscript->evaluate(exec);
1808 KJS_CHECKEXCEPTIONVALUE
1809
1810 JSObject *base = baseValue->toObject(exec);
1811
1812 uint32_t propertyIndex;
1813 if (subscript->getUInt32(propertyIndex)) {
1814 PropertySlot slot;
1815 JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1816 KJS_CHECKEXCEPTIONVALUE
1817
1818 JSValue *n2 = jsNumber(v->toNumber(exec) + 1);
1819 base->put(exec, propertyIndex, n2);
1820
1821 return n2;
1822 }
1823
1824 Identifier propertyName(subscript->toString(exec));
1825 PropertySlot slot;
1826 JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1827 KJS_CHECKEXCEPTIONVALUE
1828
1829 JSValue *n2 = jsNumber(v->toNumber(exec) + 1);
1830 base->put(exec, propertyName, n2);
1831
1832 return n2;
1833}
1834
1835JSValue *PreDecBracketNode::evaluate(ExecState *exec)
1836{
1837 JSValue *baseValue = m_base->evaluate(exec);
1838 KJS_CHECKEXCEPTIONVALUE
1839 JSValue *subscript = m_subscript->evaluate(exec);
1840 KJS_CHECKEXCEPTIONVALUE
1841
1842 JSObject *base = baseValue->toObject(exec);
1843
1844 uint32_t propertyIndex;
1845 if (subscript->getUInt32(propertyIndex)) {
1846 PropertySlot slot;
1847 JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1848 KJS_CHECKEXCEPTIONVALUE
1849
1850 JSValue *n2 = jsNumber(v->toNumber(exec) - 1);
1851 base->put(exec, propertyIndex, n2);
1852
1853 return n2;
1854 }
1855
1856 Identifier propertyName(subscript->toString(exec));
1857 PropertySlot slot;
1858 JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1859 KJS_CHECKEXCEPTIONVALUE
1860
1861 JSValue *n2 = jsNumber(v->toNumber(exec) - 1);
1862 base->put(exec, propertyName, n2);
1863
1864 return n2;
1865}
1866
1867// ------------------------------ PrefixDotNode ----------------------------------
1868
1869void PrefixDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1870{
1871 nodeStack.append(m_base.get());
1872}
1873
1874JSValue *PreIncDotNode::evaluate(ExecState *exec)
1875{
1876 JSValue *baseValue = m_base->evaluate(exec);
1877 KJS_CHECKEXCEPTIONVALUE
1878 JSObject *base = baseValue->toObject(exec);
1879
1880 PropertySlot slot;
1881 JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1882 KJS_CHECKEXCEPTIONVALUE
1883
1884 double n = v->toNumber(exec);
1885 JSValue *n2 = jsNumber(n + 1);
1886 base->put(exec, m_ident, n2);
1887
1888 return n2;
1889}
1890
1891JSValue *PreDecDotNode::evaluate(ExecState *exec)
1892{
1893 JSValue *baseValue = m_base->evaluate(exec);
1894 KJS_CHECKEXCEPTIONVALUE
1895 JSObject *base = baseValue->toObject(exec);
1896
1897 PropertySlot slot;
1898 JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1899 KJS_CHECKEXCEPTIONVALUE
1900
1901 double n = v->toNumber(exec);
1902 JSValue *n2 = jsNumber(n - 1);
1903 base->put(exec, m_ident, n2);
1904
1905 return n2;
1906}
1907
1908// ------------------------------ PrefixErrorNode -----------------------------------
1909
1910JSValue* PrefixErrorNode::evaluate(ExecState* exec)
1911{
1912 throwError(exec, ReferenceError, "Prefix %s operator applied to value that is not a reference.",
1913 m_oper == OpPlusPlus ? "++" : "--");
1914 handleException(exec);
1915 return jsUndefined();
1916}
1917
1918// ------------------------------ UnaryPlusNode --------------------------------
1919
1920void UnaryPlusNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1921{
1922 nodeStack.append(m_expr.get());
1923}
1924
1925// ECMA 11.4.6
1926JSValue* UnaryPlusNode::evaluate(ExecState* exec)
1927{
1928 JSValue *v = m_expr->evaluate(exec);
1929 KJS_CHECKEXCEPTIONVALUE
1930 return v->toJSNumber(exec);
1931}
1932
1933bool UnaryPlusNode::evaluateToBoolean(ExecState* exec)
1934{
1935 return m_expr->evaluateToBoolean(exec);
1936}
1937
1938double UnaryPlusNode::evaluateToNumber(ExecState* exec)
1939{
1940 return m_expr->evaluateToNumber(exec);
1941}
1942
1943int32_t UnaryPlusNode::evaluateToInt32(ExecState* exec)
1944{
1945 return m_expr->evaluateToInt32(exec);
1946}
1947
1948uint32_t UnaryPlusNode::evaluateToUInt32(ExecState* exec)
1949{
1950 return m_expr->evaluateToInt32(exec);
1951}
1952
1953// ------------------------------ NegateNode -----------------------------------
1954
1955void NegateNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1956{
1957 nodeStack.append(expr.get());
1958}
1959
1960// ECMA 11.4.7
1961JSValue *NegateNode::evaluate(ExecState *exec)
1962{
1963 // No need to check exception, caller will do so right after evaluate()
1964 return jsNumber(-expr->evaluateToNumber(exec));
1965}
1966
1967double NegateNode::evaluateToNumber(ExecState* exec)
1968{
1969 // No need to check exception, caller will do so right after evaluateToNumber()
1970 return -expr->evaluateToNumber(exec);
1971}
1972
1973// ------------------------------ BitwiseNotNode -------------------------------
1974
1975void BitwiseNotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
1976{
1977 nodeStack.append(expr.get());
1978}
1979
1980// ECMA 11.4.8
1981int32_t BitwiseNotNode::inlineEvaluateToInt32(ExecState* exec)
1982{
1983 return ~expr->evaluateToInt32(exec);
1984}
1985
1986JSValue* BitwiseNotNode::evaluate(ExecState* exec)
1987{
1988 return jsNumber(inlineEvaluateToInt32(exec));
1989}
1990
1991double BitwiseNotNode::evaluateToNumber(ExecState* exec)
1992{
1993 return inlineEvaluateToInt32(exec);
1994}
1995
1996bool BitwiseNotNode::evaluateToBoolean(ExecState* exec)
1997{
1998 return inlineEvaluateToInt32(exec);
1999}
2000
2001int32_t BitwiseNotNode::evaluateToInt32(ExecState* exec)
2002{
2003 return inlineEvaluateToInt32(exec);
2004}
2005
2006uint32_t BitwiseNotNode::evaluateToUInt32(ExecState* exec)
2007{
2008 return inlineEvaluateToInt32(exec);
2009}
2010
2011// ------------------------------ LogicalNotNode -------------------------------
2012
2013void LogicalNotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2014{
2015 nodeStack.append(expr.get());
2016}
2017
2018// ECMA 11.4.9
2019JSValue* LogicalNotNode::evaluate(ExecState* exec)
2020{
2021 return jsBoolean(!expr->evaluateToBoolean(exec));
2022}
2023
2024bool LogicalNotNode::evaluateToBoolean(ExecState* exec)
2025{
2026 return !expr->evaluateToBoolean(exec);
2027}
2028
2029// ------------------------------ Multiplicative Nodes -----------------------------------
2030
2031void MultNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2032{
2033 nodeStack.append(term1.get());
2034 nodeStack.append(term2.get());
2035}
2036
2037// ECMA 11.5.1
2038double MultNode::inlineEvaluateToNumber(ExecState* exec)
2039{
2040 double n1 = term1->evaluateToNumber(exec);
2041 KJS_CHECKEXCEPTIONNUMBER
2042 double n2 = term2->evaluateToNumber(exec);
2043 return n1 * n2;
2044}
2045
2046JSValue *MultNode::evaluate(ExecState* exec)
2047{
2048 return jsNumber(inlineEvaluateToNumber(exec));
2049}
2050
2051double MultNode::evaluateToNumber(ExecState* exec)
2052{
2053 return inlineEvaluateToNumber(exec);
2054}
2055
2056bool MultNode::evaluateToBoolean(ExecState* exec)
2057{
2058 return inlineEvaluateToNumber(exec);
2059}
2060
2061int32_t MultNode::evaluateToInt32(ExecState* exec)
2062{
2063 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2064}
2065
2066uint32_t MultNode::evaluateToUInt32(ExecState* exec)
2067{
2068 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2069}
2070
2071void DivNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2072{
2073 nodeStack.append(term1.get());
2074 nodeStack.append(term2.get());
2075}
2076
2077// ECMA 11.5.2
2078double DivNode::inlineEvaluateToNumber(ExecState* exec)
2079{
2080 double n1 = term1->evaluateToNumber(exec);
2081 KJS_CHECKEXCEPTIONNUMBER
2082 double n2 = term2->evaluateToNumber(exec);
2083 return n1 / n2;
2084}
2085
2086JSValue* DivNode::evaluate(ExecState* exec)
2087{
2088 return jsNumber(inlineEvaluateToNumber(exec));
2089}
2090
2091double DivNode::evaluateToNumber(ExecState* exec)
2092{
2093 return inlineEvaluateToNumber(exec);
2094}
2095
2096int32_t DivNode::evaluateToInt32(ExecState* exec)
2097{
2098 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2099}
2100
2101uint32_t DivNode::evaluateToUInt32(ExecState* exec)
2102{
2103 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2104}
2105
2106void ModNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2107{
2108 nodeStack.append(term1.get());
2109 nodeStack.append(term2.get());
2110}
2111
2112// ECMA 11.5.3
2113double ModNode::inlineEvaluateToNumber(ExecState* exec)
2114{
2115 double n1 = term1->evaluateToNumber(exec);
2116 KJS_CHECKEXCEPTIONNUMBER
2117 double n2 = term2->evaluateToNumber(exec);
2118 return fmod(n1, n2);
2119}
2120
2121JSValue* ModNode::evaluate(ExecState* exec)
2122{
2123 return jsNumber(inlineEvaluateToNumber(exec));
2124}
2125
2126double ModNode::evaluateToNumber(ExecState* exec)
2127{
2128 return inlineEvaluateToNumber(exec);
2129}
2130
2131bool ModNode::evaluateToBoolean(ExecState* exec)
2132{
2133 return inlineEvaluateToNumber(exec);
2134}
2135
2136int32_t ModNode::evaluateToInt32(ExecState* exec)
2137{
2138 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2139}
2140
2141uint32_t ModNode::evaluateToUInt32(ExecState* exec)
2142{
2143 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2144}
2145
2146// ------------------------------ Additive Nodes --------------------------------------
2147
2148static JSValue* throwOutOfMemoryError(ExecState* exec)
2149{
2150 JSObject* error = Error::create(exec, GeneralError, "Out of memory");
2151 exec->setException(error);
2152 return error;
2153}
2154
2155static double throwOutOfMemoryErrorToNumber(ExecState* exec)
2156{
2157 JSObject* error = Error::create(exec, GeneralError, "Out of memory");
2158 exec->setException(error);
2159 return 0.0;
2160}
2161
2162// ECMA 11.6
2163static JSValue* addSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
2164{
2165 // exception for the Date exception in defaultValue()
2166 JSValue *p1 = v1->toPrimitive(exec, UnspecifiedType);
2167 JSValue *p2 = v2->toPrimitive(exec, UnspecifiedType);
2168
2169 if (p1->isString() || p2->isString()) {
2170 UString value = p1->toString(exec) + p2->toString(exec);
2171 if (value.isNull())
2172 return throwOutOfMemoryError(exec);
2173 return jsString(value);
2174 }
2175
2176 return jsNumber(p1->toNumber(exec) + p2->toNumber(exec));
2177}
2178
2179static double addSlowCaseToNumber(ExecState* exec, JSValue* v1, JSValue* v2)
2180{
2181 // exception for the Date exception in defaultValue()
2182 JSValue *p1 = v1->toPrimitive(exec, UnspecifiedType);
2183 JSValue *p2 = v2->toPrimitive(exec, UnspecifiedType);
2184
2185 if (p1->isString() || p2->isString()) {
2186 UString value = p1->toString(exec) + p2->toString(exec);
2187 if (value.isNull())
2188 return throwOutOfMemoryErrorToNumber(exec);
2189 return value.toDouble();
2190 }
2191
2192 return p1->toNumber(exec) + p2->toNumber(exec);
2193}
2194
2195// Fast-path choices here are based on frequency data from SunSpider:
2196// <times> Add case: <t1> <t2>
2197// ---------------------------
2198// 5627160 Add case: 1 1
2199// 247427 Add case: 5 5
2200// 20901 Add case: 5 6
2201// 13978 Add case: 5 1
2202// 4000 Add case: 1 5
2203// 1 Add case: 3 5
2204
2205static inline JSValue* add(ExecState* exec, JSValue* v1, JSValue *v2)
2206{
2207 JSType t1 = v1->type();
2208 JSType t2 = v2->type();
2209 const unsigned bothTypes = (t1 << 3) | t2;
2210
2211 if (bothTypes == ((NumberType << 3) | NumberType))
2212 return jsNumber(v1->toNumber(exec) + v2->toNumber(exec));
2213 if (bothTypes == ((StringType << 3) | StringType)) {
2214 UString value = static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value();
2215 if (value.isNull())
2216 return throwOutOfMemoryError(exec);
2217 return jsString(value);
2218 }
2219
2220 // All other cases are pretty uncommon
2221 return addSlowCase(exec, v1, v2);
2222}
2223
2224static inline double addToNumber(ExecState* exec, JSValue* v1, JSValue *v2)
2225{
2226 JSType t1 = v1->type();
2227 JSType t2 = v2->type();
2228 const unsigned bothTypes = (t1 << 3) | t2;
2229
2230 if (bothTypes == ((NumberType << 3) | NumberType))
2231 return v1->toNumber(exec) + v2->toNumber(exec);
2232 if (bothTypes == ((StringType << 3) | StringType)) {
2233 UString value = static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value();
2234 if (value.isNull())
2235 return throwOutOfMemoryErrorToNumber(exec);
2236 return value.toDouble();
2237 }
2238
2239 // All other cases are pretty uncommon
2240 return addSlowCaseToNumber(exec, v1, v2);
2241}
2242
2243void AddNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2244{
2245 nodeStack.append(term1.get());
2246 nodeStack.append(term2.get());
2247}
2248
2249// ECMA 11.6.1
2250JSValue* AddNode::evaluate(ExecState* exec)
2251{
2252 JSValue* v1 = term1->evaluate(exec);
2253 KJS_CHECKEXCEPTIONVALUE
2254
2255 JSValue* v2 = term2->evaluate(exec);
2256 KJS_CHECKEXCEPTIONVALUE
2257
2258 return add(exec, v1, v2);
2259}
2260
2261double AddNode::inlineEvaluateToNumber(ExecState* exec)
2262{
2263 JSValue* v1 = term1->evaluate(exec);
2264 KJS_CHECKEXCEPTIONNUMBER
2265
2266 JSValue* v2 = term2->evaluate(exec);
2267 KJS_CHECKEXCEPTIONNUMBER
2268
2269 return addToNumber(exec, v1, v2);
2270}
2271
2272double AddNode::evaluateToNumber(ExecState* exec)
2273{
2274 return inlineEvaluateToNumber(exec);
2275}
2276
2277int32_t AddNode::evaluateToInt32(ExecState* exec)
2278{
2279 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2280}
2281
2282uint32_t AddNode::evaluateToUInt32(ExecState* exec)
2283{
2284 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2285}
2286
2287double AddNumbersNode::inlineEvaluateToNumber(ExecState* exec)
2288{
2289 double n1 = term1->evaluateToNumber(exec);
2290 KJS_CHECKEXCEPTIONNUMBER
2291 double n2 = term2->evaluateToNumber(exec);
2292 return n1 + n2;
2293}
2294
2295JSValue* AddNumbersNode::evaluate(ExecState* exec)
2296{
2297 return jsNumber(inlineEvaluateToNumber(exec));
2298}
2299
2300double AddNumbersNode::evaluateToNumber(ExecState* exec)
2301{
2302 return inlineEvaluateToNumber(exec);
2303}
2304
2305int32_t AddNumbersNode::evaluateToInt32(ExecState* exec)
2306{
2307 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2308}
2309
2310uint32_t AddNumbersNode::evaluateToUInt32(ExecState* exec)
2311{
2312 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2313}
2314
2315JSValue* AddStringsNode::evaluate(ExecState* exec)
2316{
2317 JSValue* v1 = term1->evaluate(exec);
2318 KJS_CHECKEXCEPTIONVALUE
2319
2320 JSValue* v2 = term2->evaluate(exec);
2321 KJS_CHECKEXCEPTIONVALUE
2322
2323 return jsString(static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value());
2324}
2325
2326JSValue* AddStringLeftNode::evaluate(ExecState* exec)
2327{
2328 JSValue* v1 = term1->evaluate(exec);
2329 KJS_CHECKEXCEPTIONVALUE
2330
2331 JSValue* v2 = term2->evaluate(exec);
2332 KJS_CHECKEXCEPTIONVALUE
2333
2334 JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
2335 return jsString(static_cast<StringImp*>(v1)->value() + p2->toString(exec));
2336}
2337
2338JSValue* AddStringRightNode::evaluate(ExecState* exec)
2339{
2340 JSValue* v1 = term1->evaluate(exec);
2341 KJS_CHECKEXCEPTIONVALUE
2342
2343 JSValue* v2 = term2->evaluate(exec);
2344 KJS_CHECKEXCEPTIONVALUE
2345
2346 JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
2347 return jsString(p1->toString(exec) + static_cast<StringImp*>(v2)->value());
2348}
2349
2350void SubNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2351{
2352 nodeStack.append(term1.get());
2353 nodeStack.append(term2.get());
2354}
2355
2356// ECMA 11.6.2
2357double SubNode::inlineEvaluateToNumber(ExecState* exec)
2358{
2359 double n1 = term1->evaluateToNumber(exec);
2360 KJS_CHECKEXCEPTIONNUMBER
2361 double n2 = term2->evaluateToNumber(exec);
2362 return n1 - n2;
2363}
2364
2365JSValue* SubNode::evaluate(ExecState* exec)
2366{
2367 return jsNumber(inlineEvaluateToNumber(exec));
2368}
2369
2370double SubNode::evaluateToNumber(ExecState* exec)
2371{
2372 return inlineEvaluateToNumber(exec);
2373}
2374
2375int32_t SubNode::evaluateToInt32(ExecState* exec)
2376{
2377 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2378}
2379
2380uint32_t SubNode::evaluateToUInt32(ExecState* exec)
2381{
2382 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2383}
2384
2385// ------------------------------ Shift Nodes ------------------------------------
2386
2387void LeftShiftNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2388{
2389 nodeStack.append(term1.get());
2390 nodeStack.append(term2.get());
2391}
2392
2393// ECMA 11.7.1
2394int32_t LeftShiftNode::inlineEvaluateToInt32(ExecState* exec)
2395{
2396 int i1 = term1->evaluateToInt32(exec);
2397 KJS_CHECKEXCEPTIONNUMBER
2398 unsigned int i2 = term2->evaluateToUInt32(exec) & 0x1f;
2399 return (i1 << i2);
2400}
2401
2402JSValue* LeftShiftNode::evaluate(ExecState* exec)
2403{
2404 return jsNumber(inlineEvaluateToInt32(exec));
2405}
2406
2407double LeftShiftNode::evaluateToNumber(ExecState* exec)
2408{
2409 return inlineEvaluateToInt32(exec);
2410}
2411
2412int32_t LeftShiftNode::evaluateToInt32(ExecState* exec)
2413{
2414 return inlineEvaluateToInt32(exec);
2415}
2416
2417uint32_t LeftShiftNode::evaluateToUInt32(ExecState* exec)
2418{
2419 return inlineEvaluateToInt32(exec);
2420}
2421
2422void RightShiftNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2423{
2424 nodeStack.append(term1.get());
2425 nodeStack.append(term2.get());
2426}
2427
2428// ECMA 11.7.2
2429int32_t RightShiftNode::inlineEvaluateToInt32(ExecState* exec)
2430{
2431 int i1 = term1->evaluateToInt32(exec);
2432 KJS_CHECKEXCEPTIONNUMBER
2433 unsigned int i2 = term2->evaluateToUInt32(exec) & 0x1f;
2434 return (i1 >> i2);
2435}
2436
2437JSValue* RightShiftNode::evaluate(ExecState* exec)
2438{
2439 return jsNumber(inlineEvaluateToInt32(exec));
2440}
2441
2442double RightShiftNode::evaluateToNumber(ExecState* exec)
2443{
2444 return inlineEvaluateToInt32(exec);
2445}
2446
2447int32_t RightShiftNode::evaluateToInt32(ExecState* exec)
2448{
2449 return inlineEvaluateToInt32(exec);
2450}
2451
2452uint32_t RightShiftNode::evaluateToUInt32(ExecState* exec)
2453{
2454 return inlineEvaluateToInt32(exec);
2455}
2456
2457void UnsignedRightShiftNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2458{
2459 nodeStack.append(term1.get());
2460 nodeStack.append(term2.get());
2461}
2462
2463// ECMA 11.7.3
2464uint32_t UnsignedRightShiftNode::inlineEvaluateToUInt32(ExecState* exec)
2465{
2466 unsigned int i1 = term1->evaluateToUInt32(exec);
2467 KJS_CHECKEXCEPTIONNUMBER
2468 unsigned int i2 = term2->evaluateToUInt32(exec) & 0x1f;
2469 return (i1 >> i2);
2470}
2471
2472JSValue* UnsignedRightShiftNode::evaluate(ExecState* exec)
2473{
2474 return jsNumber(inlineEvaluateToUInt32(exec));
2475}
2476
2477double UnsignedRightShiftNode::evaluateToNumber(ExecState* exec)
2478{
2479 return inlineEvaluateToUInt32(exec);
2480}
2481
2482int32_t UnsignedRightShiftNode::evaluateToInt32(ExecState* exec)
2483{
2484 return inlineEvaluateToUInt32(exec);
2485}
2486
2487uint32_t UnsignedRightShiftNode::evaluateToUInt32(ExecState* exec)
2488{
2489 return inlineEvaluateToUInt32(exec);
2490}
2491
2492// ------------------------------ Relational Nodes -------------------------------
2493
2494static inline bool lessThan(ExecState *exec, JSValue* v1, JSValue* v2)
2495{
2496 double n1;
2497 double n2;
2498 JSValue* p1;
2499 JSValue* p2;
2500 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
2501 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
2502
2503 if (wasNotString1 | wasNotString2)
2504 return n1 < n2;
2505
2506 return static_cast<const StringImp*>(p1)->value() < static_cast<const StringImp*>(p2)->value();
2507}
2508
2509static inline bool lessThanEq(ExecState *exec, JSValue* v1, JSValue* v2)
2510{
2511 double n1;
2512 double n2;
2513 JSValue* p1;
2514 JSValue* p2;
2515 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
2516 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
2517
2518 if (wasNotString1 | wasNotString2)
2519 return n1 <= n2;
2520
2521 return !(static_cast<const StringImp*>(p2)->value() < static_cast<const StringImp*>(p1)->value());
2522}
2523
2524void LessNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2525{
2526 nodeStack.append(expr2.get());
2527 nodeStack.append(expr1.get());
2528}
2529
2530// ECMA 11.8.1
2531bool LessNode::inlineEvaluateToBoolean(ExecState* exec)
2532{
2533 JSValue* v1 = expr1->evaluate(exec);
2534 KJS_CHECKEXCEPTIONBOOLEAN
2535 JSValue* v2 = expr2->evaluate(exec);
2536 KJS_CHECKEXCEPTIONBOOLEAN
2537 return lessThan(exec, v1, v2);
2538}
2539
2540JSValue* LessNode::evaluate(ExecState* exec)
2541{
2542 return jsBoolean(inlineEvaluateToBoolean(exec));
2543}
2544
2545bool LessNode::evaluateToBoolean(ExecState* exec)
2546{
2547 return inlineEvaluateToBoolean(exec);
2548}
2549
2550bool LessNumbersNode::inlineEvaluateToBoolean(ExecState* exec)
2551{
2552 double n1 = expr1->evaluateToNumber(exec);
2553 KJS_CHECKEXCEPTIONVALUE
2554 double n2 = expr2->evaluateToNumber(exec);
2555 return n1 < n2;
2556}
2557
2558JSValue* LessNumbersNode::evaluate(ExecState* exec)
2559{
2560 return jsBoolean(inlineEvaluateToBoolean(exec));
2561}
2562
2563bool LessNumbersNode::evaluateToBoolean(ExecState* exec)
2564{
2565 return inlineEvaluateToBoolean(exec);
2566}
2567
2568bool LessStringsNode::inlineEvaluateToBoolean(ExecState* exec)
2569{
2570 JSValue* v1 = expr1->evaluate(exec);
2571 KJS_CHECKEXCEPTIONVALUE
2572 JSValue* v2 = expr2->evaluate(exec);
2573 return static_cast<StringImp*>(v1)->value() < static_cast<StringImp*>(v2)->value();
2574}
2575
2576JSValue* LessStringsNode::evaluate(ExecState* exec)
2577{
2578 return jsBoolean(inlineEvaluateToBoolean(exec));
2579}
2580
2581bool LessStringsNode::evaluateToBoolean(ExecState* exec)
2582{
2583 return inlineEvaluateToBoolean(exec);
2584}
2585
2586void GreaterNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2587{
2588 nodeStack.append(expr2.get());
2589 nodeStack.append(expr1.get());
2590}
2591
2592// ECMA 11.8.2
2593bool GreaterNode::inlineEvaluateToBoolean(ExecState *exec)
2594{
2595 JSValue* v1 = expr1->evaluate(exec);
2596 KJS_CHECKEXCEPTIONBOOLEAN
2597 JSValue* v2 = expr2->evaluate(exec);
2598 KJS_CHECKEXCEPTIONBOOLEAN
2599 return lessThan(exec, v2, v1);
2600}
2601
2602JSValue* GreaterNode::evaluate(ExecState* exec)
2603{
2604 return jsBoolean(inlineEvaluateToBoolean(exec));
2605}
2606
2607bool GreaterNode::evaluateToBoolean(ExecState *exec)
2608{
2609 return inlineEvaluateToBoolean(exec);
2610}
2611
2612void LessEqNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2613{
2614 nodeStack.append(expr2.get());
2615 nodeStack.append(expr1.get());
2616}
2617
2618// ECMA 11.8.3
2619bool LessEqNode::inlineEvaluateToBoolean(ExecState* exec)
2620{
2621 JSValue* v1 = expr1->evaluate(exec);
2622 KJS_CHECKEXCEPTIONBOOLEAN
2623 JSValue* v2 = expr2->evaluate(exec);
2624 KJS_CHECKEXCEPTIONBOOLEAN
2625 return lessThanEq(exec, v1, v2);
2626}
2627
2628JSValue* LessEqNode::evaluate(ExecState* exec)
2629{
2630 return jsBoolean(inlineEvaluateToBoolean(exec));
2631}
2632
2633bool LessEqNode::evaluateToBoolean(ExecState* exec)
2634{
2635 return inlineEvaluateToBoolean(exec);
2636}
2637
2638void GreaterEqNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2639{
2640 nodeStack.append(expr2.get());
2641 nodeStack.append(expr1.get());
2642}
2643
2644// ECMA 11.8.4
2645bool GreaterEqNode::inlineEvaluateToBoolean(ExecState* exec)
2646{
2647 JSValue* v1 = expr1->evaluate(exec);
2648 KJS_CHECKEXCEPTIONBOOLEAN
2649 JSValue* v2 = expr2->evaluate(exec);
2650 KJS_CHECKEXCEPTIONBOOLEAN
2651 return lessThanEq(exec, v2, v1);
2652}
2653
2654JSValue* GreaterEqNode::evaluate(ExecState* exec)
2655{
2656 return jsBoolean(inlineEvaluateToBoolean(exec));
2657}
2658
2659bool GreaterEqNode::evaluateToBoolean(ExecState* exec)
2660{
2661 return inlineEvaluateToBoolean(exec);
2662}
2663
2664void InstanceOfNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2665{
2666 nodeStack.append(expr2.get());
2667 nodeStack.append(expr1.get());
2668}
2669
2670// ECMA 11.8.6
2671JSValue* InstanceOfNode::evaluate(ExecState* exec)
2672{
2673 JSValue* v1 = expr1->evaluate(exec);
2674 KJS_CHECKEXCEPTIONVALUE
2675 JSValue* v2 = expr2->evaluate(exec);
2676 KJS_CHECKEXCEPTIONVALUE
2677
2678 if (!v2->isObject())
2679 return throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with instanceof operator.", v2, expr2.get());
2680
2681 JSObject* o2 = static_cast<JSObject*>(v2);
2682
2683 // According to the spec, only some types of objects "implement" the [[HasInstance]] property.
2684 // But we are supposed to throw an exception where the object does not "have" the [[HasInstance]]
2685 // property. It seems that all objects have the property, but not all implement it, so in this
2686 // case we return false (consistent with Mozilla).
2687 if (!o2->implementsHasInstance())
2688 return jsBoolean(false);
2689
2690 return jsBoolean(o2->hasInstance(exec, v1));
2691}
2692
2693bool InstanceOfNode::evaluateToBoolean(ExecState* exec)
2694{
2695 JSValue* v1 = expr1->evaluate(exec);
2696 KJS_CHECKEXCEPTIONBOOLEAN
2697 JSValue* v2 = expr2->evaluate(exec);
2698 KJS_CHECKEXCEPTIONBOOLEAN
2699
2700 if (!v2->isObject()) {
2701 throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with 'instanceof' operator.", v2, expr2.get());
2702 return false;
2703 }
2704
2705 JSObject* o2 = static_cast<JSObject*>(v2);
2706
2707 // According to the spec, only some types of objects "implement" the [[HasInstance]] property.
2708 // But we are supposed to throw an exception where the object does not "have" the [[HasInstance]]
2709 // property. It seems that all objects have the property, but not all implement it, so in this
2710 // case we return false (consistent with Mozilla).
2711 if (!o2->implementsHasInstance())
2712 return false;
2713
2714 return o2->hasInstance(exec, v1);
2715}
2716
2717void InNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2718{
2719 nodeStack.append(expr2.get());
2720 nodeStack.append(expr1.get());
2721}
2722
2723// ECMA 11.8.7
2724JSValue* InNode::evaluate(ExecState *exec)
2725{
2726 JSValue* v1 = expr1->evaluate(exec);
2727 KJS_CHECKEXCEPTIONVALUE
2728 JSValue* v2 = expr2->evaluate(exec);
2729 KJS_CHECKEXCEPTIONVALUE
2730
2731 if (!v2->isObject())
2732 return throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with 'in' operator.", v2, expr2.get());
2733
2734 return jsBoolean(static_cast<JSObject*>(v2)->hasProperty(exec, Identifier(v1->toString(exec))));
2735}
2736
2737bool InNode::evaluateToBoolean(ExecState *exec)
2738{
2739 JSValue* v1 = expr1->evaluate(exec);
2740 KJS_CHECKEXCEPTIONBOOLEAN
2741 JSValue* v2 = expr2->evaluate(exec);
2742 KJS_CHECKEXCEPTIONBOOLEAN
2743
2744 if (!v2->isObject()) {
2745 throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with 'in' operator.", v2, expr2.get());
2746 return false;
2747 }
2748
2749 return static_cast<JSObject*>(v2)->hasProperty(exec, Identifier(v1->toString(exec)));
2750}
2751
2752// ------------------------------ Equality Nodes ------------------------------------
2753
2754void EqualNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2755{
2756 nodeStack.append(expr2.get());
2757 nodeStack.append(expr1.get());
2758}
2759
2760// ECMA 11.9.1
2761bool EqualNode::inlineEvaluateToBoolean(ExecState* exec)
2762{
2763 JSValue* v1 = expr1->evaluate(exec);
2764 KJS_CHECKEXCEPTIONBOOLEAN
2765 JSValue* v2 = expr2->evaluate(exec);
2766 KJS_CHECKEXCEPTIONBOOLEAN
2767
2768 return equal(exec, v1, v2);
2769}
2770
2771JSValue* EqualNode::evaluate(ExecState* exec)
2772{
2773 return jsBoolean(inlineEvaluateToBoolean(exec));
2774}
2775
2776bool EqualNode::evaluateToBoolean(ExecState* exec)
2777{
2778 return inlineEvaluateToBoolean(exec);
2779}
2780
2781void NotEqualNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2782{
2783 nodeStack.append(expr2.get());
2784 nodeStack.append(expr1.get());
2785}
2786
2787// ECMA 11.9.2
2788bool NotEqualNode::inlineEvaluateToBoolean(ExecState* exec)
2789{
2790 JSValue* v1 = expr1->evaluate(exec);
2791 KJS_CHECKEXCEPTIONBOOLEAN
2792 JSValue* v2 = expr2->evaluate(exec);
2793 KJS_CHECKEXCEPTIONBOOLEAN
2794
2795 return !equal(exec,v1, v2);
2796}
2797
2798JSValue* NotEqualNode::evaluate(ExecState* exec)
2799{
2800 return jsBoolean(inlineEvaluateToBoolean(exec));
2801}
2802
2803bool NotEqualNode::evaluateToBoolean(ExecState* exec)
2804{
2805 return inlineEvaluateToBoolean(exec);
2806}
2807
2808void StrictEqualNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2809{
2810 nodeStack.append(expr2.get());
2811 nodeStack.append(expr1.get());
2812}
2813
2814// ECMA 11.9.4
2815bool StrictEqualNode::inlineEvaluateToBoolean(ExecState* exec)
2816{
2817 JSValue* v1 = expr1->evaluate(exec);
2818 KJS_CHECKEXCEPTIONBOOLEAN
2819 JSValue* v2 = expr2->evaluate(exec);
2820 KJS_CHECKEXCEPTIONBOOLEAN
2821
2822 return strictEqual(exec,v1, v2);
2823}
2824
2825JSValue* StrictEqualNode::evaluate(ExecState* exec)
2826{
2827 return jsBoolean(inlineEvaluateToBoolean(exec));
2828}
2829
2830bool StrictEqualNode::evaluateToBoolean(ExecState* exec)
2831{
2832 return inlineEvaluateToBoolean(exec);
2833}
2834
2835void NotStrictEqualNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2836{
2837 nodeStack.append(expr2.get());
2838 nodeStack.append(expr1.get());
2839}
2840
2841// ECMA 11.9.5
2842bool NotStrictEqualNode::inlineEvaluateToBoolean(ExecState* exec)
2843{
2844 JSValue* v1 = expr1->evaluate(exec);
2845 KJS_CHECKEXCEPTIONBOOLEAN
2846 JSValue* v2 = expr2->evaluate(exec);
2847 KJS_CHECKEXCEPTIONBOOLEAN
2848
2849 return !strictEqual(exec,v1, v2);
2850}
2851
2852JSValue* NotStrictEqualNode::evaluate(ExecState* exec)
2853{
2854 return jsBoolean(inlineEvaluateToBoolean(exec));
2855}
2856
2857bool NotStrictEqualNode::evaluateToBoolean(ExecState* exec)
2858{
2859 return inlineEvaluateToBoolean(exec);
2860}
2861
2862// ------------------------------ Bit Operation Nodes ----------------------------------
2863
2864void BitAndNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2865{
2866 nodeStack.append(expr2.get());
2867 nodeStack.append(expr1.get());
2868}
2869
2870// ECMA 11.10
2871JSValue* BitAndNode::evaluate(ExecState* exec)
2872{
2873 JSValue *v1 = expr1->evaluate(exec);
2874 KJS_CHECKEXCEPTIONVALUE
2875 JSValue *v2 = expr2->evaluate(exec);
2876 KJS_CHECKEXCEPTIONVALUE
2877
2878 return jsNumberFromAnd(exec, v1, v2);
2879}
2880
2881int32_t BitAndNode::inlineEvaluateToInt32(ExecState* exec)
2882{
2883 int32_t i1 = expr1->evaluateToInt32(exec);
2884 KJS_CHECKEXCEPTIONNUMBER
2885 int32_t i2 = expr2->evaluateToInt32(exec);
2886 return (i1 & i2);
2887}
2888
2889double BitAndNode::evaluateToNumber(ExecState* exec)
2890{
2891 return inlineEvaluateToInt32(exec);
2892}
2893
2894bool BitAndNode::evaluateToBoolean(ExecState* exec)
2895{
2896 return inlineEvaluateToInt32(exec);
2897}
2898
2899int32_t BitAndNode::evaluateToInt32(ExecState* exec)
2900{
2901 return inlineEvaluateToInt32(exec);
2902}
2903
2904uint32_t BitAndNode::evaluateToUInt32(ExecState* exec)
2905{
2906 return inlineEvaluateToInt32(exec);
2907}
2908
2909void BitXOrNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2910{
2911 nodeStack.append(expr2.get());
2912 nodeStack.append(expr1.get());
2913}
2914
2915int32_t BitXOrNode::inlineEvaluateToInt32(ExecState* exec)
2916{
2917 int i1 = expr1->evaluateToInt32(exec);
2918 KJS_CHECKEXCEPTIONNUMBER
2919 int i2 = expr2->evaluateToInt32(exec);
2920 return (i1 ^ i2);
2921}
2922
2923JSValue* BitXOrNode::evaluate(ExecState* exec)
2924{
2925 return jsNumber(inlineEvaluateToInt32(exec));
2926}
2927
2928double BitXOrNode::evaluateToNumber(ExecState* exec)
2929{
2930 return inlineEvaluateToInt32(exec);
2931}
2932
2933bool BitXOrNode::evaluateToBoolean(ExecState* exec)
2934{
2935 return inlineEvaluateToInt32(exec);
2936}
2937
2938int32_t BitXOrNode::evaluateToInt32(ExecState* exec)
2939{
2940 return inlineEvaluateToInt32(exec);
2941}
2942
2943uint32_t BitXOrNode::evaluateToUInt32(ExecState* exec)
2944{
2945 return inlineEvaluateToInt32(exec);
2946}
2947
2948void BitOrNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2949{
2950 nodeStack.append(expr2.get());
2951 nodeStack.append(expr1.get());
2952}
2953
2954int32_t BitOrNode::inlineEvaluateToInt32(ExecState* exec)
2955{
2956 int i1 = expr1->evaluateToInt32(exec);
2957 KJS_CHECKEXCEPTIONNUMBER
2958 int i2 = expr2->evaluateToInt32(exec);
2959 return (i1 | i2);
2960}
2961
2962JSValue* BitOrNode::evaluate(ExecState* exec)
2963{
2964 return jsNumber(inlineEvaluateToInt32(exec));
2965}
2966
2967double BitOrNode::evaluateToNumber(ExecState* exec)
2968{
2969 return inlineEvaluateToInt32(exec);
2970}
2971
2972bool BitOrNode::evaluateToBoolean(ExecState* exec)
2973{
2974 return inlineEvaluateToInt32(exec);
2975}
2976
2977int32_t BitOrNode::evaluateToInt32(ExecState* exec)
2978{
2979 return inlineEvaluateToInt32(exec);
2980}
2981
2982uint32_t BitOrNode::evaluateToUInt32(ExecState* exec)
2983{
2984 return inlineEvaluateToInt32(exec);
2985}
2986
2987// ------------------------------ Binary Logical Nodes ----------------------------
2988
2989void LogicalAndNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
2990{
2991 nodeStack.append(expr2.get());
2992 nodeStack.append(expr1.get());
2993}
2994
2995// ECMA 11.11
2996JSValue* LogicalAndNode::evaluate(ExecState* exec)
2997{
2998 JSValue* v1 = expr1->evaluate(exec);
2999 KJS_CHECKEXCEPTIONVALUE
3000 bool b1 = v1->toBoolean(exec);
3001 KJS_CHECKEXCEPTIONVALUE
3002 if (!b1)
3003 return v1;
3004 JSValue* v2 = expr2->evaluate(exec);
3005 KJS_CHECKEXCEPTIONVALUE
3006 return v2;
3007}
3008
3009bool LogicalAndNode::evaluateToBoolean(ExecState* exec)
3010{
3011 bool b = expr1->evaluateToBoolean(exec);
3012 KJS_CHECKEXCEPTIONBOOLEAN
3013 return b && expr2->evaluateToBoolean(exec);
3014}
3015
3016void LogicalOrNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3017{
3018 nodeStack.append(expr2.get());
3019 nodeStack.append(expr1.get());
3020}
3021
3022JSValue* LogicalOrNode::evaluate(ExecState* exec)
3023{
3024 JSValue* v1 = expr1->evaluate(exec);
3025 KJS_CHECKEXCEPTIONVALUE
3026 if (v1->toBoolean(exec))
3027 return v1;
3028 return expr2->evaluate(exec);
3029}
3030
3031bool LogicalOrNode::evaluateToBoolean(ExecState* exec)
3032{
3033 bool b = expr1->evaluateToBoolean(exec);
3034 KJS_CHECKEXCEPTIONBOOLEAN
3035 return b || expr2->evaluateToBoolean(exec);
3036}
3037
3038// ------------------------------ ConditionalNode ------------------------------
3039
3040void ConditionalNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3041{
3042 nodeStack.append(expr2.get());
3043 nodeStack.append(expr1.get());
3044 nodeStack.append(logical.get());
3045}
3046
3047// ECMA 11.12
3048JSValue* ConditionalNode::evaluate(ExecState* exec)
3049{
3050 bool b = logical->evaluateToBoolean(exec);
3051 KJS_CHECKEXCEPTIONVALUE
3052 return b ? expr1->evaluate(exec) : expr2->evaluate(exec);
3053}
3054
3055bool ConditionalNode::evaluateToBoolean(ExecState* exec)
3056{
3057 bool b = logical->evaluateToBoolean(exec);
3058 KJS_CHECKEXCEPTIONBOOLEAN
3059 return b ? expr1->evaluateToBoolean(exec) : expr2->evaluateToBoolean(exec);
3060}
3061
3062double ConditionalNode::evaluateToNumber(ExecState* exec)
3063{
3064 bool b = logical->evaluateToBoolean(exec);
3065 KJS_CHECKEXCEPTIONNUMBER
3066 return b ? expr1->evaluateToNumber(exec) : expr2->evaluateToNumber(exec);
3067}
3068
3069int32_t ConditionalNode::evaluateToInt32(ExecState* exec)
3070{
3071 bool b = logical->evaluateToBoolean(exec);
3072 KJS_CHECKEXCEPTIONNUMBER
3073 return b ? expr1->evaluateToInt32(exec) : expr2->evaluateToInt32(exec);
3074}
3075
3076uint32_t ConditionalNode::evaluateToUInt32(ExecState* exec)
3077{
3078 bool b = logical->evaluateToBoolean(exec);
3079 KJS_CHECKEXCEPTIONNUMBER
3080 return b ? expr1->evaluateToUInt32(exec) : expr2->evaluateToUInt32(exec);
3081}
3082
3083// ECMA 11.13
3084
3085static ALWAYS_INLINE JSValue* valueForReadModifyAssignment(ExecState* exec, JSValue* current, ExpressionNode* right, Operator oper) KJS_FAST_CALL;
3086static ALWAYS_INLINE JSValue* valueForReadModifyAssignment(ExecState* exec, JSValue* current, ExpressionNode* right, Operator oper)
3087{
3088 JSValue *v;
3089 int i1;
3090 int i2;
3091 unsigned int ui;
3092 switch (oper) {
3093 case OpMultEq:
3094 v = jsNumber(current->toNumber(exec) * right->evaluateToNumber(exec));
3095 break;
3096 case OpDivEq:
3097 v = jsNumber(current->toNumber(exec) / right->evaluateToNumber(exec));
3098 break;
3099 case OpPlusEq:
3100 v = add(exec, current, right->evaluate(exec));
3101 break;
3102 case OpMinusEq:
3103 v = jsNumber(current->toNumber(exec) - right->evaluateToNumber(exec));
3104 break;
3105 case OpLShift:
3106 i1 = current->toInt32(exec);
3107 i2 = right->evaluateToInt32(exec);
3108 v = jsNumber(i1 << i2);
3109 break;
3110 case OpRShift:
3111 i1 = current->toInt32(exec);
3112 i2 = right->evaluateToInt32(exec);
3113 v = jsNumber(i1 >> i2);
3114 break;
3115 case OpURShift:
3116 ui = current->toUInt32(exec);
3117 i2 = right->evaluateToInt32(exec);
3118 v = jsNumber(ui >> i2);
3119 break;
3120 case OpAndEq:
3121 i1 = current->toInt32(exec);
3122 i2 = right->evaluateToInt32(exec);
3123 v = jsNumber(i1 & i2);
3124 break;
3125 case OpXOrEq:
3126 i1 = current->toInt32(exec);
3127 i2 = right->evaluateToInt32(exec);
3128 v = jsNumber(i1 ^ i2);
3129 break;
3130 case OpOrEq:
3131 i1 = current->toInt32(exec);
3132 i2 = right->evaluateToInt32(exec);
3133 v = jsNumber(i1 | i2);
3134 break;
3135 case OpModEq: {
3136 double d1 = current->toNumber(exec);
3137 double d2 = right->evaluateToNumber(exec);
3138 v = jsNumber(fmod(d1, d2));
3139 }
3140 break;
3141 default:
3142 ASSERT_NOT_REACHED();
3143 v = jsUndefined();
3144 }
3145
3146 return v;
3147}
3148
3149// ------------------------------ ReadModifyResolveNode -----------------------------------
3150
3151void ReadModifyResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack& nodeStack)
3152{
3153 nodeStack.append(m_right.get());
3154 size_t index = symbolTable.get(m_ident.ustring().rep());
3155 if (index != missingSymbolMarker())
3156 new (this) ReadModifyLocalVarNode(index);
3157}
3158
3159void AssignResolveNode::optimizeVariableAccess(SymbolTable& symbolTable, DeclarationStacks::NodeStack& nodeStack)
3160{
3161 nodeStack.append(m_right.get());
3162 size_t index = symbolTable.get(m_ident.ustring().rep());
3163 if (index != missingSymbolMarker())
3164 new (this) AssignLocalVarNode(index);
3165}
3166
3167JSValue* ReadModifyLocalVarNode::evaluate(ExecState* exec)
3168{
3169 ASSERT(exec->variableObject() == exec->scopeChain().top());
3170 JSValue** slot = &exec->localStorage()[m_index].value;
3171
3172 ASSERT(m_oper != OpEqual);
3173 JSValue* v = valueForReadModifyAssignment(exec, *slot, m_right.get(), m_oper);
3174
3175 KJS_CHECKEXCEPTIONVALUE
3176
3177 *slot = v;
3178 return v;
3179}
3180
3181JSValue* AssignLocalVarNode::evaluate(ExecState* exec)
3182{
3183 ASSERT(exec->variableObject() == exec->scopeChain().top());
3184 JSValue* v = m_right->evaluate(exec);
3185
3186 KJS_CHECKEXCEPTIONVALUE
3187
3188 exec->localStorage()[m_index].value = v;
3189
3190 return v;
3191}
3192
3193JSValue *ReadModifyResolveNode::evaluate(ExecState *exec)
3194{
3195 const ScopeChain& chain = exec->scopeChain();
3196 ScopeChainIterator iter = chain.begin();
3197 ScopeChainIterator end = chain.end();
3198
3199 // we must always have something in the scope chain
3200 ASSERT(iter != end);
3201
3202 PropertySlot slot;
3203 JSObject *base;
3204 do {
3205 base = *iter;
3206 if (base->getPropertySlot(exec, m_ident, slot))
3207 goto found;
3208
3209 ++iter;
3210 } while (iter != end);
3211
3212 ASSERT(m_oper != OpEqual);
3213 return throwUndefinedVariableError(exec, m_ident);
3214
3215 found:
3216 JSValue *v;
3217
3218
3219 ASSERT(m_oper != OpEqual);
3220 JSValue *v1 = slot.getValue(exec, base, m_ident);
3221 KJS_CHECKEXCEPTIONVALUE
3222 v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
3223
3224 KJS_CHECKEXCEPTIONVALUE
3225
3226 base->put(exec, m_ident, v);
3227 return v;
3228}
3229
3230JSValue *AssignResolveNode::evaluate(ExecState *exec)
3231{
3232 const ScopeChain& chain = exec->scopeChain();
3233 ScopeChainIterator iter = chain.begin();
3234 ScopeChainIterator end = chain.end();
3235
3236 // we must always have something in the scope chain
3237 ASSERT(iter != end);
3238
3239 PropertySlot slot;
3240 JSObject *base;
3241 do {
3242 base = *iter;
3243 if (base->getPropertySlot(exec, m_ident, slot))
3244 goto found;
3245
3246 ++iter;
3247 } while (iter != end);
3248
3249 found:
3250 JSValue *v = m_right->evaluate(exec);
3251
3252 KJS_CHECKEXCEPTIONVALUE
3253
3254 base->put(exec, m_ident, v);
3255 return v;
3256}
3257
3258// ------------------------------ ReadModifyDotNode -----------------------------------
3259
3260void AssignDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3261{
3262 nodeStack.append(m_right.get());
3263 nodeStack.append(m_base.get());
3264}
3265
3266JSValue *AssignDotNode::evaluate(ExecState *exec)
3267{
3268 JSValue *baseValue = m_base->evaluate(exec);
3269 KJS_CHECKEXCEPTIONVALUE
3270 JSObject *base = baseValue->toObject(exec);
3271
3272 JSValue *v = m_right->evaluate(exec);
3273
3274 KJS_CHECKEXCEPTIONVALUE
3275
3276 base->put(exec, m_ident, v);
3277 return v;
3278}
3279
3280void ReadModifyDotNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3281{
3282 nodeStack.append(m_right.get());
3283 nodeStack.append(m_base.get());
3284}
3285
3286JSValue *ReadModifyDotNode::evaluate(ExecState *exec)
3287{
3288 JSValue *baseValue = m_base->evaluate(exec);
3289 KJS_CHECKEXCEPTIONVALUE
3290 JSObject *base = baseValue->toObject(exec);
3291
3292 JSValue *v;
3293
3294 ASSERT(m_oper != OpEqual);
3295 PropertySlot slot;
3296 JSValue *v1 = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
3297 KJS_CHECKEXCEPTIONVALUE
3298 v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
3299
3300 KJS_CHECKEXCEPTIONVALUE
3301
3302 base->put(exec, m_ident, v);
3303 return v;
3304}
3305
3306// ------------------------------ AssignErrorNode -----------------------------------
3307
3308JSValue* AssignErrorNode::evaluate(ExecState* exec)
3309{
3310 throwError(exec, ReferenceError, "Left side of assignment is not a reference.");
3311 handleException(exec);
3312 return jsUndefined();
3313}
3314
3315// ------------------------------ AssignBracketNode -----------------------------------
3316
3317void AssignBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3318{
3319 nodeStack.append(m_right.get());
3320 nodeStack.append(m_subscript.get());
3321 nodeStack.append(m_base.get());
3322}
3323
3324JSValue *AssignBracketNode::evaluate(ExecState *exec)
3325{
3326 JSValue *baseValue = m_base->evaluate(exec);
3327 KJS_CHECKEXCEPTIONVALUE
3328 JSValue *subscript = m_subscript->evaluate(exec);
3329 KJS_CHECKEXCEPTIONVALUE
3330
3331 JSObject *base = baseValue->toObject(exec);
3332
3333 uint32_t propertyIndex;
3334 if (subscript->getUInt32(propertyIndex)) {
3335 JSValue *v = m_right->evaluate(exec);
3336 KJS_CHECKEXCEPTIONVALUE
3337
3338 base->put(exec, propertyIndex, v);
3339 return v;
3340 }
3341
3342 Identifier propertyName(subscript->toString(exec));
3343 JSValue *v = m_right->evaluate(exec);
3344 KJS_CHECKEXCEPTIONVALUE
3345
3346 base->put(exec, propertyName, v);
3347 return v;
3348}
3349void ReadModifyBracketNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3350{
3351 nodeStack.append(m_right.get());
3352 nodeStack.append(m_subscript.get());
3353 nodeStack.append(m_base.get());
3354}
3355
3356JSValue *ReadModifyBracketNode::evaluate(ExecState *exec)
3357{
3358 JSValue *baseValue = m_base->evaluate(exec);
3359 KJS_CHECKEXCEPTIONVALUE
3360 JSValue *subscript = m_subscript->evaluate(exec);
3361 KJS_CHECKEXCEPTIONVALUE
3362
3363 JSObject *base = baseValue->toObject(exec);
3364
3365 uint32_t propertyIndex;
3366 if (subscript->getUInt32(propertyIndex)) {
3367 JSValue *v;
3368 ASSERT(m_oper != OpEqual);
3369 PropertySlot slot;
3370 JSValue *v1 = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
3371 KJS_CHECKEXCEPTIONVALUE
3372 v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
3373
3374 KJS_CHECKEXCEPTIONVALUE
3375
3376 base->put(exec, propertyIndex, v);
3377 return v;
3378 }
3379
3380 Identifier propertyName(subscript->toString(exec));
3381 JSValue *v;
3382
3383 ASSERT(m_oper != OpEqual);
3384 PropertySlot slot;
3385 JSValue *v1 = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
3386 KJS_CHECKEXCEPTIONVALUE
3387 v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
3388
3389 KJS_CHECKEXCEPTIONVALUE
3390
3391 base->put(exec, propertyName, v);
3392 return v;
3393}
3394
3395// ------------------------------ CommaNode ------------------------------------
3396
3397void CommaNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3398{
3399 nodeStack.append(expr2.get());
3400 nodeStack.append(expr1.get());
3401}
3402
3403// ECMA 11.14
3404JSValue* CommaNode::evaluate(ExecState *exec)
3405{
3406 expr1->evaluate(exec);
3407 KJS_CHECKEXCEPTIONVALUE
3408 return expr2->evaluate(exec);
3409}
3410
3411// ------------------------------ AssignExprNode -------------------------------
3412
3413void AssignExprNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3414{
3415 nodeStack.append(expr.get());
3416}
3417
3418// ECMA 12.2
3419JSValue* AssignExprNode::evaluate(ExecState* exec)
3420{
3421 return expr->evaluate(exec);
3422}
3423
3424bool AssignExprNode::evaluateToBoolean(ExecState* exec)
3425{
3426 return expr->evaluateToBoolean(exec);
3427}
3428
3429double AssignExprNode::evaluateToNumber(ExecState* exec)
3430{
3431 return expr->evaluateToNumber(exec);
3432}
3433
3434int32_t AssignExprNode::evaluateToInt32(ExecState* exec)
3435{
3436 return expr->evaluateToInt32(exec);
3437}
3438
3439uint32_t AssignExprNode::evaluateToUInt32(ExecState* exec)
3440{
3441 return expr->evaluateToInt32(exec);
3442}
3443
3444// ------------------------------ VarDeclNode ----------------------------------
3445
3446VarDeclNode::VarDeclNode(const Identifier &id, AssignExprNode *in, Type t)
3447 : varType(t)
3448 , ident(id)
3449 , init(in)
3450{
3451}
3452
3453void VarDeclNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3454{
3455 if (next)
3456 nodeStack.append(next.get());
3457 if (init)
3458 nodeStack.append(init.get());
3459}
3460
3461void VarDeclNode::handleSlowCase(ExecState* exec, const ScopeChain& chain, JSValue* val)
3462{
3463 ScopeChainIterator iter = chain.begin();
3464 ScopeChainIterator end = chain.end();
3465
3466 // we must always have something in the scope chain
3467 ASSERT(iter != end);
3468
3469 PropertySlot slot;
3470 JSObject* base;
3471
3472 do {
3473 base = *iter;
3474 if (base->getPropertySlot(exec, ident, slot))
3475 break;
3476
3477 ++iter;
3478 } while (iter != end);
3479
3480 unsigned flags = 0;
3481 base->getPropertyAttributes(ident, flags);
3482 if (varType == VarDeclNode::Constant)
3483 flags |= ReadOnly;
3484
3485 base->put(exec, ident, val, flags);
3486}
3487
3488// ECMA 12.2
3489inline void VarDeclNode::evaluateSingle(ExecState* exec)
3490{
3491 ASSERT(exec->variableObject()->hasOwnProperty(exec, ident) || exec->codeType() == EvalCode); // Guaranteed by processDeclarations.
3492 const ScopeChain& chain = exec->scopeChain();
3493 JSObject* variableObject = exec->variableObject();
3494
3495 ASSERT(!chain.isEmpty());
3496
3497 bool inGlobalScope = ++chain.begin() == chain.end();
3498
3499 if (init) {
3500 if (inGlobalScope) {
3501 JSValue* val = init->evaluate(exec);
3502 int flags = Internal;
3503 if (exec->codeType() != EvalCode)
3504 flags |= DontDelete;
3505 if (varType == VarDeclNode::Constant)
3506 flags |= ReadOnly;
3507 variableObject->put(exec, ident, val, flags);
3508 } else {
3509 JSValue* val = init->evaluate(exec);
3510 KJS_CHECKEXCEPTIONVOID
3511
3512 // if the variable object is the top of the scope chain, then that must
3513 // be where this variable is declared, processVarDecls would have put
3514 // it there. Don't search the scope chain, to optimize this very common case.
3515 if (chain.top() != variableObject)
3516 return handleSlowCase(exec, chain, val);
3517
3518 unsigned flags = 0;
3519 variableObject->getPropertyAttributes(ident, flags);
3520 if (varType == VarDeclNode::Constant)
3521 flags |= ReadOnly;
3522
3523 variableObject->put(exec, ident, val, flags);
3524 }
3525 }
3526}
3527
3528JSValue* VarDeclNode::evaluate(ExecState* exec)
3529{
3530 evaluateSingle(exec);
3531
3532 if (VarDeclNode* n = next.get()) {
3533 do {
3534 n->evaluateSingle(exec);
3535 KJS_CHECKEXCEPTIONVALUE
3536 n = n->next.get();
3537 } while (n);
3538 }
3539 return jsUndefined();
3540}
3541
3542// ------------------------------ VarStatementNode -----------------------------
3543
3544void VarStatementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3545{
3546 ASSERT(next);
3547 nodeStack.append(next.get());
3548}
3549
3550// ECMA 12.2
3551Completion VarStatementNode::execute(ExecState *exec)
3552{
3553 KJS_BREAKPOINT;
3554
3555 next->evaluate(exec);
3556 KJS_CHECKEXCEPTION
3557
3558 return Completion(Normal);
3559}
3560
3561// ------------------------------ Helper functions for handling Vectors of StatementNode -------------------------------
3562
3563static inline void statementListPushFIFO(SourceElements& statements, DeclarationStacks::NodeStack& stack)
3564{
3565 SourceElements::iterator it = statements.end();
3566 SourceElements::iterator begin = statements.begin();
3567 while (it != begin) {
3568 --it;
3569 stack.append((*it).get());
3570 }
3571}
3572
3573static inline Node* statementListInitializeVariableAccessStack(SourceElements& statements, DeclarationStacks::NodeStack& stack)
3574{
3575 if (!statements.size())
3576 return 0;
3577
3578 SourceElements::iterator it = statements.end();
3579 SourceElements::iterator begin = statements.begin();
3580 SourceElements::iterator beginPlusOne = begin + 1;
3581
3582 while (it != beginPlusOne) {
3583 --it;
3584 stack.append((*it).get());
3585 }
3586
3587 return (*begin).get();
3588}
3589
3590static inline Completion statementListExecute(SourceElements& statements, ExecState* exec)
3591{
3592 JSValue* v = 0;
3593 Completion c(Normal);
3594 const SourceElements::iterator end = statements.end();
3595 for (SourceElements::iterator ptr = statements.begin(); ptr != end; ++ptr) {
3596 c = (*ptr)->execute(exec);
3597
3598 if (JSValue* v2 = c.value())
3599 v = v2;
3600 c.setValue(v);
3601
3602 if (c.complType() != Normal)
3603 return c;
3604 }
3605 return c;
3606}
3607
3608// ------------------------------ BlockNode ------------------------------------
3609
3610BlockNode::BlockNode(SourceElements* children)
3611 : m_children(children)
3612{
3613 ASSERT(m_children);
3614}
3615
3616void BlockNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3617{
3618 statementListPushFIFO(*m_children, nodeStack);
3619}
3620
3621// ECMA 12.1
3622Completion BlockNode::execute(ExecState *exec)
3623{
3624 return statementListExecute(*m_children, exec);
3625}
3626
3627// ------------------------------ EmptyStatementNode ---------------------------
3628
3629// ECMA 12.3
3630Completion EmptyStatementNode::execute(ExecState *)
3631{
3632 return Completion(Normal);
3633}
3634
3635// ------------------------------ ExprStatementNode ----------------------------
3636
3637void ExprStatementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3638{
3639 ASSERT(expr);
3640 nodeStack.append(expr.get());
3641}
3642
3643// ECMA 12.4
3644Completion ExprStatementNode::execute(ExecState *exec)
3645{
3646 KJS_BREAKPOINT;
3647
3648 JSValue *v = expr->evaluate(exec);
3649 KJS_CHECKEXCEPTION
3650
3651 return Completion(Normal, v);
3652}
3653
3654// ------------------------------ IfNode ---------------------------------------
3655
3656void IfNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3657{
3658 if (statement2)
3659 nodeStack.append(statement2.get());
3660 ASSERT(statement1);
3661 nodeStack.append(statement1.get());
3662 ASSERT(expr);
3663 nodeStack.append(expr.get());
3664}
3665
3666// ECMA 12.5
3667Completion IfNode::execute(ExecState* exec)
3668{
3669 KJS_BREAKPOINT;
3670
3671 bool b = expr->evaluateToBoolean(exec);
3672 KJS_CHECKEXCEPTION
3673
3674 // if ... then
3675 if (b)
3676 return statement1->execute(exec);
3677
3678 // no else
3679 if (!statement2)
3680 return Completion(Normal);
3681
3682 // else
3683 return statement2->execute(exec);
3684}
3685
3686// ------------------------------ DoWhileNode ----------------------------------
3687
3688void DoWhileNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3689{
3690 nodeStack.append(statement.get());
3691 nodeStack.append(expr.get());
3692}
3693
3694// ECMA 12.6.1
3695Completion DoWhileNode::execute(ExecState *exec)
3696{
3697 KJS_BREAKPOINT;
3698
3699 JSValue* value = 0;
3700
3701 while (1) {
3702 exec->pushIteration();
3703 Completion c = statement->execute(exec);
3704 exec->popIteration();
3705
3706 if (exec->dynamicGlobalObject()->timedOut())
3707 return Completion(Interrupted);
3708
3709 if (c.isValueCompletion())
3710 value = c.value();
3711
3712 if (!((c.complType() == Continue) && ls.contains(c.target()))) {
3713 if ((c.complType() == Break) && ls.contains(c.target()))
3714 return Completion(Normal, value);
3715 if (c.complType() != Normal)
3716 return c;
3717 }
3718
3719 bool b = expr->evaluateToBoolean(exec);
3720 KJS_CHECKEXCEPTION
3721 if (!b)
3722 return Completion(Normal, value);
3723 }
3724
3725 return Completion(); // work around gcc 4.0 bug
3726}
3727
3728// ------------------------------ WhileNode ------------------------------------
3729
3730void WhileNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3731{
3732 nodeStack.append(statement.get());
3733 nodeStack.append(expr.get());
3734}
3735
3736// ECMA 12.6.2
3737Completion WhileNode::execute(ExecState *exec)
3738{
3739 KJS_BREAKPOINT;
3740
3741 JSValue* value = 0;
3742
3743 while (1) {
3744 bool b = expr->evaluateToBoolean(exec);
3745 KJS_CHECKEXCEPTION
3746 if (!b)
3747 return Completion(Normal, value);
3748
3749 exec->pushIteration();
3750 Completion c = statement->execute(exec);
3751 exec->popIteration();
3752
3753 if (exec->dynamicGlobalObject()->timedOut())
3754 return Completion(Interrupted);
3755
3756 if (c.isValueCompletion())
3757 value = c.value();
3758
3759 if ((c.complType() == Continue) && ls.contains(c.target()))
3760 continue;
3761 if ((c.complType() == Break) && ls.contains(c.target()))
3762 return Completion(Normal, value);
3763 if (c.complType() != Normal)
3764 return c;
3765 }
3766
3767 return Completion(); // work around gcc 4.0 bug
3768}
3769
3770// ------------------------------ ForNode --------------------------------------
3771
3772void ForNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3773{
3774 nodeStack.append(statement.get());
3775 if (expr3)
3776 nodeStack.append(expr3.get());
3777 if (expr2)
3778 nodeStack.append(expr2.get());
3779 if (expr1)
3780 nodeStack.append(expr1.get());
3781}
3782
3783// ECMA 12.6.3
3784Completion ForNode::execute(ExecState *exec)
3785{
3786 JSValue* cval = 0;
3787
3788 if (expr1) {
3789 expr1->evaluate(exec);
3790 KJS_CHECKEXCEPTION
3791 }
3792
3793 while (1) {
3794 if (expr2) {
3795 bool b = expr2->evaluateToBoolean(exec);
3796 KJS_CHECKEXCEPTION
3797 if (!b)
3798 return Completion(Normal, cval);
3799 }
3800
3801 exec->pushIteration();
3802 Completion c = statement->execute(exec);
3803 exec->popIteration();
3804 if (c.isValueCompletion())
3805 cval = c.value();
3806 if (!((c.complType() == Continue) && ls.contains(c.target()))) {
3807 if ((c.complType() == Break) && ls.contains(c.target()))
3808 return Completion(Normal, cval);
3809 if (c.complType() != Normal)
3810 return c;
3811 }
3812
3813 if (exec->dynamicGlobalObject()->timedOut())
3814 return Completion(Interrupted);
3815
3816 if (expr3) {
3817 expr3->evaluate(exec);
3818 KJS_CHECKEXCEPTION
3819 }
3820 }
3821
3822 return Completion(); // work around gcc 4.0 bug
3823}
3824
3825// ------------------------------ ForInNode ------------------------------------
3826
3827ForInNode::ForInNode(ExpressionNode* l, ExpressionNode* e, StatementNode* s)
3828 : init(0L), lexpr(l), expr(e), varDecl(0L), statement(s)
3829{
3830}
3831
3832ForInNode::ForInNode(const Identifier& i, AssignExprNode* in, ExpressionNode* e, StatementNode* s)
3833 : ident(i), init(in), expr(e), statement(s)
3834{
3835 // for( var foo = bar in baz )
3836 varDecl = new VarDeclNode(ident, init.get(), VarDeclNode::Variable);
3837 lexpr = new ResolveNode(ident);
3838}
3839
3840void ForInNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3841{
3842 nodeStack.append(statement.get());
3843 nodeStack.append(expr.get());
3844 nodeStack.append(lexpr.get());
3845 if (varDecl)
3846 nodeStack.append(varDecl.get());
3847}
3848
3849// ECMA 12.6.4
3850Completion ForInNode::execute(ExecState *exec)
3851{
3852 JSValue *e;
3853 JSValue *retval = 0;
3854 JSObject *v;
3855 Completion c;
3856 PropertyNameArray propertyNames;
3857
3858 if (varDecl) {
3859 varDecl->evaluate(exec);
3860 KJS_CHECKEXCEPTION
3861 }
3862
3863 e = expr->evaluate(exec);
3864
3865 // for Null and Undefined, we want to make sure not to go through
3866 // the loop at all, because their object wrappers will have a
3867 // property list but will throw an exception if you attempt to
3868 // access any property.
3869 if (e->isUndefinedOrNull())
3870 return Completion(Normal);
3871
3872 KJS_CHECKEXCEPTION
3873 v = e->toObject(exec);
3874 v->getPropertyNames(exec, propertyNames);
3875
3876 PropertyNameArray::const_iterator end = propertyNames.end();
3877 for (PropertyNameArray::const_iterator it = propertyNames.begin(); it != end; ++it) {
3878 const Identifier &name = *it;
3879 if (!v->hasProperty(exec, name))
3880 continue;
3881
3882 JSValue *str = jsOwnedString(name.ustring());
3883
3884 if (lexpr->isResolveNode()) {
3885 const Identifier &ident = static_cast<ResolveNode *>(lexpr.get())->identifier();
3886
3887 const ScopeChain& chain = exec->scopeChain();
3888 ScopeChainIterator iter = chain.begin();
3889 ScopeChainIterator end = chain.end();
3890
3891 // we must always have something in the scope chain
3892 ASSERT(iter != end);
3893
3894 PropertySlot slot;
3895 JSObject *o;
3896 do {
3897 o = *iter;
3898 if (o->getPropertySlot(exec, ident, slot)) {
3899 o->put(exec, ident, str);
3900 break;
3901 }
3902 ++iter;
3903 } while (iter != end);
3904
3905 if (iter == end)
3906 o->put(exec, ident, str);
3907 } else if (lexpr->isDotAccessorNode()) {
3908 const Identifier& ident = static_cast<DotAccessorNode *>(lexpr.get())->identifier();
3909 JSValue *v = static_cast<DotAccessorNode *>(lexpr.get())->base()->evaluate(exec);
3910 KJS_CHECKEXCEPTION
3911 JSObject *o = v->toObject(exec);
3912
3913 o->put(exec, ident, str);
3914 } else {
3915 ASSERT(lexpr->isBracketAccessorNode());
3916 JSValue *v = static_cast<BracketAccessorNode *>(lexpr.get())->base()->evaluate(exec);
3917 KJS_CHECKEXCEPTION
3918 JSValue *v2 = static_cast<BracketAccessorNode *>(lexpr.get())->subscript()->evaluate(exec);
3919 KJS_CHECKEXCEPTION
3920 JSObject *o = v->toObject(exec);
3921
3922 uint32_t i;
3923 if (v2->getUInt32(i))
3924 o->put(exec, i, str);
3925 o->put(exec, Identifier(v2->toString(exec)), str);
3926 }
3927
3928 KJS_CHECKEXCEPTION
3929
3930 exec->pushIteration();
3931 c = statement->execute(exec);
3932 exec->popIteration();
3933 if (c.isValueCompletion())
3934 retval = c.value();
3935
3936 if (!((c.complType() == Continue) && ls.contains(c.target()))) {
3937 if ((c.complType() == Break) && ls.contains(c.target()))
3938 break;
3939 if (c.complType() != Normal) {
3940 return c;
3941 }
3942 }
3943 }
3944
3945 return Completion(Normal, retval);
3946}
3947
3948// ------------------------------ ContinueNode ---------------------------------
3949
3950// ECMA 12.7
3951Completion ContinueNode::execute(ExecState *exec)
3952{
3953 KJS_BREAKPOINT;
3954
3955 if (ident.isEmpty() && !exec->inIteration())
3956 return createErrorCompletion(exec, SyntaxError, "Invalid continue statement.");
3957 if (!ident.isEmpty() && !exec->seenLabels()->contains(ident))
3958 return createErrorCompletion(exec, SyntaxError, "Label %s not found.", ident);
3959 return Completion(Continue, &ident);
3960}
3961
3962// ------------------------------ BreakNode ------------------------------------
3963
3964// ECMA 12.8
3965Completion BreakNode::execute(ExecState *exec)
3966{
3967 KJS_BREAKPOINT;
3968
3969 if (ident.isEmpty() && !exec->inIteration() &&
3970 !exec->inSwitch())
3971 return createErrorCompletion(exec, SyntaxError, "Invalid break statement.");
3972 if (!ident.isEmpty() && !exec->seenLabels()->contains(ident))
3973 return createErrorCompletion(exec, SyntaxError, "Label %s not found.");
3974 return Completion(Break, &ident);
3975}
3976
3977// ------------------------------ ReturnNode -----------------------------------
3978
3979void ReturnNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
3980{
3981 if (value)
3982 nodeStack.append(value.get());
3983}
3984
3985// ECMA 12.9
3986Completion ReturnNode::execute(ExecState *exec)
3987{
3988 KJS_BREAKPOINT;
3989
3990 CodeType codeType = exec->codeType();
3991 if (codeType != FunctionCode)
3992 return createErrorCompletion(exec, SyntaxError, "Invalid return statement.");
3993
3994 if (!value)
3995 return Completion(ReturnValue, jsUndefined());
3996
3997 JSValue *v = value->evaluate(exec);
3998 KJS_CHECKEXCEPTION
3999
4000 return Completion(ReturnValue, v);
4001}
4002
4003// ------------------------------ WithNode -------------------------------------
4004
4005void WithNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
4006{
4007 // Can't optimize within statement because "with" introduces a dynamic scope.
4008 nodeStack.append(expr.get());
4009}
4010
4011// ECMA 12.10
4012Completion WithNode::execute(ExecState *exec)
4013{
4014 KJS_BREAKPOINT;
4015
4016 JSValue *v = expr->evaluate(exec);
4017 KJS_CHECKEXCEPTION
4018 JSObject *o = v->toObject(exec);
4019 KJS_CHECKEXCEPTION
4020 exec->pushScope(o);
4021 Completion res = statement->execute(exec);
4022 exec->popScope();
4023
4024 return res;
4025}
4026
4027// ------------------------------ CaseClauseNode -------------------------------
4028
4029void CaseClauseNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
4030{
4031 if (expr)
4032 nodeStack.append(expr.get());
4033 if (m_children)
4034 statementListPushFIFO(*m_children, nodeStack);
4035}
4036
4037// ECMA 12.11
4038JSValue *CaseClauseNode::evaluate(ExecState *exec)
4039{
4040 JSValue *v = expr->evaluate(exec);
4041 KJS_CHECKEXCEPTIONVALUE
4042
4043 return v;
4044}
4045
4046// ECMA 12.11
4047Completion CaseClauseNode::evalStatements(ExecState *exec)
4048{
4049 if (m_children)
4050 return statementListExecute(*m_children, exec);
4051 else
4052 return Completion(Normal, jsUndefined());
4053}
4054
4055// ------------------------------ ClauseListNode -------------------------------
4056
4057void ClauseListNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
4058{
4059 if (next)
4060 nodeStack.append(next.get());
4061 nodeStack.append(clause.get());
4062}
4063
4064// ------------------------------ CaseBlockNode --------------------------------
4065
4066CaseBlockNode::CaseBlockNode(ClauseListNode* l1, CaseClauseNode* d, ClauseListNode* l2)
4067 : list1(l1)
4068 , def(d)
4069 , list2(l2)
4070{
4071}
4072
4073void CaseBlockNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
4074{
4075 if (list2)
4076 nodeStack.append(list2.get());
4077 if (def)
4078 nodeStack.append(def.get());
4079 if (list1)
4080 nodeStack.append(list1.get());
4081}
4082
4083// ECMA 12.11
4084Completion CaseBlockNode::evalBlock(ExecState *exec, JSValue *input)
4085{
4086 JSValue *v;
4087 Completion res;
4088 ClauseListNode *a = list1.get();
4089 ClauseListNode *b = list2.get();
4090 CaseClauseNode *clause;
4091
4092 while (a) {
4093 clause = a->getClause();
4094 a = a->getNext();
4095 v = clause->evaluate(exec);
4096 KJS_CHECKEXCEPTION
4097 if (strictEqual(exec, input, v)) {
4098 res = clause->evalStatements(exec);
4099 if (res.complType() != Normal)
4100 return res;
4101 while (a) {
4102 res = a->getClause()->evalStatements(exec);
4103 if (res.complType() != Normal)
4104 return res;
4105 a = a->getNext();
4106 }
4107 break;
4108 }
4109 }
4110
4111 while (b) {
4112 clause = b->getClause();
4113 b = b->getNext();
4114 v = clause->evaluate(exec);
4115 KJS_CHECKEXCEPTION
4116 if (strictEqual(exec, input, v)) {
4117 res = clause->evalStatements(exec);
4118 if (res.complType() != Normal)
4119 return res;
4120 goto step18;
4121 }
4122 }
4123
4124 // default clause
4125 if (def) {
4126 res = def->evalStatements(exec);
4127 if (res.complType() != Normal)
4128 return res;
4129 }
4130 b = list2.get();
4131 step18:
4132 while (b) {
4133 clause = b->getClause();
4134 res = clause->evalStatements(exec);
4135 if (res.complType() != Normal)
4136 return res;
4137 b = b->getNext();
4138 }
4139
4140 // bail out on error
4141 KJS_CHECKEXCEPTION
4142
4143 return Completion(Normal);
4144}
4145
4146// ------------------------------ SwitchNode -----------------------------------
4147
4148void SwitchNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
4149{
4150 nodeStack.append(block.get());
4151 nodeStack.append(expr.get());
4152}
4153
4154// ECMA 12.11
4155Completion SwitchNode::execute(ExecState *exec)
4156{
4157 KJS_BREAKPOINT;
4158
4159 JSValue *v = expr->evaluate(exec);
4160 KJS_CHECKEXCEPTION
4161
4162 exec->pushSwitch();
4163 Completion res = block->evalBlock(exec,v);
4164 exec->popSwitch();
4165
4166 if ((res.complType() == Break) && ls.contains(res.target()))
4167 return Completion(Normal, res.value());
4168 return res;
4169}
4170
4171// ------------------------------ LabelNode ------------------------------------
4172
4173void LabelNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
4174{
4175 nodeStack.append(statement.get());
4176}
4177
4178// ECMA 12.12
4179Completion LabelNode::execute(ExecState *exec)
4180{
4181 if (!exec->seenLabels()->push(label))
4182 return createErrorCompletion(exec, SyntaxError, "Duplicated label %s found.", label);
4183 Completion e = statement->execute(exec);
4184 exec->seenLabels()->pop();
4185
4186 if ((e.complType() == Break) && (e.target() == label))
4187 return Completion(Normal, e.value());
4188 return e;
4189}
4190
4191// ------------------------------ ThrowNode ------------------------------------
4192
4193void ThrowNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
4194{
4195 nodeStack.append(expr.get());
4196}
4197
4198// ECMA 12.13
4199Completion ThrowNode::execute(ExecState *exec)
4200{
4201 KJS_BREAKPOINT;
4202
4203 JSValue *v = expr->evaluate(exec);
4204 KJS_CHECKEXCEPTION
4205
4206 handleException(exec, v);
4207 return Completion(Throw, v);
4208}
4209
4210// ------------------------------ TryNode --------------------------------------
4211
4212void TryNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
4213{
4214 // Can't optimize within catchBlock because "catch" introduces a dynamic scope.
4215 if (finallyBlock)
4216 nodeStack.append(finallyBlock.get());
4217 nodeStack.append(tryBlock.get());
4218}
4219
4220// ECMA 12.14
4221Completion TryNode::execute(ExecState *exec)
4222{
4223 KJS_BREAKPOINT;
4224
4225 Completion c = tryBlock->execute(exec);
4226
4227 if (Collector::isOutOfMemory())
4228 return c; // don't try to catch an out of memory exception thrown by the collector
4229
4230 if (catchBlock && c.complType() == Throw) {
4231 JSObject *obj = new JSObject;
4232 obj->put(exec, exceptionIdent, c.value(), DontDelete);
4233 exec->pushScope(obj);
4234 c = catchBlock->execute(exec);
4235 exec->popScope();
4236 }
4237
4238 if (finallyBlock) {
4239 Completion c2 = finallyBlock->execute(exec);
4240 if (c2.complType() != Normal)
4241 c = c2;
4242 }
4243
4244 return c;
4245}
4246
4247// ------------------------------ FunctionBodyNode -----------------------------
4248
4249ScopeNode::ScopeNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
4250 : BlockNode(children)
4251 , m_sourceURL(parser().sourceURL())
4252 , m_sourceId(parser().sourceId())
4253{
4254 if (varStack)
4255 m_varStack = *varStack;
4256
4257 if (funcStack)
4258 m_functionStack = *funcStack;
4259}
4260
4261ProgramNode::ProgramNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
4262 : ScopeNode(children, varStack, funcStack)
4263{
4264}
4265
4266EvalNode::EvalNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
4267 : ScopeNode(children, varStack, funcStack)
4268{
4269}
4270
4271FunctionBodyNode::FunctionBodyNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
4272 : ScopeNode(children, varStack, funcStack)
4273 , m_initialized(false)
4274{
4275}
4276
4277void FunctionBodyNode::initializeSymbolTable(ExecState* exec)
4278{
4279 SymbolTable& symbolTable = exec->variableObject()->symbolTable();
4280 ASSERT(!symbolTable.size());
4281
4282 size_t localStorageIndex = 0;
4283
4284 for (size_t i = 0, size = m_parameters.size(); i < size; ++i, ++localStorageIndex) {
4285 UString::Rep* rep = m_parameters[i].ustring().rep();
4286 symbolTable.set(rep, localStorageIndex);
4287 }
4288
4289 for (size_t i = 0, size = m_functionStack.size(); i < size; ++i, ++localStorageIndex) {
4290 UString::Rep* rep = m_functionStack[i]->ident.ustring().rep();
4291 symbolTable.set(rep, localStorageIndex);
4292 }
4293
4294 for (size_t i = 0, size = m_varStack.size(); i < size; ++i, ++localStorageIndex) {
4295 Identifier& ident = m_varStack[i]->ident;
4296 if (ident == exec->propertyNames().arguments)
4297 continue;
4298 symbolTable.add(ident.ustring().rep(), localStorageIndex);
4299 }
4300}
4301
4302void ProgramNode::initializeSymbolTable(ExecState* exec)
4303{
4304 // If a previous script defined a symbol with the same name as one of our
4305 // symbols, to avoid breaking previously optimized nodes, we need to reuse
4306 // the symbol's existing storage index. So, we can't be as efficient as
4307 // FunctionBodyNode::initializeSymbolTable, which knows that no bindings
4308 // have yet been made.
4309
4310 JSVariableObject* variableObject = exec->variableObject();
4311 SymbolTable& symbolTable = variableObject->symbolTable();
4312
4313 size_t localStorageIndex = symbolTable.size();
4314 size_t size;
4315
4316 size = m_functionStack.size();
4317 m_functionIndexes.resize(size);
4318 for (size_t i = 0; i < size; ++i) {
4319 UString::Rep* rep = m_functionStack[i]->ident.ustring().rep();
4320 pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
4321 m_functionIndexes[i] = result.first->second;
4322 if (result.second)
4323 ++localStorageIndex;
4324 }
4325
4326 size = m_varStack.size();
4327 m_varIndexes.resize(size);
4328 for (size_t i = 0; i < size; ++i) {
4329 const Identifier& ident = m_varStack[i]->ident;
4330 if (variableObject->getDirect(ident)) {
4331 m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
4332 continue;
4333 }
4334
4335 UString::Rep* rep = ident.ustring().rep();
4336 pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
4337 if (!result.second) {
4338 m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
4339 continue;
4340 }
4341 m_varIndexes[i] = result.first->second;
4342 ++localStorageIndex;
4343 }
4344}
4345
4346void ScopeNode::optimizeVariableAccess(ExecState* exec)
4347{
4348 DeclarationStacks::NodeStack nodeStack;
4349 Node* node = statementListInitializeVariableAccessStack(*m_children, nodeStack);
4350 if (!node)
4351 return;
4352
4353 SymbolTable& symbolTable = exec->variableObject()->symbolTable();
4354 while (true) {
4355 node->optimizeVariableAccess(symbolTable, nodeStack);
4356
4357 size_t size = nodeStack.size();
4358 if (!size)
4359 break;
4360 --size;
4361 node = nodeStack[size];
4362 nodeStack.shrink(size);
4363 }
4364}
4365
4366void FunctionBodyNode::processDeclarations(ExecState* exec)
4367{
4368 if (!m_initialized) {
4369 initializeSymbolTable(exec);
4370 optimizeVariableAccess(exec);
4371
4372 m_initialized = true;
4373 }
4374
4375 LocalStorage& localStorage = exec->variableObject()->localStorage();
4376
4377 // We can't just resize localStorage here because that would temporarily
4378 // leave uninitialized entries, which would crash GC during the mark phase.
4379 localStorage.reserveCapacity(m_varStack.size() + m_parameters.size() + m_functionStack.size());
4380
4381 int minAttributes = Internal | DontDelete;
4382
4383 // In order for our localStorage indexes to be correct, we must match the
4384 // order of addition in initializeSymbolTable().
4385
4386 const List& args = *exec->arguments();
4387 for (size_t i = 0, size = m_parameters.size(); i < size; ++i)
4388 localStorage.uncheckedAppend(LocalStorageEntry(args[i], DontDelete));
4389
4390 for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
4391 FuncDeclNode* node = m_functionStack[i];
4392 localStorage.uncheckedAppend(LocalStorageEntry(node->makeFunction(exec), minAttributes));
4393 }
4394
4395 for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
4396 VarDeclNode* node = m_varStack[i];
4397 int attributes = minAttributes;
4398 if (node->varType == VarDeclNode::Constant)
4399 attributes |= ReadOnly;
4400 localStorage.uncheckedAppend(LocalStorageEntry(jsUndefined(), attributes));
4401 }
4402}
4403
4404static void gccIsCrazy() KJS_FAST_CALL;
4405static void gccIsCrazy()
4406{
4407}
4408
4409void ProgramNode::processDeclarations(ExecState* exec)
4410{
4411 // If you remove this call, some SunSpider tests, including
4412 // bitops-nsieve-bits.js, will regress substantially on Mac, due to a ~40%
4413 // increase in L2 cache misses. FIXME: WTF?
4414 gccIsCrazy();
4415
4416 initializeSymbolTable(exec);
4417 optimizeVariableAccess(exec);
4418
4419 LocalStorage& localStorage = exec->variableObject()->localStorage();
4420
4421 // We can't just resize localStorage here because that would temporarily
4422 // leave uninitialized entries, which would crash GC during the mark phase.
4423 localStorage.reserveCapacity(localStorage.size() + m_varStack.size() + m_functionStack.size());
4424
4425 int minAttributes = Internal | DontDelete;
4426
4427 // In order for our localStorage indexes to be correct, we must match the
4428 // order of addition in initializeSymbolTable().
4429
4430 for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
4431 FuncDeclNode* node = m_functionStack[i];
4432 LocalStorageEntry entry = LocalStorageEntry(node->makeFunction(exec), minAttributes);
4433 size_t index = m_functionIndexes[i];
4434
4435 if (index == localStorage.size())
4436 localStorage.uncheckedAppend(entry);
4437 else {
4438 ASSERT(index < localStorage.size());
4439 localStorage[index] = entry;
4440 }
4441 }
4442
4443 for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
4444 size_t index = m_varIndexes[i];
4445 if (index == missingSymbolMarker())
4446 continue;
4447
4448 VarDeclNode* node = m_varStack[i];
4449 int attributes = minAttributes;
4450 if (node->varType == VarDeclNode::Constant)
4451 attributes |= ReadOnly;
4452 LocalStorageEntry entry = LocalStorageEntry(jsUndefined(), attributes);
4453
4454 ASSERT(index == localStorage.size());
4455 localStorage.uncheckedAppend(entry);
4456 }
4457}
4458
4459void EvalNode::processDeclarations(ExecState* exec)
4460{
4461 // We could optimize access to pre-existing symbols here, but SunSpider
4462 // reports that to be a net loss.
4463
4464 size_t i, size;
4465
4466 JSVariableObject* variableObject = exec->variableObject();
4467
4468 int minAttributes = Internal;
4469
4470 for (i = 0, size = m_varStack.size(); i < size; ++i) {
4471 VarDeclNode* node = m_varStack[i];
4472 if (variableObject->hasOwnProperty(exec, node->ident))
4473 continue;
4474 int attributes = minAttributes;
4475 if (node->varType == VarDeclNode::Constant)
4476 attributes |= ReadOnly;
4477 variableObject->put(exec, node->ident, jsUndefined(), attributes);
4478 }
4479
4480 for (i = 0, size = m_functionStack.size(); i < size; ++i) {
4481 FuncDeclNode* node = m_functionStack[i];
4482 variableObject->put(exec, node->ident, node->makeFunction(exec), minAttributes);
4483 }
4484}
4485
4486UString FunctionBodyNode::paramString() const
4487{
4488 UString s("");
4489 size_t count = m_parameters.size();
4490 for (size_t pos = 0; pos < count; ++pos) {
4491 if (!s.isEmpty())
4492 s += ", ";
4493 s += m_parameters[pos].ustring();
4494 }
4495
4496 return s;
4497}
4498
4499Completion ProgramNode::execute(ExecState* exec)
4500{
4501 processDeclarations(exec);
4502 return ScopeNode::execute(exec);
4503}
4504
4505Completion EvalNode::execute(ExecState* exec)
4506{
4507 processDeclarations(exec);
4508 return ScopeNode::execute(exec);
4509}
4510
4511Completion FunctionBodyNode::execute(ExecState* exec)
4512{
4513 processDeclarations(exec);
4514
4515 if (Debugger* dbg = exec->dynamicGlobalObject()->debugger()) {
4516 if (!dbg->callEvent(exec, sourceId(), lineNo(), exec->function(), *exec->arguments())) {
4517 dbg->imp()->abort();
4518 return Completion(Interrupted, jsUndefined());
4519 }
4520 }
4521
4522 Completion completion = ScopeNode::execute(exec);
4523
4524 if (Debugger* dbg = exec->dynamicGlobalObject()->debugger()) {
4525 if (completion.complType() == Throw)
4526 exec->setException(completion.value());
4527
4528 if (!dbg->returnEvent(exec, sourceId(), lineNo(), exec->function())) {
4529 dbg->imp()->abort();
4530 return Completion(Interrupted, jsUndefined());
4531 }
4532 }
4533
4534
4535 return completion;
4536}
4537
4538// ------------------------------ FuncDeclNode ---------------------------------
4539
4540void FuncDeclNode::addParams()
4541{
4542 for (ParameterNode *p = param.get(); p != 0L; p = p->nextParam())
4543 body->parameters().append(p->ident());
4544}
4545
4546FunctionImp* FuncDeclNode::makeFunction(ExecState* exec)
4547{
4548 FunctionImp *func = new FunctionImp(exec, ident, body.get(), exec->scopeChain());
4549
4550 JSObject *proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, List::empty());
4551 proto->put(exec, exec->propertyNames().constructor, func, ReadOnly | DontDelete | DontEnum);
4552 func->put(exec, exec->propertyNames().prototype, proto, Internal|DontDelete);
4553
4554 func->put(exec, exec->propertyNames().length, jsNumber(body->parameters().size()), ReadOnly|DontDelete|DontEnum);
4555 return func;
4556}
4557
4558Completion FuncDeclNode::execute(ExecState *)
4559{
4560 return Completion(Normal);
4561}
4562
4563// ------------------------------ FuncExprNode ---------------------------------
4564
4565// ECMA 13
4566void FuncExprNode::addParams()
4567{
4568 for (ParameterNode *p = param.get(); p != 0L; p = p->nextParam())
4569 body->parameters().append(p->ident());
4570}
4571
4572JSValue *FuncExprNode::evaluate(ExecState *exec)
4573{
4574 bool named = !ident.isNull();
4575 JSObject *functionScopeObject = 0;
4576
4577 if (named) {
4578 // named FunctionExpressions can recursively call themselves,
4579 // but they won't register with the current scope chain and should
4580 // be contained as single property in an anonymous object.
4581 functionScopeObject = new JSObject;
4582 exec->pushScope(functionScopeObject);
4583 }
4584
4585 FunctionImp* func = new FunctionImp(exec, ident, body.get(), exec->scopeChain());
4586 JSObject* proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, List::empty());
4587 proto->put(exec, exec->propertyNames().constructor, func, ReadOnly | DontDelete | DontEnum);
4588 func->put(exec, exec->propertyNames().prototype, proto, Internal | DontDelete);
4589
4590 if (named) {
4591 functionScopeObject->put(exec, ident, func, Internal | ReadOnly | (exec->codeType() == EvalCode ? 0 : DontDelete));
4592 exec->popScope();
4593 }
4594
4595 return func;
4596}
4597
4598} // namespace KJS
Note: See TracBrowser for help on using the repository browser.