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

Last change on this file since 28935 was 28935, checked in by Darin Adler, 17 years ago
  • fix broken regression tests

The broken tests were fast/js/do-while-expression-value.html and
fast/js/while-expression-value.html.

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