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

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

JavaScriptCore:

2008-04-04 Sam Weinig <[email protected]>

Reviewed by Geoffrey Garen.

First step in implementing the "split window"

  • Add a GlobalThisValue to ExecState which should be used in places that used to implement the "use the global object as this if null" rule.
  • Factor out lookupGetter/lookupSetter into virtual methods on JSObject so that they can be forwarded.
  • Make defineGetter/defineSetter virtual methods for the same reason.
  • Have PrototypeReflexiveFunction store the globalObject used to create it so that it can be used to get the correct thisObject for eval.
  • API/JSObjectRef.cpp: (JSObjectCallAsFunction):
  • JavaScriptCore.exp:
  • kjs/Activation.h:
  • kjs/ExecState.cpp: (KJS::ExecState::ExecState): (KJS::GlobalExecState::GlobalExecState):
  • kjs/ExecState.h: (KJS::ExecState::globalThisValue):
  • kjs/ExecStateInlines.h: (KJS::ExecState::ExecState): (KJS::FunctionExecState::FunctionExecState):
  • kjs/JSGlobalObject.cpp: (KJS::JSGlobalObject::reset): (KJS::JSGlobalObject::toGlobalObject):
  • kjs/JSGlobalObject.h: (KJS::JSGlobalObject::JSGlobalObjectData::JSGlobalObjectData): (KJS::JSGlobalObject::JSGlobalObject):
  • kjs/array_instance.cpp: (KJS::CompareWithCompareFunctionArguments::CompareWithCompareFunctionArguments): (KJS::compareWithCompareFunctionForQSort):
  • kjs/array_object.cpp: (KJS::arrayProtoFuncSort): (KJS::arrayProtoFuncFilter): (KJS::arrayProtoFuncMap): (KJS::arrayProtoFuncEvery): (KJS::arrayProtoFuncForEach): (KJS::arrayProtoFuncSome):
  • kjs/function.cpp: (KJS::FunctionImp::callAsFunction): (KJS::ActivationImp::toThisObject): (KJS::globalFuncEval): (KJS::PrototypeReflexiveFunction::PrototypeReflexiveFunction): (KJS::PrototypeReflexiveFunction::mark):
  • kjs/function.h: (KJS::PrototypeReflexiveFunction::cachedGlobalObject):
  • kjs/function_object.cpp: (KJS::functionProtoFuncApply): (KJS::functionProtoFuncCall):
  • kjs/nodes.cpp: (KJS::ExpressionNode::resolveAndCall): (KJS::FunctionCallValueNode::evaluate): (KJS::LocalVarFunctionCallNode::inlineEvaluate): (KJS::ScopedVarFunctionCallNode::inlineEvaluate): (KJS::FunctionCallBracketNode::evaluate): (KJS::FunctionCallDotNode::inlineEvaluate):
  • kjs/object.cpp: (KJS::JSObject::call): (KJS::JSObject::put): (KJS::tryGetAndCallProperty): (KJS::JSObject::lookupGetter): (KJS::JSObject::lookupSetter): (KJS::JSObject::toThisObject): (KJS::JSObject::toGlobalObject): (KJS::JSObject::fillGetterPropertySlot):
  • kjs/object.h:
  • kjs/object_object.cpp: (KJS::objectProtoFuncLookupGetter): (KJS::objectProtoFuncLookupSetter):
  • kjs/string_object.cpp: (KJS::replace):

WebCore:

2008-04-04 Sam Weinig <[email protected]>

Reviewed by Geoffrey Garen.

First step in implementing the "split window"

  • This patch takes the first step in changing the window navigation model from clearing the window properties on navigation, to replacing an inner window. This is necessary to safely perform security checks using the lexical global object.

This first step adds a new class called JSDOMWindowWrapper, which wraps
the real window object. All JS calls that would go to the window object
now go to it, which it forwards to the current inner window. To accomplish
this, the wrapper window is used as the ThisValue wherever the window was used
before.

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