/* * 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