X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/14957cd040308e3eeec43d26bae5d76da13fcd85..12899fa232562c774004a3a9d7d3149944dec712:/bytecompiler/NodesCodegen.cpp?ds=sidebyside diff --git a/bytecompiler/NodesCodegen.cpp b/bytecompiler/NodesCodegen.cpp index a7abadf..e3a3d26 100644 --- a/bytecompiler/NodesCodegen.cpp +++ b/bytecompiler/NodesCodegen.cpp @@ -1,10 +1,11 @@ /* * 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, 2013 Apple Inc. All rights reserved. * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) * Copyright (C) 2007 Maks Orlovich * Copyright (C) 2007 Eric Seidel + * Copyright (C) 2012 Igalia, S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -33,7 +34,7 @@ #include "JIT.h" #include "JSFunction.h" #include "JSGlobalObject.h" -#include "JSStaticScopeObject.h" +#include "JSNameScope.h" #include "LabelScope.h" #include "Lexer.h" #include "Operations.h" @@ -42,7 +43,6 @@ #include "RegExpCache.h" #include "RegExpObject.h" #include "SamplingTool.h" -#include "UStringConcatenate.h" #include #include #include @@ -74,49 +74,49 @@ namespace JSC { because the assignment node, "x =", passes r[x] as dst to the number node, "1". */ +void ExpressionNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) +{ + RegisterID* result = generator.emitNode(this); + if (fallThroughMode == FallThroughMeansTrue) + generator.emitJumpIfFalse(result, falseTarget); + else + generator.emitJumpIfTrue(result, trueTarget); +} + // ------------------------------ ThrowableExpressionData -------------------------------- -RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const UString& message) +RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const String& message) { - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); generator.emitThrowReferenceError(message); return generator.newTemporary(); } -// ------------------------------ NullNode ------------------------------------- +// ------------------------------ ConstantNode ---------------------------------- -RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) { - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, jsNull()); -} - -// ------------------------------ BooleanNode ---------------------------------- + TriState value = jsValue(generator).pureToBoolean(); + if (value == MixedTriState) + ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode); + else if (value == TrueTriState && fallThroughMode == FallThroughMeansFalse) + generator.emitJump(trueTarget); + else if (value == FalseTriState && fallThroughMode == FallThroughMeansTrue) + generator.emitJump(falseTarget); -RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); + // All other cases are unconditional fall-throughs, like "if (true)". } -// ------------------------------ NumberNode ----------------------------------- - -RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +RegisterID* ConstantNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (dst == generator.ignoredResult()) return 0; - return generator.emitLoad(dst, m_value); + return generator.emitLoad(dst, jsValue(generator)); } -// ------------------------------ StringNode ----------------------------------- - -RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +JSValue StringNode::jsValue(BytecodeGenerator& generator) const { - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); + return generator.addStringConstant(m_value); } // ------------------------------ RegExpNode ----------------------------------- @@ -125,7 +125,7 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d { if (dst == generator.ignoredResult()) return 0; - return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(generator.globalData(), m_pattern.ustring(), regExpFlags(m_flags.ustring()))); + return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(*generator.vm(), m_pattern.string(), regExpFlags(m_flags.string()))); } // ------------------------------ ThisNode ------------------------------------- @@ -141,19 +141,21 @@ RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst bool ResolveNode::isPure(BytecodeGenerator& generator) const { - return generator.isLocal(m_ident); + return generator.resolve(m_ident).isStatic(); } RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (RegisterID* local = generator.registerFor(m_ident)) { + ResolveResult resolveResult = generator.resolve(m_ident); + if (RegisterID* local = resolveResult.local()) { if (dst == generator.ignoredResult()) return 0; return generator.moveToDestinationIfNeeded(dst, local); } - generator.emitExpressionInfo(m_startOffset + m_ident.length(), m_ident.length(), 0); - return generator.emitResolve(generator.finalDestination(dst), m_ident); + unsigned divot = m_startOffset + m_ident.length(); + generator.emitExpressionInfo(divot, m_ident.length(), 0, m_divotLine, m_divotLineStart); + return generator.emitResolve(generator.finalDestination(dst), resolveResult, m_ident); } // ------------------------------ ArrayNode ------------------------------------ @@ -200,18 +202,21 @@ bool ArrayNode::isSimpleArray() const return true; } -ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData) const +ArgumentListNode* ArrayNode::toArgumentList(VM* vm, int lineNumber, int startPosition) const { ASSERT(!m_elision && !m_optional); ElementNode* ptr = m_element; if (!ptr) return 0; - ArgumentListNode* head = new (globalData) ArgumentListNode(globalData, ptr->value()); + JSTokenLocation location; + location.line = lineNumber; + location.startOffset = startPosition; + ArgumentListNode* head = new (vm) ArgumentListNode(location, 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 (vm) ArgumentListNode(location, tail, ptr->value()); } return head; } @@ -236,27 +241,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->value.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->value; + + // 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()); } @@ -264,15 +321,17 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (m_base->isResolveNode() && generator.willResolveToArguments(static_cast(m_base)->identifier())) { + if (m_base->isResolveNode() + && generator.willResolveToArguments(static_cast(m_base)->identifier()) + && !generator.symbolTable().slowArguments()) { RegisterID* property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); 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()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); } @@ -286,13 +345,13 @@ RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, Register ResolveNode* resolveNode = static_cast(m_base); if (!generator.willResolveToArguments(resolveNode->identifier())) goto nonArgumentsPath; - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedRegisterForArguments()); } nonArgumentsPath: RegisterID* base = generator.emitNode(m_base); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); return generator.emitGetById(generator.finalDestination(dst), base, m_ident); } @@ -308,35 +367,51 @@ RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, Registe RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { + ExpectedFunction expectedFunction; + if (m_expr->isResolveNode()) + expectedFunction = generator.expectedFunctionForIdentifier(static_cast(m_expr)->identifier()); + else + expectedFunction = NoExpectedFunction; RefPtr func = generator.emitNode(m_expr); CallArguments callArguments(generator, m_args); - return generator.emitConstruct(generator.finalDestinationOrIgnored(dst), func.get(), callArguments, divot(), startOffset(), endOffset()); + return generator.emitConstruct(generator.finalDestinationOrIgnored(dst), func.get(), expectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } -CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode) +inline CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode) : m_argumentsNode(argumentsNode) { if (generator.shouldEmitProfileHooks()) m_profileHookRegister = generator.newTemporary(); - m_argv.append(generator.newTemporary()); + + size_t argumentCountIncludingThis = 1; // 'this' register. if (argumentsNode) { - for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next) { - m_argv.append(generator.newTemporary()); - // op_call requires the arguments to be a sequential range of registers - ASSERT(m_argv[m_argv.size() - 1]->index() == m_argv[m_argv.size() - 2]->index() + 1); - } + 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 ---------------------------------- RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RefPtr func = generator.tempDestination(dst); CallArguments callArguments(generator, m_args); - generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); - generator.emitResolveWithBase(callArguments.thisRegister(), func.get(), generator.propertyNames().eval); - return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); + generator.emitExpressionInfo(divot() - divotStartOffset() + 4, 4, 0, divotLine(), divotLineStart()); + generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), generator.resolve(generator.propertyNames().eval), generator.propertyNames().eval); + return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } // ------------------------------ FunctionCallValueNode ---------------------------------- @@ -346,36 +421,40 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re RefPtr func = generator.emitNode(m_expr); CallArguments callArguments(generator, m_args); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } // ------------------------------ FunctionCallResolveNode ---------------------------------- RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (RefPtr local = generator.registerFor(m_ident)) { + ExpectedFunction expectedFunction = generator.expectedFunctionForIdentifier(m_ident); + ResolveResult resolveResult = generator.resolve(m_ident); + + if (RegisterID* local = resolveResult.local()) { + RefPtr func = generator.emitMove(generator.tempDestination(dst), local); CallArguments callArguments(generator, m_args); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), local.get(), callArguments, divot(), startOffset(), endOffset()); + // This passes NoExpectedFunction because we expect that if the function is in a + // local variable, then it's not one of our built-in constructors. + return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } - 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); + if (resolveResult.isStatic()) { + RefPtr func = generator.newTemporary(); CallArguments callArguments(generator, m_args); + generator.emitGetStaticVar(func.get(), resolveResult, m_ident); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), expectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } RefPtr func = generator.newTemporary(); CallArguments callArguments(generator, m_args); - int identifierStart = divot() - startOffset(); - generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0); - generator.emitResolveWithBase(callArguments.thisRegister(), func.get(), m_ident); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset()); + int identifierStart = divot() - divotStartOffset(); + + generator.emitExpressionInfo(identifierStart + m_ident.length(), m_ident.length(), 0, divotLine(), divotLineStart()); + generator.emitResolveWithThis(callArguments.thisRegister(), func.get(), resolveResult, m_ident); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), expectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } // ------------------------------ FunctionCallBracketNode ---------------------------------- @@ -384,11 +463,11 @@ RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, { RefPtr base = generator.emitNode(m_base); RegisterID* property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStartOffset(), subexpressionEndOffset(), subexpressionLine(), subexpressionLineStart()); RefPtr function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property); 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()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } // ------------------------------ FunctionCallDotNode ---------------------------------- @@ -398,10 +477,9 @@ RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, Regi RefPtr function = generator.tempDestination(dst); CallArguments callArguments(generator, m_args); generator.emitNode(callArguments.thisRegister(), m_base); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - generator.emitMethodCheck(); + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStartOffset(), subexpressionEndOffset(), subexpressionLine(), subexpressionLineStart()); generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident); - return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), callArguments, divot(), startOffset(), endOffset()); + return generator.emitCall(generator.finalDestinationOrIgnored(dst, function.get()), function.get(), NoExpectedFunction, callArguments, divot(), divotStartOffset(), divotEndOffset(), divotLine(), divotLineStart()); } RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) @@ -409,7 +487,7 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RefPtr