/* * 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 "NodeConstructors.h" #include "BytecodeGenerator.h" #include "CallFrame.h" #include "Debugger.h" #include "JIT.h" #include "JSFunction.h" #include "JSGlobalObject.h" #include "JSStaticScopeObject.h" #include "LabelScope.h" #include "Lexer.h" #include "Operations.h" #include "Parser.h" #include "PropertyNameArray.h" #include "RegExpObject.h" #include "SamplingTool.h" #include #include #include using namespace WTF; namespace JSC { /* Details of the emitBytecode function. Return value: The register holding the production's value. dst: An optional parameter specifying the most efficient destination at which to store the production's value. The callee must honor dst. The dst argument provides for a crude form of copy propagation. For example, x = 1 becomes load r[x], 1 instead of load r0, 1 mov r[x], r0 because the assignment node, "x =", passes r[x] as dst to the number node, "1". */ // ------------------------------ ThrowableExpressionData -------------------------------- static void substitute(UString& string, const UString& substring) { unsigned position = string.find("%s"); ASSERT(position != UString::NotFound); string = makeString(string.substr(0, position), substring, string.substr(position + 2)); } RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* message) { generator.emitExpressionInfo(divot(), startOffset(), endOffset()); RegisterID* exception = generator.emitNewError(generator.newTemporary(), type, jsString(generator.globalData(), message)); generator.emitThrow(exception); return exception; } RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const UString& label) { UString message = messageTemplate; substitute(message, label); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); RegisterID* exception = generator.emitNewError(generator.newTemporary(), type, jsString(generator.globalData(), message)); generator.emitThrow(exception); return exception; } inline RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const Identifier& label) { return emitThrowError(generator, type, messageTemplate, label.ustring()); } // ------------------------------ 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_value); } // ------------------------------ 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.ustring(), m_flags.ustring()); if (!regExp->isValid()) return emitThrowError(generator, SyntaxError, "Invalid regular expression: %s", regExp->errorMessage()); 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); } // ------------------------------ ArrayNode ------------------------------------ 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; firstPutElement; firstPutElement = firstPutElement->next()) { if (firstPutElement->elision()) break; ++length; } if (!firstPutElement && !m_elision) return generator.emitNewArray(generator.finalDestination(dst), m_element); RefPtr array = generator.emitNewArray(generator.tempDestination(dst), m_element); 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()); } bool ArrayNode::isSimpleArray() const { if (m_elision || m_optional) return false; for (ElementNode* ptr = m_element; ptr; ptr = ptr->next()) { if (ptr->elision()) return false; } return true; } ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData) const { ASSERT(!m_elision && !m_optional); ElementNode* ptr = m_element; if (!ptr) return 0; ArgumentListNode* head = new (globalData) ArgumentListNode(globalData, ptr->value()); ArgumentListNode* tail = head; ptr = ptr->next(); for (; ptr; ptr = ptr->next()) { ASSERT(!ptr->elision()); tail = new (globalData) ArgumentListNode(globalData, tail, ptr->value()); } return head; } // ------------------------------ ObjectLiteralNode ---------------------------- 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); } // ------------------------------ PropertyListNode ----------------------------- 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) { RegisterID* value = generator.emitNode(p->m_node->m_assign); 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 -------------------------------- RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); RegisterID* property = generator.emitNode(m_subscript); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); } // ------------------------------ DotAccessorNode -------------------------------- RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RegisterID* base = generator.emitNode(m_base); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); return generator.emitGetById(generator.finalDestination(dst), base, m_ident); } // ------------------------------ ArgumentListNode ----------------------------- RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { ASSERT(m_expr); return generator.emitNode(dst, m_expr); } // ------------------------------ NewExprNode ---------------------------------- RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr func = generator.emitNode(m_expr); return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args, divot(), startOffset(), endOffset()); } // ------------------------------ EvalFunctionCallNode ---------------------------------- 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, divot(), startOffset(), endOffset()); } // ------------------------------ FunctionCallValueNode ---------------------------------- RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr func = generator.emitNode(m_expr); RefPtr thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); } // ------------------------------ FunctionCallResolveNode ---------------------------------- 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, divot(), startOffset(), endOffset()); } int index = 0; size_t depth = 0; JSObject* globalObject = 0; bool requiresDynamicChecks = false; if (generator.findScopedProperty(m_ident, index, depth, false, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { 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, divot(), startOffset(), endOffset()); } RefPtr func = generator.newTemporary(); RefPtr thisRegister = generator.newTemporary(); int identifierStart = divot() - startOffset(); generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0); generator.emitResolveWithBase(thisRegister.get(), func.get(), m_ident); return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); } // ------------------------------ FunctionCallBracketNode ---------------------------------- RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr base = generator.emitNode(m_base); RegisterID* property = generator.emitNode(m_subscript); 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, divot(), startOffset(), endOffset()); } // ------------------------------ FunctionCallDotNode ---------------------------------- RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr function = generator.tempDestination(dst); RefPtr thisRegister = generator.newTemporary(); generator.emitNode(thisRegister.get(), m_base); generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); generator.emitMethodCheck(); generator.emitGetById(function.get(), thisRegister.get(), m_ident); return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); } RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr