📄 nodes.cpp
字号:
/** 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 <eric@webkit.org>** 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 <math.h>#include <wtf/Assertions.h>#include <wtf/HashCountedSet.h>#include <wtf/HashSet.h>#include <wtf/MathExtras.h>#include <wtf/RefCountedLeakCounter.h>#include <wtf/Threading.h>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 <typename T> void release(RefPtr<T>& node) { if (node) adopt(node.release()); } void release(RefPtr<FunctionBodyNode>& node) { if (node) adoptFunctionBodyNode(node); }private: NodeReleaser() { } ~NodeReleaser() { } void adopt(PassRefPtr<ParserRefCounted>); void adoptFunctionBodyNode(RefPtr<FunctionBodyNode>&); typedef Vector<RefPtr<ParserRefCounted> > NodeReleaseVector; OwnPtr<NodeReleaseVector> 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<ParserRefCounted> node){ ASSERT(node); if (!node->hasOneRef()) return; if (!m_vector) m_vector.set(new NodeReleaseVector); m_vector->append(node);}void NodeReleaser::adoptFunctionBodyNode(RefPtr<FunctionBodyNode>& functionBodyNode){ // This sidesteps a problem where if you assign a PassRefPtr<FunctionBodyNode> // to a PassRefPtr<Node> 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> node = functionBodyNode; functionBodyNode = 0; adopt(node.release());}// ------------------------------ ParserRefCounted -----------------------------------------#ifndef NDEBUGstatic RefCountedLeakCounter parserRefCountedCounter("JSC::Node");#endifParserRefCounted::ParserRefCounted(JSGlobalData* globalData) : m_globalData(globalData){#ifndef NDEBUG parserRefCountedCounter.increment();#endif if (!m_globalData->newParserObjects) m_globalData->newParserObjects = new HashSet<ParserRefCounted*>; 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<ParserRefCounted*>::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<ParserRefCounted*>; 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<ParserRefCounted*>::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<ParserRefCounted*>::iterator end = globalData->newParserObjects->end(); for (HashSet<ParserRefCounted*>::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<StatementNode> 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 = 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -