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

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

<rdar://problem/5759327> REGRESSION: while(NaN) acts like while(true)

Reviewed by Alexey P.

Fix yet another case where we incorrectly relied on implicit double
to bool coercion.

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