/* * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2003-2009, 2012-2013, 2015-2016 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 * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "config.h" #include "Nodes.h" #include "NodeConstructors.h" #include "BuiltinNames.h" #include "BytecodeGenerator.h" #include "CallFrame.h" #include "Debugger.h" #include "JIT.h" #include "JSFunction.h" #include "JSGeneratorFunction.h" #include "JSGlobalObject.h" #include "JSONObject.h" #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 "StackAlignment.h" #include "TemplateRegistryKey.h" #include #include #include using namespace WTF; namespace JSC { /* Details of the emitBytecode function. Return value: The register holding the production's value. dst: An optional parameter specifying the most efficient destination at which to store the production's value. The callee must honor dst. The dst argument provides for a crude form of copy propagation. For example, x = 1 becomes load r[x], 1 instead of load r0, 1 mov r[x], r0 because the assignment node, "x =", passes r[x] as dst to the number node, "1". */ void ExpressionNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) { RegisterID* result = generator.emitNode(this); if (fallThroughMode == FallThroughMeansTrue) generator.emitJumpIfFalse(result, falseTarget); else generator.emitJumpIfTrue(result, trueTarget); } // ------------------------------ ThrowableExpressionData -------------------------------- RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& generator, const String& message) { generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitThrowReferenceError(message); return generator.newTemporary(); } // ------------------------------ ConstantNode ---------------------------------- void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) { 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); // All other cases are unconditional fall-throughs, like "if (true)". } RegisterID* ConstantNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (dst == generator.ignoredResult()) return 0; return generator.emitLoad(dst, jsValue(generator)); } 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) { if (dst == generator.ignoredResult()) return 0; return generator.emitNewRegExp(generator.finalDestination(dst), RegExp::create(*generator.vm(), m_pattern.string(), regExpFlags(m_flags.string()))); } // ------------------------------ ThisNode ------------------------------------- RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { generator.ensureThis(); if (dst == generator.ignoredResult()) return 0; RegisterID* result = generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); static const unsigned thisLength = 4; generator.emitProfileType(generator.thisRegister(), position(), JSTextPosition(-1, position().offset + thisLength, -1)); return result; } // ------------------------------ SuperNode ------------------------------------- static RegisterID* emitHomeObjectForCallee(BytecodeGenerator& generator) { if (generator.isDerivedClassContext() || generator.isDerivedConstructorContext()) { RegisterID* derivedConstructor = generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(); return generator.emitGetById(generator.newTemporary(), derivedConstructor, generator.propertyNames().homeObjectPrivateName); } RegisterID callee; callee.setIndex(JSStack::Callee); return generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().homeObjectPrivateName); } static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator) { RefPtr homeObject = emitHomeObjectForCallee(generator); return generator.emitGetById(generator.newTemporary(), homeObject.get(), generator.propertyNames().underscoreProto); } static RegisterID* emitGetSuperFunctionForConstruct(BytecodeGenerator& generator) { if (generator.isDerivedConstructorContext()) return generator.emitGetById(generator.newTemporary(), generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(), generator.propertyNames().underscoreProto); RegisterID callee; callee.setIndex(JSStack::Callee); return generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().underscoreProto); } RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { RegisterID* result = emitSuperBaseForCallee(generator); return generator.moveToDestinationIfNeeded(generator.finalDestination(dst), result); } // ------------------------------ NewTargetNode ---------------------------------- RegisterID* NewTargetNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (dst == generator.ignoredResult()) return nullptr; return generator.moveToDestinationIfNeeded(dst, generator.newTarget()); } // ------------------------------ ResolveNode ---------------------------------- bool ResolveNode::isPure(BytecodeGenerator& generator) const { return generator.variable(m_ident).offset().isStack(); } RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { Variable var = generator.variable(m_ident); if (RegisterID* local = var.local()) { generator.emitTDZCheckIfNecessary(var, local, nullptr); if (dst == generator.ignoredResult()) return nullptr; generator.emitProfileType(local, var, 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(dst, var); RegisterID* finalDest = generator.finalDestination(dst); RegisterID* result = generator.emitGetFromScope(finalDest, scope.get(), var, ThrowIfNotFound); generator.emitTDZCheckIfNecessary(var, finalDest, nullptr); generator.emitProfileType(finalDest, var, m_position, JSTextPosition(-1, m_position.offset + m_ident.length(), -1)); return result; } // ------------------------------ 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()) { generator.emitTDZCheckIfNecessary(var, local, nullptr); 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); generator.emitTDZCheckIfNecessary(var, tag.get(), nullptr); } } 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()); if (bracket->base()->isSuperNode()) { RefPtr thisValue = generator.ensureThis(); tag = generator.emitGetByVal(generator.newTemporary(), base.get(), thisValue.get(), property.get()); } else 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()); if (dot->base()->isSuperNode()) { RefPtr thisValue = generator.ensureThis(); tag = generator.emitGetById(generator.newTemporary(), base.get(), thisValue.get(), dot->identifier()); } else 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()); } // ------------------------------ ArrayNode ------------------------------------ RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { // FIXME: Should we put all of this code into emitNewArray? unsigned length = 0; ElementNode* firstPutElement; for (firstPutElement = m_element; firstPutElement; firstPutElement = firstPutElement->next()) { if (firstPutElement->elision() || firstPutElement->value()->isSpreadExpression()) break; ++length; } if (!firstPutElement && !m_elision) return generator.emitNewArray(generator.finalDestination(dst), m_element, length); 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(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 { if (m_elision || m_optional) return false; for (ElementNode* ptr = m_element; ptr; ptr = ptr->next()) { if (ptr->elision()) return false; } return true; } ArgumentListNode* ArrayNode::toArgumentList(ParserArena& parserArena, int lineNumber, int startPosition) const { ASSERT(!m_elision && !m_optional); ElementNode* ptr = m_element; if (!ptr) return 0; 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 (parserArena) ArgumentListNode(location, tail, ptr->value()); } return head; } // ------------------------------ ObjectLiteralNode ---------------------------- RegisterID* ObjectLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (!m_list) { if (dst == generator.ignoredResult()) return 0; return generator.emitNewObject(generator.finalDestination(dst)); } 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) { // 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; } 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; } } // 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; } RefPtr value = generator.emitNode(node->m_assign); bool needsSuperBinding = node->needsSuperBinding(); if (needsSuperBinding) emitPutHomeObject(generator, value.get(), dst); unsigned attributes = node->isClassProperty() ? (Accessor | DontEnum) : Accessor; 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) { // Computed accessors. if (node->m_type & PropertyNode::Computed) { RefPtr propertyName = generator.emitNode(node->m_expression); generator.emitSetFunctionNameIfNeeded(node->m_assign, value.get(), propertyName.get()); if (node->m_type & PropertyNode::Getter) generator.emitPutGetterByVal(dst, propertyName.get(), attributes, value.get()); else generator.emitPutSetterByVal(dst, propertyName.get(), attributes, value.get()); continue; } if (node->m_type & PropertyNode::Getter) generator.emitPutGetterById(dst, *node->name(), attributes, value.get()); else generator.emitPutSetterById(dst, *node->name(), attributes, value.get()); 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()); } } ASSERT(!pair.second || needsSuperBinding == pair.second->needsSuperBinding()); if (needsSuperBinding && pair.second) emitPutHomeObject(generator, secondReg, dst); generator.emitPutGetterSetter(dst, *node->name(), attributes, getterReg.get(), setterReg.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); unsigned attributes = BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable; if (!node.isClassProperty()) attributes |= BytecodeGenerator::PropertyEnumerable; generator.emitSetFunctionNameIfNeeded(node.m_assign, value.get(), propertyNameRegister.get()); generator.emitCallDefineProperty(newObj, propertyNameRegister.get(), value.get(), nullptr, nullptr, attributes, 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.emitSetFunctionNameIfNeeded(node.m_assign, value.get(), propertyName.get()); generator.emitDirectPutByVal(newObj, propertyName.get(), value.get()); } // ------------------------------ BracketAccessorNode -------------------------------- static bool isNonIndexStringElement(ExpressionNode& element) { return element.isString() && !parseIndex(static_cast(element).value()); } RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (m_base->isSuperNode()) { RefPtr finalDest = generator.finalDestination(dst); RefPtr thisValue = generator.ensureThis(); RefPtr superBase = emitSuperBaseForCallee(generator); if (isNonIndexStringElement(*m_subscript)) { const Identifier& id = static_cast(m_subscript)->value(); generator.emitGetById(finalDest.get(), superBase.get(), thisValue.get(), id); } else { RefPtr subscript = generator.emitNode(m_subscript); generator.emitGetByVal(finalDest.get(), superBase.get(), thisValue.get(), subscript.get()); } generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitProfileType(finalDest.get(), divotStart(), divotEnd()); return finalDest.get(); } RegisterID* ret; RefPtr finalDest = generator.finalDestination(dst); if (isNonIndexStringElement(*m_subscript)) { RefPtr base = generator.emitNode(m_base); ret = generator.emitGetById(finalDest.get(), 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.get(), base.get(), property); } generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); generator.emitProfileType(finalDest.get(), divotStart(), divotEnd()); return ret; } // ------------------------------ DotAccessorNode -------------------------------- RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { bool baseIsSuper = m_base->isSuperNode(); RefPtr base = baseIsSuper ? emitSuperBaseForCallee(generator) : generator.emitNode(m_base); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); RegisterID* finalDest = generator.finalDestination(dst); RegisterID* ret; if (baseIsSuper) { RefPtr thisValue = generator.ensureThis(); ret = generator.emitGetById(finalDest, base.get(), thisValue.get(), m_ident); } else ret = generator.emitGetById(finalDest, base.get(), m_ident); generator.emitProfileType(finalDest, divotStart(), divotEnd()); return ret; } // ------------------------------ ArgumentListNode ----------------------------- RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { ASSERT(m_expr); return generator.emitNode(dst, m_expr); } // ------------------------------ NewExprNode ---------------------------------- RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { ExpectedFunction expectedFunction; if (m_expr->isResolveNode()) expectedFunction = generator.expectedFunctionForIdentifier(static_cast(m_expr)->identifier()); else expectedFunction = NoExpectedFunction; 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()); } CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode, unsigned additionalArguments) : m_argumentsNode(argumentsNode) , m_padding(0) { 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); } // We need to ensure that the frame size is stack-aligned while ((JSStack::CallFrameHeaderSize + m_argv.size()) % stackAlignmentRegisters()) { m_argv.insert(0, generator.newTemporary()); m_padding++; } while (stackOffset() % stackAlignmentRegisters()) { m_argv.insert(0, generator.newTemporary()); m_padding++; } } // ------------------------------ EvalFunctionCallNode ---------------------------------- RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { // We need try to load 'this' before call eval in constructor, because 'this' can created by 'super' in some of the arrow function // var A = class A { // constructor () { this.id = 'A'; } // } // // var B = class B extend A { // constructor () { // var arrow = () => super(); // arrow(); // eval("this.id = 'B'"); // } // } if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext() && generator.isThisUsedInInnerArrowFunction()) generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); 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 ---------------------------------- RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { if (m_expr->isSuperNode()) { RefPtr func = emitGetSuperFunctionForConstruct(generator); RefPtr returnValue = generator.finalDestination(dst, func.get()); CallArguments callArguments(generator, m_args); ASSERT(generator.isConstructor() || generator.derivedContextType() == DerivedContextType::DerivedConstructorContext); ASSERT(generator.constructorKind() == ConstructorKind::Derived || generator.derivedContextType() == DerivedContextType::DerivedConstructorContext); generator.emitMove(callArguments.thisRegister(), generator.newTarget()); RegisterID* ret = generator.emitConstruct(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd()); bool isConstructorKindDerived = generator.constructorKind() == ConstructorKind::Derived; bool doWeUseArrowFunctionInConstructor = isConstructorKindDerived && generator.needsToUpdateArrowFunctionContext(); if (generator.isDerivedConstructorContext() || (doWeUseArrowFunctionInConstructor && generator.isSuperCallUsedInInnerArrowFunction())) generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); RefPtr