X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/40a37d088818fc2fbeba2ef850dbcaaf294befbf..HEAD:/bytecompiler/NodesCodegen.cpp diff --git a/bytecompiler/NodesCodegen.cpp b/bytecompiler/NodesCodegen.cpp index 0e81cfa..cfd3ef1 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, 2012, 2013 Apple Inc. All rights reserved. +* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013, 2015 Apple Inc. All rights reserved. * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) * Copyright (C) 2007 Maks Orlovich * Copyright (C) 2007 Eric Seidel @@ -40,12 +40,14 @@ #include "LabelScope.h" #include "Lexer.h" #include "JSCInlines.h" +#include "JSTemplateRegistryKey.h" #include "Parser.h" #include "PropertyNameArray.h" #include "RegExpCache.h" #include "RegExpObject.h" #include "SamplingTool.h" #include "StackAlignment.h" +#include "TemplateRegistryKey.h" #include #include #include @@ -122,6 +124,15 @@ JSValue StringNode::jsValue(BytecodeGenerator& generator) const return generator.addStringConstant(m_value); } +// ------------------------------ NumberNode ---------------------------------- + +RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return nullptr; + return generator.emitLoad(dst, jsValue(generator), isIntegerNode() ? SourceCodeRepresentation::Integer : SourceCodeRepresentation::Double); +} + // ------------------------------ RegExpNode ----------------------------------- RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) @@ -135,31 +146,184 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { + if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived) + generator.emitTDZCheck(generator.thisRegister()); + if (dst == generator.ignoredResult()) return 0; - return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); + + RegisterID* result = generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(generator.thisRegister(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + static const unsigned thisLength = 4; + generator.emitTypeProfilerExpressionInfo(position(), JSTextPosition(-1, position().offset + thisLength, -1)); + } + return result; +} + +// ------------------------------ SuperNode ------------------------------------- + +RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + + RegisterID callee; + callee.setIndex(JSStack::Callee); + + RefPtr homeObject = generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName); + RefPtr protoParent = generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto); + return generator.emitGetById(generator.finalDestination(dst), protoParent.get(), generator.propertyNames().constructor); +} + +static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator) +{ + RegisterID callee; + callee.setIndex(JSStack::Callee); + + RefPtr homeObject = generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName); + return generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto); } // ------------------------------ ResolveNode ---------------------------------- bool ResolveNode::isPure(BytecodeGenerator& generator) const { - return generator.local(m_ident).get(); + return generator.variable(m_ident).offset().isStack(); } RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (Local local = generator.local(m_ident)) { + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { if (dst == generator.ignoredResult()) - return 0; - return generator.moveToDestinationIfNeeded(dst, local.get()); + return nullptr; + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(local, ProfileTypeBytecodeHasGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1)); + } + return generator.moveToDestinationIfNeeded(dst, local); } JSTextPosition divot = m_start + m_ident.length(); generator.emitExpressionInfo(divot, m_start, divot); - RefPtr scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident); - return generator.emitGetFromScope(generator.finalDestination(dst), scope.get(), m_ident, ThrowIfNotFound); + RefPtr scope = generator.emitResolveScope(dst, var); + RegisterID* finalDest = generator.finalDestination(dst); + RegisterID* result = generator.emitGetFromScope(finalDest, scope.get(), var, ThrowIfNotFound); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(finalDest, var.isResolved() ? ProfileTypeBytecodeGetFromLocalScope : ProfileTypeBytecodeGetFromScope, &m_ident); + generator.emitTypeProfilerExpressionInfo(m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1)); + } + return result; +} + +#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) +// ------------------------------ TemplateStringNode ----------------------------------- + +RegisterID* TemplateStringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return nullptr; + return generator.emitLoad(dst, JSValue(generator.addStringConstant(cooked()))); +} + +// ------------------------------ TemplateLiteralNode ----------------------------------- + +RegisterID* TemplateLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (!m_templateExpressions) { + TemplateStringNode* templateString = m_templateStrings->value(); + ASSERT_WITH_MESSAGE(!m_templateStrings->next(), "Only one template element exists because there's no expression in a given template literal."); + return generator.emitNode(dst, templateString); + } + + Vector, 16> temporaryRegisters; + + TemplateStringListNode* templateString = m_templateStrings; + TemplateExpressionListNode* templateExpression = m_templateExpressions; + for (; templateExpression; templateExpression = templateExpression->next(), templateString = templateString->next()) { + // Evaluate TemplateString. + if (!templateString->value()->cooked().isEmpty()) { + temporaryRegisters.append(generator.newTemporary()); + generator.emitNode(temporaryRegisters.last().get(), templateString->value()); + } + + // Evaluate Expression. + temporaryRegisters.append(generator.newTemporary()); + generator.emitNode(temporaryRegisters.last().get(), templateExpression->value()); + generator.emitToString(temporaryRegisters.last().get(), temporaryRegisters.last().get()); + } + + // Evaluate tail TemplateString. + if (!templateString->value()->cooked().isEmpty()) { + temporaryRegisters.append(generator.newTemporary()); + generator.emitNode(temporaryRegisters.last().get(), templateString->value()); + } + + return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); +} + +// ------------------------------ TaggedTemplateNode ----------------------------------- + +RegisterID* TaggedTemplateNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + ExpectedFunction expectedFunction = NoExpectedFunction; + RefPtr tag = nullptr; + RefPtr base = nullptr; + if (!m_tag->isLocation()) { + tag = generator.newTemporary(); + tag = generator.emitNode(tag.get(), m_tag); + } else if (m_tag->isResolveNode()) { + ResolveNode* resolve = static_cast(m_tag); + const Identifier& identifier = resolve->identifier(); + expectedFunction = generator.expectedFunctionForIdentifier(identifier); + + Variable var = generator.variable(identifier); + if (RegisterID* local = var.local()) + tag = generator.emitMove(generator.newTemporary(), local); + else { + tag = generator.newTemporary(); + base = generator.newTemporary(); + + JSTextPosition newDivot = divotStart() + identifier.length(); + generator.emitExpressionInfo(newDivot, divotStart(), newDivot); + generator.moveToDestinationIfNeeded(base.get(), generator.emitResolveScope(base.get(), var)); + generator.emitGetFromScope(tag.get(), base.get(), var, ThrowIfNotFound); + } + } else if (m_tag->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast(m_tag); + base = generator.newTemporary(); + base = generator.emitNode(base.get(), bracket->base()); + RefPtr property = generator.emitNode(bracket->subscript()); + tag = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); + } else { + ASSERT(m_tag->isDotAccessorNode()); + DotAccessorNode* dot = static_cast(m_tag); + base = generator.newTemporary(); + base = generator.emitNode(base.get(), dot->base()); + tag = generator.emitGetById(generator.newTemporary(), base.get(), dot->identifier()); + } + + RefPtr templateObject = generator.emitGetTemplateObject(generator.newTemporary(), this); + + unsigned expressionsCount = 0; + for (TemplateExpressionListNode* templateExpression = m_templateLiteral->templateExpressions(); templateExpression; templateExpression = templateExpression->next()) + ++expressionsCount; + + CallArguments callArguments(generator, nullptr, 1 + expressionsCount); + if (base) + generator.emitMove(callArguments.thisRegister(), base.get()); + else + generator.emitLoad(callArguments.thisRegister(), jsUndefined()); + + unsigned argumentIndex = 0; + generator.emitMove(callArguments.argumentRegister(argumentIndex++), templateObject.get()); + for (TemplateExpressionListNode* templateExpression = m_templateLiteral->templateExpressions(); templateExpression; templateExpression = templateExpression->next()) + generator.emitNode(callArguments.argumentRegister(argumentIndex++), templateExpression->value()); + + return generator.emitCall(generator.finalDestination(dst, tag.get()), tag.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); } +#endif // ------------------------------ ArrayNode ------------------------------------ @@ -232,7 +396,7 @@ bool ArrayNode::isSimpleArray() const return true; } -ArgumentListNode* ArrayNode::toArgumentList(VM* vm, int lineNumber, int startPosition) const +ArgumentListNode* ArrayNode::toArgumentList(ParserArena& parserArena, int lineNumber, int startPosition) const { ASSERT(!m_elision && !m_optional); ElementNode* ptr = m_element; @@ -241,12 +405,12 @@ ArgumentListNode* ArrayNode::toArgumentList(VM* vm, int lineNumber, int startPos JSTokenLocation location; location.line = lineNumber; location.startOffset = startPosition; - ArgumentListNode* head = new (vm) ArgumentListNode(location, ptr->value()); + ArgumentListNode* head = new (parserArena) ArgumentListNode(location, ptr->value()); ArgumentListNode* tail = head; ptr = ptr->next(); for (; ptr; ptr = ptr->next()) { ASSERT(!ptr->elision()); - tail = new (vm) ArgumentListNode(location, tail, ptr->value()); + tail = new (parserArena) ArgumentListNode(location, tail, ptr->value()); } return head; } @@ -255,49 +419,59 @@ ArgumentListNode* ArrayNode::toArgumentList(VM* vm, int lineNumber, int startPos 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); + if (!m_list) { + if (dst == generator.ignoredResult()) + return 0; + return generator.emitNewObject(generator.finalDestination(dst)); + } + RefPtr newObj = generator.emitNewObject(generator.tempDestination(dst)); + generator.emitNode(newObj.get(), m_list); + return generator.moveToDestinationIfNeeded(dst, newObj.get()); } // ------------------------------ PropertyListNode ----------------------------- +static inline void emitPutHomeObject(BytecodeGenerator& generator, RegisterID* function, RegisterID* homeObject) +{ + generator.emitPutById(function, generator.propertyNames().homeObjectPrivateName, homeObject); +} + RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr newObj = generator.tempDestination(dst); - - generator.emitNewObject(newObj.get()); - // 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) { - if (p->m_node->m_name) { - generator.emitDirectPutById(newObj.get(), *p->m_node->name(), generator.emitNode(p->m_node->m_assign)); - continue; - } - RefPtr propertyName = generator.emitNode(p->m_node->m_expression); - generator.emitDirectPutByVal(newObj.get(), propertyName.get(), generator.emitNode(p->m_node->m_assign)); - } + for (; p && (p->m_node->m_type & PropertyNode::Constant); p = p->m_next) + emitPutConstantProperty(generator, dst, *p->m_node); // Were there any get/set properties? if (p) { + // Build a list of getter/setter pairs to try to put them at the same time. If we encounter + // a computed property, just emit everything as that may override previous values. + bool hasComputedProperty = false; + typedef std::pair GetterSetterPair; - typedef HashMap GetterSetterMap; + 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) + if (node->m_type & PropertyNode::Computed) { + hasComputedProperty = true; + break; + } + if (node->m_type & PropertyNode::Constant) continue; - GetterSetterPair pair(node, static_cast(0)); + // Duplicates are possible. + GetterSetterPair pair(node, static_cast(nullptr)); GetterSetterMap::AddResult result = map.add(node->name()->impl(), pair); - if (!result.isNewEntry) - result.iterator->value.second = node; + if (!result.isNewEntry) { + if (result.iterator->value.first->m_type == node->m_type) + result.iterator->value.first = node; + else + result.iterator->value.second = node; + } } // Iterate over the remaining properties in the list. @@ -305,20 +479,28 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe PropertyNode* node = p->m_node; // Handle regular values. - if (node->m_type == PropertyNode::Constant) { - if (node->name()) { - generator.emitDirectPutById(newObj.get(), *node->name(), generator.emitNode(node->m_assign)); - continue; - } - RefPtr propertyName = generator.emitNode(p->m_node->m_expression); - generator.emitDirectPutByVal(newObj.get(), propertyName.get(), generator.emitNode(p->m_node->m_assign)); + if (node->m_type & PropertyNode::Constant) { + emitPutConstantProperty(generator, dst, *node); continue; } - + RegisterID* value = generator.emitNode(node->m_assign); + bool isClassProperty = node->needsSuperBinding(); + if (isClassProperty) + emitPutHomeObject(generator, value, dst); + + ASSERT(node->m_type & (PropertyNode::Getter | PropertyNode::Setter)); + + // This is a get/set property which may be overridden by a computed property later. + if (hasComputedProperty) { + if (node->m_type & PropertyNode::Getter) + generator.emitPutGetterById(dst, *node->name(), value); + else + generator.emitPutSetterById(dst, *node->name(), value); + continue; + } - // This is a get/set property, find its entry in the map. - ASSERT(node->m_type == PropertyNode::Getter || node->m_type == PropertyNode::Setter); + // This is a get/set property pair. GetterSetterMap::iterator it = map.find(node->name()->impl()); ASSERT(it != map.end()); GetterSetterPair& pair = it->value; @@ -326,75 +508,129 @@ RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe // Was this already generated as a part of its partner? if (pair.second == node) continue; - + // Generate the paired node now. RefPtr getterReg; RefPtr setterReg; + RegisterID* secondReg = nullptr; - if (node->m_type == PropertyNode::Getter) { + if (node->m_type & PropertyNode::Getter) { getterReg = value; if (pair.second) { - ASSERT(pair.second->m_type == PropertyNode::Setter); + ASSERT(pair.second->m_type & PropertyNode::Setter); setterReg = generator.emitNode(pair.second->m_assign); + secondReg = setterReg.get(); } else { setterReg = generator.newTemporary(); generator.emitLoad(setterReg.get(), jsUndefined()); } } else { - ASSERT(node->m_type == PropertyNode::Setter); + ASSERT(node->m_type & PropertyNode::Setter); setterReg = value; if (pair.second) { - ASSERT(pair.second->m_type == PropertyNode::Getter); + ASSERT(pair.second->m_type & PropertyNode::Getter); getterReg = generator.emitNode(pair.second->m_assign); + secondReg = getterReg.get(); } else { getterReg = generator.newTemporary(); generator.emitLoad(getterReg.get(), jsUndefined()); } } - generator.emitPutGetterSetter(newObj.get(), *node->name(), getterReg.get(), setterReg.get()); + ASSERT(!pair.second || isClassProperty == pair.second->needsSuperBinding()); + if (isClassProperty && pair.second) + emitPutHomeObject(generator, secondReg, dst); + + if (isClassProperty) { + RefPtr propertyNameRegister = generator.emitLoad(generator.newTemporary(), *node->name()); + generator.emitCallDefineProperty(dst, propertyNameRegister.get(), + nullptr, getterReg.get(), setterReg.get(), BytecodeGenerator::PropertyConfigurable, m_position); + } else + generator.emitPutGetterSetter(dst, *node->name(), getterReg.get(), setterReg.get()); } } - return generator.moveToDestinationIfNeeded(dst, newObj.get()); + return dst; +} + +void PropertyListNode::emitPutConstantProperty(BytecodeGenerator& generator, RegisterID* newObj, PropertyNode& node) +{ + RefPtr value = generator.emitNode(node.m_assign); + if (node.needsSuperBinding()) { + emitPutHomeObject(generator, value.get(), newObj); + + RefPtr propertyNameRegister; + if (node.name()) + propertyNameRegister = generator.emitLoad(generator.newTemporary(), *node.name()); + else + propertyNameRegister = generator.emitNode(node.m_expression); + + generator.emitCallDefineProperty(newObj, propertyNameRegister.get(), + value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position); + return; + } + if (const auto* identifier = node.name()) { + Optional optionalIndex = parseIndex(*identifier); + if (!optionalIndex) { + generator.emitDirectPutById(newObj, *identifier, value.get(), node.putType()); + return; + } + + RefPtr index = generator.emitLoad(generator.newTemporary(), jsNumber(optionalIndex.value())); + generator.emitDirectPutByVal(newObj, index.get(), value.get()); + return; + } + RefPtr propertyName = generator.emitNode(node.m_expression); + generator.emitDirectPutByVal(newObj, propertyName.get(), value.get()); } // ------------------------------ BracketAccessorNode -------------------------------- RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (m_base->isResolveNode() - && generator.willResolveToArguments(static_cast(m_base)->identifier()) - && !generator.symbolTable().slowArguments()) { - RefPtr property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property.get()); + if (m_base->isSuperNode()) { + // FIXME: Should we generate the profiler info? + if (m_subscript->isString()) { + const Identifier& id = static_cast(m_subscript)->value(); + return generator.emitGetById(generator.finalDestination(dst), emitSuperBaseForCallee(generator), id); + } + return generator.emitGetByVal(generator.finalDestination(dst), emitSuperBaseForCallee(generator), generator.emitNode(m_subscript)); + } + + RegisterID* ret; + RegisterID* finalDest = generator.finalDestination(dst); + + if (m_subscript->isString()) { + RefPtr base = generator.emitNode(m_base); + ret = generator.emitGetById(finalDest, base.get(), static_cast(m_subscript)->value()); + } else { + RefPtr base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); + RegisterID* property = generator.emitNode(m_subscript); + ret = generator.emitGetByVal(finalDest, base.get(), property); } - RefPtr base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); - RegisterID* property = generator.emitNode(m_subscript); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); + + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(finalDest, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } // ------------------------------ DotAccessorNode -------------------------------- 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(), divotStart(), divotEnd()); - return generator.emitGetArgumentsLength(generator.finalDestination(dst), generator.uncheckedRegisterForArguments()); - } - -nonArgumentsPath: - RefPtr base = generator.emitNode(m_base); + RefPtr base = m_base->isSuperNode() ? emitSuperBaseForCallee(generator) : generator.emitNode(m_base); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitGetById(generator.finalDestination(dst), base.get(), m_ident); + RegisterID* finalDest = generator.finalDestination(dst); + RegisterID* ret = generator.emitGetById(finalDest, base.get(), m_ident); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(finalDest, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } // ------------------------------ ArgumentListNode ----------------------------- @@ -417,6 +653,7 @@ RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* RefPtr func = generator.emitNode(m_expr); RefPtr returnValue = generator.finalDestination(dst, func.get()); CallArguments callArguments(generator, m_args); + generator.emitMove(callArguments.thisRegister(), func.get()); return generator.emitConstruct(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); } @@ -449,8 +686,9 @@ CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argume RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (Local local = generator.local(generator.propertyNames().eval)) { - RefPtr func = generator.emitMove(generator.tempDestination(dst), local.get()); + Variable var = generator.variable(generator.propertyNames().eval); + if (RegisterID* local = var.local()) { + RefPtr func = generator.emitMove(generator.tempDestination(dst), local); CallArguments callArguments(generator, m_args); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd()); @@ -460,8 +698,10 @@ RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, Reg CallArguments callArguments(generator, m_args); JSTextPosition newDivot = divotStart() + 4; generator.emitExpressionInfo(newDivot, divotStart(), newDivot); - generator.emitResolveScope(callArguments.thisRegister(), generator.propertyNames().eval); - generator.emitGetFromScope(func.get(), callArguments.thisRegister(), generator.propertyNames().eval, ThrowIfNotFound); + generator.moveToDestinationIfNeeded( + callArguments.thisRegister(), + generator.emitResolveScope(callArguments.thisRegister(), var)); + generator.emitGetFromScope(func.get(), callArguments.thisRegister(), var, ThrowIfNotFound); return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd()); } @@ -472,8 +712,21 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re RefPtr func = generator.emitNode(m_expr); RefPtr returnValue = generator.finalDestination(dst, func.get()); CallArguments callArguments(generator, m_args); + if (m_expr->isSuperNode()) { + ASSERT(generator.isConstructor()); + ASSERT(generator.constructorKind() == ConstructorKind::Derived); + generator.emitMove(callArguments.thisRegister(), generator.newTarget()); + RegisterID* ret = generator.emitConstruct(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + generator.emitMove(generator.thisRegister(), ret); + return ret; + } generator.emitLoad(callArguments.thisRegister(), jsUndefined()); - return generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } // ------------------------------ FunctionCallResolveNode ---------------------------------- @@ -482,14 +735,20 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, { ExpectedFunction expectedFunction = generator.expectedFunctionForIdentifier(m_ident); - if (Local local = generator.local(m_ident)) { - RefPtr func = generator.emitMove(generator.tempDestination(dst), local.get()); + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { + RefPtr func = generator.emitMove(generator.tempDestination(dst), local); RefPtr returnValue = generator.finalDestination(dst, func.get()); CallArguments callArguments(generator, m_args); generator.emitLoad(callArguments.thisRegister(), jsUndefined()); // 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(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } RefPtr func = generator.newTemporary(); @@ -498,23 +757,87 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, JSTextPosition newDivot = divotStart() + m_ident.length(); generator.emitExpressionInfo(newDivot, divotStart(), newDivot); - generator.emitResolveScope(callArguments.thisRegister(), m_ident); - generator.emitGetFromScope(func.get(), callArguments.thisRegister(), m_ident, ThrowIfNotFound); - return generator.emitCall(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); + generator.moveToDestinationIfNeeded( + callArguments.thisRegister(), + generator.emitResolveScope(callArguments.thisRegister(), var)); + generator.emitGetFromScope(func.get(), callArguments.thisRegister(), var, ThrowIfNotFound); + RegisterID* ret = generator.emitCall(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; +} + +// ------------------------------ BytecodeIntrinsicNode ---------------------------------- + +RegisterID* BytecodeIntrinsicNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + return (this->*m_emitter)(generator, dst); +} + +RegisterID* BytecodeIntrinsicNode::emit_intrinsic_putByValDirect(BytecodeGenerator& generator, RegisterID* dst) +{ + ArgumentListNode* node = m_args->m_listNode; + RefPtr base = generator.emitNode(node); + node = node->m_next; + RefPtr index = generator.emitNode(node); + node = node->m_next; + RefPtr value = generator.emitNode(node); + + ASSERT(!node->m_next); + + return generator.moveToDestinationIfNeeded(dst, generator.emitDirectPutByVal(base.get(), index.get(), value.get())); +} + +RegisterID* BytecodeIntrinsicNode::emit_intrinsic_toString(BytecodeGenerator& generator, RegisterID* dst) +{ + ArgumentListNode* node = m_args->m_listNode; + RefPtr src = generator.emitNode(node); + ASSERT(!node->m_next); + + return generator.moveToDestinationIfNeeded(dst, generator.emitToString(generator.tempDestination(dst), src.get())); } // ------------------------------ FunctionCallBracketNode ---------------------------------- RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr base = generator.emitNode(m_base); - RefPtr property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); - RefPtr function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); + bool baseIsSuper = m_base->isSuperNode(); + bool subscriptIsString = m_subscript->isString(); + + RefPtr base; + if (baseIsSuper) + base = emitSuperBaseForCallee(generator); + else { + if (subscriptIsString) + base = generator.emitNode(m_base); + else + base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); + } + + RefPtr function; + if (subscriptIsString) { + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); + function = generator.emitGetById(generator.tempDestination(dst), base.get(), static_cast(m_subscript)->value()); + } else { + RefPtr property = generator.emitNode(m_subscript); + generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); + function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); + } + RefPtr returnValue = generator.finalDestination(dst, function.get()); CallArguments callArguments(generator, m_args); - generator.emitMove(callArguments.thisRegister(), base.get()); - return generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (baseIsSuper) + generator.emitMove(callArguments.thisRegister(), generator.thisRegister()); + else + generator.emitMove(callArguments.thisRegister(), base.get()); + RegisterID* ret = generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } // ------------------------------ FunctionCallDotNode ---------------------------------- @@ -524,21 +847,19 @@ RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, Regi RefPtr function = generator.tempDestination(dst); RefPtr returnValue = generator.finalDestination(dst, function.get()); CallArguments callArguments(generator, m_args); - generator.emitNode(callArguments.thisRegister(), m_base); + bool baseIsSuper = m_base->isSuperNode(); + if (baseIsSuper) + generator.emitMove(callArguments.thisRegister(), generator.thisRegister()); + else + generator.emitNode(callArguments.thisRegister(), m_base); generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd()); - generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident); - return generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); -} - -static RegisterID* getArgumentByVal(BytecodeGenerator& generator, ExpressionNode* base, RegisterID* property, RegisterID* dst, JSTextPosition divot, JSTextPosition divotStart, JSTextPosition divotEnd) -{ - if (base->isResolveNode() - && generator.willResolveToArguments(static_cast(base)->identifier()) - && !generator.symbolTable().slowArguments()) { - generator.emitExpressionInfo(divot, divotStart, divotEnd); - return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property); + generator.emitGetById(function.get(), baseIsSuper ? emitSuperBaseForCallee(generator) : callArguments.thisRegister(), m_ident); + RegisterID* ret = generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); } - return nullptr; + return ret; } RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) @@ -561,15 +882,10 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, profileHookRegister = generator.newTemporary(); SpreadExpressionNode* spread = static_cast(m_args->m_listNode->m_expr); ExpressionNode* subject = spread->expression(); - RefPtr thisRegister = getArgumentByVal(generator, subject, generator.emitLoad(0, jsNumber(0)), 0, spread->divot(), spread->divotStart(), spread->divotEnd()); RefPtr argumentsRegister; - if (thisRegister) - argumentsRegister = generator.uncheckedRegisterForArguments(); - else { - argumentsRegister = generator.emitNode(subject); - generator.emitExpressionInfo(spread->divot(), spread->divotStart(), spread->divotEnd()); - thisRegister = generator.emitGetByVal(generator.newTemporary(), argumentsRegister.get(), generator.emitLoad(0, jsNumber(0))); - } + argumentsRegister = generator.emitNode(subject); + generator.emitExpressionInfo(spread->divot(), spread->divotStart(), spread->divotEnd()); + RefPtr thisRegister = generator.emitGetByVal(generator.newTemporary(), argumentsRegister.get(), generator.emitLoad(0, jsNumber(0))); generator.emitCallVarargs(returnValue.get(), base.get(), thisRegister.get(), argumentsRegister.get(), generator.newTemporary(), 1, profileHookRegister.get(), divot(), divotStart(), divotEnd()); } else if (m_args->m_listNode && m_args->m_listNode->m_expr) { ArgumentListNode* oldList = m_args->m_listNode; @@ -597,6 +913,10 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, } generator.emitLabel(end.get()); } + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return returnValue.get(); } @@ -659,7 +979,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, } else 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.vm(), 0, 0); + m_args->m_listNode = static_cast(m_args->m_listNode->m_next->m_expr)->toArgumentList(generator.parserArena(), 0, 0); RefPtr realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); CallArguments callArguments(generator, m_args); generator.emitNode(callArguments.thisRegister(), oldList->m_expr); @@ -687,10 +1007,7 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RefPtr thisRegister = generator.emitNode(m_args->m_listNode->m_expr); RefPtr argsRegister; ArgumentListNode* args = m_args->m_listNode->m_next; - if (args->m_expr->isResolveNode() && generator.willResolveToArguments(static_cast(args->m_expr)->identifier()) && !generator.symbolTable().slowArguments()) - argsRegister = generator.uncheckedRegisterForArguments(); - else - argsRegister = generator.emitNode(args->m_expr); + argsRegister = generator.emitNode(args->m_expr); // Function.prototype.apply ignores extra arguments, but we still // need to evaluate them for side effects. @@ -707,6 +1024,10 @@ RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, generator.emitCall(returnValue.get(), function.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); generator.emitLabel(end.get()); } + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(returnValue.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return returnValue.get(); } @@ -735,12 +1056,13 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d ResolveNode* resolve = static_cast(m_expr); const Identifier& ident = resolve->identifier(); - if (Local local = generator.local(ident)) { - RefPtr localReg = local.get(); - if (local.isReadOnly()) { + Variable var = generator.variable(ident); + if (RegisterID* local = var.local()) { + RefPtr localReg = local; + if (var.isReadOnly()) { generator.emitReadOnlyExceptionIfNeeded(); - localReg = generator.emitMove(generator.tempDestination(dst), localReg.get()); - } else if (local.isCaptured()) { + localReg = generator.emitMove(generator.tempDestination(dst), local); + } else if (generator.vm()->typeProfiler()) { RefPtr tempDst = generator.finalDestination(dst); ASSERT(dst != localReg); RefPtr tempDstSrc = generator.newTemporary(); @@ -748,16 +1070,23 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d generator.emitMove(tempDstSrc.get(), localReg.get()); emitIncOrDec(generator, tempDstSrc.get(), m_operator); generator.emitMove(localReg.get(), tempDstSrc.get()); + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); return tempDst.get(); } return emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator); } generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - RefPtr scope = generator.emitResolveScope(generator.newTemporary(), ident); - RefPtr value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound); + RefPtr scope = generator.emitResolveScope(nullptr, var); + RefPtr value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); RefPtr oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); - generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound); + generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return oldValue.get(); } @@ -779,6 +1108,10 @@ RegisterID* PostfixNode::emitBracket(BytecodeGenerator& generator, RegisterID* d RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitPutByVal(base.get(), property.get(), value.get()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, oldValue); } @@ -799,6 +1132,10 @@ RegisterID* PostfixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) RegisterID* oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitPutById(base.get(), ident, value.get()); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value.get(), ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, oldValue); } @@ -814,19 +1151,20 @@ RegisterID* PostfixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* return emitDot(generator, dst); 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."); + ? ASCIILiteral("Postfix ++ operator applied to value that is not a reference.") + : ASCIILiteral("Postfix -- operator applied to value that is not a reference.")); } // ------------------------------ DeleteResolveNode ----------------------------------- RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (generator.local(m_ident).get()) + Variable var = generator.variable(m_ident); + if (var.local()) return generator.emitLoad(generator.finalDestination(dst), false); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - RefPtr base = generator.emitResolveScope(generator.tempDestination(dst), m_ident); + RefPtr base = generator.emitResolveScope(dst, var); return generator.emitDeleteById(generator.finalDestination(dst, base.get()), base.get(), m_ident); } @@ -838,6 +1176,8 @@ RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, Regist RefPtr r1 = generator.emitNode(m_subscript); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); + if (m_base->isSuperNode()) + return emitThrowReferenceError(generator, "Cannot delete a super property"); return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1.get()); } @@ -848,6 +1188,8 @@ RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID RefPtr r0 = generator.emitNode(m_base); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); + if (m_base->isSuperNode()) + return emitThrowReferenceError(generator, "Cannot delete a super property"); return generator.emitDeleteById(generator.finalDestination(dst), r0.get(), m_ident); } @@ -873,18 +1215,19 @@ RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst return generator.emitLoad(dst, jsUndefined()); } -// ------------------------------ TypeOfValueNode ----------------------------------- +// ------------------------------ TypeOfResolveNode ----------------------------------- RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (Local local = generator.local(m_ident)) { + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { if (dst == generator.ignoredResult()) return 0; - return generator.emitTypeOf(generator.finalDestination(dst), local.get()); + return generator.emitTypeOf(generator.finalDestination(dst), local); } - RefPtr scope = generator.emitResolveScope(generator.tempDestination(dst), m_ident); - RefPtr value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, DoNotThrowIfNotFound); + RefPtr scope = generator.emitResolveScope(dst, var); + RefPtr value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, DoNotThrowIfNotFound); if (dst == generator.ignoredResult()) return 0; return generator.emitTypeOf(generator.finalDestination(dst, scope.get()), value.get()); @@ -910,16 +1253,19 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds ResolveNode* resolve = static_cast(m_expr); const Identifier& ident = resolve->identifier(); - if (Local local = generator.local(ident)) { - RefPtr localReg = local.get(); - if (local.isReadOnly()) { + Variable var = generator.variable(ident); + if (RegisterID* local = var.local()) { + RefPtr localReg = local; + if (var.isReadOnly()) { generator.emitReadOnlyExceptionIfNeeded(); localReg = generator.emitMove(generator.tempDestination(dst), localReg.get()); - } else if (local.isCaptured()) { + } else if (generator.vm()->typeProfiler()) { RefPtr tempDst = generator.tempDestination(dst); generator.emitMove(tempDst.get(), localReg.get()); emitIncOrDec(generator, tempDst.get(), m_operator); generator.emitMove(localReg.get(), tempDst.get()); + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); return generator.moveToDestinationIfNeeded(dst, tempDst.get()); } emitIncOrDec(generator, localReg.get(), m_operator); @@ -927,10 +1273,14 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds } generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - RefPtr scope = generator.emitResolveScope(generator.tempDestination(dst), ident); - RefPtr value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), ident, ThrowIfNotFound); + RefPtr scope = generator.emitResolveScope(dst, var); + RefPtr value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); emitIncOrDec(generator, value.get(), m_operator); - generator.emitPutToScope(scope.get(), ident, value.get(), ThrowIfNotFound); + generator.emitPutToScope(scope.get(), var, value.get(), ThrowIfNotFound); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &ident); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, value.get()); } @@ -950,6 +1300,10 @@ RegisterID* PrefixNode::emitBracket(BytecodeGenerator& generator, RegisterID* ds emitIncOrDec(generator, value, m_operator); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitPutByVal(base.get(), property.get(), value); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, propDst.get()); } @@ -968,6 +1322,10 @@ RegisterID* PrefixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst) emitIncOrDec(generator, value, m_operator); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitPutById(base.get(), ident, value); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(value, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, propDst.get()); } @@ -983,8 +1341,8 @@ RegisterID* PrefixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d return emitDot(generator, dst); 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."); + ? ASCIILiteral("Prefix ++ operator applied to value that is not a reference.") + : ASCIILiteral("Prefix -- operator applied to value that is not a reference.")); } // ------------------------------ Unary Operation Nodes ----------------------------------- @@ -1216,7 +1574,7 @@ RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* } RefPtr src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator)); - bool wasTypeof = generator.m_lastOpcodeID == op_typeof; + bool wasTypeof = generator.lastOpcodeID() == op_typeof; RefPtr src2 = generator.emitNode(right); generator.emitExpressionInfo(position(), position(), position()); if (wasTypeof && (opcodeID == op_neq || opcodeID == op_nstricteq)) { @@ -1335,14 +1693,18 @@ RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, Register generator.emitNodeInConditionContext(m_logical, beforeThen.get(), beforeElse.get(), FallThroughMeansTrue); generator.emitLabel(beforeThen.get()); + generator.emitProfileControlFlow(m_expr1->startOffset()); generator.emitNode(newDst.get(), m_expr1); generator.emitJump(afterElse.get()); generator.emitLabel(beforeElse.get()); + generator.emitProfileControlFlow(m_expr1->endOffset() + 1); generator.emitNode(newDst.get(), m_expr2); generator.emitLabel(afterElse.get()); + generator.emitProfileControlFlow(m_expr2->endOffset() + 1); + return newDst.get(); } @@ -1407,60 +1769,80 @@ static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& gen RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (Local local = generator.local(m_ident)) { - if (local.isReadOnly()) { + JSTextPosition newDivot = divotStart() + m_ident.length(); + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { + if (var.isReadOnly()) { generator.emitReadOnlyExceptionIfNeeded(); - return emitReadModifyAssignment(generator, generator.finalDestination(dst), local.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); } - if (local.isCaptured() + if (generator.vm()->typeProfiler() || generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { RefPtr result = generator.newTemporary(); - generator.emitMove(result.get(), local.get()); + generator.emitMove(result.get(), local); emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - generator.emitMove(local.get(), result.get()); + generator.emitMove(local, result.get()); + generator.invalidateForInContextForLocal(local); + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); return generator.moveToDestinationIfNeeded(dst, result.get()); } - RegisterID* result = emitReadModifyAssignment(generator, local.get(), local.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + generator.invalidateForInContextForLocal(local); return generator.moveToDestinationIfNeeded(dst, result); } - JSTextPosition newDivot = divotStart() + m_ident.length(); generator.emitExpressionInfo(newDivot, divotStart(), newDivot); - RefPtr scope = generator.emitResolveScope(generator.newTemporary(), m_ident); - RefPtr value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), m_ident, ThrowIfNotFound); + RefPtr scope = generator.emitResolveScope(nullptr, var); + RefPtr value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, ThrowIfNotFound); RefPtr result = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); - return generator.emitPutToScope(scope.get(), m_ident, result.get(), ThrowIfNotFound); + RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), ThrowIfNotFound); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(result.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_ident); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return returnResult; } // ------------------------------ AssignResolveNode ----------------------------------- RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (Local local = generator.local(m_ident)) { - if (local.isReadOnly()) { + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { + if (var.isReadOnly()) { generator.emitReadOnlyExceptionIfNeeded(); return generator.emitNode(dst, m_right); } - if (local.isCaptured()) { + if (var.isSpecial() || generator.vm()->typeProfiler()) { RefPtr tempDst = generator.tempDestination(dst); generator.emitNode(tempDst.get(), m_right); - generator.emitMove(local.get(), tempDst.get()); + generator.emitMove(local, tempDst.get()); + generator.invalidateForInContextForLocal(local); + if (generator.vm()->typeProfiler()) + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); return generator.moveToDestinationIfNeeded(dst, tempDst.get()); } - RegisterID* result = generator.emitNode(local.get(), m_right); + RegisterID* result = generator.emitNode(local, m_right); + generator.invalidateForInContextForLocal(local); return generator.moveToDestinationIfNeeded(dst, result); } if (generator.isStrictMode()) generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - RefPtr scope = generator.emitResolveScope(generator.newTemporary(), m_ident); + RefPtr scope = generator.emitResolveScope(nullptr, var); if (dst == generator.ignoredResult()) dst = 0; RefPtr result = generator.emitNode(dst, m_right); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitPutToScope(scope.get(), m_ident, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); + RegisterID* returnResult = generator.emitPutToScope(scope.get(), var, result.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(result.get(), var.isResolved() ? ProfileTypeBytecodePutToLocalScope : ProfileTypeBytecodePutToScope, &m_ident); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return returnResult; } // ------------------------------ AssignDotNode ----------------------------------- @@ -1473,6 +1855,10 @@ RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get()); generator.emitPutById(base.get(), m_ident, forwardResult); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(forwardResult, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, forwardResult); } @@ -1487,14 +1873,19 @@ RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, Regist RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, static_cast(m_operator), OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitPutById(base.get(), m_ident, updatedValue); + RegisterID* ret = generator.emitPutById(base.get(), m_ident, updatedValue); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(updatedValue, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } // ------------------------------ AssignErrorNode ----------------------------------- RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) { - return emitThrowReferenceError(generator, "Left side of assignment is not a reference."); + return emitThrowReferenceError(generator, ASCIILiteral("Left side of assignment is not a reference.")); } // ------------------------------ AssignBracketNode ----------------------------------- @@ -1508,7 +1899,16 @@ RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, Regist generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get()); - generator.emitPutByVal(base.get(), property.get(), forwardResult); + + if (m_subscript->isString()) + generator.emitPutById(base.get(), static_cast(m_subscript)->value(), forwardResult); + else + generator.emitPutByVal(base.get(), property.get(), forwardResult); + + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(forwardResult, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return generator.moveToDestinationIfNeeded(dst, forwardResult); } @@ -1525,6 +1925,10 @@ RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, Re generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitPutByVal(base.get(), property.get(), updatedValue); + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(updatedValue, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } return updatedValue; } @@ -1533,10 +1937,10 @@ RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, Re RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - ASSERT(m_expressions.size() > 1); - for (size_t i = 0; i < m_expressions.size() - 1; i++) - generator.emitNode(generator.ignoredResult(), m_expressions[i]); - return generator.emitNode(dst, m_expressions.last()); + CommaNode* node = this; + for (; node && node->next(); node = node->next()) + generator.emitNode(generator.ignoredResult(), node->m_expr); + return generator.emitNode(dst, node->m_expr); } // ------------------------------ ConstDeclNode ------------------------------------ @@ -1544,17 +1948,19 @@ 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 (Local local = generator.constLocal(m_ident)) { + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { if (!m_init) - return local.get(); + return local; - if (local.isCaptured()) { + // FIXME: Maybe call emitExpressionInfo here. + if (var.isSpecial() || generator.vm()->typeProfiler()) { RefPtr tempDst = generator.newTemporary(); generator.emitNode(tempDst.get(), m_init); - return generator.emitMove(local.get(), tempDst.get()); + return generator.emitMove(local, tempDst.get()); } - return generator.emitNode(local.get(), m_init); + return generator.emitNode(local, m_init); } RefPtr value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined()); @@ -1562,12 +1968,24 @@ RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) if (generator.codeType() == GlobalCode) return generator.emitInitGlobalConst(m_ident, value.get()); - if (generator.codeType() != EvalCode) - return value.get(); + if (generator.codeType() != EvalCode) { + // Do a special kind of resolution. If anything fails, then don't perform the assignment. This is + // pretty shady - particularly how negligent it is with inteleaving scopes - but it's the + // behavior that JSC has had for a long time. + + ASSERT(generator.codeType() == FunctionCode); + + var = generator.variablePerSymbolTable(m_ident); + if (!var.isResolved()) + return value.get(); + + RefPtr scope = generator.emitResolveScope(generator.newTemporary(), var); + return generator.emitPutToScope(scope.get(), var, value.get(), DoNotThrowIfNotFound); + } // FIXME: This will result in incorrect assignment if m_ident exists in an intervening with scope. - RefPtr scope = generator.emitResolveScope(generator.newTemporary(), m_ident); - return generator.emitPutToScope(scope.get(), m_ident, value.get(), DoNotThrowIfNotFound); + RefPtr scope = generator.emitResolveScope(nullptr, var); + return generator.emitPutToScope(scope.get(), var, value.get(), DoNotThrowIfNotFound); } RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) @@ -1592,15 +2010,13 @@ void ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) inline StatementNode* SourceElements::lastStatement() const { - size_t size = m_statements.size(); - return size ? m_statements[size - 1] : 0; + return m_tail; } inline void SourceElements::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - size_t size = m_statements.size(); - for (size_t i = 0; i < size; ++i) - generator.emitNode(dst, m_statements[i]); + for (StatementNode* statement = m_head; statement; statement = statement->next()) + generator.emitNode(dst, statement); } // ------------------------------ BlockNode ------------------------------------ @@ -1610,7 +2026,7 @@ inline StatementNode* BlockNode::lastStatement() const return m_statements ? m_statements->lastStatement() : 0; } -inline StatementNode* BlockNode::singleStatement() const +StatementNode* BlockNode::singleStatement() const { return m_statements ? m_statements->singleStatement() : 0; } @@ -1654,6 +2070,28 @@ void VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) generator.emitNode(m_expr); } +// ------------------------------ EmptyVarExpression ---------------------------- + +RegisterID* EmptyVarExpression::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + if (!generator.vm()->typeProfiler()) + return nullptr; + + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) + generator.emitProfileType(local, ProfileTypeBytecodeHasGlobalID, nullptr); + else { + RefPtr scope = generator.emitResolveScope(nullptr, var); + RefPtr value = generator.emitGetFromScope(generator.newTemporary(), scope.get(), var, DoNotThrowIfNotFound); + generator.emitProfileType(value.get(), var.isResolved() ? ProfileTypeBytecodeGetFromLocalScope : ProfileTypeBytecodeGetFromScope, &m_ident); + } + + generator.emitTypeProfilerExpressionInfo(position(), JSTextPosition(-1, position().offset + m_ident.length(), -1)); + + // It's safe to return null here because this node will always be a child node of VarStatementNode which ignores our return value. + return nullptr; +} + // ------------------------------ IfElseNode --------------------------------------- static inline StatementNode* singleStatement(StatementNode* statementNode) @@ -1708,6 +2146,7 @@ void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) generator.emitNodeInConditionContext(m_condition, trueTarget, falseTarget, fallThroughMode); generator.emitLabel(beforeThen.get()); + generator.emitProfileControlFlow(m_ifBlock->startOffset()); if (!didFoldIfBlock) { generator.emitNode(dst, m_ifBlock); @@ -1717,10 +2156,14 @@ void IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) generator.emitLabel(beforeElse.get()); - if (m_elseBlock) + if (m_elseBlock) { + generator.emitProfileControlFlow(m_ifBlock->endOffset() + (m_ifBlock->isBlock() ? 1 : 0)); generator.emitNode(dst, m_elseBlock); + } generator.emitLabel(afterElse.get()); + StatementNode* endingBlock = m_elseBlock ? m_elseBlock : m_ifBlock; + generator.emitProfileControlFlow(endingBlock->endOffset() + (endingBlock->isBlock() ? 1 : 0)); } // ------------------------------ DoWhileNode ---------------------------------- @@ -1750,12 +2193,13 @@ void WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop); RefPtr