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