From e15dd966d523731101f70ccf768bba12435a0208 Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Thu, 15 Oct 2015 09:45:50 +0000 Subject: webkitgtk-2.10.2 --- .../bytecompiler/BytecodeGenerator.cpp | 3544 ++++++++++++++++++++ 1 file changed, 3544 insertions(+) create mode 100644 Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (limited to 'Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp') diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp new file mode 100644 index 000000000..60e060553 --- /dev/null +++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -0,0 +1,3544 @@ +/* + * Copyright (C) 2008, 2009, 2012-2015 Apple Inc. All rights reserved. + * Copyright (C) 2008 Cameron Zwarich + * Copyright (C) 2012 Igalia, S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "BytecodeGenerator.h" + +#include "BuiltinExecutables.h" +#include "Interpreter.h" +#include "JSFunction.h" +#include "JSLexicalEnvironment.h" +#include "JSTemplateRegistryKey.h" +#include "LowLevelInterpreter.h" +#include "JSCInlines.h" +#include "Options.h" +#include "StackAlignment.h" +#include "StrongInlines.h" +#include "UnlinkedCodeBlock.h" +#include "UnlinkedInstructionStream.h" +#include +#include + +using namespace std; + +namespace JSC { + +void Label::setLocation(unsigned location) +{ + m_location = location; + + unsigned size = m_unresolvedJumps.size(); + for (unsigned i = 0; i < size; ++i) + m_generator.instructions()[m_unresolvedJumps[i].second].u.operand = m_location - m_unresolvedJumps[i].first; +} + +ParserError BytecodeGenerator::generate() +{ + SamplingRegion samplingRegion("Bytecode Generation"); + + m_codeBlock->setThisRegister(m_thisRegister.virtualRegister()); + + // If we have declared a variable named "arguments" and we are using arguments then we should + // perform that assignment now. + if (m_needToInitializeArguments) + initializeVariable(variable(propertyNames().arguments), m_argumentsRegister); + + pushLexicalScope(m_scopeNode, true); + + { + RefPtr temp = newTemporary(); + RefPtr globalScope = m_topMostScope; + for (auto functionPair : m_functionsToInitialize) { + FunctionMetadataNode* metadata = functionPair.first; + FunctionVariableType functionType = functionPair.second; + emitNewFunction(temp.get(), metadata); + if (functionType == NormalFunctionVariable) + initializeVariable(variable(metadata->ident()) , temp.get()); + else if (functionType == GlobalFunctionVariable) + emitPutToScope(globalScope.get(), Variable(metadata->ident()), temp.get(), ThrowIfNotFound); + else + RELEASE_ASSERT_NOT_REACHED(); + } + } + + bool callingClassConstructor = constructorKind() != ConstructorKind::None && !isConstructor(); + if (!callingClassConstructor) + m_scopeNode->emitBytecode(*this); + + m_staticPropertyAnalyzer.kill(); + + for (unsigned i = 0; i < m_tryRanges.size(); ++i) { + TryRange& range = m_tryRanges[i]; + int start = range.start->bind(); + int end = range.end->bind(); + + // This will happen for empty try blocks and for some cases of finally blocks: + // + // try { + // try { + // } finally { + // return 42; + // // *HERE* + // } + // } finally { + // print("things"); + // } + // + // The return will pop scopes to execute the outer finally block. But this includes + // popping the try context for the inner try. The try context is live in the fall-through + // part of the finally block not because we will emit a handler that overlaps the finally, + // but because we haven't yet had a chance to plant the catch target. Then when we finish + // emitting code for the outer finally block, we repush the try contex, this time with a + // new start index. But that means that the start index for the try range corresponding + // to the inner-finally-following-the-return (marked as "*HERE*" above) will be greater + // than the end index of the try block. This is harmless since end < start handlers will + // never get matched in our logic, but we do the runtime a favor and choose to not emit + // such handlers at all. + if (end <= start) + continue; + + ASSERT(range.tryData->handlerType != HandlerType::Illegal); + UnlinkedHandlerInfo info(static_cast(start), static_cast(end), + static_cast(range.tryData->target->bind()), range.tryData->handlerType); + m_codeBlock->addExceptionHandler(info); + } + + m_codeBlock->setInstructions(std::make_unique(m_instructions)); + + m_codeBlock->shrinkToFit(); + + if (m_expressionTooDeep) + return ParserError(ParserError::OutOfMemory); + return ParserError(ParserError::ErrorNone); +} + +BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode, const VariableEnvironment* parentScopeTDZVariables) + : m_shouldEmitDebugHooks(Options::forceDebuggerBytecodeGeneration() || debuggerMode == DebuggerOn) + , m_shouldEmitProfileHooks(Options::forceProfilerBytecodeGeneration() || profilerMode == ProfilerOn) + , m_scopeNode(programNode) + , m_codeBlock(vm, codeBlock) + , m_thisRegister(CallFrame::thisArgumentOffset()) + , m_codeType(GlobalCode) + , m_vm(&vm) +{ + ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables->size()); + + for (auto& constantRegister : m_linkTimeConstantRegisters) + constantRegister = nullptr; + + m_codeBlock->setNumParameters(1); // Allocate space for "this" + + emitOpcode(op_enter); + + allocateAndEmitScope(); + + const FunctionStack& functionStack = programNode->functionStack(); + + for (size_t i = 0; i < functionStack.size(); ++i) { + FunctionMetadataNode* function = functionStack[i]; + m_functionsToInitialize.append(std::make_pair(function, GlobalFunctionVariable)); + } + if (Options::validateBytecode()) { + for (auto& entry : programNode->varDeclarations()) + RELEASE_ASSERT(entry.value.isVar()); + } + codeBlock->setVariableDeclarations(programNode->varDeclarations()); +} + +BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode, const VariableEnvironment* parentScopeTDZVariables) + : m_shouldEmitDebugHooks(Options::forceDebuggerBytecodeGeneration() || debuggerMode == DebuggerOn) + , m_shouldEmitProfileHooks(Options::forceProfilerBytecodeGeneration() || profilerMode == ProfilerOn) + , m_scopeNode(functionNode) + , m_codeBlock(vm, codeBlock) + , m_codeType(FunctionCode) + , m_vm(&vm) + , m_isBuiltinFunction(codeBlock->isBuiltinFunction()) + , m_usesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode()) +{ + for (auto& constantRegister : m_linkTimeConstantRegisters) + constantRegister = nullptr; + + if (m_isBuiltinFunction) + m_shouldEmitDebugHooks = false; + + SymbolTable* functionSymbolTable = SymbolTable::create(*m_vm); + functionSymbolTable->setUsesNonStrictEval(m_usesNonStrictEval); + int symbolTableConstantIndex = addConstantValue(functionSymbolTable)->index(); + + Vector boundParameterProperties; + FunctionParameters& parameters = *functionNode->parameters(); + if (!parameters.hasDefaultParameterValues()) { + // If we do have default parameters, they will be allocated in a separate scope. + for (size_t i = 0; i < parameters.size(); i++) { + auto pattern = parameters.at(i).first; + if (pattern->isBindingNode()) + continue; + pattern->collectBoundIdentifiers(boundParameterProperties); + } + } + + bool shouldCaptureSomeOfTheThings = m_shouldEmitDebugHooks || m_codeBlock->needsFullScopeChain(); + bool shouldCaptureAllOfTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval(); + bool needsArguments = functionNode->usesArguments() || codeBlock->usesEval(); + if (shouldCaptureAllOfTheThings) + functionNode->varDeclarations().markAllVariablesAsCaptured(); + + auto captures = [&] (UniquedStringImpl* uid) -> bool { + if (!shouldCaptureSomeOfTheThings) + return false; + if (needsArguments && uid == propertyNames().arguments.impl()) { + // Actually, we only need to capture the arguments object when we "need full activation" + // because of name scopes. But historically we did it this way, so for now we just preserve + // the old behavior. + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=143072 + return true; + } + return functionNode->captures(uid); + }; + auto varKind = [&] (UniquedStringImpl* uid) -> VarKind { + return captures(uid) ? VarKind::Scope : VarKind::Stack; + }; + + emitOpcode(op_enter); + + allocateAndEmitScope(); + + m_calleeRegister.setIndex(JSStack::Callee); + + if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode()) + && functionNameScopeIsDynamic(codeBlock->usesEval(), codeBlock->isStrictMode())) { + emitPushFunctionNameScope(functionNode->ident(), &m_calleeRegister); + } + + if (shouldCaptureSomeOfTheThings) { + m_lexicalEnvironmentRegister = addVar(); + // We can allocate the "var" environment if we don't have default parameter expressions. If we have + // default parameter expressions, we have to hold off on allocating the "var" environment because + // the parent scope of the "var" environment is the parameter environment. + if (!parameters.hasDefaultParameterValues()) + initializeVarLexicalEnvironment(symbolTableConstantIndex); + } + + // Make sure the code block knows about all of our parameters, and make sure that parameters + // needing destructuring are noted. + m_parameters.grow(parameters.size() + 1); // reserve space for "this" + m_thisRegister.setIndex(initializeNextParameter()->index()); // this + for (unsigned i = 0; i < parameters.size(); ++i) + initializeNextParameter(); + + // Figure out some interesting facts about our arguments. + bool capturesAnyArgumentByName = false; + if (functionNode->hasCapturedVariables()) { + FunctionParameters& parameters = *functionNode->parameters(); + for (size_t i = 0; i < parameters.size(); ++i) { + auto pattern = parameters.at(i).first; + if (!pattern->isBindingNode()) + continue; + const Identifier& ident = static_cast(pattern)->boundProperty(); + capturesAnyArgumentByName |= captures(ident.impl()); + } + } + + if (capturesAnyArgumentByName) + ASSERT(m_lexicalEnvironmentRegister); + + // Need to know what our functions are called. Parameters have some goofy behaviors when it + // comes to functions of the same name. + for (FunctionMetadataNode* function : functionNode->functionStack()) + m_functions.add(function->ident().impl()); + + if (needsArguments) { + // Create the arguments object now. We may put the arguments object into the activation if + // it is captured. Either way, we create two arguments object variables: one is our + // private variable that is immutable, and another that is the user-visible variable. The + // immutable one is only used here, or during formal parameter resolutions if we opt for + // DirectArguments. + + m_argumentsRegister = addVar(); + m_argumentsRegister->ref(); + } + + if (needsArguments && !codeBlock->isStrictMode() && !parameters.hasDefaultParameterValues()) { + // If we captured any formal parameter by name, then we use ScopedArguments. Otherwise we + // use DirectArguments. With ScopedArguments, we lift all of our arguments into the + // activation. + + if (capturesAnyArgumentByName) { + functionSymbolTable->setArgumentsLength(vm, parameters.size()); + + // For each parameter, we have two possibilities: + // Either it's a binding node with no function overlap, in which case it gets a name + // in the symbol table - or it just gets space reserved in the symbol table. Either + // way we lift the value into the scope. + for (unsigned i = 0; i < parameters.size(); ++i) { + ScopeOffset offset = functionSymbolTable->takeNextScopeOffset(); + functionSymbolTable->setArgumentOffset(vm, i, offset); + if (UniquedStringImpl* name = visibleNameForParameter(parameters.at(i).first)) { + VarOffset varOffset(offset); + SymbolTableEntry entry(varOffset); + // Stores to these variables via the ScopedArguments object will not do + // notifyWrite(), since that would be cumbersome. Also, watching formal + // parameters when "arguments" is in play is unlikely to be super profitable. + // So, we just disable it. + entry.disableWatching(); + functionSymbolTable->set(name, entry); + } + emitOpcode(op_put_to_scope); + instructions().append(m_lexicalEnvironmentRegister->index()); + instructions().append(UINT_MAX); + instructions().append(virtualRegisterForArgument(1 + i).offset()); + instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand()); + instructions().append(symbolTableConstantIndex); + instructions().append(offset.offset()); + } + + // This creates a scoped arguments object and copies the overflow arguments into the + // scope. It's the equivalent of calling ScopedArguments::createByCopying(). + emitOpcode(op_create_scoped_arguments); + instructions().append(m_argumentsRegister->index()); + instructions().append(m_lexicalEnvironmentRegister->index()); + } else { + // We're going to put all parameters into the DirectArguments object. First ensure + // that the symbol table knows that this is happening. + for (unsigned i = 0; i < parameters.size(); ++i) { + if (UniquedStringImpl* name = visibleNameForParameter(parameters.at(i).first)) + functionSymbolTable->set(name, SymbolTableEntry(VarOffset(DirectArgumentsOffset(i)))); + } + + emitOpcode(op_create_direct_arguments); + instructions().append(m_argumentsRegister->index()); + } + } else if (!parameters.hasDefaultParameterValues()) { + // Create the formal parameters the normal way. Any of them could be captured, or not. If + // captured, lift them into the scope. We can not do this if we have default parameter expressions + // because when default parameter expressions exist, they belong in their own lexical environment + // separate from the "var" lexical environment. + for (unsigned i = 0; i < parameters.size(); ++i) { + UniquedStringImpl* name = visibleNameForParameter(parameters.at(i).first); + if (!name) + continue; + + if (!captures(name)) { + // This is the easy case - just tell the symbol table about the argument. It will + // be accessed directly. + functionSymbolTable->set(name, SymbolTableEntry(VarOffset(virtualRegisterForArgument(1 + i)))); + continue; + } + + ScopeOffset offset = functionSymbolTable->takeNextScopeOffset(); + const Identifier& ident = + static_cast(parameters.at(i).first)->boundProperty(); + functionSymbolTable->set(name, SymbolTableEntry(VarOffset(offset))); + + emitOpcode(op_put_to_scope); + instructions().append(m_lexicalEnvironmentRegister->index()); + instructions().append(addConstant(ident)); + instructions().append(virtualRegisterForArgument(1 + i).offset()); + instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand()); + instructions().append(symbolTableConstantIndex); + instructions().append(offset.offset()); + } + } + + if (needsArguments && (codeBlock->isStrictMode() || parameters.hasDefaultParameterValues())) { + // Allocate an out-of-bands arguments object. + emitOpcode(op_create_out_of_band_arguments); + instructions().append(m_argumentsRegister->index()); + } + + // Now declare all variables. + for (const Identifier& ident : boundParameterProperties) { + ASSERT(!parameters.hasDefaultParameterValues()); + createVariable(ident, varKind(ident.impl()), functionSymbolTable); + } + for (FunctionMetadataNode* function : functionNode->functionStack()) { + const Identifier& ident = function->ident(); + createVariable(ident, varKind(ident.impl()), functionSymbolTable); + m_functionsToInitialize.append(std::make_pair(function, NormalFunctionVariable)); + } + for (auto& entry : functionNode->varDeclarations()) { + ASSERT(!entry.value.isLet() && !entry.value.isConst()); + if (!entry.value.isVar()) // This is either a parameter or callee. + continue; + // Variables named "arguments" are never const. + createVariable(Identifier::fromUid(m_vm, entry.key.get()), varKind(entry.key.get()), functionSymbolTable, IgnoreExisting); + } + + // There are some variables that need to be preinitialized to something other than Undefined: + // + // - "arguments": unless it's used as a function or parameter, this should refer to the + // arguments object. + // + // - callee: unless it's used as a var, function, or parameter, this should refer to the + // callee (i.e. our function). + // + // - functions: these always override everything else. + // + // The most logical way to do all of this is to initialize none of the variables until now, + // and then initialize them in BytecodeGenerator::generate() in such an order that the rules + // for how these things override each other end up holding. We would initialize the callee + // first, then "arguments", then all arguments, then the functions. + // + // But some arguments are already initialized by default, since if they aren't captured and we + // don't have "arguments" then we just point the symbol table at the stack slot of those + // arguments. We end up initializing the rest of the arguments that have an uncomplicated + // binding (i.e. don't involve destructuring) above when figuring out how to lay them out, + // because that's just the simplest thing. This means that when we initialize them, we have to + // watch out for the things that override arguments (namely, functions). + // + // We also initialize callee here as well, just because it's so weird. We know whether we want + // to do this because we can just check if it's in the symbol table. + if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode()) + && !functionNameScopeIsDynamic(codeBlock->usesEval(), codeBlock->isStrictMode()) + && functionSymbolTable->get(functionNode->ident().impl()).isNull()) { + if (captures(functionNode->ident().impl())) { + ScopeOffset offset; + { + ConcurrentJITLocker locker(functionSymbolTable->m_lock); + offset = functionSymbolTable->takeNextScopeOffset(locker); + functionSymbolTable->add( + locker, functionNode->ident().impl(), + SymbolTableEntry(VarOffset(offset), ReadOnly)); + } + + emitOpcode(op_put_to_scope); + instructions().append(m_lexicalEnvironmentRegister->index()); + instructions().append(addConstant(functionNode->ident())); + instructions().append(m_calleeRegister.index()); + instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand()); + instructions().append(symbolTableConstantIndex); + instructions().append(offset.offset()); + } else { + functionSymbolTable->add( + functionNode->ident().impl(), + SymbolTableEntry(VarOffset(m_calleeRegister.virtualRegister()), ReadOnly)); + } + } + + // This is our final act of weirdness. "arguments" is overridden by everything except the + // callee. We add it to the symbol table if it's not already there and it's not an argument. + if (needsArguments) { + // If "arguments" is overridden by a function or destructuring parameter name, then it's + // OK for us to call createVariable() because it won't change anything. It's also OK for + // us to them tell BytecodeGenerator::generate() to write to it because it will do so + // before it initializes functions and destructuring parameters. But if "arguments" is + // overridden by a "simple" function parameter, then we have to bail: createVariable() + // would assert and BytecodeGenerator::generate() would write the "arguments" after the + // argument value had already been properly initialized. + + bool haveParameterNamedArguments = false; + for (unsigned i = 0; i < parameters.size(); ++i) { + UniquedStringImpl* name = visibleNameForParameter(parameters.at(i).first); + if (name == propertyNames().arguments.impl()) { + haveParameterNamedArguments = true; + break; + } + } + + if (!haveParameterNamedArguments) { + createVariable( + propertyNames().arguments, varKind(propertyNames().arguments.impl()), functionSymbolTable); + m_needToInitializeArguments = true; + } + } + + m_newTargetRegister = addVar(); + if (isConstructor()) { + emitMove(m_newTargetRegister, &m_thisRegister); + if (constructorKind() == ConstructorKind::Derived) { + emitMoveEmptyValue(&m_thisRegister); + } else + emitCreateThis(&m_thisRegister); + } else if (constructorKind() != ConstructorKind::None) { + emitThrowTypeError("Cannot call a class constructor"); + } else if (functionNode->usesThis() || codeBlock->usesEval()) { + m_codeBlock->addPropertyAccessInstruction(instructions().size()); + emitOpcode(op_to_this); + instructions().append(kill(&m_thisRegister)); + instructions().append(0); + instructions().append(0); + } + + // All "addVar()"s needs to happen before "initializeDefaultParameterValuesAndSetupFunctionScopeStack()" is called + // because a function's default parameter ExpressionNodes will use temporary registers. + m_TDZStack.append(std::make_pair(*parentScopeTDZVariables, false)); + initializeDefaultParameterValuesAndSetupFunctionScopeStack(parameters, functionNode, functionSymbolTable, symbolTableConstantIndex, captures); +} + +BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode, const VariableEnvironment* parentScopeTDZVariables) + : m_shouldEmitDebugHooks(Options::forceDebuggerBytecodeGeneration() || debuggerMode == DebuggerOn) + , m_shouldEmitProfileHooks(Options::forceProfilerBytecodeGeneration() || profilerMode == ProfilerOn) + , m_scopeNode(evalNode) + , m_codeBlock(vm, codeBlock) + , m_thisRegister(CallFrame::thisArgumentOffset()) + , m_codeType(EvalCode) + , m_vm(&vm) + , m_usesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode()) +{ + for (auto& constantRegister : m_linkTimeConstantRegisters) + constantRegister = nullptr; + + m_codeBlock->setNumParameters(1); + + emitOpcode(op_enter); + + allocateAndEmitScope(); + + const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack(); + for (size_t i = 0; i < functionStack.size(); ++i) + m_codeBlock->addFunctionDecl(makeFunction(functionStack[i])); + + const VariableEnvironment& varDeclarations = evalNode->varDeclarations(); + unsigned numVariables = varDeclarations.size(); + Vector variables; + variables.reserveCapacity(numVariables); + for (auto& entry : varDeclarations) { + ASSERT(entry.value.isVar()); + ASSERT(entry.key->isAtomic() || entry.key->isSymbol()); + variables.append(Identifier::fromUid(m_vm, entry.key.get())); + } + codeBlock->adoptVariables(variables); + + m_TDZStack.append(std::make_pair(*parentScopeTDZVariables, false)); +} + +BytecodeGenerator::~BytecodeGenerator() +{ +} + +void BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack( + FunctionParameters& parameters, FunctionNode* functionNode, SymbolTable* functionSymbolTable, + int symbolTableConstantIndex, const std::function& captures) +{ + Vector>> valuesToMoveIntoVars; + if (parameters.hasDefaultParameterValues()) { + // Refer to the ES6 spec section 9.2.12: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-functiondeclarationinstantiation + // This implements step 21. + VariableEnvironment environment; + Vector allParameterNames; + for (unsigned i = 0; i < parameters.size(); i++) + parameters.at(i).first->collectBoundIdentifiers(allParameterNames); + IdentifierSet parameterSet; + for (auto& ident : allParameterNames) { + parameterSet.add(ident.impl()); + auto addResult = environment.add(ident); + addResult.iterator->value.setIsLet(); // When we have default parameter expressions, parameters act like "let" variables. + if (captures(ident.impl())) + addResult.iterator->value.setIsCaptured(); + } + + // This implements step 25 of section 9.2.12. + pushLexicalScopeInternal(environment, true, nullptr, TDZRequirement::UnderTDZ, ScopeType::LetConstScope, ScopeRegisterType::Block); + + RefPtr temp = newTemporary(); + for (unsigned i = 0; i < parameters.size(); i++) { + std::pair parameter = parameters.at(i); + RefPtr parameterValue = ®isterFor(virtualRegisterForArgument(1 + i)); + emitMove(temp.get(), parameterValue.get()); + if (parameter.second) { + RefPtr condition = emitIsUndefined(newTemporary(), parameterValue.get()); + RefPtr