From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- .../JavaScriptCore/bytecompiler/NodesCodegen.cpp | 3014 +++++++++++++++----- 1 file changed, 2357 insertions(+), 657 deletions(-) (limited to 'Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp') diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp index 1ffd4f311..8f6f0582d 100644 --- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp +++ b/Source/JavaScriptCore/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-2017 Apple Inc. All rights reserved. * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) * Copyright (C) 2007 Maks Orlovich * Copyright (C) 2007 Eric Seidel @@ -28,26 +28,21 @@ #include "Nodes.h" #include "NodeConstructors.h" +#include "BuiltinNames.h" #include "BytecodeGenerator.h" #include "CallFrame.h" -#include "Debugger.h" #include "JIT.h" +#include "JSCInlines.h" #include "JSFunction.h" +#include "JSGeneratorFunction.h" #include "JSGlobalObject.h" -#include "JSNameScope.h" -#include "JSONObject.h" #include "LabelScope.h" #include "Lexer.h" -#include "Operations.h" #include "Parser.h" -#include "PropertyNameArray.h" -#include "RegExpCache.h" -#include "RegExpObject.h" -#include "SamplingTool.h" #include "StackAlignment.h" #include -#include #include +#include using namespace WTF; @@ -76,7 +71,7 @@ namespace JSC { because the assignment node, "x =", passes r[x] as dst to the number node, "1". */ -void ExpressionNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) +void ExpressionNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label& trueTarget, Label& falseTarget, FallThroughMode fallThroughMode) { RegisterID* result = generator.emitNode(this); if (fallThroughMode == FallThroughMeansTrue) @@ -96,9 +91,15 @@ RegisterID* ThrowableExpressionData::emitThrowReferenceError(BytecodeGenerator& // ------------------------------ ConstantNode ---------------------------------- -void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) +void ConstantNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label& trueTarget, Label& falseTarget, FallThroughMode fallThroughMode) { TriState value = jsValue(generator).pureToBoolean(); + + if (UNLIKELY(needsDebugHook())) { + if (value != MixedTriState) + generator.emitDebugHook(this); + } + if (value == MixedTriState) ExpressionNode::emitBytecodeInConditionContext(generator, trueTarget, falseTarget, fallThroughMode); else if (value == TrueTriState && fallThroughMode == FallThroughMeansFalse) @@ -121,6 +122,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) @@ -134,30 +144,222 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) { + generator.ensureThis(); if (dst == generator.ignoredResult()) return 0; - return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); + + 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().builtinNames().homeObjectPrivateName()); + } + + RegisterID callee; + callee.setIndex(CallFrameSlot::callee); + return generator.emitGetById(generator.newTemporary(), &callee, generator.propertyNames().builtinNames().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(CallFrameSlot::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); +} + +// ------------------------------ ImportNode ------------------------------------- + +RegisterID* ImportNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr importModule = generator.emitGetGlobalPrivate(generator.newTemporary(), generator.propertyNames().builtinNames().importModulePrivateName()); + CallArguments arguments(generator, nullptr, 1); + generator.emitLoad(arguments.thisRegister(), jsUndefined()); + generator.emitNode(arguments.argumentRegister(0), m_expr); + return generator.emitCall(generator.finalDestination(dst, importModule.get()), importModule.get(), NoExpectedFunction, arguments, divot(), divotStart(), divotEnd(), DebuggableCall::No); +} + +// ------------------------------ 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.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()) { + generator.emitTDZCheckIfNecessary(var, local, nullptr); if (dst == generator.ignoredResult()) - return 0; - return generator.moveToDestinationIfNeeded(dst, local.get()); + 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(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); + 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; + ASSERT(cooked()); + 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. + ASSERT(templateString->value()->cooked()); + 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. + ASSERT(templateString->value()->cooked()); + if (!templateString->value()->cooked()->isEmpty()) { + temporaryRegisters.append(generator.newTemporary()); + generator.emitNode(temporaryRegisters.last().get(), templateString->value()); + } + + if (temporaryRegisters.size() == 1) + return generator.emitToString(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get()); + + 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.emitCallInTailPosition(generator.finalDestination(dst, tag.get()), tag.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::Yes); } // ------------------------------ ArrayNode ------------------------------------ @@ -177,6 +379,21 @@ RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds if (!firstPutElement && !m_elision) return generator.emitNewArray(generator.finalDestination(dst), m_element, length); + if (firstPutElement && firstPutElement->value()->isSpreadExpression()) { + bool hasElision = false; + for (ElementNode* node = m_element; node; node = node->next()) { + if (!!node->elision()) { + hasElision = true; + break; + } + } + if (!!m_elision) + hasElision = true; + + if (!hasElision) + return generator.emitNewArrayWithSpread(generator.finalDestination(dst), m_element); + } + RefPtr array = generator.emitNewArray(generator.tempDestination(dst), m_element, length); ElementNode* n = firstPutElement; for (; n; n = n->next()) { @@ -227,11 +444,13 @@ bool ArrayNode::isSimpleArray() const for (ElementNode* ptr = m_element; ptr; ptr = ptr->next()) { if (ptr->elision()) return false; + if (ptr->value()->isSpreadExpression()) + return false; } 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; @@ -240,12 +459,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; } @@ -254,49 +473,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().builtinNames().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. @@ -304,20 +533,41 @@ 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)); + 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; } - 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::Getter) + generator.emitPutGetterById(dst, *node->name(), attributes, value.get()); + else + generator.emitPutSetterById(dst, *node->name(), attributes, value.get()); continue; } - - RegisterID* value = generator.emitNode(node->m_assign); - // 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; @@ -325,75 +575,142 @@ 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 || needsSuperBinding == pair.second->needsSuperBinding()); + if (needsSuperBinding && pair.second) + emitPutHomeObject(generator, secondReg, dst); + + generator.emitPutGetterSetter(dst, *node->name(), attributes, 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); + + if (node.isClassProperty()) { + ASSERT(node.needsSuperBinding()); + RefPtr propertyNameRegister; + if (node.name()) + propertyNameRegister = generator.emitLoad(nullptr, *node.name()); + else + propertyNameRegister = generator.emitNode(node.m_expression); + + generator.emitSetFunctionNameIfNeeded(node.m_assign, value.get(), propertyNameRegister.get()); + generator.emitCallDefineProperty(newObj, propertyNameRegister.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable, m_position); + return; + } + if (const auto* identifier = node.name()) { + std::optional optionalIndex = parseIndex(*identifier); + if (!optionalIndex) { + generator.emitDirectPutById(newObj, *identifier, value.get(), node.putType()); + return; + } + + RefPtr index = generator.emitLoad(nullptr, 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->isResolveNode() - && generator.willResolveToArguments(static_cast(m_base)->identifier()) - && !generator.symbolTable().slowArguments()) { + 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.emitExpressionInfo(divot(), divotStart(), divotEnd()); + generator.emitGetById(finalDest.get(), superBase.get(), thisValue.get(), id); + } else { + RefPtr subscript = generator.emitNode(m_subscript); + generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); + generator.emitGetByVal(finalDest.get(), superBase.get(), thisValue.get(), subscript.get()); + } + + 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); + generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); + 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); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property); + ret = generator.emitGetByVal(finalDest.get(), 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); + generator.emitProfileType(finalDest.get(), 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: - RegisterID* base = generator.emitNode(m_base); + bool baseIsSuper = m_base->isSuperNode(); + RefPtr base = baseIsSuper ? emitSuperBaseForCallee(generator) : generator.emitNode(m_base); generator.emitExpressionInfo(divot(), divotStart(), divotEnd()); - return generator.emitGetById(generator.finalDestination(dst), base, m_ident); + 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 ----------------------------- @@ -416,6 +733,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()); } @@ -423,9 +741,6 @@ CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argume : 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) @@ -437,6 +752,12 @@ CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argume 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 ((CallFrame::headerSizeInRegisters + m_argv.size()) % stackAlignmentRegisters()) { + m_argv.insert(0, generator.newTemporary()); + m_padding++; + } while (stackOffset() % stackAlignmentRegisters()) { m_argv.insert(0, generator.newTemporary()); @@ -448,31 +769,81 @@ 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()); + // 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::Extends && generator.needsToUpdateArrowFunctionContext() && generator.isThisUsedInInnerArrowFunction()) + generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); + + Variable var = generator.variable(generator.propertyNames().eval); + if (RegisterID* local = var.local()) { + generator.emitTDZCheckIfNecessary(var, local, nullptr); + 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()); + return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::No); } RefPtr func = generator.newTemporary(); 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); - return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd()); + generator.moveToDestinationIfNeeded( + callArguments.thisRegister(), + generator.emitResolveScope(callArguments.thisRegister(), var)); + generator.emitGetFromScope(func.get(), callArguments.thisRegister(), var, ThrowIfNotFound); + generator.emitTDZCheckIfNecessary(var, func.get(), nullptr); + return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), callArguments, divot(), divotStart(), divotEnd(), DebuggableCall::No); } // ------------------------------ 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::Extends || 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::Extends; + bool doWeUseArrowFunctionInConstructor = isConstructorKindDerived && generator.needsToUpdateArrowFunctionContext(); + + if (generator.isDerivedConstructorContext() || (doWeUseArrowFunctionInConstructor && generator.isSuperCallUsedInInnerArrowFunction())) + generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); + + Ref