X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/b80e619319b1def83d1e8b4f84042b661be1be7f..6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174:/bytecompiler/NodesCodegen.cpp diff --git a/bytecompiler/NodesCodegen.cpp b/bytecompiler/NodesCodegen.cpp index a7455e4..5ada260 100644 --- a/bytecompiler/NodesCodegen.cpp +++ b/bytecompiler/NodesCodegen.cpp @@ -1,7 +1,7 @@ /* * 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) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved. * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) * Copyright (C) 2007 Maks Orlovich * Copyright (C) 2007 Eric Seidel @@ -42,6 +42,7 @@ #include "RegExpCache.h" #include "RegExpObject.h" #include "SamplingTool.h" +#include "UStringConcatenate.h" #include #include #include @@ -75,34 +76,11 @@ namespace JSC { // ------------------------------ ThrowableExpressionData -------------------------------- -static void substitute(UString& string, const UString& substring) +RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const UString& message) { - 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()); + generator.emitThrowReferenceError(message); + return generator.newTemporary(); } // ------------------------------ NullNode ------------------------------------- @@ -145,12 +123,9 @@ RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr regExp = generator.globalData()->regExpCache()->lookupOrCreate(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()); + return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(*generator.globalData(), m_pattern.ustring(), regExpFlags(m_flags.ustring()))); } // ------------------------------ ThisNode ------------------------------------- @@ -177,7 +152,7 @@ RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* return generator.moveToDestinationIfNeeded(dst, local); } - generator.emitExpressionInfo(m_startOffset + m_ident.size(), m_ident.size(), 0); + generator.emitExpressionInfo(m_startOffset + m_ident.length(), m_ident.length(), 0); return generator.emitResolve(generator.finalDestination(dst), m_ident); } @@ -196,9 +171,9 @@ RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds } if (!firstPutElement && !m_elision) - return generator.emitNewArray(generator.finalDestination(dst), m_element); + return generator.emitNewArray(generator.finalDestination(dst), m_element, length); - RefPtr array = generator.emitNewArray(generator.tempDestination(dst), m_element); + RefPtr array = generator.emitNewArray(generator.tempDestination(dst), m_element, length); for (ElementNode* n = firstPutElement; n; n = n->next()) { RegisterID* value = generator.emitNode(n->value()); @@ -207,7 +182,7 @@ RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds } if (m_elision) { - RegisterID* value = generator.emitLoad(0, jsNumber(generator.globalData(), m_elision + length)); + RegisterID* value = generator.emitLoad(0, jsNumber(m_elision + length)); generator.emitPutById(array.get(), generator.propertyNames().length, value); } @@ -225,18 +200,18 @@ bool ArrayNode::isSimpleArray() const return true; } -ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData) const +ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData, int lineNumber) const { ASSERT(!m_elision && !m_optional); ElementNode* ptr = m_element; if (!ptr) return 0; - ArgumentListNode* head = new (globalData) ArgumentListNode(globalData, ptr->value()); + ArgumentListNode* head = new (globalData) ArgumentListNode(lineNumber, ptr->value()); ArgumentListNode* tail = head; ptr = ptr->next(); for (; ptr; ptr = ptr->next()) { ASSERT(!ptr->elision()); - tail = new (globalData) ArgumentListNode(globalData, tail, ptr->value()); + tail = new (globalData) ArgumentListNode(lineNumber, tail, ptr->value()); } return head; } @@ -261,27 +236,79 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe 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.emitDirectPutById(newObj.get(), p->m_node->name(), value); - break; - } - case PropertyNode::Getter: { - generator.emitPutGetter(newObj.get(), p->m_node->name(), value); - break; + // Fast case: this loop just handles regular value properties. + PropertyListNode* p = this; + for (; p && p->m_node->m_type == PropertyNode::Constant; p = p->m_next) + generator.emitDirectPutById(newObj.get(), p->m_node->name(), generator.emitNode(p->m_node->m_assign)); + + // Were there any get/set properties? + if (p) { + typedef std::pair GetterSetterPair; + typedef HashMap GetterSetterMap; + GetterSetterMap map; + + // Build a map, pairing get/set values together. + for (PropertyListNode* q = p; q; q = q->m_next) { + PropertyNode* node = q->m_node; + if (node->m_type == PropertyNode::Constant) + continue; + + GetterSetterPair pair(node, static_cast(0)); + GetterSetterMap::AddResult result = map.add(node->name().impl(), pair); + if (!result.isNewEntry) + result.iterator->second.second = node; + } + + // Iterate over the remaining properties in the list. + for (; p; p = p->m_next) { + PropertyNode* node = p->m_node; + RegisterID* value = generator.emitNode(node->m_assign); + + // Handle regular values. + if (node->m_type == PropertyNode::Constant) { + generator.emitDirectPutById(newObj.get(), node->name(), value); + continue; } - case PropertyNode::Setter: { - generator.emitPutSetter(newObj.get(), p->m_node->name(), value); - break; + + // This is a get/set property, find its entry in the map. + ASSERT(node->m_type == PropertyNode::Getter || node->m_type == PropertyNode::Setter); + GetterSetterMap::iterator it = map.find(node->name().impl()); + ASSERT(it != map.end()); + GetterSetterPair& pair = it->second; + + // Was this already generated as a part of its partner? + if (pair.second == node) + continue; + + // Generate the paired node now. + RefPtr getterReg; + RefPtr setterReg; + + if (node->m_type == PropertyNode::Getter) { + getterReg = value; + if (pair.second) { + ASSERT(pair.second->m_type == PropertyNode::Setter); + setterReg = generator.emitNode(pair.second->m_assign); + } else { + setterReg = generator.newTemporary(); + generator.emitLoad(setterReg.get(), jsUndefined()); + } + } else { + ASSERT(node->m_type == PropertyNode::Setter); + setterReg = value; + if (pair.second) { + ASSERT(pair.second->m_type == PropertyNode::Getter); + getterReg = generator.emitNode(pair.second->m_assign); + } else { + getterReg = generator.newTemporary(); + generator.emitLoad(getterReg.get(), jsUndefined()); + } } - default: - ASSERT_NOT_REACHED(); + + generator.emitPutGetterSetter(newObj.get(), node->name(), getterReg.get(), setterReg.get()); } } - + return generator.moveToDestinationIfNeeded(dst, newObj.get()); } @@ -289,6 +316,12 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { + if (m_base->isResolveNode() && generator.willResolveToArguments(static_cast(m_base)->identifier())) { + RegisterID* property = generator.emitNode(m_subscript); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property); + } + RefPtr base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); RegisterID* property = generator.emitNode(m_subscript); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); @@ -299,6 +332,17 @@ RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, Regi RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { + if (m_ident == generator.propertyNames().length) { + if (!m_base->isResolveNode()) + goto nonArgumentsPath; + ResolveNode* resolveNode = static_cast(m_base); + if (!generator.willResolveToArguments(resolveNode->identifier())) + goto nonArgumentsPath; + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedRegisterForArguments()); + } + +nonArgumentsPath: RegisterID* base = generator.emitNode(m_base); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); return generator.emitGetById(generator.finalDestination(dst), base, m_ident); @@ -317,7 +361,34 @@ RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, Registe 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()); + CallArguments callArguments(generator, m_args); + return generator.emitConstruct(generator.finalDestinationOrIgnored(dst), func.get(), callArguments, divot(), startOffset(), endOffset()); +} + +inline CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode) + : m_argumentsNode(argumentsNode) +{ + if (generator.shouldEmitProfileHooks()) + m_profileHookRegister = generator.newTemporary(); + + size_t argumentCountIncludingThis = 1; // 'this' register. + if (argumentsNode) { + for (ArgumentListNode* node = argumentsNode->m_listNode; node; node = node->m_next) + ++argumentCountIncludingThis; + } + + m_argv.grow(argumentCountIncludingThis); + for (int i = argumentCountIncludingThis - 1; i >= 0; --i) { + m_argv[i] = generator.newTemporary(); + ASSERT(static_cast(i) == m_argv.size() - 1 || m_argv[i]->index() == m_argv[i + 1]->index() + 1); + } +} + +inline void CallArguments::newArgument(BytecodeGenerator& generator) +{ + RefPtr tmp = generator.newTemporary(); + ASSERT(m_argv.isEmpty() || tmp->index() == m_argv.last()->index() + 1); // Calling convention assumes that all arguments are contiguous. + m_argv.append(tmp.release()); } // ------------------------------ EvalFunctionCallNode ---------------------------------- @@ -325,10 +396,10 @@ RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr func = generator.tempDestination(dst); - RefPtr thisRegister = generator.newTemporary(); + CallArguments callArguments(generator, m_args); 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()); + generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), generator.propertyNames().eval); + return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); } // ------------------------------ FunctionCallValueNode ---------------------------------- @@ -336,8 +407,9 @@ RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, Reg 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()); + CallArguments callArguments(generator, m_args); + generator.emitLoad(callArguments.thisRegister(), jsUndefined()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); } // ------------------------------ FunctionCallResolveNode ---------------------------------- @@ -345,8 +417,10 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re 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()); + RefPtr function = generator.emitMove(generator.tempDestination(dst), local.get()); + CallArguments callArguments(generator, m_args); + generator.emitLoad(callArguments.thisRegister(), jsUndefined()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), function.get(), callArguments, divot(), startOffset(), endOffset()); } int index = 0; @@ -355,16 +429,17 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, 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()); + CallArguments callArguments(generator, m_args); + generator.emitLoad(callArguments.thisRegister(), jsUndefined()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); } RefPtr func = generator.newTemporary(); - RefPtr thisRegister = generator.newTemporary(); + CallArguments callArguments(generator, m_args); 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()); + generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0); + generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), m_ident); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); } // ------------------------------ FunctionCallBracketNode ---------------------------------- @@ -375,8 +450,9 @@ RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, 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()); + CallArguments callArguments(generator, m_args); + generator.emitMove(callArguments.thisRegister(), base.get()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), callArguments, divot(), startOffset(), endOffset()); } // ------------------------------ FunctionCallDotNode ---------------------------------- @@ -384,12 +460,12 @@ RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr function = generator.tempDestination(dst); - RefPtr thisRegister = generator.newTemporary(); - generator.emitNode(thisRegister.get(), m_base); + CallArguments callArguments(generator, m_args); + generator.emitNode(callArguments.thisRegister(), 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()); + generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), callArguments, divot(), startOffset(), endOffset()); } RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) @@ -399,31 +475,38 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RefPtr base = generator.emitNode(m_base); generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); RefPtr function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); - RefPtr finalDestination = generator.finalDestination(dst, function.get()); + RefPtr finalDestinationOrIgnored = generator.finalDestinationOrIgnored(dst, function.get()); generator.emitJumpIfNotFunctionCall(function.get(), realCall.get()); { - RefPtr realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); - RefPtr thisRegister = generator.newTemporary(); - ArgumentListNode* oldList = m_args->m_listNode; if (m_args->m_listNode && m_args->m_listNode->m_expr) { - generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); + ArgumentListNode* oldList = m_args->m_listNode; m_args->m_listNode = m_args->m_listNode->m_next; - } else - generator.emitLoad(thisRegister.get(), jsNull()); - generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); - generator.emitJump(end.get()); - m_args->m_listNode = oldList; + RefPtr realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); + CallArguments callArguments(generator, m_args); + generator.emitNode(callArguments.thisRegister(), oldList->m_expr); + generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset()); + generator.emitJump(end.get()); + + m_args->m_listNode = oldList; + } else { + RefPtr realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); + CallArguments callArguments(generator, m_args); + generator.emitLoad(callArguments.thisRegister(), jsUndefined()); + generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset()); + generator.emitJump(end.get()); + } } generator.emitLabel(realCall.get()); { - RefPtr thisRegister = generator.emitMove(generator.newTemporary(), base.get()); - generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + CallArguments callArguments(generator, m_args); + generator.emitMove(callArguments.thisRegister(), base.get()); + generator.emitCall(finalDestinationOrIgnored.get(), function.get(), callArguments, divot(), startOffset(), endOffset()); } generator.emitLabel(end.get()); - return finalDestination.get(); + return finalDestinationOrIgnored.get(); } - + static bool areTrivialApplyArguments(ArgumentsNode* args) { return !args->m_listNode || !args->m_listNode->m_expr || !args->m_listNode->m_next @@ -442,57 +525,65 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RefPtr base = generator.emitNode(m_base); generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); RefPtr function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); - RefPtr finalDestination = generator.finalDestination(dst, function.get()); + RefPtr finalDestinationOrIgnored = generator.finalDestinationOrIgnored(dst, function.get()); generator.emitJumpIfNotFunctionApply(function.get(), realCall.get()); { if (mayBeCall) { - RefPtr realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); - RefPtr thisRegister = generator.newTemporary(); - ArgumentListNode* oldList = m_args->m_listNode; if (m_args->m_listNode && m_args->m_listNode->m_expr) { - generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); - m_args->m_listNode = m_args->m_listNode->m_next; - if (m_args->m_listNode) { - ASSERT(m_args->m_listNode->m_expr->isSimpleArray()); - ASSERT(!m_args->m_listNode->m_next); - m_args->m_listNode = static_cast(m_args->m_listNode->m_expr)->toArgumentList(generator.globalData()); + ArgumentListNode* oldList = m_args->m_listNode; + if (m_args->m_listNode->m_next) { + ASSERT(m_args->m_listNode->m_next->m_expr->isSimpleArray()); + ASSERT(!m_args->m_listNode->m_next->m_next); + m_args->m_listNode = static_cast(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.globalData(), 0); + RefPtr realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); + CallArguments callArguments(generator, m_args); + generator.emitNode(callArguments.thisRegister(), oldList->m_expr); + generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset()); + } else { + m_args->m_listNode = m_args->m_listNode->m_next; + RefPtr realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); + CallArguments callArguments(generator, m_args); + generator.emitNode(callArguments.thisRegister(), oldList->m_expr); + generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset()); } - } else - generator.emitLoad(thisRegister.get(), jsNull()); - generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); - m_args->m_listNode = oldList; + m_args->m_listNode = oldList; + } else { + RefPtr realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); + CallArguments callArguments(generator, m_args); + generator.emitLoad(callArguments.thisRegister(), jsUndefined()); + generator.emitCall(finalDestinationOrIgnored.get(), realFunction.get(), callArguments, divot(), startOffset(), endOffset()); + } } else { ASSERT(m_args->m_listNode && m_args->m_listNode->m_next); - RefPtr realFunction = generator.emitMove(generator.newTemporary(), base.get()); - RefPtr argsCountRegister = generator.newTemporary(); - RefPtr thisRegister = generator.newTemporary(); - RefPtr argsRegister = generator.newTemporary(); - generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); + RefPtr profileHookRegister; + if (generator.shouldEmitProfileHooks()) + profileHookRegister = generator.newTemporary(); + RefPtr realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); + RefPtr thisRegister = generator.emitNode(m_args->m_listNode->m_expr); + RefPtr argsRegister; ArgumentListNode* args = m_args->m_listNode->m_next; - bool isArgumentsApply = false; - if (args->m_expr->isResolveNode()) { - ResolveNode* resolveNode = static_cast(args->m_expr); - isArgumentsApply = generator.willResolveToArguments(resolveNode->identifier()); - if (isArgumentsApply) - generator.emitMove(argsRegister.get(), generator.uncheckedRegisterForArguments()); - } - if (!isArgumentsApply) - generator.emitNode(argsRegister.get(), args->m_expr); + if (args->m_expr->isResolveNode() && generator.willResolveToArguments(static_cast(args->m_expr)->identifier())) + argsRegister = generator.uncheckedRegisterForArguments(); + else + argsRegister = generator.emitNode(args->m_expr); + + // Function.prototype.apply ignores extra arguments, but we still + // need to evaluate them for side effects. while ((args = args->m_next)) generator.emitNode(args->m_expr); - generator.emitLoadVarargs(argsCountRegister.get(), argsRegister.get()); - generator.emitCallVarargs(finalDestination.get(), realFunction.get(), thisRegister.get(), argsCountRegister.get(), divot(), startOffset(), endOffset()); + generator.emitCallVarargs(finalDestinationOrIgnored.get(), realFunction.get(), thisRegister.get(), argsRegister.get(), generator.newTemporary(), profileHookRegister.get(), divot(), startOffset(), endOffset()); } generator.emitJump(end.get()); } generator.emitLabel(realCall.get()); { - RefPtr thisRegister = generator.emitMove(generator.newTemporary(), base.get()); - generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + CallArguments callArguments(generator, m_args); + generator.emitMove(callArguments.thisRegister(), base.get()); + generator.emitCall(finalDestinationOrIgnored.get(), function.get(), callArguments, divot(), startOffset(), endOffset()); } generator.emitLabel(end.get()); - return finalDestination.get(); + return finalDestinationOrIgnored.get(); } // ------------------------------ PostfixResolveNode ---------------------------------- @@ -605,7 +696,7 @@ RegisterID* PostfixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterI RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus + return emitThrowReferenceError(generator, m_operator == OpPlusPlus ? "Postfix ++ operator applied to value that is not a reference." : "Postfix -- operator applied to value that is not a reference."); } @@ -714,7 +805,7 @@ RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, Regist size_t depth = 0; JSObject* globalObject = 0; bool requiresDynamicChecks = false; - if (generator.findScopedProperty(m_ident, index, depth, false, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { + if (generator.findScopedProperty(m_ident, index, depth, true, requiresDynamicChecks, globalObject) && index != missingSymbolMarker() && !requiresDynamicChecks) { RefPtr propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); emitPreIncOrDec(generator, propDst.get(), m_operator); generator.emitPutScopedVar(depth, index, propDst.get(), globalObject); @@ -770,7 +861,7 @@ RegisterID* PrefixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus + return emitThrowReferenceError(generator, m_operator == OpPlusPlus ? "Prefix ++ operator applied to value that is not a reference." : "Prefix -- operator applied to value that is not a reference."); } @@ -783,7 +874,15 @@ RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src); } - +// ------------------------------ BitwiseNotNode ----------------------------------- + +RegisterID* BitwiseNotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr src2 = generator.emitLoad(generator.newTemporary(), jsNumber(-1)); + RegisterID* src1 = generator.emitNode(m_expr); + return generator.emitBinaryOp(op_bitxor, generator.finalDestination(dst, src1), src1, src2.get(), OperandTypes(m_expr->resultDescriptor(), ResultType::numberTypeIsInt32())); +} + // ------------------------------ LogicalNotNode ----------------------------------- void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) @@ -830,8 +929,6 @@ RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* d ASSERT(isAdd()); ASSERT(resultDescriptor().definitelyIsString()); - IncreaseEmitNodeDepth stackGuard(generator, 3); - // Create a list of expressions for all the adds in the tree of nodes we can convert into // a string concatenation. The rightmost node (c) is added first. The rightmost node is // added first, and the leftmost child is never added, so the vector produced for the @@ -957,13 +1054,6 @@ RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, Register 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, m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2); - 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, m_rightHasAssignments, m_expr2->isPure(generator)); @@ -978,7 +1068,9 @@ RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterI RefPtr src2 = generator.emitNode(m_expr2); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitGetByIdExceptionInfo(op_instanceof); + generator.emitCheckHasInstance(src2.get()); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); @@ -1119,10 +1211,9 @@ static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& gen RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { + if (generator.isLocalConstant(m_ident)) return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - } - + if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { RefPtr result = generator.newTemporary(); generator.emitMove(result.get(), local); @@ -1147,7 +1238,7 @@ RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, Re } RefPtr src1 = generator.tempDestination(dst); - generator.emitExpressionInfo(divot() - startOffset() + m_ident.size(), m_ident.size(), 0); + generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0); RefPtr base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident); RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); return generator.emitPutById(base.get(), m_ident, result); @@ -1177,7 +1268,7 @@ RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, Regist return value; } - RefPtr base = generator.emitResolveBase(generator.newTemporary(), m_ident); + RefPtr base = generator.emitResolveBaseForPut(generator.newTemporary(), m_ident); if (dst == generator.ignoredResult()) dst = 0; RegisterID* value = generator.emitNode(dst, m_right); @@ -1193,8 +1284,9 @@ RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID RefPtr value = generator.destinationForAssignResult(dst); RegisterID* result = generator.emitNode(value.get(), m_right); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutById(base.get(), m_ident, result); - return generator.moveToDestinationIfNeeded(dst, result); + RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result : generator.moveToDestinationIfNeeded(generator.tempDestination(result), result); + generator.emitPutById(base.get(), m_ident, forwardResult); + return generator.moveToDestinationIfNeeded(dst, forwardResult); } // ------------------------------ ReadModifyDotNode ----------------------------------- @@ -1215,7 +1307,7 @@ RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, Regist RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - return emitThrowError(generator, ReferenceError, "Left side of assignment is not a reference."); + return emitThrowReferenceError(generator, "Left side of assignment is not a reference."); } // ------------------------------ AssignBracketNode ----------------------------------- @@ -1228,8 +1320,9 @@ RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, Regist RegisterID* result = generator.emitNode(value.get(), m_right); generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutByVal(base.get(), property.get(), result); - return generator.moveToDestinationIfNeeded(dst, result); + RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result : generator.moveToDestinationIfNeeded(generator.tempDestination(result), result); + generator.emitPutByVal(base.get(), property.get(), forwardResult); + return generator.moveToDestinationIfNeeded(dst, forwardResult); } // ------------------------------ ReadModifyBracketNode ----------------------------------- @@ -1263,6 +1356,7 @@ RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) { + // FIXME: This code does not match the behavior of const in Firefox. if (RegisterID* local = generator.constRegisterFor(m_ident)) { if (!m_init) return local; @@ -1270,17 +1364,30 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) return generator.emitNode(local, m_init); } - if (generator.codeType() != EvalCode) { - if (m_init) - return generator.emitNode(m_init); - else - return generator.emitResolve(generator.newTemporary(), m_ident); + RefPtr value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); + + ScopeChainIterator iter = generator.scopeChain()->begin(); + ScopeChainIterator end = generator.scopeChain()->end(); + size_t depth = 0; + for (; iter != end; ++iter, ++depth) { + JSObject* currentScope = iter->get(); + if (!currentScope->isVariableObject()) + continue; + JSVariableObject* currentVariableObject = static_cast(currentScope); + SymbolTableEntry entry = currentVariableObject->symbolTable().get(m_ident.impl()); + if (entry.isNull()) + continue; + + return generator.emitPutScopedVar(generator.scopeDepth() + depth, entry.getIndex(), value.get(), currentVariableObject->isGlobalObject() ? currentVariableObject : 0); } - // FIXME: While this code should only be hit in eval code, it will potentially - // assign to the wrong base if m_ident exists in an intervening dynamic scope. + + if (generator.codeType() != EvalCode) + return value.get(); + + // FIXME: While this code should only be hit in an eval block, it will assign + // to the wrong base if m_ident exists in an intervening with scope. RefPtr base = generator.emitResolveBase(generator.newTemporary(), m_ident); - RegisterID* value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); - return generator.emitPutById(base.get(), m_ident, value); + return generator.emitPutById(base.get(), m_ident, value.get()); } RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) @@ -1323,6 +1430,11 @@ inline StatementNode* BlockNode::lastStatement() const return m_statements ? m_statements->lastStatement() : 0; } +inline StatementNode* BlockNode::singleStatement() const +{ + return m_statements ? m_statements->singleStatement() : 0; +} + RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (m_statements) @@ -1427,7 +1539,7 @@ RegisterID* DoWhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* RefPtr