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

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

Reviewed by Oliver Hunt.

Patch for http://bugs.webkit.org/show_bug.cgi?id=17025
nodes.h/cpp has been rolling around in the mud - lets hose it down

  • Rename member variables to use the m_ prefix.

(NOTE: Specific changed functions elided for space and clarity)

  • kjs/grammar.y:
  • kjs/nodes.cpp:
  • kjs/nodes.h:
  • kjs/nodes2string.cpp:
  • Property svn:eol-style set to native
File size: 131.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 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Cameron Zwarich ([email protected])
6 * Copyright (C) 2007 Maks Orlovich
7 * Copyright (C) 2007 Eric Seidel <[email protected]>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include "config.h"
27#include "nodes.h"
28
29#include "ExecState.h"
30#include "JSGlobalObject.h"
31#include "Parser.h"
32#include "PropertyNameArray.h"
33#include "array_object.h"
34#include "debugger.h"
35#include "function_object.h"
36#include "lexer.h"
37#include "operations.h"
38#include "regexp_object.h"
39#include <math.h>
40#include <wtf/Assertions.h>
41#include <wtf/HashCountedSet.h>
42#include <wtf/HashSet.h>
43#include <wtf/MathExtras.h>
44
45namespace KJS {
46
47 class FunctionBodyNodeWithDebuggerHooks : public FunctionBodyNode {
48 public:
49 FunctionBodyNodeWithDebuggerHooks(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
50 virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
51 };
52
53#define KJS_CHECKEXCEPTION \
54 if (exec->hadException()) \
55 return rethrowException(exec);
56
57#define KJS_CHECKEXCEPTIONVALUE \
58 if (exec->hadException()) { \
59 handleException(exec); \
60 return jsUndefined(); \
61 }
62
63#define KJS_CHECKEXCEPTIONNUMBER \
64 if (exec->hadException()) { \
65 handleException(exec); \
66 return 0; \
67 }
68
69#define KJS_CHECKEXCEPTIONBOOLEAN \
70 if (exec->hadException()) { \
71 handleException(exec); \
72 return false; \
73 }
74
75#define KJS_CHECKEXCEPTIONVOID \
76 if (exec->hadException()) { \
77 handleException(exec); \
78 return; \
79 }
80
81#if !ASSERT_DISABLED
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
308
309JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, const Identifier &label)
310{
311 UString message = msg;
312 substitute(message, label.ustring());
313 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
314}
315
316JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *e1, Node *e2)
317{
318 UString message = msg;
319 substitute(message, v->toString(exec));
320 substitute(message, e1->toString());
321 substitute(message, e2->toString());
322 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
323}
324
325JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *expr, const Identifier &label)
326{
327 UString message = msg;
328 substitute(message, v->toString(exec));
329 substitute(message, expr->toString());
330 substitute(message, label.ustring());
331 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
332}
333
334JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, const Identifier &label)
335{
336 UString message = msg;
337 substitute(message, v->toString(exec));
338 substitute(message, label.ustring());
339 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
340}
341
342JSValue *Node::throwUndefinedVariableError(ExecState *exec, const Identifier &ident)
343{
344 return throwError(exec, ReferenceError, "Can't find variable: %s", ident);
345}
346
347void Node::handleException(ExecState* exec)
348{
349 handleException(exec, exec->exception());
350}
351
352void Node::handleException(ExecState* exec, JSValue* exceptionValue)
353{
354 if (exceptionValue->isObject()) {
355 JSObject* exception = static_cast<JSObject*>(exceptionValue);
356 if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
357 exception->put(exec, "line", jsNumber(m_line));
358 exception->put(exec, "sourceURL", jsString(currentSourceURL(exec)));
359 }
360 }
361 Debugger* dbg = exec->dynamicGlobalObject()->debugger();
362 if (dbg && !dbg->hasHandledException(exec, exceptionValue)) {
363 bool cont = dbg->exception(exec, currentSourceId(exec), m_line, exceptionValue);
364 if (!cont)
365 dbg->imp()->abort();
366 }
367}
368
369NEVER_INLINE JSValue* Node::rethrowException(ExecState* exec)
370{
371 JSValue* exception = exec->exception();
372 exec->clearException();
373 handleException(exec, exception);
374 return exec->setThrowCompletion(exception);
375}
376
377// ------------------------------ StatementNode --------------------------------
378
379StatementNode::StatementNode()
380 : m_lastLine(-1)
381{
382 m_line = -1;
383}
384
385void StatementNode::setLoc(int firstLine, int lastLine)
386{
387 m_line = firstLine;
388 m_lastLine = lastLine;
389}
390
391// ------------------------------ SourceElements --------------------------------
392
393void SourceElements::append(PassRefPtr<StatementNode> statement)
394{
395 if (statement->isEmptyStatement())
396 return;
397
398 if (Debugger::debuggersPresent)
399 m_statements.append(new BreakpointCheckStatement(statement));
400 else
401 m_statements.append(statement);
402}
403
404// ------------------------------ BreakpointCheckStatement --------------------------------
405
406BreakpointCheckStatement::BreakpointCheckStatement(PassRefPtr<StatementNode> statement)
407 : m_statement(statement)
408{
409 ASSERT(m_statement);
410}
411
412JSValue* BreakpointCheckStatement::execute(ExecState* exec)
413{
414 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger())
415 if (!debugger->atStatement(exec, currentSourceId(exec), m_statement->firstLine(), m_statement->lastLine()))
416 return exec->setNormalCompletion();
417 return m_statement->execute(exec);
418}
419
420void BreakpointCheckStatement::streamTo(SourceStream& stream) const
421{
422 m_statement->streamTo(stream);
423}
424
425void BreakpointCheckStatement::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
426{
427 nodeStack.append(m_statement.get());
428}
429
430// ------------------------------ NullNode -------------------------------------
431
432JSValue *NullNode::evaluate(ExecState *)
433{
434 return jsNull();
435}
436
437// ------------------------------ FalseNode ----------------------------------
438
439JSValue* FalseNode::evaluate(ExecState*)
440{
441 return jsBoolean(false);
442}
443
444// ------------------------------ TrueNode ----------------------------------
445
446JSValue* TrueNode::evaluate(ExecState*)
447{
448 return jsBoolean(true);
449}
450
451// ------------------------------ NumberNode -----------------------------------
452
453JSValue* NumberNode::evaluate(ExecState*)
454{
455 // Number nodes are only created when the number can't fit in a JSImmediate, so no need to check again.
456 return jsNumberCell(m_double);
457}
458
459double NumberNode::evaluateToNumber(ExecState*)
460{
461 return m_double;
462}
463
464bool NumberNode::evaluateToBoolean(ExecState*)
465{
466 return m_double < 0.0 || m_double > 0.0; // false for NaN as well as 0
467}
468
469int32_t NumberNode::evaluateToInt32(ExecState*)
470{
471 return JSValue::toInt32(m_double);
472}
473
474uint32_t NumberNode::evaluateToUInt32(ExecState*)
475{
476 return JSValue::toUInt32(m_double);
477}
478
479// ------------------------------ ImmediateNumberNode -----------------------------------
480
481JSValue* ImmediateNumberNode::evaluate(ExecState*)
482{
483 return m_value;
484}
485
486int32_t ImmediateNumberNode::evaluateToInt32(ExecState*)
487{
488 return JSImmediate::getTruncatedInt32(m_value);
489}
490
491uint32_t ImmediateNumberNode::evaluateToUInt32(ExecState*)
492{
493 uint32_t i;
494 if (JSImmediate::getTruncatedUInt32(m_value, i))
495 return i;
496 bool ok;
497 return JSValue::toUInt32SlowCase(m_double, ok);
498}
499
500// ------------------------------ StringNode -----------------------------------
501
502JSValue* StringNode::evaluate(ExecState*)
503{
504 return jsOwnedString(m_value);
505}
506
507double StringNode::evaluateToNumber(ExecState*)
508{
509 return m_value.toDouble();
510}
511
512bool StringNode::evaluateToBoolean(ExecState*)
513{
514 return !m_value.isEmpty();
515}
516
517// ------------------------------ RegExpNode -----------------------------------
518
519JSValue* RegExpNode::evaluate(ExecState* exec)
520{
521 return exec->lexicalGlobalObject()->regExpConstructor()->createRegExpImp(exec, m_regExp);
522}
523
524// ------------------------------ ThisNode -------------------------------------
525
526// ECMA 11.1.1
527JSValue *ThisNode::evaluate(ExecState *exec)
528{
529 return exec->thisValue();
530}
531
532// ------------------------------ ResolveNode ----------------------------------
533
534// ECMA 11.1.2 & 10.1.4
535JSValue* ResolveNode::inlineEvaluate(ExecState* exec)
536{
537 // Check for missed optimization opportunity.
538 ASSERT(!canSkipLookup(exec, m_ident));
539
540 const ScopeChain& chain = exec->scopeChain();
541 ScopeChainIterator iter = chain.begin();
542 ScopeChainIterator end = chain.end();
543
544 // we must always have something in the scope chain
545 ASSERT(iter != end);
546
547 PropertySlot slot;
548 do {
549 JSObject *o = *iter;
550
551 if (o->getPropertySlot(exec, m_ident, slot))
552 return slot.getValue(exec, o, m_ident);
553
554 ++iter;
555 } while (iter != end);
556
557 return throwUndefinedVariableError(exec, m_ident);
558}
559
560JSValue* ResolveNode::evaluate(ExecState* exec)
561{
562 return inlineEvaluate(exec);
563}
564
565double ResolveNode::evaluateToNumber(ExecState* exec)
566{
567 JSValue* v = inlineEvaluate(exec);
568 KJS_CHECKEXCEPTIONNUMBER
569 return v->toNumber(exec);
570}
571
572bool ResolveNode::evaluateToBoolean(ExecState* exec)
573{
574 JSValue* v = inlineEvaluate(exec);
575 KJS_CHECKEXCEPTIONBOOLEAN
576 return v->toBoolean(exec);
577}
578
579int32_t ResolveNode::evaluateToInt32(ExecState* exec)
580{
581 JSValue* v = inlineEvaluate(exec);
582 KJS_CHECKEXCEPTIONNUMBER
583 return v->toInt32(exec);
584}
585
586uint32_t ResolveNode::evaluateToUInt32(ExecState* exec)
587{
588 JSValue* v = inlineEvaluate(exec);
589 KJS_CHECKEXCEPTIONNUMBER
590 return v->toUInt32(exec);
591}
592
593void ResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
594{
595 size_t index = symbolTable.get(m_ident.ustring().rep());
596 if (index != missingSymbolMarker())
597 new (this) LocalVarAccessNode(index);
598}
599
600JSValue* LocalVarAccessNode::inlineEvaluate(ExecState* exec)
601{
602 ASSERT(exec->variableObject() == exec->scopeChain().top());
603 return exec->localStorage()[m_index].value;
604}
605
606JSValue* LocalVarAccessNode::evaluate(ExecState* exec)
607{
608 return inlineEvaluate(exec);
609}
610
611double LocalVarAccessNode::evaluateToNumber(ExecState* exec)
612{
613 return inlineEvaluate(exec)->toNumber(exec);
614}
615
616bool LocalVarAccessNode::evaluateToBoolean(ExecState* exec)
617{
618 return inlineEvaluate(exec)->toBoolean(exec);
619}
620
621int32_t LocalVarAccessNode::evaluateToInt32(ExecState* exec)
622{
623 return inlineEvaluate(exec)->toInt32(exec);
624}
625
626uint32_t LocalVarAccessNode::evaluateToUInt32(ExecState* exec)
627{
628 return inlineEvaluate(exec)->toUInt32(exec);
629}
630
631// ------------------------------ ElementNode ----------------------------------
632
633void ElementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
634{
635 if (m_next)
636 nodeStack.append(m_next.get());
637 ASSERT(m_node);
638 nodeStack.append(m_node.get());
639}
640
641// ECMA 11.1.4
642JSValue *ElementNode::evaluate(ExecState *exec)
643{
644 JSObject* array = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList());
645 int length = 0;
646 for (ElementNode *n = this; n; n = n->m_next.get()) {
647 JSValue *val = n->m_node->evaluate(exec);
648 KJS_CHECKEXCEPTIONVALUE
649 length += n->m_elision;
650 array->put(exec, length++, val);
651 }
652 return array;
653}
654
655// ------------------------------ ArrayNode ------------------------------------
656
657void ArrayNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
658{
659 if (m_element)
660 nodeStack.append(m_element.get());
661}
662
663
664// ECMA 11.1.4
665JSValue *ArrayNode::evaluate(ExecState *exec)
666{
667 JSObject *array;
668 int length;
669
670 if (m_element) {
671 array = static_cast<JSObject*>(m_element->evaluate(exec));
672 KJS_CHECKEXCEPTIONVALUE
673 length = m_opt ? array->get(exec, exec->propertyNames().length)->toInt32(exec) : 0;
674 } else {
675 JSValue* newArr = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList());
676 array = static_cast<JSObject*>(newArr);
677 length = 0;
678 }
679
680 if (m_opt)
681 array->put(exec, exec->propertyNames().length, jsNumber(m_elision + length), DontEnum | DontDelete);
682
683 return array;
684}
685
686// ------------------------------ ObjectLiteralNode ----------------------------
687
688void ObjectLiteralNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
689{
690 if (m_list)
691 nodeStack.append(m_list.get());
692}
693
694// ECMA 11.1.5
695JSValue *ObjectLiteralNode::evaluate(ExecState *exec)
696{
697 if (m_list)
698 return m_list->evaluate(exec);
699
700 return exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
701}
702
703// ------------------------------ PropertyListNode -----------------------------
704
705void PropertyListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
706{
707 if (m_next)
708 nodeStack.append(m_next.get());
709 nodeStack.append(m_node.get());
710}
711
712// ECMA 11.1.5
713JSValue *PropertyListNode::evaluate(ExecState *exec)
714{
715 JSObject* obj = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
716
717 for (PropertyListNode *p = this; p; p = p->m_next.get()) {
718 JSValue *v = p->m_node->m_assign->evaluate(exec);
719 KJS_CHECKEXCEPTIONVALUE
720
721 switch (p->m_node->m_type) {
722 case PropertyNode::Getter:
723 ASSERT(v->isObject());
724 obj->defineGetter(exec, p->m_node->name(), static_cast<JSObject *>(v));
725 break;
726 case PropertyNode::Setter:
727 ASSERT(v->isObject());
728 obj->defineSetter(exec, p->m_node->name(), static_cast<JSObject *>(v));
729 break;
730 case PropertyNode::Constant:
731 obj->put(exec, p->m_node->name(), v);
732 break;
733 }
734 }
735
736 return obj;
737}
738
739// ------------------------------ PropertyNode -----------------------------
740
741void PropertyNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
742{
743 nodeStack.append(m_assign.get());
744}
745
746// ECMA 11.1.5
747JSValue *PropertyNode::evaluate(ExecState*)
748{
749 ASSERT(false);
750 return jsNull();
751}
752
753// ------------------------------ BracketAccessorNode --------------------------------
754
755void BracketAccessorNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
756{
757 nodeStack.append(m_subscript.get());
758 nodeStack.append(m_base.get());
759}
760
761// ECMA 11.2.1a
762JSValue* BracketAccessorNode::inlineEvaluate(ExecState* exec)
763{
764 JSValue* v1 = m_base->evaluate(exec);
765 KJS_CHECKEXCEPTIONVALUE
766 JSValue* v2 = m_subscript->evaluate(exec);
767 KJS_CHECKEXCEPTIONVALUE
768 JSObject* o = v1->toObject(exec);
769 uint32_t i;
770 if (v2->getUInt32(i))
771 return o->get(exec, i);
772 return o->get(exec, Identifier(v2->toString(exec)));
773}
774
775JSValue* BracketAccessorNode::evaluate(ExecState* exec)
776{
777 return inlineEvaluate(exec);
778}
779
780double BracketAccessorNode::evaluateToNumber(ExecState* exec)
781{
782 JSValue* v = inlineEvaluate(exec);
783 KJS_CHECKEXCEPTIONNUMBER
784 return v->toNumber(exec);
785}
786
787bool BracketAccessorNode::evaluateToBoolean(ExecState* exec)
788{
789 JSValue* v = inlineEvaluate(exec);
790 KJS_CHECKEXCEPTIONBOOLEAN
791 return v->toBoolean(exec);
792}
793
794int32_t BracketAccessorNode::evaluateToInt32(ExecState* exec)
795{
796 JSValue* v = inlineEvaluate(exec);
797 KJS_CHECKEXCEPTIONNUMBER
798 return v->toInt32(exec);
799}
800
801uint32_t BracketAccessorNode::evaluateToUInt32(ExecState* exec)
802{
803 JSValue* v = inlineEvaluate(exec);
804 KJS_CHECKEXCEPTIONNUMBER
805 return v->toUInt32(exec);
806}
807
808// ------------------------------ DotAccessorNode --------------------------------
809
810void DotAccessorNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
811{
812 nodeStack.append(m_base.get());
813}
814
815// ECMA 11.2.1b
816JSValue* DotAccessorNode::inlineEvaluate(ExecState* exec)
817{
818 JSValue* v = m_base->evaluate(exec);
819 KJS_CHECKEXCEPTIONVALUE
820 return v->toObject(exec)->get(exec, m_ident);
821}
822
823JSValue* DotAccessorNode::evaluate(ExecState* exec)
824{
825 return inlineEvaluate(exec);
826}
827
828double DotAccessorNode::evaluateToNumber(ExecState* exec)
829{
830 JSValue* v = inlineEvaluate(exec);
831 KJS_CHECKEXCEPTIONNUMBER
832 return v->toNumber(exec);
833}
834
835bool DotAccessorNode::evaluateToBoolean(ExecState* exec)
836{
837 JSValue* v = inlineEvaluate(exec);
838 KJS_CHECKEXCEPTIONBOOLEAN
839 return v->toBoolean(exec);
840}
841
842int32_t DotAccessorNode::evaluateToInt32(ExecState* exec)
843{
844 JSValue* v = inlineEvaluate(exec);
845 KJS_CHECKEXCEPTIONNUMBER
846 return v->toInt32(exec);
847}
848
849uint32_t DotAccessorNode::evaluateToUInt32(ExecState* exec)
850{
851 JSValue* v = inlineEvaluate(exec);
852 KJS_CHECKEXCEPTIONNUMBER
853 return v->toUInt32(exec);
854}
855
856// ------------------------------ ArgumentListNode -----------------------------
857
858void ArgumentListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
859{
860 if (m_next)
861 nodeStack.append(m_next.get());
862 ASSERT(m_expr);
863 nodeStack.append(m_expr.get());
864}
865
866// ECMA 11.2.4
867void ArgumentListNode::evaluateList(ExecState* exec, List& list)
868{
869 for (ArgumentListNode *n = this; n; n = n->m_next.get()) {
870 JSValue *v = n->m_expr->evaluate(exec);
871 KJS_CHECKEXCEPTIONVOID
872 list.append(v);
873 }
874}
875
876// ------------------------------ ArgumentsNode --------------------------------
877
878void ArgumentsNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
879{
880 if (m_listNode)
881 nodeStack.append(m_listNode.get());
882}
883
884// ------------------------------ NewExprNode ----------------------------------
885
886void NewExprNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
887{
888 if (m_args)
889 nodeStack.append(m_args.get());
890 nodeStack.append(m_expr.get());
891}
892
893// ECMA 11.2.2
894
895JSValue* NewExprNode::inlineEvaluate(ExecState* exec)
896{
897 JSValue* v = m_expr->evaluate(exec);
898 KJS_CHECKEXCEPTIONVALUE
899
900 List argList;
901 if (m_args) {
902 m_args->evaluateList(exec, argList);
903 KJS_CHECKEXCEPTIONVALUE
904 }
905
906 if (!v->isObject())
907 return throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with new.", v, m_expr.get());
908
909 JSObject *constr = static_cast<JSObject*>(v);
910 if (!constr->implementsConstruct())
911 return throwError(exec, TypeError, "Value %s (result of expression %s) is not a constructor. Cannot be used with new.", v, m_expr.get());
912
913 return constr->construct(exec, argList);
914}
915
916JSValue* NewExprNode::evaluate(ExecState* exec)
917{
918 return inlineEvaluate(exec);
919}
920
921double NewExprNode::evaluateToNumber(ExecState* exec)
922{
923 JSValue* v = inlineEvaluate(exec);
924 KJS_CHECKEXCEPTIONNUMBER
925 return v->toNumber(exec);
926}
927
928bool NewExprNode::evaluateToBoolean(ExecState* exec)
929{
930 JSValue* v = inlineEvaluate(exec);
931 KJS_CHECKEXCEPTIONBOOLEAN
932 return v->toBoolean(exec);
933}
934
935int32_t NewExprNode::evaluateToInt32(ExecState* exec)
936{
937 JSValue* v = inlineEvaluate(exec);
938 KJS_CHECKEXCEPTIONNUMBER
939 return v->toInt32(exec);
940}
941
942uint32_t NewExprNode::evaluateToUInt32(ExecState* exec)
943{
944 JSValue* v = inlineEvaluate(exec);
945 KJS_CHECKEXCEPTIONNUMBER
946 return v->toUInt32(exec);
947}
948
949void FunctionCallValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
950{
951 nodeStack.append(m_args.get());
952 nodeStack.append(m_expr.get());
953}
954
955// ECMA 11.2.3
956JSValue *FunctionCallValueNode::evaluate(ExecState *exec)
957{
958 JSValue *v = m_expr->evaluate(exec);
959 KJS_CHECKEXCEPTIONVALUE
960
961 if (!v->isObject()) {
962 return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, m_expr.get());
963 }
964
965 JSObject *func = static_cast<JSObject*>(v);
966
967 if (!func->implementsCall()) {
968 return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, m_expr.get());
969 }
970
971 List argList;
972 m_args->evaluateList(exec, argList);
973 KJS_CHECKEXCEPTIONVALUE
974
975 JSObject *thisObj = exec->dynamicGlobalObject();
976
977 return func->call(exec, thisObj, argList);
978}
979
980void FunctionCallResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack& nodeStack)
981{
982 nodeStack.append(m_args.get());
983
984 size_t index = symbolTable.get(m_ident.ustring().rep());
985 if (index != missingSymbolMarker())
986 new (this) LocalVarFunctionCallNode(index);
987}
988
989// ECMA 11.2.3
990JSValue* FunctionCallResolveNode::inlineEvaluate(ExecState* exec)
991{
992 // Check for missed optimization opportunity.
993 ASSERT(!canSkipLookup(exec, m_ident));
994
995 const ScopeChain& chain = exec->scopeChain();
996 ScopeChainIterator iter = chain.begin();
997 ScopeChainIterator end = chain.end();
998
999 // we must always have something in the scope chain
1000 ASSERT(iter != end);
1001
1002 PropertySlot slot;
1003 JSObject* base;
1004 do {
1005 base = *iter;
1006 if (base->getPropertySlot(exec, m_ident, slot)) {
1007 JSValue* v = slot.getValue(exec, base, m_ident);
1008 KJS_CHECKEXCEPTIONVALUE
1009
1010 if (!v->isObject())
1011 return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, m_ident);
1012
1013 JSObject *func = static_cast<JSObject*>(v);
1014
1015 if (!func->implementsCall())
1016 return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, m_ident);
1017
1018 List argList;
1019 m_args->evaluateList(exec, argList);
1020 KJS_CHECKEXCEPTIONVALUE
1021
1022 JSObject* thisObj = base;
1023 // ECMA 11.2.3 says that in this situation the this value should be null.
1024 // However, section 10.2.3 says that in the case where the value provided
1025 // by the caller is null, the global object should be used. It also says
1026 // that the section does not apply to internal functions, but for simplicity
1027 // of implementation we use the global object anyway here. This guarantees
1028 // that in host objects you always get a valid object for this.
1029 if (thisObj->isActivationObject())
1030 thisObj = exec->dynamicGlobalObject();
1031
1032 return func->call(exec, thisObj, argList);
1033 }
1034 ++iter;
1035 } while (iter != end);
1036
1037 return throwUndefinedVariableError(exec, m_ident);
1038}
1039
1040JSValue* FunctionCallResolveNode::evaluate(ExecState* exec)
1041{
1042 return inlineEvaluate(exec);
1043}
1044
1045double FunctionCallResolveNode::evaluateToNumber(ExecState* exec)
1046{
1047 JSValue* v = inlineEvaluate(exec);
1048 KJS_CHECKEXCEPTIONNUMBER
1049 return v->toNumber(exec);
1050}
1051
1052bool FunctionCallResolveNode::evaluateToBoolean(ExecState* exec)
1053{
1054 JSValue* v = inlineEvaluate(exec);
1055 KJS_CHECKEXCEPTIONBOOLEAN
1056 return v->toBoolean(exec);
1057}
1058
1059int32_t FunctionCallResolveNode::evaluateToInt32(ExecState* exec)
1060{
1061 JSValue* v = inlineEvaluate(exec);
1062 KJS_CHECKEXCEPTIONNUMBER
1063 return v->toInt32(exec);
1064}
1065
1066uint32_t FunctionCallResolveNode::evaluateToUInt32(ExecState* exec)
1067{
1068 JSValue* v = inlineEvaluate(exec);
1069 KJS_CHECKEXCEPTIONNUMBER
1070 return v->toUInt32(exec);
1071}
1072
1073JSValue* LocalVarFunctionCallNode::inlineEvaluate(ExecState* exec)
1074{
1075 ASSERT(exec->variableObject() == exec->scopeChain().top());
1076
1077 JSValue* v = exec->localStorage()[m_index].value;
1078
1079 if (!v->isObject())
1080 return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, m_ident);
1081
1082 JSObject* func = static_cast<JSObject*>(v);
1083 if (!func->implementsCall())
1084 return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, m_ident);
1085
1086 List argList;
1087 m_args->evaluateList(exec, argList);
1088 KJS_CHECKEXCEPTIONVALUE
1089
1090 return func->call(exec, exec->dynamicGlobalObject(), argList);
1091}
1092
1093JSValue* LocalVarFunctionCallNode::evaluate(ExecState* exec)
1094{
1095 return inlineEvaluate(exec);
1096}
1097
1098double LocalVarFunctionCallNode::evaluateToNumber(ExecState* exec)
1099{
1100 JSValue* v = inlineEvaluate(exec);
1101 KJS_CHECKEXCEPTIONNUMBER
1102 return v->toNumber(exec);
1103}
1104
1105bool LocalVarFunctionCallNode::evaluateToBoolean(ExecState* exec)
1106{
1107 JSValue* v = inlineEvaluate(exec);
1108 KJS_CHECKEXCEPTIONBOOLEAN
1109 return v->toBoolean(exec);
1110}
1111
1112int32_t LocalVarFunctionCallNode::evaluateToInt32(ExecState* exec)
1113{
1114 JSValue* v = inlineEvaluate(exec);
1115 KJS_CHECKEXCEPTIONNUMBER
1116 return v->toInt32(exec);
1117}
1118
1119uint32_t LocalVarFunctionCallNode::evaluateToUInt32(ExecState* exec)
1120{
1121 JSValue* v = inlineEvaluate(exec);
1122 KJS_CHECKEXCEPTIONNUMBER
1123 return v->toUInt32(exec);
1124}
1125
1126void FunctionCallBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1127{
1128 nodeStack.append(m_args.get());
1129 nodeStack.append(m_subscript.get());
1130 nodeStack.append(m_base.get());
1131}
1132
1133// ECMA 11.2.3
1134JSValue *FunctionCallBracketNode::evaluate(ExecState *exec)
1135{
1136 JSValue *baseVal = m_base->evaluate(exec);
1137 KJS_CHECKEXCEPTIONVALUE
1138
1139 JSValue *subscriptVal = m_subscript->evaluate(exec);
1140
1141 JSObject *baseObj = baseVal->toObject(exec);
1142 uint32_t i;
1143 PropertySlot slot;
1144
1145 JSValue *funcVal;
1146 if (subscriptVal->getUInt32(i)) {
1147 if (baseObj->getPropertySlot(exec, i, slot))
1148 funcVal = slot.getValue(exec, baseObj, i);
1149 else
1150 funcVal = jsUndefined();
1151 } else {
1152 Identifier ident(subscriptVal->toString(exec));
1153 if (baseObj->getPropertySlot(exec, ident, slot))
1154 funcVal = baseObj->get(exec, ident);
1155 else
1156 funcVal = jsUndefined();
1157 }
1158
1159 KJS_CHECKEXCEPTIONVALUE
1160
1161 if (!funcVal->isObject()) {
1162 return throwError(exec, TypeError, "Value %s (result of expression %s[%s]) is not object.", funcVal, m_base.get(), m_subscript.get());
1163 }
1164
1165 JSObject *func = static_cast<JSObject*>(funcVal);
1166
1167 if (!func->implementsCall()) {
1168 return throwError(exec, TypeError, "Object %s (result of expression %s[%s]) does not allow calls.", funcVal, m_base.get(), m_subscript.get());
1169 }
1170
1171 List argList;
1172 m_args->evaluateList(exec, argList);
1173 KJS_CHECKEXCEPTIONVALUE
1174
1175 JSObject *thisObj = baseObj;
1176 ASSERT(thisObj);
1177 ASSERT(thisObj->isObject());
1178 ASSERT(!thisObj->isActivationObject());
1179
1180 return func->call(exec, thisObj, argList);
1181}
1182
1183static const char *dotExprNotAnObjectString() KJS_FAST_CALL;
1184static const char *dotExprNotAnObjectString()
1185{
1186 return "Value %s (result of expression %s.%s) is not object.";
1187}
1188
1189static const char *dotExprDoesNotAllowCallsString() KJS_FAST_CALL;
1190static const char *dotExprDoesNotAllowCallsString()
1191{
1192 return "Object %s (result of expression %s.%s) does not allow calls.";
1193}
1194
1195void FunctionCallDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1196{
1197 nodeStack.append(m_args.get());
1198 nodeStack.append(m_base.get());
1199}
1200
1201// ECMA 11.2.3
1202JSValue* FunctionCallDotNode::inlineEvaluate(ExecState* exec)
1203{
1204 JSValue *baseVal = m_base->evaluate(exec);
1205 KJS_CHECKEXCEPTIONVALUE
1206
1207 JSObject *baseObj = baseVal->toObject(exec);
1208 PropertySlot slot;
1209 JSValue *funcVal = baseObj->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, baseObj, m_ident) : jsUndefined();
1210 KJS_CHECKEXCEPTIONVALUE
1211
1212 if (!funcVal->isObject())
1213 return throwError(exec, TypeError, dotExprNotAnObjectString(), funcVal, m_base.get(), m_ident);
1214
1215 JSObject *func = static_cast<JSObject*>(funcVal);
1216
1217 if (!func->implementsCall())
1218 return throwError(exec, TypeError, dotExprDoesNotAllowCallsString(), funcVal, m_base.get(), m_ident);
1219
1220 List argList;
1221 m_args->evaluateList(exec, argList);
1222 KJS_CHECKEXCEPTIONVALUE
1223
1224 JSObject *thisObj = baseObj;
1225 ASSERT(thisObj);
1226 ASSERT(thisObj->isObject());
1227 ASSERT(!thisObj->isActivationObject());
1228
1229 return func->call(exec, thisObj, argList);
1230}
1231
1232JSValue* FunctionCallDotNode::evaluate(ExecState* exec)
1233{
1234 return inlineEvaluate(exec);
1235}
1236
1237double FunctionCallDotNode::evaluateToNumber(ExecState* exec)
1238{
1239 JSValue* v = inlineEvaluate(exec);
1240 KJS_CHECKEXCEPTIONNUMBER
1241 return v->toNumber(exec);
1242}
1243
1244bool FunctionCallDotNode::evaluateToBoolean(ExecState* exec)
1245{
1246 JSValue* v = inlineEvaluate(exec);
1247 KJS_CHECKEXCEPTIONBOOLEAN
1248 return v->toBoolean(exec);
1249}
1250
1251int32_t FunctionCallDotNode::evaluateToInt32(ExecState* exec)
1252{
1253 JSValue* v = inlineEvaluate(exec);
1254 KJS_CHECKEXCEPTIONNUMBER
1255 return v->toInt32(exec);
1256}
1257
1258uint32_t FunctionCallDotNode::evaluateToUInt32(ExecState* exec)
1259{
1260 JSValue* v = inlineEvaluate(exec);
1261 KJS_CHECKEXCEPTIONNUMBER
1262 return v->toUInt32(exec);
1263}
1264
1265// ECMA 11.3
1266
1267// ------------------------------ PostfixResolveNode ----------------------------------
1268
1269// Increment
1270void PostIncResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
1271{
1272 size_t index = symbolTable.get(m_ident.ustring().rep());
1273 if (index != missingSymbolMarker()) {
1274 if (isConstant(localStorage, index))
1275 new (this) PostIncConstNode(index);
1276 else
1277 new (this) PostIncLocalVarNode(index);
1278 }
1279}
1280
1281JSValue *PostIncResolveNode::evaluate(ExecState *exec)
1282{
1283 // Check for missed optimization opportunity.
1284 ASSERT(!canSkipLookup(exec, m_ident));
1285
1286 const ScopeChain& chain = exec->scopeChain();
1287 ScopeChainIterator iter = chain.begin();
1288 ScopeChainIterator end = chain.end();
1289
1290 // we must always have something in the scope chain
1291 ASSERT(iter != end);
1292
1293 PropertySlot slot;
1294 do {
1295 if ((*iter)->getPropertySlot(exec, m_ident, slot)) {
1296 // See the comment in PostIncResolveNode::evaluate().
1297
1298 JSObject* base = *iter;
1299 JSValue* v = slot.getValue(exec, base, m_ident)->toJSNumber(exec);
1300 base->put(exec, m_ident, jsNumber(v->toNumber(exec) + 1));
1301 return v;
1302 }
1303
1304 ++iter;
1305 } while (iter != end);
1306
1307 return throwUndefinedVariableError(exec, m_ident);
1308}
1309
1310void PostIncResolveNode::optimizeForUnnecessaryResult()
1311{
1312 new (this) PreIncResolveNode(PlacementNewAdopt);
1313}
1314
1315JSValue* PostIncLocalVarNode::evaluate(ExecState* exec)
1316{
1317 ASSERT(exec->variableObject() == exec->scopeChain().top());
1318
1319 JSValue** slot = &exec->localStorage()[m_index].value;
1320 JSValue* v = (*slot)->toJSNumber(exec);
1321 *slot = jsNumber(v->toNumber(exec) + 1);
1322 return v;
1323}
1324
1325void PostIncLocalVarNode::optimizeForUnnecessaryResult()
1326{
1327 new (this) PreIncLocalVarNode(m_index);
1328}
1329
1330
1331// Decrement
1332void PostDecResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
1333{
1334 size_t index = symbolTable.get(m_ident.ustring().rep());
1335 if (index != missingSymbolMarker()) {
1336 if (isConstant(localStorage, index))
1337 new (this) PostDecConstNode(index);
1338 else
1339 new (this) PostDecLocalVarNode(index);
1340 }
1341}
1342
1343JSValue *PostDecResolveNode::evaluate(ExecState *exec)
1344{
1345 // Check for missed optimization opportunity.
1346 ASSERT(!canSkipLookup(exec, m_ident));
1347
1348 const ScopeChain& chain = exec->scopeChain();
1349 ScopeChainIterator iter = chain.begin();
1350 ScopeChainIterator end = chain.end();
1351
1352 // we must always have something in the scope chain
1353 ASSERT(iter != end);
1354
1355 PropertySlot slot;
1356 do {
1357 if ((*iter)->getPropertySlot(exec, m_ident, slot)) {
1358 // See the comment in PostIncResolveNode::evaluate().
1359
1360 JSObject* base = *iter;
1361 JSValue* v = slot.getValue(exec, base, m_ident)->toJSNumber(exec);
1362 base->put(exec, m_ident, jsNumber(v->toNumber(exec) - 1));
1363 return v;
1364 }
1365
1366 ++iter;
1367 } while (iter != end);
1368
1369 return throwUndefinedVariableError(exec, m_ident);
1370}
1371
1372void PostDecResolveNode::optimizeForUnnecessaryResult()
1373{
1374 new (this) PreDecResolveNode(PlacementNewAdopt);
1375}
1376
1377JSValue* PostDecLocalVarNode::evaluate(ExecState* exec)
1378{
1379 ASSERT(exec->variableObject() == exec->scopeChain().top());
1380
1381 JSValue** slot = &exec->localStorage()[m_index].value;
1382 JSValue* v = (*slot)->toJSNumber(exec);
1383 *slot = jsNumber(v->toNumber(exec) - 1);
1384 return v;
1385}
1386
1387double PostDecLocalVarNode::inlineEvaluateToNumber(ExecState* exec)
1388{
1389 ASSERT(exec->variableObject() == exec->scopeChain().top());
1390
1391 JSValue** slot = &exec->localStorage()[m_index].value;
1392 double n = (*slot)->toNumber(exec);
1393 *slot = jsNumber(n - 1);
1394 return n;
1395}
1396
1397double PostDecLocalVarNode::evaluateToNumber(ExecState* exec)
1398{
1399 return inlineEvaluateToNumber(exec);
1400}
1401
1402bool PostDecLocalVarNode::evaluateToBoolean(ExecState* exec)
1403{
1404 return inlineEvaluateToNumber(exec);
1405}
1406
1407int32_t PostDecLocalVarNode::evaluateToInt32(ExecState* exec)
1408{
1409 return JSValue::toInt32(inlineEvaluateToNumber(exec));
1410}
1411
1412uint32_t PostDecLocalVarNode::evaluateToUInt32(ExecState* exec)
1413{
1414 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
1415}
1416
1417void PostDecLocalVarNode::optimizeForUnnecessaryResult()
1418{
1419 new (this) PreDecLocalVarNode(m_index);
1420}
1421
1422// ------------------------------ PostfixBracketNode ----------------------------------
1423
1424void PostfixBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1425{
1426 nodeStack.append(m_subscript.get());
1427 nodeStack.append(m_base.get());
1428}
1429
1430JSValue *PostIncBracketNode::evaluate(ExecState *exec)
1431{
1432 JSValue *baseValue = m_base->evaluate(exec);
1433 KJS_CHECKEXCEPTIONVALUE
1434 JSValue *subscript = m_subscript->evaluate(exec);
1435 KJS_CHECKEXCEPTIONVALUE
1436
1437 JSObject *base = baseValue->toObject(exec);
1438
1439 uint32_t propertyIndex;
1440 if (subscript->getUInt32(propertyIndex)) {
1441 PropertySlot slot;
1442 JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1443 KJS_CHECKEXCEPTIONVALUE
1444
1445 JSValue* v2 = v->toJSNumber(exec);
1446 base->put(exec, propertyIndex, jsNumber(v2->toNumber(exec) + 1));
1447
1448 return v2;
1449 }
1450
1451 Identifier propertyName(subscript->toString(exec));
1452 PropertySlot slot;
1453 JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1454 KJS_CHECKEXCEPTIONVALUE
1455
1456 JSValue* v2 = v->toJSNumber(exec);
1457 base->put(exec, propertyName, jsNumber(v2->toNumber(exec) + 1));
1458 return v2;
1459}
1460
1461JSValue *PostDecBracketNode::evaluate(ExecState *exec)
1462{
1463 JSValue *baseValue = m_base->evaluate(exec);
1464 KJS_CHECKEXCEPTIONVALUE
1465 JSValue *subscript = m_subscript->evaluate(exec);
1466 KJS_CHECKEXCEPTIONVALUE
1467
1468 JSObject *base = baseValue->toObject(exec);
1469
1470 uint32_t propertyIndex;
1471 if (subscript->getUInt32(propertyIndex)) {
1472 PropertySlot slot;
1473 JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1474 KJS_CHECKEXCEPTIONVALUE
1475
1476 JSValue* v2 = v->toJSNumber(exec);
1477 base->put(exec, propertyIndex, jsNumber(v2->toNumber(exec) - 1));
1478 return v2;
1479 }
1480
1481 Identifier propertyName(subscript->toString(exec));
1482 PropertySlot slot;
1483 JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1484 KJS_CHECKEXCEPTIONVALUE
1485
1486 JSValue* v2 = v->toJSNumber(exec);
1487 base->put(exec, propertyName, jsNumber(v2->toNumber(exec) - 1));
1488 return v2;
1489}
1490
1491// ------------------------------ PostfixDotNode ----------------------------------
1492
1493void PostfixDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1494{
1495 nodeStack.append(m_base.get());
1496}
1497
1498JSValue *PostIncDotNode::evaluate(ExecState *exec)
1499{
1500 JSValue *baseValue = m_base->evaluate(exec);
1501 KJS_CHECKEXCEPTIONVALUE
1502 JSObject *base = baseValue->toObject(exec);
1503
1504 PropertySlot slot;
1505 JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1506 KJS_CHECKEXCEPTIONVALUE
1507
1508 JSValue* v2 = v->toJSNumber(exec);
1509 base->put(exec, m_ident, jsNumber(v2->toNumber(exec) + 1));
1510 return v2;
1511}
1512
1513JSValue *PostDecDotNode::evaluate(ExecState *exec)
1514{
1515 JSValue *baseValue = m_base->evaluate(exec);
1516 KJS_CHECKEXCEPTIONVALUE
1517 JSObject *base = baseValue->toObject(exec);
1518
1519 PropertySlot slot;
1520 JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1521 KJS_CHECKEXCEPTIONVALUE
1522
1523 JSValue* v2 = v->toJSNumber(exec);
1524 base->put(exec, m_ident, jsNumber(v2->toNumber(exec) - 1));
1525 return v2;
1526}
1527
1528// ------------------------------ PostfixErrorNode -----------------------------------
1529
1530JSValue* PostfixErrorNode::evaluate(ExecState* exec)
1531{
1532 throwError(exec, ReferenceError, "Postfix %s operator applied to value that is not a reference.",
1533 m_oper == OpPlusPlus ? "++" : "--");
1534 handleException(exec);
1535 return jsUndefined();
1536}
1537
1538// ------------------------------ DeleteResolveNode -----------------------------------
1539
1540void DeleteResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
1541{
1542 size_t index = symbolTable.get(m_ident.ustring().rep());
1543 if (index != missingSymbolMarker())
1544 new (this) LocalVarDeleteNode();
1545}
1546
1547// ECMA 11.4.1
1548
1549JSValue *DeleteResolveNode::evaluate(ExecState *exec)
1550{
1551 // Check for missed optimization opportunity.
1552 ASSERT(!canSkipLookup(exec, m_ident));
1553
1554 const ScopeChain& chain = exec->scopeChain();
1555 ScopeChainIterator iter = chain.begin();
1556 ScopeChainIterator end = chain.end();
1557
1558 // we must always have something in the scope chain
1559 ASSERT(iter != end);
1560
1561 PropertySlot slot;
1562 JSObject *base;
1563 do {
1564 base = *iter;
1565 if (base->getPropertySlot(exec, m_ident, slot)) {
1566 return jsBoolean(base->deleteProperty(exec, m_ident));
1567 }
1568
1569 ++iter;
1570 } while (iter != end);
1571
1572 return jsBoolean(true);
1573}
1574
1575JSValue* LocalVarDeleteNode::evaluate(ExecState*)
1576{
1577 return jsBoolean(false);
1578}
1579
1580// ------------------------------ DeleteBracketNode -----------------------------------
1581
1582void DeleteBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1583{
1584 nodeStack.append(m_subscript.get());
1585 nodeStack.append(m_base.get());
1586}
1587
1588JSValue *DeleteBracketNode::evaluate(ExecState *exec)
1589{
1590 JSValue *baseValue = m_base->evaluate(exec);
1591 KJS_CHECKEXCEPTIONVALUE
1592 JSValue *subscript = m_subscript->evaluate(exec);
1593 KJS_CHECKEXCEPTIONVALUE
1594
1595 JSObject *base = baseValue->toObject(exec);
1596
1597 uint32_t propertyIndex;
1598 if (subscript->getUInt32(propertyIndex))
1599 return jsBoolean(base->deleteProperty(exec, propertyIndex));
1600
1601 Identifier propertyName(subscript->toString(exec));
1602 return jsBoolean(base->deleteProperty(exec, propertyName));
1603}
1604
1605// ------------------------------ DeleteDotNode -----------------------------------
1606
1607void DeleteDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1608{
1609 nodeStack.append(m_base.get());
1610}
1611
1612JSValue *DeleteDotNode::evaluate(ExecState *exec)
1613{
1614 JSValue *baseValue = m_base->evaluate(exec);
1615 JSObject *base = baseValue->toObject(exec);
1616 KJS_CHECKEXCEPTIONVALUE
1617
1618 return jsBoolean(base->deleteProperty(exec, m_ident));
1619}
1620
1621// ------------------------------ DeleteValueNode -----------------------------------
1622
1623void DeleteValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1624{
1625 nodeStack.append(m_expr.get());
1626}
1627
1628JSValue *DeleteValueNode::evaluate(ExecState *exec)
1629{
1630 m_expr->evaluate(exec);
1631 KJS_CHECKEXCEPTIONVALUE
1632
1633 // delete on a non-location expression ignores the value and returns true
1634 return jsBoolean(true);
1635}
1636
1637// ------------------------------ VoidNode -------------------------------------
1638
1639void VoidNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1640{
1641 nodeStack.append(m_expr.get());
1642}
1643
1644// ECMA 11.4.2
1645JSValue *VoidNode::evaluate(ExecState *exec)
1646{
1647 m_expr->evaluate(exec);
1648 KJS_CHECKEXCEPTIONVALUE
1649
1650 return jsUndefined();
1651}
1652
1653// ECMA 11.4.3
1654
1655// ------------------------------ TypeOfValueNode -----------------------------------
1656
1657void TypeOfValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1658{
1659 nodeStack.append(m_expr.get());
1660}
1661
1662static JSValue *typeStringForValue(JSValue *v) KJS_FAST_CALL;
1663static JSValue *typeStringForValue(JSValue *v)
1664{
1665 switch (v->type()) {
1666 case UndefinedType:
1667 return jsString("undefined");
1668 case NullType:
1669 return jsString("object");
1670 case BooleanType:
1671 return jsString("boolean");
1672 case NumberType:
1673 return jsString("number");
1674 case StringType:
1675 return jsString("string");
1676 default:
1677 if (v->isObject()) {
1678 // Return "undefined" for objects that should be treated
1679 // as null when doing comparisons.
1680 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
1681 return jsString("undefined");
1682 else if (static_cast<JSObject*>(v)->implementsCall())
1683 return jsString("function");
1684 }
1685
1686 return jsString("object");
1687 }
1688}
1689
1690void TypeOfResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
1691{
1692 size_t index = symbolTable.get(m_ident.ustring().rep());
1693 if (index != missingSymbolMarker())
1694 new (this) LocalVarTypeOfNode(index);
1695}
1696
1697JSValue* LocalVarTypeOfNode::evaluate(ExecState* exec)
1698{
1699 ASSERT(exec->variableObject() == exec->scopeChain().top());
1700
1701 return typeStringForValue(exec->localStorage()[m_index].value);
1702}
1703
1704JSValue *TypeOfResolveNode::evaluate(ExecState *exec)
1705{
1706 const ScopeChain& chain = exec->scopeChain();
1707 ScopeChainIterator iter = chain.begin();
1708 ScopeChainIterator end = chain.end();
1709
1710 // we must always have something in the scope chain
1711 ASSERT(iter != end);
1712
1713 PropertySlot slot;
1714 JSObject *base;
1715 do {
1716 base = *iter;
1717 if (base->getPropertySlot(exec, m_ident, slot)) {
1718 JSValue *v = slot.getValue(exec, base, m_ident);
1719 return typeStringForValue(v);
1720 }
1721
1722 ++iter;
1723 } while (iter != end);
1724
1725 return jsString("undefined");
1726}
1727
1728// ------------------------------ TypeOfValueNode -----------------------------------
1729
1730JSValue *TypeOfValueNode::evaluate(ExecState *exec)
1731{
1732 JSValue *v = m_expr->evaluate(exec);
1733 KJS_CHECKEXCEPTIONVALUE
1734
1735 return typeStringForValue(v);
1736}
1737
1738// ECMA 11.4.4 and 11.4.5
1739
1740// ------------------------------ PrefixResolveNode ----------------------------------
1741
1742void PreIncResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
1743{
1744 size_t index = symbolTable.get(m_ident.ustring().rep());
1745 if (index != missingSymbolMarker()) {
1746 if (isConstant(localStorage, index))
1747 new (this) PreIncConstNode(index);
1748 else
1749 new (this) PreIncLocalVarNode(index);
1750 }
1751}
1752
1753JSValue* PreIncLocalVarNode::evaluate(ExecState* exec)
1754{
1755 ASSERT(exec->variableObject() == exec->scopeChain().top());
1756 JSValue** slot = &exec->localStorage()[m_index].value;
1757
1758 double n = (*slot)->toNumber(exec);
1759 JSValue* n2 = jsNumber(n + 1);
1760 *slot = n2;
1761 return n2;
1762}
1763
1764JSValue *PreIncResolveNode::evaluate(ExecState *exec)
1765{
1766 const ScopeChain& chain = exec->scopeChain();
1767 ScopeChainIterator iter = chain.begin();
1768 ScopeChainIterator end = chain.end();
1769
1770 // we must always have something in the scope chain
1771 ASSERT(iter != end);
1772
1773 PropertySlot slot;
1774 do {
1775 if ((*iter)->getPropertySlot(exec, m_ident, slot)) {
1776 // See the comment in PostIncResolveNode::evaluate().
1777
1778 JSObject* base = *iter;
1779 JSValue *v = slot.getValue(exec, base, m_ident);
1780
1781 double n = v->toNumber(exec);
1782 JSValue *n2 = jsNumber(n + 1);
1783 base->put(exec, m_ident, n2);
1784
1785 return n2;
1786 }
1787
1788 ++iter;
1789 } while (iter != end);
1790
1791 return throwUndefinedVariableError(exec, m_ident);
1792}
1793
1794void PreDecResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
1795{
1796 size_t index = symbolTable.get(m_ident.ustring().rep());
1797 if (index != missingSymbolMarker()) {
1798 if (isConstant(localStorage, index))
1799 new (this) PreDecConstNode(index);
1800 else
1801 new (this) PreDecLocalVarNode(index);
1802 }
1803}
1804
1805JSValue* PreDecLocalVarNode::evaluate(ExecState* exec)
1806{
1807 ASSERT(exec->variableObject() == exec->scopeChain().top());
1808 JSValue** slot = &exec->localStorage()[m_index].value;
1809
1810 double n = (*slot)->toNumber(exec);
1811 JSValue* n2 = jsNumber(n - 1);
1812 *slot = n2;
1813 return n2;
1814}
1815
1816JSValue *PreDecResolveNode::evaluate(ExecState *exec)
1817{
1818 const ScopeChain& chain = exec->scopeChain();
1819 ScopeChainIterator iter = chain.begin();
1820 ScopeChainIterator end = chain.end();
1821
1822 // we must always have something in the scope chain
1823 ASSERT(iter != end);
1824
1825 PropertySlot slot;
1826 do {
1827 if ((*iter)->getPropertySlot(exec, m_ident, slot)) {
1828 // See the comment in PostIncResolveNode::evaluate().
1829
1830 JSObject* base = *iter;
1831 JSValue *v = slot.getValue(exec, base, m_ident);
1832
1833 double n = v->toNumber(exec);
1834 JSValue *n2 = jsNumber(n - 1);
1835 base->put(exec, m_ident, n2);
1836
1837 return n2;
1838 }
1839
1840 ++iter;
1841 } while (iter != end);
1842
1843 return throwUndefinedVariableError(exec, m_ident);
1844}
1845
1846// ------------------------------ PreIncConstNode ----------------------------------
1847
1848JSValue* PreIncConstNode::evaluate(ExecState* exec)
1849{
1850 ASSERT(exec->variableObject() == exec->scopeChain().top());
1851 return jsNumber(exec->localStorage()[m_index].value->toNumber(exec) + 1);
1852}
1853
1854// ------------------------------ PreDecConstNode ----------------------------------
1855
1856JSValue* PreDecConstNode::evaluate(ExecState* exec)
1857{
1858 ASSERT(exec->variableObject() == exec->scopeChain().top());
1859 return jsNumber(exec->localStorage()[m_index].value->toNumber(exec) - 1);
1860}
1861
1862// ------------------------------ PostIncConstNode ----------------------------------
1863
1864JSValue* PostIncConstNode::evaluate(ExecState* exec)
1865{
1866 ASSERT(exec->variableObject() == exec->scopeChain().top());
1867 return jsNumber(exec->localStorage()[m_index].value->toNumber(exec));
1868}
1869
1870// ------------------------------ PostDecConstNode ----------------------------------
1871
1872JSValue* PostDecConstNode::evaluate(ExecState* exec)
1873{
1874 ASSERT(exec->variableObject() == exec->scopeChain().top());
1875 return jsNumber(exec->localStorage()[m_index].value->toNumber(exec));
1876}
1877
1878// ------------------------------ PrefixBracketNode ----------------------------------
1879
1880void PrefixBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1881{
1882 nodeStack.append(m_subscript.get());
1883 nodeStack.append(m_base.get());
1884}
1885
1886JSValue *PreIncBracketNode::evaluate(ExecState *exec)
1887{
1888 JSValue *baseValue = m_base->evaluate(exec);
1889 KJS_CHECKEXCEPTIONVALUE
1890 JSValue *subscript = m_subscript->evaluate(exec);
1891 KJS_CHECKEXCEPTIONVALUE
1892
1893 JSObject *base = baseValue->toObject(exec);
1894
1895 uint32_t propertyIndex;
1896 if (subscript->getUInt32(propertyIndex)) {
1897 PropertySlot slot;
1898 JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1899 KJS_CHECKEXCEPTIONVALUE
1900
1901 JSValue *n2 = jsNumber(v->toNumber(exec) + 1);
1902 base->put(exec, propertyIndex, n2);
1903
1904 return n2;
1905 }
1906
1907 Identifier propertyName(subscript->toString(exec));
1908 PropertySlot slot;
1909 JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1910 KJS_CHECKEXCEPTIONVALUE
1911
1912 JSValue *n2 = jsNumber(v->toNumber(exec) + 1);
1913 base->put(exec, propertyName, n2);
1914
1915 return n2;
1916}
1917
1918JSValue *PreDecBracketNode::evaluate(ExecState *exec)
1919{
1920 JSValue *baseValue = m_base->evaluate(exec);
1921 KJS_CHECKEXCEPTIONVALUE
1922 JSValue *subscript = m_subscript->evaluate(exec);
1923 KJS_CHECKEXCEPTIONVALUE
1924
1925 JSObject *base = baseValue->toObject(exec);
1926
1927 uint32_t propertyIndex;
1928 if (subscript->getUInt32(propertyIndex)) {
1929 PropertySlot slot;
1930 JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1931 KJS_CHECKEXCEPTIONVALUE
1932
1933 JSValue *n2 = jsNumber(v->toNumber(exec) - 1);
1934 base->put(exec, propertyIndex, n2);
1935
1936 return n2;
1937 }
1938
1939 Identifier propertyName(subscript->toString(exec));
1940 PropertySlot slot;
1941 JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1942 KJS_CHECKEXCEPTIONVALUE
1943
1944 JSValue *n2 = jsNumber(v->toNumber(exec) - 1);
1945 base->put(exec, propertyName, n2);
1946
1947 return n2;
1948}
1949
1950// ------------------------------ PrefixDotNode ----------------------------------
1951
1952void PrefixDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1953{
1954 nodeStack.append(m_base.get());
1955}
1956
1957JSValue *PreIncDotNode::evaluate(ExecState *exec)
1958{
1959 JSValue *baseValue = m_base->evaluate(exec);
1960 KJS_CHECKEXCEPTIONVALUE
1961 JSObject *base = baseValue->toObject(exec);
1962
1963 PropertySlot slot;
1964 JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1965 KJS_CHECKEXCEPTIONVALUE
1966
1967 double n = v->toNumber(exec);
1968 JSValue *n2 = jsNumber(n + 1);
1969 base->put(exec, m_ident, n2);
1970
1971 return n2;
1972}
1973
1974JSValue *PreDecDotNode::evaluate(ExecState *exec)
1975{
1976 JSValue *baseValue = m_base->evaluate(exec);
1977 KJS_CHECKEXCEPTIONVALUE
1978 JSObject *base = baseValue->toObject(exec);
1979
1980 PropertySlot slot;
1981 JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1982 KJS_CHECKEXCEPTIONVALUE
1983
1984 double n = v->toNumber(exec);
1985 JSValue *n2 = jsNumber(n - 1);
1986 base->put(exec, m_ident, n2);
1987
1988 return n2;
1989}
1990
1991// ------------------------------ PrefixErrorNode -----------------------------------
1992
1993JSValue* PrefixErrorNode::evaluate(ExecState* exec)
1994{
1995 throwError(exec, ReferenceError, "Prefix %s operator applied to value that is not a reference.",
1996 m_oper == OpPlusPlus ? "++" : "--");
1997 handleException(exec);
1998 return jsUndefined();
1999}
2000
2001// ------------------------------ UnaryPlusNode --------------------------------
2002
2003void UnaryPlusNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2004{
2005 nodeStack.append(m_expr.get());
2006}
2007
2008// ECMA 11.4.6
2009JSValue* UnaryPlusNode::evaluate(ExecState* exec)
2010{
2011 JSValue *v = m_expr->evaluate(exec);
2012 KJS_CHECKEXCEPTIONVALUE
2013 return v->toJSNumber(exec);
2014}
2015
2016bool UnaryPlusNode::evaluateToBoolean(ExecState* exec)
2017{
2018 return m_expr->evaluateToBoolean(exec);
2019}
2020
2021double UnaryPlusNode::evaluateToNumber(ExecState* exec)
2022{
2023 return m_expr->evaluateToNumber(exec);
2024}
2025
2026int32_t UnaryPlusNode::evaluateToInt32(ExecState* exec)
2027{
2028 return m_expr->evaluateToInt32(exec);
2029}
2030
2031uint32_t UnaryPlusNode::evaluateToUInt32(ExecState* exec)
2032{
2033 return m_expr->evaluateToInt32(exec);
2034}
2035
2036// ------------------------------ NegateNode -----------------------------------
2037
2038void NegateNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2039{
2040 nodeStack.append(m_expr.get());
2041}
2042
2043// ECMA 11.4.7
2044JSValue* NegateNode::evaluate(ExecState* exec)
2045{
2046 // No need to check exception, caller will do so right after evaluate()
2047 return jsNumber(-m_expr->evaluateToNumber(exec));
2048}
2049
2050double NegateNode::evaluateToNumber(ExecState* exec)
2051{
2052 // No need to check exception, caller will do so right after evaluateToNumber()
2053 return -m_expr->evaluateToNumber(exec);
2054}
2055
2056// ------------------------------ BitwiseNotNode -------------------------------
2057
2058void BitwiseNotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2059{
2060 nodeStack.append(m_expr.get());
2061}
2062
2063// ECMA 11.4.8
2064int32_t BitwiseNotNode::inlineEvaluateToInt32(ExecState* exec)
2065{
2066 return ~m_expr->evaluateToInt32(exec);
2067}
2068
2069JSValue* BitwiseNotNode::evaluate(ExecState* exec)
2070{
2071 return jsNumber(inlineEvaluateToInt32(exec));
2072}
2073
2074double BitwiseNotNode::evaluateToNumber(ExecState* exec)
2075{
2076 return inlineEvaluateToInt32(exec);
2077}
2078
2079bool BitwiseNotNode::evaluateToBoolean(ExecState* exec)
2080{
2081 return inlineEvaluateToInt32(exec);
2082}
2083
2084int32_t BitwiseNotNode::evaluateToInt32(ExecState* exec)
2085{
2086 return inlineEvaluateToInt32(exec);
2087}
2088
2089uint32_t BitwiseNotNode::evaluateToUInt32(ExecState* exec)
2090{
2091 return inlineEvaluateToInt32(exec);
2092}
2093
2094// ------------------------------ LogicalNotNode -------------------------------
2095
2096void LogicalNotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2097{
2098 nodeStack.append(m_expr.get());
2099}
2100
2101// ECMA 11.4.9
2102JSValue* LogicalNotNode::evaluate(ExecState* exec)
2103{
2104 return jsBoolean(!m_expr->evaluateToBoolean(exec));
2105}
2106
2107bool LogicalNotNode::evaluateToBoolean(ExecState* exec)
2108{
2109 return !m_expr->evaluateToBoolean(exec);
2110}
2111
2112// ------------------------------ Multiplicative Nodes -----------------------------------
2113
2114void MultNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2115{
2116 nodeStack.append(m_term1.get());
2117 nodeStack.append(m_term2.get());
2118}
2119
2120// ECMA 11.5.1
2121double MultNode::inlineEvaluateToNumber(ExecState* exec)
2122{
2123 double n1 = m_term1->evaluateToNumber(exec);
2124 KJS_CHECKEXCEPTIONNUMBER
2125 double n2 = m_term2->evaluateToNumber(exec);
2126 return n1 * n2;
2127}
2128
2129JSValue *MultNode::evaluate(ExecState* exec)
2130{
2131 return jsNumber(inlineEvaluateToNumber(exec));
2132}
2133
2134double MultNode::evaluateToNumber(ExecState* exec)
2135{
2136 return inlineEvaluateToNumber(exec);
2137}
2138
2139bool MultNode::evaluateToBoolean(ExecState* exec)
2140{
2141 return inlineEvaluateToNumber(exec);
2142}
2143
2144int32_t MultNode::evaluateToInt32(ExecState* exec)
2145{
2146 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2147}
2148
2149uint32_t MultNode::evaluateToUInt32(ExecState* exec)
2150{
2151 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2152}
2153
2154void DivNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2155{
2156 nodeStack.append(m_term1.get());
2157 nodeStack.append(m_term2.get());
2158}
2159
2160// ECMA 11.5.2
2161double DivNode::inlineEvaluateToNumber(ExecState* exec)
2162{
2163 double n1 = m_term1->evaluateToNumber(exec);
2164 KJS_CHECKEXCEPTIONNUMBER
2165 double n2 = m_term2->evaluateToNumber(exec);
2166 return n1 / n2;
2167}
2168
2169JSValue* DivNode::evaluate(ExecState* exec)
2170{
2171 return jsNumber(inlineEvaluateToNumber(exec));
2172}
2173
2174double DivNode::evaluateToNumber(ExecState* exec)
2175{
2176 return inlineEvaluateToNumber(exec);
2177}
2178
2179int32_t DivNode::evaluateToInt32(ExecState* exec)
2180{
2181 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2182}
2183
2184uint32_t DivNode::evaluateToUInt32(ExecState* exec)
2185{
2186 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2187}
2188
2189void ModNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2190{
2191 nodeStack.append(m_term1.get());
2192 nodeStack.append(m_term2.get());
2193}
2194
2195// ECMA 11.5.3
2196double ModNode::inlineEvaluateToNumber(ExecState* exec)
2197{
2198 double n1 = m_term1->evaluateToNumber(exec);
2199 KJS_CHECKEXCEPTIONNUMBER
2200 double n2 = m_term2->evaluateToNumber(exec);
2201 return fmod(n1, n2);
2202}
2203
2204JSValue* ModNode::evaluate(ExecState* exec)
2205{
2206 return jsNumber(inlineEvaluateToNumber(exec));
2207}
2208
2209double ModNode::evaluateToNumber(ExecState* exec)
2210{
2211 return inlineEvaluateToNumber(exec);
2212}
2213
2214bool ModNode::evaluateToBoolean(ExecState* exec)
2215{
2216 return inlineEvaluateToNumber(exec);
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 JSValue** slot = &exec->localStorage()[m_index].value;
3266
3267 ASSERT(m_oper != OpEqual);
3268 JSValue* v = valueForReadModifyAssignment(exec, *slot, m_right.get(), m_oper);
3269
3270 KJS_CHECKEXCEPTIONVALUE
3271
3272 *slot = v;
3273 return v;
3274}
3275
3276// ------------------------------ AssignLocalVarNode -----------------------------------
3277
3278JSValue* AssignLocalVarNode::evaluate(ExecState* exec)
3279{
3280 ASSERT(exec->variableObject() == exec->scopeChain().top());
3281 JSValue* v = m_right->evaluate(exec);
3282
3283 KJS_CHECKEXCEPTIONVALUE
3284
3285 exec->localStorage()[m_index].value = v;
3286
3287 return v;
3288}
3289
3290// ------------------------------ ReadModifyConstNode -----------------------------------
3291
3292JSValue* ReadModifyConstNode::evaluate(ExecState* exec)
3293{
3294 ASSERT(exec->variableObject() == exec->scopeChain().top());
3295 JSValue* left = exec->localStorage()[m_index].value;
3296 ASSERT(m_oper != OpEqual);
3297 JSValue* result = valueForReadModifyAssignment(exec, left, m_right.get(), m_oper);
3298 KJS_CHECKEXCEPTIONVALUE
3299 return result;
3300}
3301
3302// ------------------------------ AssignConstNode -----------------------------------
3303
3304JSValue* AssignConstNode::evaluate(ExecState* exec)
3305{
3306 return m_right->evaluate(exec);
3307}
3308
3309JSValue *ReadModifyResolveNode::evaluate(ExecState *exec)
3310{
3311 const ScopeChain& chain = exec->scopeChain();
3312 ScopeChainIterator iter = chain.begin();
3313 ScopeChainIterator end = chain.end();
3314
3315 // we must always have something in the scope chain
3316 ASSERT(iter != end);
3317
3318 PropertySlot slot;
3319 JSObject *base;
3320 do {
3321 base = *iter;
3322 if (base->getPropertySlot(exec, m_ident, slot)) {
3323 // See the comment in PostIncResolveNode::evaluate().
3324
3325 base = *iter;
3326 goto found;
3327 }
3328
3329 ++iter;
3330 } while (iter != end);
3331
3332 ASSERT(m_oper != OpEqual);
3333 return throwUndefinedVariableError(exec, m_ident);
3334
3335 found:
3336 JSValue *v;
3337
3338
3339 ASSERT(m_oper != OpEqual);
3340 JSValue *v1 = slot.getValue(exec, base, m_ident);
3341 KJS_CHECKEXCEPTIONVALUE
3342 v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
3343
3344 KJS_CHECKEXCEPTIONVALUE
3345
3346 base->put(exec, m_ident, v);
3347 return v;
3348}
3349
3350JSValue *AssignResolveNode::evaluate(ExecState *exec)
3351{
3352 const ScopeChain& chain = exec->scopeChain();
3353 ScopeChainIterator iter = chain.begin();
3354 ScopeChainIterator end = chain.end();
3355
3356 // we must always have something in the scope chain
3357 ASSERT(iter != end);
3358
3359 PropertySlot slot;
3360 JSObject *base;
3361 do {
3362 base = *iter;
3363 if (base->getPropertySlot(exec, m_ident, slot)) {
3364 // See the comment in PostIncResolveNode::evaluate().
3365
3366 base = *iter;
3367 goto found;
3368 }
3369
3370 ++iter;
3371 } while (iter != end);
3372
3373 found:
3374 JSValue *v = m_right->evaluate(exec);
3375
3376 KJS_CHECKEXCEPTIONVALUE
3377
3378 base->put(exec, m_ident, v);
3379 return v;
3380}
3381
3382// ------------------------------ ReadModifyDotNode -----------------------------------
3383
3384void AssignDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3385{
3386 nodeStack.append(m_right.get());
3387 nodeStack.append(m_base.get());
3388}
3389
3390JSValue *AssignDotNode::evaluate(ExecState *exec)
3391{
3392 JSValue *baseValue = m_base->evaluate(exec);
3393 KJS_CHECKEXCEPTIONVALUE
3394 JSObject *base = baseValue->toObject(exec);
3395
3396 JSValue *v = m_right->evaluate(exec);
3397
3398 KJS_CHECKEXCEPTIONVALUE
3399
3400 base->put(exec, m_ident, v);
3401 return v;
3402}
3403
3404void ReadModifyDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3405{
3406 nodeStack.append(m_right.get());
3407 nodeStack.append(m_base.get());
3408}
3409
3410JSValue *ReadModifyDotNode::evaluate(ExecState *exec)
3411{
3412 JSValue *baseValue = m_base->evaluate(exec);
3413 KJS_CHECKEXCEPTIONVALUE
3414 JSObject *base = baseValue->toObject(exec);
3415
3416 JSValue *v;
3417
3418 ASSERT(m_oper != OpEqual);
3419 PropertySlot slot;
3420 JSValue *v1 = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
3421 KJS_CHECKEXCEPTIONVALUE
3422 v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
3423
3424 KJS_CHECKEXCEPTIONVALUE
3425
3426 base->put(exec, m_ident, v);
3427 return v;
3428}
3429
3430// ------------------------------ AssignErrorNode -----------------------------------
3431
3432JSValue* AssignErrorNode::evaluate(ExecState* exec)
3433{
3434 throwError(exec, ReferenceError, "Left side of assignment is not a reference.");
3435 handleException(exec);
3436 return jsUndefined();
3437}
3438
3439// ------------------------------ AssignBracketNode -----------------------------------
3440
3441void AssignBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3442{
3443 nodeStack.append(m_right.get());
3444 nodeStack.append(m_subscript.get());
3445 nodeStack.append(m_base.get());
3446}
3447
3448JSValue *AssignBracketNode::evaluate(ExecState *exec)
3449{
3450 JSValue *baseValue = m_base->evaluate(exec);
3451 KJS_CHECKEXCEPTIONVALUE
3452 JSValue *subscript = m_subscript->evaluate(exec);
3453 KJS_CHECKEXCEPTIONVALUE
3454
3455 JSObject *base = baseValue->toObject(exec);
3456
3457 uint32_t propertyIndex;
3458 if (subscript->getUInt32(propertyIndex)) {
3459 JSValue *v = m_right->evaluate(exec);
3460 KJS_CHECKEXCEPTIONVALUE
3461
3462 base->put(exec, propertyIndex, v);
3463 return v;
3464 }
3465
3466 Identifier propertyName(subscript->toString(exec));
3467 JSValue *v = m_right->evaluate(exec);
3468 KJS_CHECKEXCEPTIONVALUE
3469
3470 base->put(exec, propertyName, v);
3471 return v;
3472}
3473void ReadModifyBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3474{
3475 nodeStack.append(m_right.get());
3476 nodeStack.append(m_subscript.get());
3477 nodeStack.append(m_base.get());
3478}
3479
3480JSValue *ReadModifyBracketNode::evaluate(ExecState *exec)
3481{
3482 JSValue *baseValue = m_base->evaluate(exec);
3483 KJS_CHECKEXCEPTIONVALUE
3484 JSValue *subscript = m_subscript->evaluate(exec);
3485 KJS_CHECKEXCEPTIONVALUE
3486
3487 JSObject *base = baseValue->toObject(exec);
3488
3489 uint32_t propertyIndex;
3490 if (subscript->getUInt32(propertyIndex)) {
3491 JSValue *v;
3492 ASSERT(m_oper != OpEqual);
3493 PropertySlot slot;
3494 JSValue *v1 = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
3495 KJS_CHECKEXCEPTIONVALUE
3496 v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
3497
3498 KJS_CHECKEXCEPTIONVALUE
3499
3500 base->put(exec, propertyIndex, v);
3501 return v;
3502 }
3503
3504 Identifier propertyName(subscript->toString(exec));
3505 JSValue *v;
3506
3507 ASSERT(m_oper != OpEqual);
3508 PropertySlot slot;
3509 JSValue *v1 = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
3510 KJS_CHECKEXCEPTIONVALUE
3511 v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_oper);
3512
3513 KJS_CHECKEXCEPTIONVALUE
3514
3515 base->put(exec, propertyName, v);
3516 return v;
3517}
3518
3519// ------------------------------ CommaNode ------------------------------------
3520
3521void CommaNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3522{
3523 nodeStack.append(m_expr2.get());
3524 nodeStack.append(m_expr1.get());
3525}
3526
3527// ECMA 11.14
3528JSValue* CommaNode::evaluate(ExecState *exec)
3529{
3530 m_expr1->evaluate(exec);
3531 KJS_CHECKEXCEPTIONVALUE
3532 return m_expr2->evaluate(exec);
3533}
3534
3535// ------------------------------ ConstDeclNode ----------------------------------
3536
3537ConstDeclNode::ConstDeclNode(const Identifier& ident, ExpressionNode* init)
3538 : m_ident(ident)
3539 , m_init(init)
3540{
3541}
3542
3543void ConstDeclNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3544{
3545 if (m_next)
3546 nodeStack.append(m_next.get());
3547 if (m_init)
3548 nodeStack.append(m_init.get());
3549}
3550
3551void ConstDeclNode::handleSlowCase(ExecState* exec, const ScopeChain& chain, JSValue* val)
3552{
3553 ScopeChainIterator iter = chain.begin();
3554 ScopeChainIterator end = chain.end();
3555
3556 // we must always have something in the scope chain
3557 ASSERT(iter != end);
3558
3559 PropertySlot slot;
3560 JSObject* base;
3561
3562 do {
3563 base = *iter;
3564 if (base->getPropertySlot(exec, m_ident, slot))
3565 break;
3566
3567 ++iter;
3568 } while (iter != end);
3569
3570 unsigned flags = 0;
3571 base->getPropertyAttributes(m_ident, flags);
3572 flags |= ReadOnly;
3573
3574 base->put(exec, m_ident, val, flags);
3575}
3576
3577// ECMA 12.2
3578inline void ConstDeclNode::evaluateSingle(ExecState* exec)
3579{
3580 ASSERT(exec->variableObject()->hasOwnProperty(exec, m_ident) || exec->codeType() == EvalCode); // Guaranteed by processDeclarations.
3581 const ScopeChain& chain = exec->scopeChain();
3582 JSObject* variableObject = exec->variableObject();
3583
3584 ASSERT(!chain.isEmpty());
3585
3586 bool inGlobalScope = ++chain.begin() == chain.end();
3587
3588 if (m_init) {
3589 if (inGlobalScope) {
3590 JSValue* val = m_init->evaluate(exec);
3591 int flags = Internal;
3592 if (exec->codeType() != EvalCode)
3593 flags |= DontDelete;
3594 flags |= ReadOnly;
3595 variableObject->put(exec, m_ident, val, flags);
3596 } else {
3597 JSValue* val = m_init->evaluate(exec);
3598 KJS_CHECKEXCEPTIONVOID
3599
3600 // if the variable object is the top of the scope chain, then that must
3601 // be where this variable is declared, processVarDecls would have put
3602 // it there. Don't search the scope chain, to optimize this very common case.
3603 if (chain.top() != variableObject)
3604 return handleSlowCase(exec, chain, val);
3605
3606 unsigned flags = 0;
3607 variableObject->getPropertyAttributes(m_ident, flags);
3608 flags |= ReadOnly;
3609
3610 variableObject->put(exec, m_ident, val, flags);
3611 }
3612 }
3613}
3614
3615JSValue* ConstDeclNode::evaluate(ExecState* exec)
3616{
3617 evaluateSingle(exec);
3618
3619 if (ConstDeclNode* n = m_next.get()) {
3620 do {
3621 n->evaluateSingle(exec);
3622 KJS_CHECKEXCEPTIONVALUE
3623 n = n->m_next.get();
3624 } while (n);
3625 }
3626 return jsUndefined();
3627}
3628
3629// ------------------------------ ConstStatementNode -----------------------------
3630
3631void ConstStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3632{
3633 ASSERT(m_next);
3634 nodeStack.append(m_next.get());
3635}
3636
3637// ECMA 12.2
3638JSValue* ConstStatementNode::execute(ExecState* exec)
3639{
3640 m_next->evaluate(exec);
3641 KJS_CHECKEXCEPTION
3642
3643 return exec->setNormalCompletion();
3644}
3645
3646// ------------------------------ Helper functions for handling Vectors of StatementNode -------------------------------
3647
3648static inline void statementListPushFIFO(StatementVector& statements, DeclarationStacks::NodeStack& stack)
3649{
3650 StatementVector::iterator it = statements.end();
3651 StatementVector::iterator begin = statements.begin();
3652 while (it != begin) {
3653 --it;
3654 stack.append((*it).get());
3655 }
3656}
3657
3658static inline Node* statementListInitializeVariableAccessStack(StatementVector& statements, DeclarationStacks::NodeStack& stack)
3659{
3660 if (!statements.size())
3661 return 0;
3662
3663 StatementVector::iterator it = statements.end();
3664 StatementVector::iterator begin = statements.begin();
3665 StatementVector::iterator beginPlusOne = begin + 1;
3666
3667 while (it != beginPlusOne) {
3668 --it;
3669 stack.append((*it).get());
3670 }
3671
3672 return (*begin).get();
3673}
3674
3675static inline JSValue* statementListExecute(StatementVector& statements, ExecState* exec)
3676{
3677 JSValue* value = 0;
3678 size_t size = statements.size();
3679 for (size_t i = 0; i != size; ++i) {
3680 JSValue* statementValue = statements[i]->execute(exec);
3681 if (statementValue)
3682 value = statementValue;
3683 if (exec->completionType() != Normal)
3684 return value;
3685 }
3686 return exec->setNormalCompletion(value);
3687}
3688
3689// ------------------------------ BlockNode ------------------------------------
3690
3691BlockNode::BlockNode(SourceElements* children)
3692{
3693 if (children)
3694 children->releaseContentsIntoVector(m_children);
3695}
3696
3697void BlockNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3698{
3699 statementListPushFIFO(m_children, nodeStack);
3700}
3701
3702// ECMA 12.1
3703JSValue* BlockNode::execute(ExecState* exec)
3704{
3705 return statementListExecute(m_children, exec);
3706}
3707
3708// ------------------------------ EmptyStatementNode ---------------------------
3709
3710// ECMA 12.3
3711JSValue* EmptyStatementNode::execute(ExecState* exec)
3712{
3713 return exec->setNormalCompletion();
3714}
3715
3716// ------------------------------ ExprStatementNode ----------------------------
3717
3718void ExprStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3719{
3720 ASSERT(m_expr);
3721 nodeStack.append(m_expr.get());
3722}
3723
3724// ECMA 12.4
3725JSValue* ExprStatementNode::execute(ExecState* exec)
3726{
3727 JSValue* value = m_expr->evaluate(exec);
3728 KJS_CHECKEXCEPTION
3729
3730 return exec->setNormalCompletion(value);
3731}
3732
3733// ------------------------------ VarStatementNode ----------------------------
3734
3735void VarStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3736{
3737 ASSERT(m_expr);
3738 nodeStack.append(m_expr.get());
3739}
3740
3741JSValue* VarStatementNode::execute(ExecState* exec)
3742{
3743 m_expr->evaluate(exec);
3744 KJS_CHECKEXCEPTION
3745
3746 return exec->setNormalCompletion();
3747}
3748
3749// ------------------------------ IfNode ---------------------------------------
3750
3751void IfNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3752{
3753 nodeStack.append(m_ifBlock.get());
3754 nodeStack.append(m_condition.get());
3755}
3756
3757// ECMA 12.5
3758JSValue* IfNode::execute(ExecState* exec)
3759{
3760 bool b = m_condition->evaluateToBoolean(exec);
3761 KJS_CHECKEXCEPTION
3762
3763 if (b)
3764 return m_ifBlock->execute(exec);
3765 return exec->setNormalCompletion();
3766}
3767
3768void IfElseNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
3769{
3770 nodeStack.append(m_elseBlock.get());
3771 IfNode::optimizeVariableAccess(symbolTable, localStorage, nodeStack);
3772}
3773
3774// ECMA 12.5
3775JSValue* IfElseNode::execute(ExecState* exec)
3776{
3777 bool b = m_condition->evaluateToBoolean(exec);
3778 KJS_CHECKEXCEPTION
3779
3780 if (b)
3781 return m_ifBlock->execute(exec);
3782
3783 return m_elseBlock->execute(exec);
3784}
3785
3786// ------------------------------ DoWhileNode ----------------------------------
3787
3788void DoWhileNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3789{
3790 nodeStack.append(m_statement.get());
3791 nodeStack.append(m_expr.get());
3792}
3793
3794// ECMA 12.6.1
3795JSValue* DoWhileNode::execute(ExecState* exec)
3796{
3797 JSValue* value = 0;
3798
3799 while (1) {
3800 exec->pushIteration();
3801 JSValue* statementValue = m_statement->execute(exec);
3802 exec->popIteration();
3803
3804 if (exec->dynamicGlobalObject()->timedOut())
3805 return exec->setInterruptedCompletion();
3806
3807 if (statementValue)
3808 value = statementValue;
3809
3810 if (exec->completionType() != Normal) {
3811 if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
3812 goto continueDoWhileLoop;
3813 if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
3814 break;
3815 return statementValue;
3816 }
3817
3818continueDoWhileLoop:
3819 bool b = m_expr->evaluateToBoolean(exec);
3820 KJS_CHECKEXCEPTION
3821 if (!b)
3822 break;
3823 }
3824
3825 return exec->setNormalCompletion(value);
3826}
3827
3828// ------------------------------ WhileNode ------------------------------------
3829
3830void WhileNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3831{
3832 nodeStack.append(m_statement.get());
3833 nodeStack.append(m_expr.get());
3834}
3835
3836// ECMA 12.6.2
3837JSValue* WhileNode::execute(ExecState* exec)
3838{
3839 JSValue* value = 0;
3840
3841 while (1) {
3842 bool b = m_expr->evaluateToBoolean(exec);
3843 KJS_CHECKEXCEPTION
3844 if (!b)
3845 break;
3846
3847 exec->pushIteration();
3848 JSValue* statementValue = m_statement->execute(exec);
3849 exec->popIteration();
3850
3851 if (exec->dynamicGlobalObject()->timedOut())
3852 return exec->setInterruptedCompletion();
3853
3854 if (statementValue)
3855 value = statementValue;
3856
3857 if (exec->completionType() != Normal) {
3858 if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
3859 continue;
3860 if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
3861 break;
3862 return statementValue;
3863 }
3864 }
3865
3866 return exec->setNormalCompletion(value);
3867}
3868
3869// ------------------------------ ForNode --------------------------------------
3870
3871void ForNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3872{
3873 nodeStack.append(m_statement.get());
3874 nodeStack.append(m_expr3.get());
3875 nodeStack.append(m_expr2.get());
3876 nodeStack.append(m_expr1.get());
3877}
3878
3879// ECMA 12.6.3
3880JSValue* ForNode::execute(ExecState *exec)
3881{
3882 JSValue* value = 0;
3883
3884 m_expr1->evaluate(exec);
3885 KJS_CHECKEXCEPTION
3886
3887 while (1) {
3888 bool b = m_expr2->evaluateToBoolean(exec);
3889 KJS_CHECKEXCEPTION
3890 if (!b)
3891 break;
3892
3893 exec->pushIteration();
3894 JSValue* statementValue = m_statement->execute(exec);
3895 exec->popIteration();
3896 if (statementValue)
3897 value = statementValue;
3898
3899 if (exec->dynamicGlobalObject()->timedOut())
3900 return exec->setInterruptedCompletion();
3901
3902 if (exec->completionType() != Normal) {
3903 if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
3904 goto continueForLoop;
3905 if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
3906 break;
3907 return statementValue;
3908 }
3909
3910continueForLoop:
3911 m_expr3->evaluate(exec);
3912 KJS_CHECKEXCEPTION
3913 }
3914
3915 return exec->setNormalCompletion(value);
3916}
3917
3918// ------------------------------ ForInNode ------------------------------------
3919
3920ForInNode::ForInNode(ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
3921 : m_init(0L)
3922 , m_lexpr(l)
3923 , m_expr(expr)
3924 , m_statement(statement)
3925 , m_identIsVarDecl(false)
3926{
3927}
3928
3929ForInNode::ForInNode(const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement)
3930 : m_ident(ident)
3931 , m_lexpr(new ResolveNode(ident))
3932 , m_expr(expr)
3933 , m_statement(statement)
3934 , m_identIsVarDecl(true)
3935{
3936 if (in)
3937 m_init = new AssignResolveNode(ident, in);
3938 // for( var foo = bar in baz )
3939}
3940
3941void ForInNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3942{
3943 nodeStack.append(m_statement.get());
3944 nodeStack.append(m_expr.get());
3945 nodeStack.append(m_lexpr.get());
3946 if (m_init)
3947 nodeStack.append(m_init.get());
3948}
3949
3950// ECMA 12.6.4
3951JSValue* ForInNode::execute(ExecState* exec)
3952{
3953 JSValue* value = 0;
3954
3955 if (m_init) {
3956 m_init->evaluate(exec);
3957 KJS_CHECKEXCEPTION
3958 }
3959
3960 JSValue* e = m_expr->evaluate(exec);
3961 KJS_CHECKEXCEPTION
3962
3963 // For Null and Undefined, we want to make sure not to go through
3964 // the loop at all, because toObject will throw an exception.
3965 if (e->isUndefinedOrNull())
3966 return exec->setNormalCompletion();
3967
3968 JSObject* v = e->toObject(exec);
3969 PropertyNameArray propertyNames;
3970 v->getPropertyNames(exec, propertyNames);
3971
3972 PropertyNameArray::const_iterator end = propertyNames.end();
3973 for (PropertyNameArray::const_iterator it = propertyNames.begin(); it != end; ++it) {
3974 const Identifier& name = *it;
3975 if (!v->hasProperty(exec, name))
3976 continue;
3977
3978 JSValue *str = jsOwnedString(name.ustring());
3979
3980 if (m_lexpr->isResolveNode()) {
3981 const Identifier& ident = static_cast<ResolveNode*>(m_lexpr.get())->identifier();
3982
3983 const ScopeChain& chain = exec->scopeChain();
3984 ScopeChainIterator iter = chain.begin();
3985 ScopeChainIterator end = chain.end();
3986
3987 // we must always have something in the scope chain
3988 ASSERT(iter != end);
3989
3990 PropertySlot slot;
3991 JSObject *o;
3992 do {
3993 o = *iter;
3994 if (o->getPropertySlot(exec, ident, slot)) {
3995 o->put(exec, ident, str);
3996 break;
3997 }
3998 ++iter;
3999 } while (iter != end);
4000
4001 if (iter == end)
4002 o->put(exec, ident, str);
4003 } else if (m_lexpr->isDotAccessorNode()) {
4004 const Identifier& ident = static_cast<DotAccessorNode*>(m_lexpr.get())->identifier();
4005 JSValue* v = static_cast<DotAccessorNode*>(m_lexpr.get())->base()->evaluate(exec);
4006 KJS_CHECKEXCEPTION
4007 JSObject *o = v->toObject(exec);
4008
4009 o->put(exec, ident, str);
4010 } else {
4011 ASSERT(m_lexpr->isBracketAccessorNode());
4012 JSValue* v = static_cast<BracketAccessorNode*>(m_lexpr.get())->base()->evaluate(exec);
4013 KJS_CHECKEXCEPTION
4014 JSValue* v2 = static_cast<BracketAccessorNode*>(m_lexpr.get())->subscript()->evaluate(exec);
4015 KJS_CHECKEXCEPTION
4016 JSObject *o = v->toObject(exec);
4017
4018 uint32_t i;
4019 if (v2->getUInt32(i))
4020 o->put(exec, i, str);
4021 o->put(exec, Identifier(v2->toString(exec)), str);
4022 }
4023
4024 KJS_CHECKEXCEPTION
4025
4026 exec->pushIteration();
4027 JSValue* statementValue = m_statement->execute(exec);
4028 exec->popIteration();
4029 if (statementValue)
4030 value = statementValue;
4031
4032 if (exec->completionType() != Normal) {
4033 if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
4034 continue;
4035 if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
4036 break;
4037 return statementValue;
4038 }
4039 }
4040
4041 return exec->setNormalCompletion(value);
4042}
4043
4044// ------------------------------ ContinueNode ---------------------------------
4045
4046// ECMA 12.7
4047JSValue* ContinueNode::execute(ExecState* exec)
4048{
4049 if (m_ident.isEmpty() && !exec->inIteration())
4050 return setErrorCompletion(exec, SyntaxError, "Invalid continue statement.");
4051 if (!m_ident.isEmpty() && !exec->seenLabels().contains(m_ident))
4052 return setErrorCompletion(exec, SyntaxError, "Label %s not found.", m_ident);
4053 return exec->setContinueCompletion(&m_ident);
4054}
4055
4056// ------------------------------ BreakNode ------------------------------------
4057
4058// ECMA 12.8
4059JSValue* BreakNode::execute(ExecState *exec)
4060{
4061 if (m_ident.isEmpty() && !exec->inIteration() && !exec->inSwitch())
4062 return setErrorCompletion(exec, SyntaxError, "Invalid break statement.");
4063 if (!m_ident.isEmpty() && !exec->seenLabels().contains(m_ident))
4064 return setErrorCompletion(exec, SyntaxError, "Label %s not found.");
4065 return exec->setBreakCompletion(&m_ident);
4066}
4067
4068// ------------------------------ ReturnNode -----------------------------------
4069
4070void ReturnNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4071{
4072 if (m_value)
4073 nodeStack.append(m_value.get());
4074}
4075
4076// ECMA 12.9
4077JSValue* ReturnNode::execute(ExecState* exec)
4078{
4079 CodeType codeType = exec->codeType();
4080 if (codeType != FunctionCode)
4081 return setErrorCompletion(exec, SyntaxError, "Invalid return statement.");
4082
4083 if (!m_value)
4084 return exec->setReturnValueCompletion(jsUndefined());
4085
4086 JSValue* v = m_value->evaluate(exec);
4087 KJS_CHECKEXCEPTION
4088
4089 return exec->setReturnValueCompletion(v);
4090}
4091
4092// ------------------------------ WithNode -------------------------------------
4093
4094void WithNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4095{
4096 // Can't optimize within statement because "with" introduces a dynamic scope.
4097 nodeStack.append(m_expr.get());
4098}
4099
4100// ECMA 12.10
4101JSValue* WithNode::execute(ExecState *exec)
4102{
4103 JSValue *v = m_expr->evaluate(exec);
4104 KJS_CHECKEXCEPTION
4105 JSObject *o = v->toObject(exec);
4106 KJS_CHECKEXCEPTION
4107 exec->dynamicGlobalObject()->tearOffActivation(exec);
4108 exec->pushScope(o);
4109 JSValue* value = m_statement->execute(exec);
4110 exec->popScope();
4111
4112 return value;
4113}
4114
4115// ------------------------------ CaseClauseNode -------------------------------
4116
4117void CaseClauseNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4118{
4119 if (m_expr)
4120 nodeStack.append(m_expr.get());
4121 statementListPushFIFO(m_children, nodeStack);
4122}
4123
4124// ECMA 12.11
4125JSValue *CaseClauseNode::evaluate(ExecState *exec)
4126{
4127 JSValue *v = m_expr->evaluate(exec);
4128 KJS_CHECKEXCEPTIONVALUE
4129
4130 return v;
4131}
4132
4133// ECMA 12.11
4134JSValue* CaseClauseNode::executeStatements(ExecState* exec)
4135{
4136 return statementListExecute(m_children, exec);
4137}
4138
4139// ------------------------------ ClauseListNode -------------------------------
4140
4141void ClauseListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4142{
4143 if (m_next)
4144 nodeStack.append(m_next.get());
4145 nodeStack.append(m_clause.get());
4146}
4147
4148// ------------------------------ CaseBlockNode --------------------------------
4149
4150CaseBlockNode::CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2)
4151 : m_list1(list1)
4152 , m_defaultClause(defaultClause)
4153 , m_list2(list2)
4154{
4155}
4156
4157void CaseBlockNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4158{
4159 if (m_list2)
4160 nodeStack.append(m_list2.get());
4161 if (m_defaultClause)
4162 nodeStack.append(m_defaultClause.get());
4163 if (m_list1)
4164 nodeStack.append(m_list1.get());
4165}
4166
4167// ECMA 12.11
4168JSValue* CaseBlockNode::executeBlock(ExecState* exec, JSValue* input)
4169{
4170 ClauseListNode* a = m_list1.get();
4171 while (a) {
4172 CaseClauseNode* clause = a->getClause();
4173 a = a->getNext();
4174 JSValue* v = clause->evaluate(exec);
4175 KJS_CHECKEXCEPTION
4176 if (strictEqual(exec, input, v)) {
4177 JSValue* res = clause->executeStatements(exec);
4178 if (exec->completionType() != Normal)
4179 return res;
4180 for (; a; a = a->getNext()) {
4181 JSValue* res = a->getClause()->executeStatements(exec);
4182 if (exec->completionType() != Normal)
4183 return res;
4184 }
4185 break;
4186 }
4187 }
4188
4189 ClauseListNode* b = m_list2.get();
4190 while (b) {
4191 CaseClauseNode* clause = b->getClause();
4192 b = b->getNext();
4193 JSValue* v = clause->evaluate(exec);
4194 KJS_CHECKEXCEPTION
4195 if (strictEqual(exec, input, v)) {
4196 JSValue* res = clause->executeStatements(exec);
4197 if (exec->completionType() != Normal)
4198 return res;
4199 goto step18;
4200 }
4201 }
4202
4203 // default clause
4204 if (m_defaultClause) {
4205 JSValue* res = m_defaultClause->executeStatements(exec);
4206 if (exec->completionType() != Normal)
4207 return res;
4208 }
4209 b = m_list2.get();
4210 step18:
4211 while (b) {
4212 CaseClauseNode* clause = b->getClause();
4213 JSValue* res = clause->executeStatements(exec);
4214 if (exec->completionType() != Normal)
4215 return res;
4216 b = b->getNext();
4217 }
4218
4219 // bail out on error
4220 KJS_CHECKEXCEPTION
4221
4222 return exec->setNormalCompletion();
4223}
4224
4225// ------------------------------ SwitchNode -----------------------------------
4226
4227void SwitchNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4228{
4229 nodeStack.append(m_block.get());
4230 nodeStack.append(m_expr.get());
4231}
4232
4233// ECMA 12.11
4234JSValue* SwitchNode::execute(ExecState* exec)
4235{
4236 JSValue *v = m_expr->evaluate(exec);
4237 KJS_CHECKEXCEPTION
4238
4239 exec->pushSwitch();
4240 JSValue* result = m_block->executeBlock(exec, v);
4241 exec->popSwitch();
4242
4243 if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
4244 exec->setCompletionType(Normal);
4245 return result;
4246}
4247
4248// ------------------------------ LabelNode ------------------------------------
4249
4250void LabelNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4251{
4252 nodeStack.append(m_statement.get());
4253}
4254
4255// ECMA 12.12
4256JSValue* LabelNode::execute(ExecState* exec)
4257{
4258 if (!exec->seenLabels().push(m_label))
4259 return setErrorCompletion(exec, SyntaxError, "Duplicated label %s found.", m_label);
4260 JSValue* result = m_statement->execute(exec);
4261 exec->seenLabels().pop();
4262
4263 if (exec->completionType() == Break && exec->breakOrContinueTarget() == m_label)
4264 exec->setCompletionType(Normal);
4265 return result;
4266}
4267
4268// ------------------------------ ThrowNode ------------------------------------
4269
4270void ThrowNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4271{
4272 nodeStack.append(m_expr.get());
4273}
4274
4275// ECMA 12.13
4276JSValue* ThrowNode::execute(ExecState* exec)
4277{
4278 JSValue *v = m_expr->evaluate(exec);
4279 KJS_CHECKEXCEPTION
4280
4281 handleException(exec, v);
4282 return exec->setThrowCompletion(v);
4283}
4284
4285// ------------------------------ TryNode --------------------------------------
4286
4287void TryNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4288{
4289 // Can't optimize within catchBlock because "catch" introduces a dynamic scope.
4290 if (m_finallyBlock)
4291 nodeStack.append(m_finallyBlock.get());
4292 nodeStack.append(m_tryBlock.get());
4293}
4294
4295// ECMA 12.14
4296JSValue* TryNode::execute(ExecState* exec)
4297{
4298 JSValue* result = m_tryBlock->execute(exec);
4299
4300 if (Collector::isOutOfMemory())
4301 return result; // don't try to catch an out of memory exception thrown by the collector
4302
4303 if (m_catchBlock && exec->completionType() == Throw) {
4304 JSObject* obj = new JSObject;
4305 obj->put(exec, m_exceptionIdent, result, DontDelete);
4306 exec->dynamicGlobalObject()->tearOffActivation(exec);
4307 exec->pushScope(obj);
4308 result = m_catchBlock->execute(exec);
4309 exec->popScope();
4310 }
4311
4312 if (m_finallyBlock) {
4313 ComplType savedCompletionType = exec->completionType();
4314 JSValue* finallyResult = m_finallyBlock->execute(exec);
4315 if (exec->completionType() != Normal)
4316 result = finallyResult;
4317 else
4318 exec->setCompletionType(savedCompletionType);
4319 }
4320
4321 return result;
4322}
4323
4324// ------------------------------ FunctionBodyNode -----------------------------
4325
4326ScopeNode::ScopeNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4327 : BlockNode(children)
4328 , m_sourceURL(parser().sourceURL())
4329 , m_sourceId(parser().sourceId())
4330{
4331 if (varStack)
4332 m_varStack = *varStack;
4333 if (funcStack)
4334 m_functionStack = *funcStack;
4335}
4336
4337// ------------------------------ ProgramNode -----------------------------
4338
4339ProgramNode::ProgramNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4340 : ScopeNode(children, varStack, funcStack)
4341{
4342}
4343
4344ProgramNode* ProgramNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4345{
4346 return new ProgramNode(children, varStack, funcStack);
4347}
4348
4349// ------------------------------ EvalNode -----------------------------
4350
4351EvalNode::EvalNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4352 : ScopeNode(children, varStack, funcStack)
4353{
4354}
4355
4356EvalNode* EvalNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4357{
4358 return new EvalNode(children, varStack, funcStack);
4359}
4360
4361// ------------------------------ FunctionBodyNode -----------------------------
4362
4363FunctionBodyNode::FunctionBodyNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4364 : ScopeNode(children, varStack, funcStack)
4365 , m_initialized(false)
4366{
4367}
4368
4369FunctionBodyNode* FunctionBodyNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4370{
4371 if (Debugger::debuggersPresent)
4372 return new FunctionBodyNodeWithDebuggerHooks(children, varStack, funcStack);
4373 return new FunctionBodyNode(children, varStack, funcStack);
4374}
4375
4376void FunctionBodyNode::initializeSymbolTable(ExecState* exec)
4377{
4378 SymbolTable& symbolTable = exec->variableObject()->symbolTable();
4379 ASSERT(!symbolTable.size());
4380
4381 size_t localStorageIndex = 0;
4382
4383 // Order must match the order in processDeclarations.
4384
4385 for (size_t i = 0, size = m_parameters.size(); i < size; ++i, ++localStorageIndex) {
4386 UString::Rep* rep = m_parameters[i].ustring().rep();
4387 symbolTable.set(rep, localStorageIndex);
4388 }
4389
4390 for (size_t i = 0, size = m_functionStack.size(); i < size; ++i, ++localStorageIndex) {
4391 UString::Rep* rep = m_functionStack[i]->m_ident.ustring().rep();
4392 symbolTable.set(rep, localStorageIndex);
4393 }
4394
4395 for (size_t i = 0, size = m_varStack.size(); i < size; ++i, ++localStorageIndex) {
4396 Identifier& ident = m_varStack[i].first;
4397 if (ident == exec->propertyNames().arguments)
4398 continue;
4399 symbolTable.add(ident.ustring().rep(), localStorageIndex);
4400 }
4401}
4402
4403void ProgramNode::initializeSymbolTable(ExecState* exec)
4404{
4405 // If a previous script defined a symbol with the same name as one of our
4406 // symbols, to avoid breaking previously optimized nodes, we need to reuse
4407 // the symbol's existing storage index. So, we can't be as efficient as
4408 // FunctionBodyNode::initializeSymbolTable, which knows that no bindings
4409 // have yet been made.
4410
4411 JSVariableObject* variableObject = exec->variableObject();
4412 SymbolTable& symbolTable = variableObject->symbolTable();
4413
4414 size_t localStorageIndex = symbolTable.size();
4415 size_t size;
4416
4417 // Order must match the order in processDeclarations.
4418
4419 size = m_functionStack.size();
4420 m_functionIndexes.resize(size);
4421 for (size_t i = 0; i < size; ++i) {
4422 UString::Rep* rep = m_functionStack[i]->m_ident.ustring().rep();
4423 pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
4424 m_functionIndexes[i] = result.first->second;
4425 if (result.second)
4426 ++localStorageIndex;
4427 }
4428
4429 size = m_varStack.size();
4430 m_varIndexes.resize(size);
4431 for (size_t i = 0; i < size; ++i) {
4432 const Identifier& ident = m_varStack[i].first;
4433 if (variableObject->hasProperty(exec, ident)) {
4434 m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
4435 continue;
4436 }
4437
4438 UString::Rep* rep = ident.ustring().rep();
4439 pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
4440 if (!result.second) {
4441 m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
4442 continue;
4443 }
4444
4445 m_varIndexes[i] = result.first->second;
4446 ++localStorageIndex;
4447 }
4448}
4449
4450void ScopeNode::optimizeVariableAccess(ExecState* exec)
4451{
4452 NodeStack nodeStack;
4453 Node* node = statementListInitializeVariableAccessStack(m_children, nodeStack);
4454 if (!node)
4455 return;
4456
4457 const SymbolTable& symbolTable = exec->variableObject()->symbolTable();
4458 const LocalStorage& localStorage = exec->variableObject()->localStorage();
4459 while (true) {
4460 node->optimizeVariableAccess(symbolTable, localStorage, nodeStack);
4461
4462 size_t size = nodeStack.size();
4463 if (!size)
4464 break;
4465 --size;
4466 node = nodeStack[size];
4467 nodeStack.shrink(size);
4468 }
4469}
4470
4471void FunctionBodyNode::processDeclarations(ExecState* exec)
4472{
4473 if (!m_initialized)
4474 initializeSymbolTable(exec);
4475
4476 if (m_functionStack.size() != 0)
4477 exec->dynamicGlobalObject()->tearOffActivation(exec);
4478
4479 LocalStorage& localStorage = exec->variableObject()->localStorage();
4480
4481 // We can't just resize localStorage here because that would temporarily
4482 // leave uninitialized entries, which would crash GC during the mark phase.
4483 size_t totalSize = m_varStack.size() + m_parameters.size() + m_functionStack.size();
4484 if (totalSize > localStorage.capacity()) // Doing this check inline avoids function call overhead.
4485 localStorage.reserveCapacity(totalSize);
4486
4487 int minAttributes = Internal | DontDelete;
4488
4489 // In order for our localStorage indexes to be correct, we must match the
4490 // order of addition in initializeSymbolTable().
4491
4492 const List& args = *exec->arguments();
4493 for (size_t i = 0, size = m_parameters.size(); i < size; ++i)
4494 localStorage.uncheckedAppend(LocalStorageEntry(args[i], DontDelete));
4495
4496 for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
4497 FuncDeclNode* node = m_functionStack[i];
4498 localStorage.uncheckedAppend(LocalStorageEntry(node->makeFunction(exec), minAttributes));
4499 }
4500
4501 for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
4502 int attributes = minAttributes;
4503 if (m_varStack[i].second & DeclarationStacks::IsConstant)
4504 attributes |= ReadOnly;
4505 localStorage.uncheckedAppend(LocalStorageEntry(jsUndefined(), attributes));
4506 }
4507
4508 if (!m_initialized) {
4509 optimizeVariableAccess(exec);
4510 m_initialized = true;
4511 }
4512}
4513
4514static void gccIsCrazy() KJS_FAST_CALL;
4515static void gccIsCrazy()
4516{
4517}
4518
4519void ProgramNode::processDeclarations(ExecState* exec)
4520{
4521 // If you remove this call, some SunSpider tests, including
4522 // bitops-nsieve-bits.js, will regress substantially on Mac, due to a ~40%
4523 // increase in L2 cache misses. FIXME: <rdar://problem/5657439> WTF?
4524 gccIsCrazy();
4525
4526 initializeSymbolTable(exec);
4527
4528 LocalStorage& localStorage = exec->variableObject()->localStorage();
4529
4530 // We can't just resize localStorage here because that would temporarily
4531 // leave uninitialized entries, which would crash GC during the mark phase.
4532 localStorage.reserveCapacity(localStorage.size() + m_varStack.size() + m_functionStack.size());
4533
4534 int minAttributes = Internal | DontDelete;
4535
4536 // In order for our localStorage indexes to be correct, we must match the
4537 // order of addition in initializeSymbolTable().
4538
4539 for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
4540 FuncDeclNode* node = m_functionStack[i];
4541 LocalStorageEntry entry = LocalStorageEntry(node->makeFunction(exec), minAttributes);
4542 size_t index = m_functionIndexes[i];
4543
4544 if (index == localStorage.size())
4545 localStorage.uncheckedAppend(entry);
4546 else {
4547 ASSERT(index < localStorage.size());
4548 localStorage[index] = entry;
4549 }
4550 }
4551
4552 for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
4553 size_t index = m_varIndexes[i];
4554 if (index == missingSymbolMarker())
4555 continue;
4556
4557 int attributes = minAttributes;
4558 if (m_varStack[i].second & DeclarationStacks::IsConstant)
4559 attributes |= ReadOnly;
4560 LocalStorageEntry entry = LocalStorageEntry(jsUndefined(), attributes);
4561
4562 ASSERT(index == localStorage.size());
4563 localStorage.uncheckedAppend(entry);
4564 }
4565
4566 optimizeVariableAccess(exec);
4567}
4568
4569void EvalNode::processDeclarations(ExecState* exec)
4570{
4571 // We could optimize access to pre-existing symbols here, but SunSpider
4572 // reports that to be a net loss.
4573
4574 size_t i, size;
4575
4576 JSVariableObject* variableObject = exec->variableObject();
4577
4578 int minAttributes = Internal;
4579
4580 for (i = 0, size = m_varStack.size(); i < size; ++i) {
4581 Identifier& ident = m_varStack[i].first;
4582 if (variableObject->hasProperty(exec, ident))
4583 continue;
4584 int attributes = minAttributes;
4585 if (m_varStack[i].second & DeclarationStacks::IsConstant)
4586 attributes |= ReadOnly;
4587 variableObject->put(exec, ident, jsUndefined(), attributes);
4588 }
4589
4590 for (i = 0, size = m_functionStack.size(); i < size; ++i) {
4591 FuncDeclNode* node = m_functionStack[i];
4592 variableObject->put(exec, node->m_ident, node->makeFunction(exec), minAttributes);
4593 }
4594}
4595
4596UString FunctionBodyNode::paramString() const
4597{
4598 UString s("");
4599 size_t count = m_parameters.size();
4600 for (size_t pos = 0; pos < count; ++pos) {
4601 if (!s.isEmpty())
4602 s += ", ";
4603 s += m_parameters[pos].ustring();
4604 }
4605
4606 return s;
4607}
4608
4609JSValue* ProgramNode::execute(ExecState* exec)
4610{
4611 processDeclarations(exec);
4612 return ScopeNode::execute(exec);
4613}
4614
4615JSValue* EvalNode::execute(ExecState* exec)
4616{
4617 processDeclarations(exec);
4618 return ScopeNode::execute(exec);
4619}
4620
4621JSValue* FunctionBodyNode::execute(ExecState* exec)
4622{
4623 processDeclarations(exec);
4624 return ScopeNode::execute(exec);
4625}
4626
4627// ------------------------------ FunctionBodyNodeWithDebuggerHooks ---------------------------------
4628
4629FunctionBodyNodeWithDebuggerHooks::FunctionBodyNodeWithDebuggerHooks(SourceElements* children,
4630 DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
4631 : FunctionBodyNode(children, varStack, funcStack)
4632{
4633}
4634
4635JSValue* FunctionBodyNodeWithDebuggerHooks::execute(ExecState* exec)
4636{
4637 if (Debugger* dbg = exec->dynamicGlobalObject()->debugger()) {
4638 if (!dbg->callEvent(exec, sourceId(), lineNo(), exec->function(), *exec->arguments())) {
4639 dbg->imp()->abort();
4640 return exec->setInterruptedCompletion();
4641 }
4642 }
4643
4644 JSValue* result = FunctionBodyNode::execute(exec);
4645
4646 if (Debugger* dbg = exec->dynamicGlobalObject()->debugger()) {
4647 if (exec->completionType() == Throw)
4648 exec->setException(result);
4649 if (!dbg->returnEvent(exec, sourceId(), lineNo(), exec->function())) {
4650 dbg->imp()->abort();
4651 return exec->setInterruptedCompletion();
4652 }
4653 }
4654
4655 return result;
4656}
4657
4658// ------------------------------ FuncDeclNode ---------------------------------
4659
4660void FuncDeclNode::addParams()
4661{
4662 for (ParameterNode *p = m_parameter.get(); p != 0L; p = p->nextParam())
4663 m_body->parameters().append(p->ident());
4664}
4665
4666FunctionImp* FuncDeclNode::makeFunction(ExecState* exec)
4667{
4668 FunctionImp *func = new FunctionImp(exec, m_ident, m_body.get(), exec->scopeChain());
4669
4670 JSObject* proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
4671 proto->put(exec, exec->propertyNames().constructor, func, ReadOnly | DontDelete | DontEnum);
4672 func->put(exec, exec->propertyNames().prototype, proto, Internal|DontDelete);
4673
4674 func->put(exec, exec->propertyNames().length, jsNumber(m_body->parameters().size()), ReadOnly|DontDelete|DontEnum);
4675 return func;
4676}
4677
4678JSValue* FuncDeclNode::execute(ExecState* exec)
4679{
4680 return exec->setNormalCompletion();
4681}
4682
4683// ------------------------------ FuncExprNode ---------------------------------
4684
4685// ECMA 13
4686void FuncExprNode::addParams()
4687{
4688 for (ParameterNode* p = m_parameter.get(); p != 0L; p = p->nextParam())
4689 m_body->parameters().append(p->ident());
4690}
4691
4692JSValue *FuncExprNode::evaluate(ExecState *exec)
4693{
4694 exec->dynamicGlobalObject()->tearOffActivation(exec);
4695
4696 bool named = !m_ident.isNull();
4697 JSObject *functionScopeObject = 0;
4698
4699 if (named) {
4700 // named FunctionExpressions can recursively call themselves,
4701 // but they won't register with the current scope chain and should
4702 // be contained as single property in an anonymous object.
4703 functionScopeObject = new JSObject;
4704 exec->pushScope(functionScopeObject);
4705 }
4706
4707 FunctionImp* func = new FunctionImp(exec, m_ident, m_body.get(), exec->scopeChain());
4708 JSObject* proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
4709 proto->put(exec, exec->propertyNames().constructor, func, ReadOnly | DontDelete | DontEnum);
4710 func->put(exec, exec->propertyNames().prototype, proto, Internal | DontDelete);
4711
4712 if (named) {
4713 functionScopeObject->put(exec, m_ident, func, Internal | ReadOnly | (exec->codeType() == EvalCode ? 0 : DontDelete));
4714 exec->popScope();
4715 }
4716
4717 return func;
4718}
4719
4720} // namespace KJS
Note: See TracBrowser for help on using the repository browser.