X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/f9bf01c6616d5ddcf65b13b33cedf9e387ff7a63..ed1e77d3adeb83d26fd1dfb16dd84cabdcefd250:/bytecompiler/NodesCodegen.cpp diff --git a/bytecompiler/NodesCodegen.cpp b/bytecompiler/NodesCodegen.cpp index b66c50d..cfd3ef1 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, 2015 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 @@ -27,20 +28,26 @@ #include "Nodes.h" #include "NodeConstructors.h" +#include "BuiltinNames.h" #include "BytecodeGenerator.h" #include "CallFrame.h" #include "Debugger.h" #include "JIT.h" #include "JSFunction.h" #include "JSGlobalObject.h" -#include "JSStaticScopeObject.h" +#include "JSNameScope.h" +#include "JSONObject.h" #include "LabelScope.h" #include "Lexer.h" -#include "Operations.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 @@ -72,113 +79,251 @@ namespace JSC { because the assignment node, "x =", passes r[x] as dst to the number node, "1". */ -// ------------------------------ ThrowableExpressionData -------------------------------- - -static void substitute(UString& string, const UString& substring) +void ExpressionNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) { - int position = string.find("%s"); - ASSERT(position != -1); - string = makeString(string.substr(0, position), substring, string.substr(position + 2)); + RegisterID* result = generator.emitNode(this); + if (fallThroughMode == FallThroughMeansTrue) + generator.emitJumpIfFalse(result, falseTarget); + else + generator.emitJumpIfTrue(result, trueTarget); } -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; -} +// ------------------------------ ThrowableExpressionData -------------------------------- -RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const UString& label) +RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const String& message) { - 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; + generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); + generator.emitThrowReferenceError(message); + return generator.newTemporary(); } -inline RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const Identifier& label) +// ------------------------------ ConstantNode ---------------------------------- + +void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) { - return emitThrowError(generator, type, messageTemplate, label.ustring()); -} + 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); -// ------------------------------ NullNode ------------------------------------- + // All other cases are unconditional fall-throughs, like "if (true)". +} -RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +RegisterID* ConstantNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (dst == generator.ignoredResult()) return 0; - return generator.emitLoad(dst, jsNull()); + return generator.emitLoad(dst, jsValue(generator)); } -// ------------------------------ BooleanNode ---------------------------------- - -RegisterID* BooleanNode::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); } -// ------------------------------ NumberNode ----------------------------------- +// ------------------------------ NumberNode ---------------------------------- RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); + return nullptr; + return generator.emitLoad(dst, jsValue(generator), isIntegerNode() ? SourceCodeRepresentation::Integer : SourceCodeRepresentation::Double); } -// ------------------------------ StringNode ----------------------------------- +// ------------------------------ RegExpNode ----------------------------------- -RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (dst == generator.ignoredResult()) return 0; - return generator.emitLoad(dst, m_value); + return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(*generator.vm(), m_pattern.string(), regExpFlags(m_flags.string()))); } -// ------------------------------ RegExpNode ----------------------------------- +// ------------------------------ ThisNode ------------------------------------- -RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr regExp = RegExp::create(generator.globalData(), m_pattern.ustring(), m_flags.ustring()); - if (!regExp->isValid()) - return emitThrowError(generator, SyntaxError, "Invalid regular expression: %s", regExp->errorMessage()); + if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived) + generator.emitTDZCheck(generator.thisRegister()); + if (dst == generator.ignoredResult()) return 0; - return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get()); + + 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; } -// ------------------------------ ThisNode ------------------------------------- +// ------------------------------ SuperNode ------------------------------------- -RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (dst == generator.ignoredResult()) return 0; - return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); + + 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.isLocal(m_ident); + return generator.variable(m_ident).offset().isStack(); } RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - if (RegisterID* local = generator.registerFor(m_ident)) { + Variable var = generator.variable(m_ident); + if (RegisterID* local = var.local()) { if (dst == generator.ignoredResult()) - return 0; + 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); } - generator.emitExpressionInfo(m_startOffset + m_ident.size(), m_ident.size(), 0); - return generator.emitResolve(generator.finalDestination(dst), m_ident); + JSTextPosition divot = m_start + m_ident.length(); + generator.emitExpressionInfo(divot, m_start, divot); + 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 ------------------------------------ @@ -189,28 +334,55 @@ RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds unsigned length = 0; ElementNode* firstPutElement; for (firstPutElement = m_element; firstPutElement; firstPutElement = firstPutElement->next()) { - if (firstPutElement->elision()) + if (firstPutElement->elision() || firstPutElement->value()->isSpreadExpression()) break; ++length; } if (!firstPutElement && !m_elision) - return generator.emitNewArray(generator.finalDestination(dst), m_element); - - RefPtr array = generator.emitNewArray(generator.tempDestination(dst), m_element); + return generator.emitNewArray(generator.finalDestination(dst), m_element, length); - for (ElementNode* n = firstPutElement; n; n = n->next()) { + RefPtr array = generator.emitNewArray(generator.tempDestination(dst), m_element, length); + ElementNode* n = firstPutElement; + for (; n; n = n->next()) { + if (n->value()->isSpreadExpression()) + goto handleSpread; RegisterID* value = generator.emitNode(n->value()); length += n->elision(); generator.emitPutByIndex(array.get(), length++, value); } if (m_elision) { - RegisterID* value = generator.emitLoad(0, jsNumber(generator.globalData(), m_elision + length)); + RegisterID* value = generator.emitLoad(0, jsNumber(m_elision + length)); generator.emitPutById(array.get(), generator.propertyNames().length, value); } return generator.moveToDestinationIfNeeded(dst, array.get()); + +handleSpread: + RefPtr index = generator.emitLoad(generator.newTemporary(), jsNumber(length)); + auto spreader = [this, array, index](BytecodeGenerator& generator, RegisterID* value) + { + generator.emitDirectPutByVal(array.get(), index.get(), value); + generator.emitInc(index.get()); + }; + for (; n; n = n->next()) { + if (n->elision()) + generator.emitBinaryOp(op_add, index.get(), index.get(), generator.emitLoad(0, jsNumber(n->elision())), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); + if (n->value()->isSpreadExpression()) { + SpreadExpressionNode* spread = static_cast(n->value()); + generator.emitEnumeration(spread, spread->expression(), spreader); + } else { + generator.emitDirectPutByVal(array.get(), index.get(), generator.emitNode(n->value())); + generator.emitInc(index.get()); + } + } + + if (m_elision) { + generator.emitBinaryOp(op_add, index.get(), index.get(), generator.emitLoad(0, jsNumber(m_elision)), OperandTypes(ResultType::numberTypeIsInt32(), ResultType::numberTypeIsInt32())); + generator.emitPutById(array.get(), generator.propertyNames().length, index.get()); + } + return generator.moveToDestinationIfNeeded(dst, array.get()); } bool ArrayNode::isSimpleArray() const @@ -224,18 +396,21 @@ bool ArrayNode::isSimpleArray() const return true; } -ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData) const +ArgumentListNode* ArrayNode::toArgumentList(ParserArena& parserArena, 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 (parserArena) 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 (parserArena) ArgumentListNode(location, tail, ptr->value()); } return head; } @@ -244,63 +419,218 @@ ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData) const 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()); - - for (PropertyListNode* p = this; p; p = p->m_next) { - RegisterID* value = generator.emitNode(p->m_node->m_assign); - - switch (p->m_node->m_type) { - case PropertyNode::Constant: { - generator.emitPutById(newObj.get(), p->m_node->name(), value); + // 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) + 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; + 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::Computed) { + hasComputedProperty = true; break; } - case PropertyNode::Getter: { - generator.emitPutGetter(newObj.get(), p->m_node->name(), value); - break; + if (node->m_type & PropertyNode::Constant) + continue; + + // Duplicates are possible. + GetterSetterPair pair(node, static_cast(nullptr)); + GetterSetterMap::AddResult result = map.add(node->name()->impl(), pair); + if (!result.isNewEntry) { + if (result.iterator->value.first->m_type == node->m_type) + result.iterator->value.first = node; + else + result.iterator->value.second = node; } - case PropertyNode::Setter: { - generator.emitPutSetter(newObj.get(), p->m_node->name(), value); - break; + } + + // Iterate over the remaining properties in the list. + for (; p; p = p->m_next) { + PropertyNode* node = p->m_node; + + // Handle regular values. + 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 pair. + 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; + RegisterID* secondReg = nullptr; + + 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); + secondReg = setterReg.get(); + } 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); + secondReg = getterReg.get(); + } else { + getterReg = generator.newTemporary(); + generator.emitLoad(getterReg.get(), jsUndefined()); + } } - default: - ASSERT_NOT_REACHED(); + + 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) { - RefPtr base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); - RegisterID* property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); + 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); + } + + generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); + + if (generator.vm()->typeProfiler()) { + generator.emitProfileType(finalDest, ProfileTypeBytecodeDoesNotHaveGlobalID, nullptr); + generator.emitTypeProfilerExpressionInfo(divotStart(), divotEnd()); + } + return ret; } // ------------------------------ DotAccessorNode -------------------------------- RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RegisterID* base = generator.emitNode(m_base); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitGetById(generator.finalDestination(dst), base, m_ident); + RefPtr base = m_base->isSuperNode() ? emitSuperBaseForCallee(generator) : generator.emitNode(m_base); + generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); + 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 ----------------------------- @@ -315,19 +645,64 @@ 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); - return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args, divot(), startOffset(), endOffset()); + 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()); +} + +CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode, unsigned additionalArguments) + : m_argumentsNode(argumentsNode) + , m_padding(0) +{ + if (generator.shouldEmitProfileHooks()) + m_profileHookRegister = generator.newTemporary(); + + size_t argumentCountIncludingThis = 1 + additionalArguments; // '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); + } + + while (stackOffset() % stackAlignmentRegisters()) { + m_argv.insert(0, generator.newTemporary()); + m_padding++; + } } // ------------------------------ EvalFunctionCallNode ---------------------------------- RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { - RefPtr func = generator.tempDestination(dst); - RefPtr thisRegister = generator.newTemporary(); - generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); - generator.emitResolveWithBase(thisRegister.get(), func.get(), generator.propertyNames().eval); - return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + 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()); + } + + RefPtr func = generator.newTemporary(); + CallArguments callArguments(generator, m_args); + JSTextPosition newDivot = divotStart() + 4; + generator.emitExpressionInfo(newDivot, divotStart(), newDivot); + 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()); } // ------------------------------ FunctionCallValueNode ---------------------------------- @@ -335,46 +710,134 @@ 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()); + 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()); + 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 ---------------------------------- 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()); + ExpectedFunction expectedFunction = generator.expectedFunctionForIdentifier(m_ident); + + 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. + 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; } - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) { - RefPtr func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); - RefPtr thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); - return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + RefPtr func = generator.newTemporary(); + RefPtr returnValue = generator.finalDestination(dst, func.get()); + CallArguments callArguments(generator, m_args); + + JSTextPosition newDivot = divotStart() + m_ident.length(); + generator.emitExpressionInfo(newDivot, divotStart(), newDivot); + 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; +} - RefPtr func = generator.newTemporary(); - RefPtr thisRegister = generator.newTemporary(); - int identifierStart = divot() - startOffset(); - generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0); - generator.emitResolveWithBase(thisRegister.get(), func.get(), m_ident); - return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); +// ------------------------------ 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); - 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()); + 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); + 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 ---------------------------------- @@ -382,12 +845,21 @@ 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); - 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()); + RefPtr returnValue = generator.finalDestination(dst, function.get()); + CallArguments callArguments(generator, m_args); + 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(), 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 ret; } RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) @@ -395,33 +867,59 @@ RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RefPtr