X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/b5422865f473faf3977f31b96a635c4c8c4ede09..9dae56ea45a0f5f8136a5c93d6f3a7f99399ca73:/parser/Nodes.cpp diff --git a/parser/Nodes.cpp b/parser/Nodes.cpp new file mode 100644 index 0000000..8aa1788 --- /dev/null +++ b/parser/Nodes.cpp @@ -0,0 +1,2750 @@ +/* +* Copyright (C) 1999-2002 Harri Porten (porten@kde.org) +* Copyright (C) 2001 Peter Kelly (pmk@post.com) +* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. +* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) +* Copyright (C) 2007 Maks Orlovich +* Copyright (C) 2007 Eric Seidel +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public License +* along with this library; see the file COPYING.LIB. If not, write to +* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +* Boston, MA 02110-1301, USA. +* +*/ + +#include "config.h" +#include "Nodes.h" + +#include "BytecodeGenerator.h" +#include "CallFrame.h" +#include "JSGlobalObject.h" +#include "JSStaticScopeObject.h" +#include "LabelScope.h" +#include "Parser.h" +#include "PropertyNameArray.h" +#include "RegExpObject.h" +#include "SamplingTool.h" +#include "Debugger.h" +#include "Lexer.h" +#include "Operations.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace WTF; + +namespace JSC { + +static void substitute(UString& string, const UString& substring) JSC_FAST_CALL; + +// ------------------------------ NodeReleaser -------------------------------- + +class NodeReleaser : Noncopyable { +public: + // Call this function inside the destructor of a class derived from Node. + // This will traverse the tree below this node, destroying all of those nodes, + // but without relying on recursion. + static void releaseAllNodes(ParserRefCounted* root); + + // Call this on each node in a the releaseNodes virtual function. + // It gives the node to the NodeReleaser, which will then release the + // node later at the end of the releaseAllNodes process. + template void release(RefPtr& node) { if (node) adopt(node.release()); } + void release(RefPtr& node) { if (node) adoptFunctionBodyNode(node); } + +private: + NodeReleaser() { } + ~NodeReleaser() { } + + void adopt(PassRefPtr); + void adoptFunctionBodyNode(RefPtr&); + + typedef Vector > NodeReleaseVector; + OwnPtr m_vector; +}; + +void NodeReleaser::releaseAllNodes(ParserRefCounted* root) +{ + ASSERT(root); + NodeReleaser releaser; + root->releaseNodes(releaser); + if (!releaser.m_vector) + return; + // Note: The call to release.m_vector->size() is intentionally inside + // the loop, since calls to releaseNodes are expected to increase the size. + for (size_t i = 0; i < releaser.m_vector->size(); ++i) { + ParserRefCounted* node = (*releaser.m_vector)[i].get(); + if (node->hasOneRef()) + node->releaseNodes(releaser); + } +} + +void NodeReleaser::adopt(PassRefPtr node) +{ + ASSERT(node); + if (!node->hasOneRef()) + return; + if (!m_vector) + m_vector.set(new NodeReleaseVector); + m_vector->append(node); +} + +void NodeReleaser::adoptFunctionBodyNode(RefPtr& functionBodyNode) +{ + // This sidesteps a problem where if you assign a PassRefPtr + // to a PassRefPtr we leave the two reference counts (FunctionBodyNode + // and ParserRefCounted) unbalanced. It would be nice to fix this problem in + // a cleaner way -- perhaps we could remove the FunctionBodyNode reference + // count at some point. + RefPtr node = functionBodyNode; + functionBodyNode = 0; + adopt(node.release()); +} + +// ------------------------------ ParserRefCounted ----------------------------------------- + +#ifndef NDEBUG +static RefCountedLeakCounter parserRefCountedCounter("JSC::Node"); +#endif + +ParserRefCounted::ParserRefCounted(JSGlobalData* globalData) + : m_globalData(globalData) +{ +#ifndef NDEBUG + parserRefCountedCounter.increment(); +#endif + if (!m_globalData->newParserObjects) + m_globalData->newParserObjects = new HashSet; + m_globalData->newParserObjects->add(this); + ASSERT(m_globalData->newParserObjects->contains(this)); +} + +ParserRefCounted::~ParserRefCounted() +{ +#ifndef NDEBUG + parserRefCountedCounter.decrement(); +#endif +} + +void ParserRefCounted::releaseNodes(NodeReleaser&) +{ +} + +void ParserRefCounted::ref() +{ + // bumping from 0 to 1 is just removing from the new nodes set + if (m_globalData->newParserObjects) { + HashSet::iterator it = m_globalData->newParserObjects->find(this); + if (it != m_globalData->newParserObjects->end()) { + m_globalData->newParserObjects->remove(it); + ASSERT(!m_globalData->parserObjectExtraRefCounts || !m_globalData->parserObjectExtraRefCounts->contains(this)); + return; + } + } + + ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this)); + + if (!m_globalData->parserObjectExtraRefCounts) + m_globalData->parserObjectExtraRefCounts = new HashCountedSet; + m_globalData->parserObjectExtraRefCounts->add(this); +} + +void ParserRefCounted::deref() +{ + ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this)); + + if (!m_globalData->parserObjectExtraRefCounts) { + delete this; + return; + } + + HashCountedSet::iterator it = m_globalData->parserObjectExtraRefCounts->find(this); + if (it == m_globalData->parserObjectExtraRefCounts->end()) + delete this; + else + m_globalData->parserObjectExtraRefCounts->remove(it); +} + +bool ParserRefCounted::hasOneRef() +{ + if (m_globalData->newParserObjects && m_globalData->newParserObjects->contains(this)) { + ASSERT(!m_globalData->parserObjectExtraRefCounts || !m_globalData->parserObjectExtraRefCounts->contains(this)); + return false; + } + + ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this)); + + if (!m_globalData->parserObjectExtraRefCounts) + return true; + + return !m_globalData->parserObjectExtraRefCounts->contains(this); +} + +void ParserRefCounted::deleteNewObjects(JSGlobalData* globalData) +{ + if (!globalData->newParserObjects) + return; + +#ifndef NDEBUG + HashSet::iterator end = globalData->newParserObjects->end(); + for (HashSet::iterator it = globalData->newParserObjects->begin(); it != end; ++it) + ASSERT(!globalData->parserObjectExtraRefCounts || !globalData->parserObjectExtraRefCounts->contains(*it)); +#endif + deleteAllValues(*globalData->newParserObjects); + delete globalData->newParserObjects; + globalData->newParserObjects = 0; +} + +// ------------------------------ Node -------------------------------- + +Node::Node(JSGlobalData* globalData) + : ParserRefCounted(globalData) +{ + m_line = globalData->lexer->lineNo(); +} + +// ------------------------------ ThrowableExpressionData -------------------------------- + +static void substitute(UString& string, const UString& substring) +{ + int position = string.find("%s"); + ASSERT(position != -1); + UString newString = string.substr(0, position); + newString.append(substring); + newString.append(string.substr(position + 2)); + string = newString; +} + +RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType e, const char* msg) +{ + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), msg)); + generator.emitThrow(exception); + return exception; +} + +RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType e, const char* msg, const Identifier& label) +{ + UString message = msg; + substitute(message, label.ustring()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), message)); + generator.emitThrow(exception); + return exception; +} + +// ------------------------------ StatementNode -------------------------------- + +StatementNode::StatementNode(JSGlobalData* globalData) + : Node(globalData) + , m_lastLine(-1) +{ +} + +void StatementNode::setLoc(int firstLine, int lastLine) +{ + m_line = firstLine; + m_lastLine = lastLine; +} + +// ------------------------------ SourceElements -------------------------------- + +void SourceElements::append(PassRefPtr statement) +{ + if (statement->isEmptyStatement()) + return; + + m_statements.append(statement); +} + +// ------------------------------ NullNode ------------------------------------- + +RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, jsNull()); +} + +// ------------------------------ BooleanNode ---------------------------------- + +RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, m_value); +} + +// ------------------------------ NumberNode ----------------------------------- + +RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, m_double); +} + +// ------------------------------ StringNode ----------------------------------- + +RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, m_value); +} + +// ------------------------------ RegExpNode ----------------------------------- + +RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr regExp = RegExp::create(generator.globalData(), m_pattern, m_flags); + if (!regExp->isValid()) + return emitThrowError(generator, SyntaxError, ("Invalid regular expression: " + UString(regExp->errorMessage())).UTF8String().c_str()); + if (dst == generator.ignoredResult()) + return 0; + return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get()); +} + +// ------------------------------ ThisNode ------------------------------------- + +RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); +} + +// ------------------------------ ResolveNode ---------------------------------- + +bool ResolveNode::isPure(BytecodeGenerator& generator) const +{ + return generator.isLocal(m_ident); +} + +RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (dst == generator.ignoredResult()) + return 0; + return generator.moveToDestinationIfNeeded(dst, local); + } + + generator.emitExpressionInfo(m_startOffset + m_ident.size(), m_ident.size(), 0); + return generator.emitResolve(generator.finalDestination(dst), m_ident); +} + +// ------------------------------ ElementNode ------------------------------------ + +ElementNode::~ElementNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ElementNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_next); + releaser.release(m_node); +} + +// ------------------------------ ArrayNode ------------------------------------ + +ArrayNode::~ArrayNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ArrayNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_element); +} + +RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + // FIXME: Should we put all of this code into emitNewArray? + + unsigned length = 0; + ElementNode* firstPutElement; + for (firstPutElement = m_element.get(); firstPutElement; firstPutElement = firstPutElement->next()) { + if (firstPutElement->elision()) + break; + ++length; + } + + if (!firstPutElement && !m_elision) + return generator.emitNewArray(generator.finalDestination(dst), m_element.get()); + + RefPtr array = generator.emitNewArray(generator.tempDestination(dst), m_element.get()); + + for (ElementNode* n = firstPutElement; n; n = n->next()) { + RegisterID* value = generator.emitNode(n->value()); + length += n->elision(); + generator.emitPutByIndex(array.get(), length++, value); + } + + if (m_elision) { + RegisterID* value = generator.emitLoad(0, jsNumber(generator.globalData(), m_elision + length)); + generator.emitPutById(array.get(), generator.propertyNames().length, value); + } + + return generator.moveToDestinationIfNeeded(dst, array.get()); +} + +// ------------------------------ PropertyNode ---------------------------- + +PropertyNode::~PropertyNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PropertyNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_assign); +} + +// ------------------------------ ObjectLiteralNode ---------------------------- + +ObjectLiteralNode::~ObjectLiteralNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ObjectLiteralNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_list); +} + +RegisterID* ObjectLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (!m_list) { + if (dst == generator.ignoredResult()) + return 0; + return generator.emitNewObject(generator.finalDestination(dst)); + } + return generator.emitNode(dst, m_list.get()); +} + +// ------------------------------ PropertyListNode ----------------------------- + +PropertyListNode::~PropertyListNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PropertyListNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_node); + releaser.release(m_next); +} + +RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr newObj = generator.tempDestination(dst); + + generator.emitNewObject(newObj.get()); + + for (PropertyListNode* p = this; p; p = p->m_next.get()) { + RegisterID* value = generator.emitNode(p->m_node->m_assign.get()); + + switch (p->m_node->m_type) { + case PropertyNode::Constant: { + generator.emitPutById(newObj.get(), p->m_node->name(), value); + break; + } + case PropertyNode::Getter: { + generator.emitPutGetter(newObj.get(), p->m_node->name(), value); + break; + } + case PropertyNode::Setter: { + generator.emitPutSetter(newObj.get(), p->m_node->name(), value); + break; + } + default: + ASSERT_NOT_REACHED(); + } + } + + return generator.moveToDestinationIfNeeded(dst, newObj.get()); +} + +// ------------------------------ BracketAccessorNode -------------------------------- + +BracketAccessorNode::~BracketAccessorNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void BracketAccessorNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); +} + +RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments, m_subscript->isPure(generator)); + RegisterID* property = generator.emitNode(m_subscript.get()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); +} + +// ------------------------------ DotAccessorNode -------------------------------- + +DotAccessorNode::~DotAccessorNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void DotAccessorNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); +} + +RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* base = generator.emitNode(m_base.get()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetById(generator.finalDestination(dst), base, m_ident); +} + +// ------------------------------ ArgumentListNode ----------------------------- + +ArgumentListNode::~ArgumentListNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ArgumentListNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_next); + releaser.release(m_expr); +} + +RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + ASSERT(m_expr); + return generator.emitNode(dst, m_expr.get()); +} + +// ------------------------------ ArgumentsNode ----------------------------- + +ArgumentsNode::~ArgumentsNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ArgumentsNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_listNode); +} + +// ------------------------------ NewExprNode ---------------------------------- + +NewExprNode::~NewExprNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void NewExprNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); + releaser.release(m_args); +} + +RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr func = generator.emitNode(m_expr.get()); + return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ EvalFunctionCallNode ---------------------------------- + +EvalFunctionCallNode::~EvalFunctionCallNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void EvalFunctionCallNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_args); +} + +RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr func = generator.tempDestination(dst); + RefPtr thisRegister = generator.newTemporary(); + generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); + generator.emitResolveWithBase(thisRegister.get(), func.get(), generator.propertyNames().eval); + return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallValueNode ---------------------------------- + +FunctionCallValueNode::~FunctionCallValueNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void FunctionCallValueNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); + releaser.release(m_args); +} + +RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr func = generator.emitNode(m_expr.get()); + RefPtr thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); + return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallResolveNode ---------------------------------- + +FunctionCallResolveNode::~FunctionCallResolveNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void FunctionCallResolveNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_args); +} + +RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RefPtr local = generator.registerFor(m_ident)) { + RefPtr thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); + return generator.emitCall(generator.finalDestination(dst, thisRegister.get()), local.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); + } + + int index = 0; + size_t depth = 0; + JSObject* globalObject = 0; + if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) { + RefPtr func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); + RefPtr thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); + return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); + } + + RefPtr func = generator.tempDestination(dst); + RefPtr thisRegister = generator.newTemporary(); + int identifierStart = divot() - startOffset(); + generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0); + generator.emitResolveFunction(thisRegister.get(), func.get(), m_ident); + return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallBracketNode ---------------------------------- + +FunctionCallBracketNode::~FunctionCallBracketNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void FunctionCallBracketNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); + releaser.release(m_args); +} + +RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr base = generator.emitNode(m_base.get()); + RegisterID* property = generator.emitNode(m_subscript.get()); + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property); + RefPtr thisRegister = generator.emitMove(generator.newTemporary(), base.get()); + return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallDotNode ---------------------------------- + +FunctionCallDotNode::~FunctionCallDotNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void FunctionCallDotNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_args); +} + +RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr base = generator.emitNode(m_base.get()); + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); + RefPtr thisRegister = generator.emitMove(generator.newTemporary(), base.get()); + return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ PostfixResolveNode ---------------------------------- + +static RegisterID* emitPreIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper) +{ + return (oper == OpPlusPlus) ? generator.emitPreInc(srcDst) : generator.emitPreDec(srcDst); +} + +static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper) +{ + return (oper == OpPlusPlus) ? generator.emitPostInc(dst, srcDst) : generator.emitPostDec(dst, srcDst); +} + +RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (generator.isLocalConstant(m_ident)) { + if (dst == generator.ignoredResult()) + return 0; + return generator.emitToJSNumber(generator.finalDestination(dst), local); + } + + if (dst == generator.ignoredResult()) + return emitPreIncOrDec(generator, local, m_operator); + return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator); + } + + int index = 0; + size_t depth = 0; + JSObject* globalObject = 0; + if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { + RefPtr value = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); + RegisterID* oldValue; + if (dst == generator.ignoredResult()) { + oldValue = 0; + emitPreIncOrDec(generator, value.get(), m_operator); + } else { + oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); + } + generator.emitPutScopedVar(depth, index, value.get(), globalObject); + return oldValue; + } + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RefPtr value = generator.newTemporary(); + RefPtr base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident); + RegisterID* oldValue; + if (dst == generator.ignoredResult()) { + oldValue = 0; + emitPreIncOrDec(generator, value.get(), m_operator); + } else { + oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); + } + generator.emitPutById(base.get(), m_ident, value.get()); + return oldValue; +} + +// ------------------------------ PostfixBracketNode ---------------------------------- + +PostfixBracketNode::~PostfixBracketNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PostfixBracketNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); +} + +RegisterID* PostfixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr base = generator.emitNode(m_base.get()); + RefPtr property = generator.emitNode(m_subscript.get()); + + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); + RegisterID* oldValue; + if (dst == generator.ignoredResult()) { + oldValue = 0; + if (m_operator == OpPlusPlus) + generator.emitPreInc(value.get()); + else + generator.emitPreDec(value.get()); + } else { + oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get()); + } + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), value.get()); + return oldValue; +} + +// ------------------------------ PostfixDotNode ---------------------------------- + +PostfixDotNode::~PostfixDotNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PostfixDotNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); +} + +RegisterID* PostfixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr base = generator.emitNode(m_base.get()); + + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident); + RegisterID* oldValue; + if (dst == generator.ignoredResult()) { + oldValue = 0; + if (m_operator == OpPlusPlus) + generator.emitPreInc(value.get()); + else + generator.emitPreDec(value.get()); + } else { + oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get()); + } + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutById(base.get(), m_ident, value.get()); + return oldValue; +} + +// ------------------------------ PostfixErrorNode ----------------------------------- + +PostfixErrorNode::~PostfixErrorNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PostfixErrorNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Postfix ++ operator applied to value that is not a reference." : "Postfix -- operator applied to value that is not a reference."); +} + +// ------------------------------ DeleteResolveNode ----------------------------------- + +RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (generator.registerFor(m_ident)) + return generator.emitUnexpectedLoad(generator.finalDestination(dst), false); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident); + return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident); +} + +// ------------------------------ DeleteBracketNode ----------------------------------- + +DeleteBracketNode::~DeleteBracketNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void DeleteBracketNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); +} + +RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr r0 = generator.emitNode(m_base.get()); + RegisterID* r1 = generator.emitNode(m_subscript.get()); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1); +} + +// ------------------------------ DeleteDotNode ----------------------------------- + +DeleteDotNode::~DeleteDotNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void DeleteDotNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); +} + +RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* r0 = generator.emitNode(m_base.get()); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident); +} + +// ------------------------------ DeleteValueNode ----------------------------------- + +DeleteValueNode::~DeleteValueNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void DeleteValueNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* DeleteValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitNode(generator.ignoredResult(), m_expr.get()); + + // delete on a non-location expression ignores the value and returns true + return generator.emitUnexpectedLoad(generator.finalDestination(dst), true); +} + +// ------------------------------ VoidNode ------------------------------------- + +VoidNode::~VoidNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void VoidNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) { + generator.emitNode(generator.ignoredResult(), m_expr.get()); + return 0; + } + RefPtr r0 = generator.emitNode(m_expr.get()); + return generator.emitLoad(dst, jsUndefined()); +} + +// ------------------------------ TypeOfValueNode ----------------------------------- + +RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (dst == generator.ignoredResult()) + return 0; + return generator.emitTypeOf(generator.finalDestination(dst), local); + } + + RefPtr scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident); + generator.emitGetById(scratch.get(), scratch.get(), m_ident); + if (dst == generator.ignoredResult()) + return 0; + return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get()); +} + +// ------------------------------ TypeOfValueNode ----------------------------------- + +TypeOfValueNode::~TypeOfValueNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void TypeOfValueNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) { + generator.emitNode(generator.ignoredResult(), m_expr.get()); + return 0; + } + RefPtr src = generator.emitNode(m_expr.get()); + return generator.emitTypeOf(generator.finalDestination(dst), src.get()); +} + +// ------------------------------ PrefixResolveNode ---------------------------------- + +RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (generator.isLocalConstant(m_ident)) { + if (dst == generator.ignoredResult()) + return 0; + RefPtr r0 = generator.emitUnexpectedLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0); + return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes()); + } + + emitPreIncOrDec(generator, local, m_operator); + return generator.moveToDestinationIfNeeded(dst, local); + } + + int index = 0; + size_t depth = 0; + JSObject* globalObject = 0; + if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) { + RefPtr propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); + emitPreIncOrDec(generator, propDst.get(), m_operator); + generator.emitPutScopedVar(depth, index, propDst.get(), globalObject); + return generator.moveToDestinationIfNeeded(dst, propDst.get()); + } + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RefPtr propDst = generator.tempDestination(dst); + RefPtr base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident); + emitPreIncOrDec(generator, propDst.get(), m_operator); + generator.emitPutById(base.get(), m_ident, propDst.get()); + return generator.moveToDestinationIfNeeded(dst, propDst.get()); +} + +// ------------------------------ PrefixBracketNode ---------------------------------- + +PrefixBracketNode::~PrefixBracketNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PrefixBracketNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); +} + +RegisterID* PrefixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr base = generator.emitNode(m_base.get()); + RefPtr property = generator.emitNode(m_subscript.get()); + RefPtr propDst = generator.tempDestination(dst); + + generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, endOffset() - m_subexpressionDivotOffset); + RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get()); + if (m_operator == OpPlusPlus) + generator.emitPreInc(value); + else + generator.emitPreDec(value); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), value); + return generator.moveToDestinationIfNeeded(dst, propDst.get()); +} + +// ------------------------------ PrefixDotNode ---------------------------------- + +PrefixDotNode::~PrefixDotNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PrefixDotNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); +} + +RegisterID* PrefixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr base = generator.emitNode(m_base.get()); + RefPtr propDst = generator.tempDestination(dst); + + generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, endOffset() - m_subexpressionDivotOffset); + RegisterID* value = generator.emitGetById(propDst.get(), base.get(), m_ident); + if (m_operator == OpPlusPlus) + generator.emitPreInc(value); + else + generator.emitPreDec(value); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutById(base.get(), m_ident, value); + return generator.moveToDestinationIfNeeded(dst, propDst.get()); +} + +// ------------------------------ PrefixErrorNode ----------------------------------- + +PrefixErrorNode::~PrefixErrorNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PrefixErrorNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Prefix ++ operator applied to value that is not a reference." : "Prefix -- operator applied to value that is not a reference."); +} + +// ------------------------------ Unary Operation Nodes ----------------------------------- + +UnaryOpNode::~UnaryOpNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void UnaryOpNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* src = generator.emitNode(m_expr.get()); + return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src); +} + +// ------------------------------ Binary Operation Nodes ----------------------------------- + +BinaryOpNode::~BinaryOpNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void BinaryOpNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr1); + releaser.release(m_expr2); +} + +RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + OpcodeID opcodeID = this->opcodeID(); + if (opcodeID == op_neq) { + if (m_expr1->isNull() || m_expr2->isNull()) { + RefPtr src = generator.tempDestination(dst); + generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2.get() : m_expr1.get()); + return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get()); + } + } + + RefPtr src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2.get()); + return generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); +} + +RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (m_expr1->isNull() || m_expr2->isNull()) { + RefPtr src = generator.tempDestination(dst); + generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2.get() : m_expr1.get()); + return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get()); + } + + RefPtr src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2.get()); + return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2); +} + +RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2.get()); + return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2); +} + +RegisterID* ReverseBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2.get()); + return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src2, src1.get(), OperandTypes(m_expr2->resultDescriptor(), m_expr1->resultDescriptor())); +} + +RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2.get()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); +} + +RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RefPtr src2 = generator.emitNode(m_expr2.get()); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitGetByIdExceptionInfo(op_instanceof); + RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitInstanceOf(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), src2Prototype); +} + +// ------------------------------ LogicalOpNode ---------------------------- + +LogicalOpNode::~LogicalOpNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void LogicalOpNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr1); + releaser.release(m_expr2); +} + +RegisterID* LogicalOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr temp = generator.tempDestination(dst); + RefPtr