Changeset 238989 in webkit


Ignore:
Timestamp:
Dec 7, 2018 4:25:46 PM (5 years ago)
Author:
Michael Catanzaro
Message:

Merge r236161 - Ensure that ForInContexts are invalidated if their loop local is over-written.
https://bugs.webkit.org/show_bug.cgi?id=189571
<rdar://problem/44402277>

Reviewed by Saam Barati.

JSTests:

  • stress/regress-189571.js: Added.

Source/JavaScriptCore:

Instead of hunting down every place in the BytecodeGenerator that potentially
needs to invalidate an enclosing ForInContext (if one exists), we simply iterate
the bytecode range of the loop body when the ForInContext is popped, and
invalidate the context if we ever find the loop temp variable over-written.

This has 2 benefits:

  1. It ensures that every type of opcode that can write to the loop temp will be handled appropriately, not just the op_mov that we've hunted down.
  2. It avoids us having to check the BytecodeGenerator's m_forInContextStack every time we emit an op_mov (or other opcodes that can write to a local) even when we're not inside a for-in loop.

JSC benchmarks show that that this change is performance neutral.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::pushIndexedForInScope):
(JSC::BytecodeGenerator::popIndexedForInScope):
(JSC::BytecodeGenerator::pushStructureForInScope):
(JSC::BytecodeGenerator::popStructureForInScope):
(JSC::ForInContext::finalize):
(JSC::StructureForInContext::finalize):
(JSC::IndexedForInContext::finalize):
(JSC::BytecodeGenerator::invalidateForInContextForLocal): Deleted.

  • bytecompiler/BytecodeGenerator.h:

(JSC::ForInContext::ForInContext):
(JSC::ForInContext::bodyBytecodeStartOffset const):
(JSC::StructureForInContext::StructureForInContext):
(JSC::IndexedForInContext::IndexedForInContext):

  • bytecompiler/NodesCodegen.cpp:

(JSC::PostfixNode::emitResolve):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::EmptyLetExpression::emitBytecode):
(JSC::ForInNode::emitLoopHeader):
(JSC::ForOfNode::emitBytecode):
(JSC::BindingNode::bindValue const):
(JSC::AssignmentElementNode::bindValue const):

  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

Location:
releases/WebKitGTK/webkit-2.22
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • releases/WebKitGTK/webkit-2.22/JSTests/ChangeLog

    r238986 r238989  
     12018-09-17  Mark Lam  <mark.lam@apple.com>
     2
     3        Ensure that ForInContexts are invalidated if their loop local is over-written.
     4        https://bugs.webkit.org/show_bug.cgi?id=189571
     5        <rdar://problem/44402277>
     6
     7        Reviewed by Saam Barati.
     8
     9        * stress/regress-189571.js: Added.
     10
    1112018-08-24  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
    212
  • releases/WebKitGTK/webkit-2.22/Source/JavaScriptCore/ChangeLog

    r238988 r238989  
     12018-09-18  Mark Lam  <mark.lam@apple.com>
     2
     3        Ensure that ForInContexts are invalidated if their loop local is over-written.
     4        https://bugs.webkit.org/show_bug.cgi?id=189571
     5        <rdar://problem/44402277>
     6
     7        Reviewed by Saam Barati.
     8
     9        Instead of hunting down every place in the BytecodeGenerator that potentially
     10        needs to invalidate an enclosing ForInContext (if one exists), we simply iterate
     11        the bytecode range of the loop body when the ForInContext is popped, and
     12        invalidate the context if we ever find the loop temp variable over-written.
     13
     14        This has 2 benefits:
     15        1. It ensures that every type of opcode that can write to the loop temp will be
     16           handled appropriately, not just the op_mov that we've hunted down.
     17        2. It avoids us having to check the BytecodeGenerator's m_forInContextStack
     18           every time we emit an op_mov (or other opcodes that can write to a local)
     19           even when we're not inside a for-in loop.
     20
     21        JSC benchmarks show that that this change is performance neutral.
     22
     23        * bytecompiler/BytecodeGenerator.cpp:
     24        (JSC::BytecodeGenerator::pushIndexedForInScope):
     25        (JSC::BytecodeGenerator::popIndexedForInScope):
     26        (JSC::BytecodeGenerator::pushStructureForInScope):
     27        (JSC::BytecodeGenerator::popStructureForInScope):
     28        (JSC::ForInContext::finalize):
     29        (JSC::StructureForInContext::finalize):
     30        (JSC::IndexedForInContext::finalize):
     31        (JSC::BytecodeGenerator::invalidateForInContextForLocal): Deleted.
     32        * bytecompiler/BytecodeGenerator.h:
     33        (JSC::ForInContext::ForInContext):
     34        (JSC::ForInContext::bodyBytecodeStartOffset const):
     35        (JSC::StructureForInContext::StructureForInContext):
     36        (JSC::IndexedForInContext::IndexedForInContext):
     37        * bytecompiler/NodesCodegen.cpp:
     38        (JSC::PostfixNode::emitResolve):
     39        (JSC::PrefixNode::emitResolve):
     40        (JSC::ReadModifyResolveNode::emitBytecode):
     41        (JSC::AssignResolveNode::emitBytecode):
     42        (JSC::EmptyLetExpression::emitBytecode):
     43        (JSC::ForInNode::emitLoopHeader):
     44        (JSC::ForOfNode::emitBytecode):
     45        (JSC::BindingNode::bindValue const):
     46        (JSC::AssignmentElementNode::bindValue const):
     47        * runtime/CommonSlowPaths.cpp:
     48        (JSC::SLOW_PATH_DECL):
     49
    1502018-09-14  Mark Lam  <mark.lam@apple.com>
    251
  • releases/WebKitGTK/webkit-2.22/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r238988 r238989  
    3737#include "BytecodeGeneratorification.h"
    3838#include "BytecodeLivenessAnalysis.h"
     39#include "BytecodeUseDef.h"
    3940#include "CatchScope.h"
    4041#include "DefinePropertyAttributes.h"
     
    46254626    if (!localRegister)
    46264627        return;
    4627     m_forInContextStack.append(adoptRef(*new IndexedForInContext(localRegister, indexRegister)));
     4628    unsigned bodyBytecodeStartOffset = instructions().size();
     4629    m_forInContextStack.append(adoptRef(*new IndexedForInContext(localRegister, indexRegister, bodyBytecodeStartOffset)));
    46284630}
    46294631
     
    46324634    if (!localRegister)
    46334635        return;
    4634     m_forInContextStack.last()->asIndexedForInContext().finalize(*this);
     4636    unsigned bodyBytecodeEndOffset = instructions().size();
     4637    m_forInContextStack.last()->asIndexedForInContext().finalize(*this, m_codeBlock.get(), bodyBytecodeEndOffset);
    46354638    m_forInContextStack.removeLast();
    46364639}
     
    47354738    if (!localRegister)
    47364739        return;
    4737     m_forInContextStack.append(adoptRef(*new StructureForInContext(localRegister, indexRegister, propertyRegister, enumeratorRegister)));
     4740    unsigned bodyBytecodeStartOffset = instructions().size();
     4741    m_forInContextStack.append(adoptRef(*new StructureForInContext(localRegister, indexRegister, propertyRegister, enumeratorRegister, bodyBytecodeStartOffset)));
    47384742}
    47394743
     
    47424746    if (!localRegister)
    47434747        return;
    4744     m_forInContextStack.last()->asStructureForInContext().finalize(*this);
     4748    unsigned bodyBytecodeEndOffset = instructions().size();
     4749    m_forInContextStack.last()->asStructureForInContext().finalize(*this, m_codeBlock.get(), bodyBytecodeEndOffset);
    47454750    m_forInContextStack.removeLast();
    47464751}
    47474752
    4748 void BytecodeGenerator::invalidateForInContextForLocal(RegisterID* localRegister)
     4753RegisterID* BytecodeGenerator::emitRestParameter(RegisterID* result, unsigned numParametersToSkip)
     4754{
     4755    RefPtr<RegisterID> restArrayLength = newTemporary();
     4756    emitOpcode(op_get_rest_length);
     4757    instructions().append(restArrayLength->index());
     4758    instructions().append(numParametersToSkip);
     4759
     4760    emitOpcode(op_create_rest);
     4761    instructions().append(result->index());
     4762    instructions().append(restArrayLength->index());
     4763    instructions().append(numParametersToSkip);
     4764
     4765    return result;
     4766}
     4767
     4768void BytecodeGenerator::emitRequireObjectCoercible(RegisterID* value, const String& error)
     4769{
     4770    // FIXME: op_jneq_null treats "undetectable" objects as null/undefined. RequireObjectCoercible
     4771    // thus incorrectly throws a TypeError for interfaces like HTMLAllCollection.
     4772    Ref<Label> target = newLabel();
     4773    size_t begin = instructions().size();
     4774    emitOpcode(op_jneq_null);
     4775    instructions().append(value->index());
     4776    instructions().append(target->bind(begin, instructions().size()));
     4777    emitThrowTypeError(error);
     4778    emitLabel(target.get());
     4779}
     4780
     4781void BytecodeGenerator::emitYieldPoint(RegisterID* argument, JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason result)
     4782{
     4783    Ref<Label> mergePoint = newLabel();
     4784    unsigned yieldPointIndex = m_yieldPoints++;
     4785    emitGeneratorStateChange(yieldPointIndex + 1);
     4786
     4787    if (parseMode() == SourceParseMode::AsyncGeneratorBodyMode) {
     4788        int suspendReason = static_cast<int32_t>(result);
     4789        emitPutById(generatorRegister(), propertyNames().builtinNames().asyncGeneratorSuspendReasonPrivateName(), emitLoad(nullptr, jsNumber(suspendReason)));
     4790    }
     4791
     4792    // Split the try range here.
     4793    Ref<Label> savePoint = newEmittedLabel();
     4794    for (unsigned i = m_tryContextStack.size(); i--;) {
     4795        TryContext& context = m_tryContextStack[i];
     4796        m_tryRanges.append(TryRange {
     4797            context.start.copyRef(),
     4798            savePoint.copyRef(),
     4799            context.tryData
     4800        });
     4801        // Try range will be restared at the merge point.
     4802        context.start = mergePoint.get();
     4803    }
     4804    Vector<TryContext> savedTryContextStack;
     4805    m_tryContextStack.swap(savedTryContextStack);
     4806
     4807    emitOpcode(op_yield);
     4808    instructions().append(generatorFrameRegister()->index());
     4809    instructions().append(yieldPointIndex);
     4810    instructions().append(argument->index());
     4811
     4812    // Restore the try contexts, which start offset is updated to the merge point.
     4813    m_tryContextStack.swap(savedTryContextStack);
     4814    emitLabel(mergePoint.get());
     4815}
     4816
     4817RegisterID* BytecodeGenerator::emitYield(RegisterID* argument, JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason result)
     4818{
     4819    emitYieldPoint(argument, result);
     4820
     4821    Ref<Label> normalLabel = newLabel();
     4822    RefPtr<RegisterID> condition = newTemporary();
     4823    emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))));
     4824    emitJumpIfTrue(condition.get(), normalLabel.get());
     4825
     4826    Ref<Label> throwLabel = newLabel();
     4827    emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode))));
     4828    emitJumpIfTrue(condition.get(), throwLabel.get());
     4829    // Return.
     4830    {
     4831        RefPtr<RegisterID> returnRegister = generatorValueRegister();
     4832        bool hasFinally = emitReturnViaFinallyIfNeeded(returnRegister.get());
     4833        if (!hasFinally)
     4834            emitReturn(returnRegister.get());
     4835    }
     4836
     4837    // Throw.
     4838    emitLabel(throwLabel.get());
     4839    emitThrow(generatorValueRegister());
     4840
     4841    // Normal.
     4842    emitLabel(normalLabel.get());
     4843    return generatorValueRegister();
     4844}
     4845
     4846RegisterID* BytecodeGenerator::emitCallIterator(RegisterID* iterator, RegisterID* argument, ThrowableExpressionData* node)
     4847{
     4848    CallArguments args(*this, nullptr);
     4849    move(args.thisRegister(), argument);
     4850    emitCall(iterator, iterator, NoExpectedFunction, args, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
     4851
     4852    return iterator;
     4853}
     4854
     4855void BytecodeGenerator::emitAwait(RegisterID* value)
     4856{
     4857    emitYield(value, JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason::Await);
     4858    move(value, generatorValueRegister());
     4859}
     4860
     4861RegisterID* BytecodeGenerator::emitGetIterator(RegisterID* argument, ThrowableExpressionData* node)
     4862{
     4863    RefPtr<RegisterID> iterator = emitGetById(newTemporary(), argument, propertyNames().iteratorSymbol);
     4864    emitCallIterator(iterator.get(), argument, node);
     4865
     4866    return iterator.get();
     4867}
     4868
     4869RegisterID* BytecodeGenerator::emitGetAsyncIterator(RegisterID* argument, ThrowableExpressionData* node)
     4870{
     4871    RefPtr<RegisterID> iterator = emitGetById(newTemporary(), argument, propertyNames().asyncIteratorSymbol);
     4872    Ref<Label> asyncIteratorNotFound = newLabel();
     4873    Ref<Label> asyncIteratorFound = newLabel();
     4874    Ref<Label> iteratorReceived = newLabel();
     4875
     4876    emitJumpIfTrue(emitUnaryOp(op_eq_null, newTemporary(), iterator.get()), asyncIteratorNotFound.get());
     4877
     4878    emitJump(asyncIteratorFound.get());
     4879    emitLabel(asyncIteratorNotFound.get());
     4880
     4881    RefPtr<RegisterID> commonIterator = emitGetIterator(argument, node);
     4882    move(iterator.get(), commonIterator.get());
     4883
     4884    RefPtr<RegisterID> nextMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().next);
     4885
     4886    auto varCreateAsyncFromSyncIterator = variable(propertyNames().builtinNames().createAsyncFromSyncIteratorPrivateName());
     4887    RefPtr<RegisterID> scope = newTemporary();
     4888    move(scope.get(), emitResolveScope(scope.get(), varCreateAsyncFromSyncIterator));
     4889    RefPtr<RegisterID> createAsyncFromSyncIterator = emitGetFromScope(newTemporary(), scope.get(), varCreateAsyncFromSyncIterator, ThrowIfNotFound);
     4890
     4891    CallArguments args(*this, nullptr, 2);
     4892    emitLoad(args.thisRegister(), jsUndefined());
     4893
     4894    move(args.argumentRegister(0), iterator.get());
     4895    move(args.argumentRegister(1), nextMethod.get());
     4896
     4897    JSTextPosition divot(m_scopeNode->firstLine(), m_scopeNode->startOffset(), m_scopeNode->lineStartOffset());
     4898    emitCall(iterator.get(), createAsyncFromSyncIterator.get(), NoExpectedFunction, args, divot, divot, divot, DebuggableCall::No);
     4899
     4900    emitJump(iteratorReceived.get());
     4901
     4902    emitLabel(asyncIteratorFound.get());
     4903    emitCallIterator(iterator.get(), argument, node);
     4904    emitLabel(iteratorReceived.get());
     4905
     4906    return iterator.get();
     4907}
     4908
     4909RegisterID* BytecodeGenerator::emitDelegateYield(RegisterID* argument, ThrowableExpressionData* node)
     4910{
     4911    RefPtr<RegisterID> value = newTemporary();
     4912    {
     4913        RefPtr<RegisterID> iterator = parseMode() == SourceParseMode::AsyncGeneratorBodyMode ? emitGetAsyncIterator(argument, node) : emitGetIterator(argument, node);
     4914        RefPtr<RegisterID> nextMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().next);
     4915
     4916        Ref<Label> loopDone = newLabel();
     4917        {
     4918            Ref<Label> nextElement = newLabel();
     4919            emitLoad(value.get(), jsUndefined());
     4920
     4921            emitJump(nextElement.get());
     4922
     4923            Ref<Label> loopStart = newLabel();
     4924            emitLabel(loopStart.get());
     4925            emitLoopHint();
     4926
     4927            Ref<Label> branchOnResult = newLabel();
     4928            {
     4929                emitYieldPoint(value.get(), JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason::Yield);
     4930
     4931                Ref<Label> normalLabel = newLabel();
     4932                Ref<Label> returnLabel = newLabel();
     4933                {
     4934                    RefPtr<RegisterID> condition = newTemporary();
     4935                    emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))));
     4936                    emitJumpIfTrue(condition.get(), normalLabel.get());
     4937
     4938                    emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ReturnMode))));
     4939                    emitJumpIfTrue(condition.get(), returnLabel.get());
     4940
     4941                    // Fallthrough to ThrowMode.
     4942                }
     4943
     4944                // Throw.
     4945                {
     4946                    Ref<Label> throwMethodFound = newLabel();
     4947                    RefPtr<RegisterID> throwMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().throwKeyword);
     4948                    emitJumpIfFalse(emitIsUndefined(newTemporary(), throwMethod.get()), throwMethodFound.get());
     4949
     4950                    EmitAwait emitAwaitInIteratorClose = parseMode() == SourceParseMode::AsyncGeneratorBodyMode ? EmitAwait::Yes : EmitAwait::No;
     4951                    emitIteratorClose(iterator.get(), node, emitAwaitInIteratorClose);
     4952
     4953                    emitThrowTypeError("Delegated generator does not have a 'throw' method."_s);
     4954
     4955                    emitLabel(throwMethodFound.get());
     4956                    CallArguments throwArguments(*this, nullptr, 1);
     4957                    move(throwArguments.thisRegister(), iterator.get());
     4958                    move(throwArguments.argumentRegister(0), generatorValueRegister());
     4959                    emitCall(value.get(), throwMethod.get(), NoExpectedFunction, throwArguments, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
     4960
     4961                    emitJump(branchOnResult.get());
     4962                }
     4963
     4964                // Return.
     4965                emitLabel(returnLabel.get());
     4966                {
     4967                    Ref<Label> returnMethodFound = newLabel();
     4968                    RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword);
     4969                    emitJumpIfFalse(emitIsUndefined(newTemporary(), returnMethod.get()), returnMethodFound.get());
     4970
     4971                    move(value.get(), generatorValueRegister());
     4972
     4973                    Ref<Label> returnSequence = newLabel();
     4974                    emitJump(returnSequence.get());
     4975
     4976                    emitLabel(returnMethodFound.get());
     4977                    CallArguments returnArguments(*this, nullptr, 1);
     4978                    move(returnArguments.thisRegister(), iterator.get());
     4979                    move(returnArguments.argumentRegister(0), generatorValueRegister());
     4980                    emitCall(value.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
     4981
     4982                    if (parseMode() == SourceParseMode::AsyncGeneratorBodyMode)
     4983                        emitAwait(value.get());
     4984
     4985                    Ref<Label> returnIteratorResultIsObject = newLabel();
     4986                    emitJumpIfTrue(emitIsObject(newTemporary(), value.get()), returnIteratorResultIsObject.get());
     4987                    emitThrowTypeError("Iterator result interface is not an object."_s);
     4988
     4989                    emitLabel(returnIteratorResultIsObject.get());
     4990
     4991                    Ref<Label> returnFromGenerator = newLabel();
     4992                    emitJumpIfTrue(emitGetById(newTemporary(), value.get(), propertyNames().done), returnFromGenerator.get());
     4993
     4994                    emitGetById(value.get(), value.get(), propertyNames().value);
     4995                    emitJump(loopStart.get());
     4996
     4997                    emitLabel(returnFromGenerator.get());
     4998                    emitGetById(value.get(), value.get(), propertyNames().value);
     4999
     5000                    emitLabel(returnSequence.get());
     5001                    bool hasFinally = emitReturnViaFinallyIfNeeded(value.get());
     5002                    if (!hasFinally)
     5003                        emitReturn(value.get());
     5004                }
     5005
     5006                // Normal.
     5007                emitLabel(normalLabel.get());
     5008                move(value.get(), generatorValueRegister());
     5009            }
     5010
     5011            emitLabel(nextElement.get());
     5012            emitIteratorNextWithValue(value.get(), nextMethod.get(), iterator.get(), value.get(), node);
     5013
     5014            emitLabel(branchOnResult.get());
     5015
     5016            if (parseMode() == SourceParseMode::AsyncGeneratorBodyMode)
     5017                emitAwait(value.get());
     5018
     5019            Ref<Label> iteratorValueIsObject = newLabel();
     5020            emitJumpIfTrue(emitIsObject(newTemporary(), value.get()), iteratorValueIsObject.get());
     5021            emitThrowTypeError("Iterator result interface is not an object."_s);
     5022            emitLabel(iteratorValueIsObject.get());
     5023
     5024            emitJumpIfTrue(emitGetById(newTemporary(), value.get(), propertyNames().done), loopDone.get());
     5025            emitGetById(value.get(), value.get(), propertyNames().value);
     5026
     5027            emitJump(loopStart.get());
     5028        }
     5029        emitLabel(loopDone.get());
     5030    }
     5031
     5032    emitGetById(value.get(), value.get(), propertyNames().value);
     5033    return value.get();
     5034}
     5035
     5036
     5037void BytecodeGenerator::emitGeneratorStateChange(int32_t state)
     5038{
     5039    RegisterID* completedState = emitLoad(nullptr, jsNumber(state));
     5040    emitPutById(generatorRegister(), propertyNames().builtinNames().generatorStatePrivateName(), completedState);
     5041}
     5042
     5043bool BytecodeGenerator::emitJumpViaFinallyIfNeeded(int targetLabelScopeDepth, Label& jumpTarget)
     5044{
     5045    ASSERT(labelScopeDepth() - targetLabelScopeDepth >= 0);
     5046    size_t numberOfScopesToCheckForFinally = labelScopeDepth() - targetLabelScopeDepth;
     5047    ASSERT(numberOfScopesToCheckForFinally <= m_controlFlowScopeStack.size());
     5048    if (!numberOfScopesToCheckForFinally)
     5049        return false;
     5050
     5051    FinallyContext* innermostFinallyContext = nullptr;
     5052    FinallyContext* outermostFinallyContext = nullptr;
     5053    size_t scopeIndex = m_controlFlowScopeStack.size() - 1;
     5054    while (numberOfScopesToCheckForFinally--) {
     5055        ControlFlowScope* scope = &m_controlFlowScopeStack[scopeIndex--];
     5056        if (scope->isFinallyScope()) {
     5057            FinallyContext* finallyContext = &scope->finallyContext;
     5058            if (!innermostFinallyContext)
     5059                innermostFinallyContext = finallyContext;
     5060            outermostFinallyContext = finallyContext;
     5061            finallyContext->incNumberOfBreaksOrContinues();
     5062        }
     5063    }
     5064    if (!outermostFinallyContext)
     5065        return false; // No finallys to thread through.
     5066
     5067    auto jumpID = bytecodeOffsetToJumpID(instructions().size());
     5068    int lexicalScopeIndex = labelScopeDepthToLexicalScopeIndex(targetLabelScopeDepth);
     5069    outermostFinallyContext->registerJump(jumpID, lexicalScopeIndex, jumpTarget);
     5070
     5071    emitSetCompletionType(jumpID);
     5072    emitJump(*innermostFinallyContext->finallyLabel());
     5073    return true; // We'll be jumping to a finally block.
     5074}
     5075
     5076bool BytecodeGenerator::emitReturnViaFinallyIfNeeded(RegisterID* returnRegister)
     5077{
     5078    size_t numberOfScopesToCheckForFinally = m_controlFlowScopeStack.size();
     5079    if (!numberOfScopesToCheckForFinally)
     5080        return false;
     5081
     5082    FinallyContext* innermostFinallyContext = nullptr;
     5083    while (numberOfScopesToCheckForFinally) {
     5084        size_t scopeIndex = --numberOfScopesToCheckForFinally;
     5085        ControlFlowScope* scope = &m_controlFlowScopeStack[scopeIndex];
     5086        if (scope->isFinallyScope()) {
     5087            FinallyContext* finallyContext = &scope->finallyContext;
     5088            if (!innermostFinallyContext)
     5089                innermostFinallyContext = finallyContext;
     5090            finallyContext->setHandlesReturns();
     5091        }
     5092    }
     5093    if (!innermostFinallyContext)
     5094        return false; // No finallys to thread through.
     5095
     5096    emitSetCompletionType(CompletionType::Return);
     5097    emitSetCompletionValue(returnRegister);
     5098    emitJump(*innermostFinallyContext->finallyLabel());
     5099    return true; // We'll be jumping to a finally block.
     5100}
     5101
     5102void BytecodeGenerator::emitFinallyCompletion(FinallyContext& context, RegisterID* completionTypeRegister, Label& normalCompletionLabel)
     5103{
     5104    if (context.numberOfBreaksOrContinues() || context.handlesReturns()) {
     5105        emitJumpIf(op_stricteq, completionTypeRegister, CompletionType::Normal, normalCompletionLabel);
     5106
     5107        FinallyContext* outerContext = context.outerContext();
     5108
     5109        size_t numberOfJumps = context.numberOfJumps();
     5110        ASSERT(outerContext || numberOfJumps == context.numberOfBreaksOrContinues());
     5111
     5112        for (size_t i = 0; i < numberOfJumps; i++) {
     5113            Ref<Label> nextLabel = newLabel();
     5114            auto& jump = context.jumps(i);
     5115            emitJumpIf(op_nstricteq, completionTypeRegister, jump.jumpID, nextLabel.get());
     5116
     5117            restoreScopeRegister(jump.targetLexicalScopeIndex);
     5118            emitSetCompletionType(CompletionType::Normal);
     5119            emitJump(jump.targetLabel.get());
     5120
     5121            emitLabel(nextLabel.get());
     5122        }
     5123
     5124        if (outerContext) {
     5125            // We are not the outermost finally.
     5126            bool hasBreaksOrContinuesNotCoveredByJumps = context.numberOfBreaksOrContinues() > numberOfJumps;
     5127            if (hasBreaksOrContinuesNotCoveredByJumps || context.handlesReturns())
     5128                emitJumpIf(op_nstricteq, completionTypeRegister, CompletionType::Throw, *outerContext->finallyLabel());
     5129
     5130        } else {
     5131            // We are the outermost finally.
     5132            if (context.handlesReturns()) {
     5133                Ref<Label> notReturnLabel = newLabel();
     5134                emitJumpIf(op_nstricteq, completionTypeRegister, CompletionType::Return, notReturnLabel.get());
     5135
     5136                emitWillLeaveCallFrameDebugHook();
     5137                emitReturn(completionValueRegister(), ReturnFrom::Finally);
     5138               
     5139                emitLabel(notReturnLabel.get());
     5140            }
     5141        }
     5142    }
     5143    emitJumpIf(op_nstricteq, completionTypeRegister, CompletionType::Throw, normalCompletionLabel);
     5144    emitThrow(completionValueRegister());
     5145}
     5146
     5147bool BytecodeGenerator::allocateCompletionRecordRegisters()
     5148{
     5149    if (m_completionTypeRegister)
     5150        return false;
     5151
     5152    ASSERT(!m_completionValueRegister);
     5153    m_completionTypeRegister = newTemporary();
     5154    m_completionValueRegister = newTemporary();
     5155
     5156    emitSetCompletionType(CompletionType::Normal);
     5157    moveEmptyValue(m_completionValueRegister.get());
     5158    return true;
     5159}
     5160
     5161void BytecodeGenerator::releaseCompletionRecordRegisters()
     5162{
     5163    ASSERT(m_completionTypeRegister && m_completionValueRegister);
     5164    m_completionTypeRegister = nullptr;
     5165    m_completionValueRegister = nullptr;
     5166}
     5167
     5168void BytecodeGenerator::emitJumpIf(OpcodeID compareOpcode, RegisterID* completionTypeRegister, CompletionType type, Label& jumpTarget)
     5169{
     5170    RefPtr<RegisterID> tempRegister = newTemporary();
     5171    RegisterID* valueConstant = addConstantValue(jsNumber(static_cast<int>(type)));
     5172    OperandTypes operandTypes = OperandTypes(ResultType::numberTypeIsInt32(), ResultType::unknownType());
     5173
     5174    auto equivalenceResult = emitBinaryOp(compareOpcode, tempRegister.get(), valueConstant, completionTypeRegister, operandTypes);
     5175    emitJumpIfTrue(equivalenceResult, jumpTarget);
     5176}
     5177
     5178void ForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlock* codeBlock, unsigned bodyBytecodeEndOffset)
    47495179{
    47505180    // Lexically invalidating ForInContexts is kind of weak sauce, but it only occurs if
     
    47595189    // reassigned, or we'd have to resort to runtime checks to see if the variable had been
    47605190    // reassigned from its original value.
    4761     for (size_t i = m_forInContextStack.size(); i--; ) {
    4762         ForInContext& context = m_forInContextStack[i].get();
    4763         if (context.local() == localRegister)
    4764             context.invalidate();
    4765     }
    4766 }
    4767 
    4768 RegisterID* BytecodeGenerator::emitRestParameter(RegisterID* result, unsigned numParametersToSkip)
    4769 {
    4770     RefPtr<RegisterID> restArrayLength = newTemporary();
    4771     emitOpcode(op_get_rest_length);
    4772     instructions().append(restArrayLength->index());
    4773     instructions().append(numParametersToSkip);
    4774 
    4775     emitOpcode(op_create_rest);
    4776     instructions().append(result->index());
    4777     instructions().append(restArrayLength->index());
    4778     instructions().append(numParametersToSkip);
    4779 
    4780     return result;
    4781 }
    4782 
    4783 void BytecodeGenerator::emitRequireObjectCoercible(RegisterID* value, const String& error)
    4784 {
    4785     // FIXME: op_jneq_null treats "undetectable" objects as null/undefined. RequireObjectCoercible
    4786     // thus incorrectly throws a TypeError for interfaces like HTMLAllCollection.
    4787     Ref<Label> target = newLabel();
    4788     size_t begin = instructions().size();
    4789     emitOpcode(op_jneq_null);
    4790     instructions().append(value->index());
    4791     instructions().append(target->bind(begin, instructions().size()));
    4792     emitThrowTypeError(error);
    4793     emitLabel(target.get());
    4794 }
    4795 
    4796 void BytecodeGenerator::emitYieldPoint(RegisterID* argument, JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason result)
    4797 {
    4798     Ref<Label> mergePoint = newLabel();
    4799     unsigned yieldPointIndex = m_yieldPoints++;
    4800     emitGeneratorStateChange(yieldPointIndex + 1);
    4801 
    4802     if (parseMode() == SourceParseMode::AsyncGeneratorBodyMode) {
    4803         int suspendReason = static_cast<int32_t>(result);
    4804         emitPutById(generatorRegister(), propertyNames().builtinNames().asyncGeneratorSuspendReasonPrivateName(), emitLoad(nullptr, jsNumber(suspendReason)));
    4805     }
    4806 
    4807     // Split the try range here.
    4808     Ref<Label> savePoint = newEmittedLabel();
    4809     for (unsigned i = m_tryContextStack.size(); i--;) {
    4810         TryContext& context = m_tryContextStack[i];
    4811         m_tryRanges.append(TryRange {
    4812             context.start.copyRef(),
    4813             savePoint.copyRef(),
    4814             context.tryData
     5191
     5192    for (unsigned offset = bodyBytecodeStartOffset(); isValid() && offset < bodyBytecodeEndOffset;) {
     5193        UnlinkedInstruction* instruction = &generator.instructions()[offset];
     5194        OpcodeID opcodeID = instruction->u.opcode;
     5195        unsigned opcodeLength = opcodeLengths[opcodeID];
     5196
     5197        ASSERT(opcodeID != op_enter);
     5198        computeDefsForBytecodeOffset(codeBlock, opcodeID, instruction, [&] (UnlinkedCodeBlock*, UnlinkedInstruction*, OpcodeID, int operand) {
     5199            if (local()->index() == operand)
     5200                invalidate();
    48155201        });
    4816         // Try range will be restared at the merge point.
    4817         context.start = mergePoint.get();
    4818     }
    4819     Vector<TryContext> savedTryContextStack;
    4820     m_tryContextStack.swap(savedTryContextStack);
    4821 
    4822     emitOpcode(op_yield);
    4823     instructions().append(generatorFrameRegister()->index());
    4824     instructions().append(yieldPointIndex);
    4825     instructions().append(argument->index());
    4826 
    4827     // Restore the try contexts, which start offset is updated to the merge point.
    4828     m_tryContextStack.swap(savedTryContextStack);
    4829     emitLabel(mergePoint.get());
    4830 }
    4831 
    4832 RegisterID* BytecodeGenerator::emitYield(RegisterID* argument, JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason result)
    4833 {
    4834     emitYieldPoint(argument, result);
    4835 
    4836     Ref<Label> normalLabel = newLabel();
    4837     RefPtr<RegisterID> condition = newTemporary();
    4838     emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))));
    4839     emitJumpIfTrue(condition.get(), normalLabel.get());
    4840 
    4841     Ref<Label> throwLabel = newLabel();
    4842     emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode))));
    4843     emitJumpIfTrue(condition.get(), throwLabel.get());
    4844     // Return.
    4845     {
    4846         RefPtr<RegisterID> returnRegister = generatorValueRegister();
    4847         bool hasFinally = emitReturnViaFinallyIfNeeded(returnRegister.get());
    4848         if (!hasFinally)
    4849             emitReturn(returnRegister.get());
    4850     }
    4851 
    4852     // Throw.
    4853     emitLabel(throwLabel.get());
    4854     emitThrow(generatorValueRegister());
    4855 
    4856     // Normal.
    4857     emitLabel(normalLabel.get());
    4858     return generatorValueRegister();
    4859 }
    4860 
    4861 RegisterID* BytecodeGenerator::emitCallIterator(RegisterID* iterator, RegisterID* argument, ThrowableExpressionData* node)
    4862 {
    4863     CallArguments args(*this, nullptr);
    4864     move(args.thisRegister(), argument);
    4865     emitCall(iterator, iterator, NoExpectedFunction, args, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
    4866 
    4867     return iterator;
    4868 }
    4869 
    4870 void BytecodeGenerator::emitAwait(RegisterID* value)
    4871 {
    4872     emitYield(value, JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason::Await);
    4873     move(value, generatorValueRegister());
    4874 }
    4875 
    4876 RegisterID* BytecodeGenerator::emitGetIterator(RegisterID* argument, ThrowableExpressionData* node)
    4877 {
    4878     RefPtr<RegisterID> iterator = emitGetById(newTemporary(), argument, propertyNames().iteratorSymbol);
    4879     emitCallIterator(iterator.get(), argument, node);
    4880 
    4881     return iterator.get();
    4882 }
    4883 
    4884 RegisterID* BytecodeGenerator::emitGetAsyncIterator(RegisterID* argument, ThrowableExpressionData* node)
    4885 {
    4886     RefPtr<RegisterID> iterator = emitGetById(newTemporary(), argument, propertyNames().asyncIteratorSymbol);
    4887     Ref<Label> asyncIteratorNotFound = newLabel();
    4888     Ref<Label> asyncIteratorFound = newLabel();
    4889     Ref<Label> iteratorReceived = newLabel();
    4890 
    4891     emitJumpIfTrue(emitUnaryOp(op_eq_null, newTemporary(), iterator.get()), asyncIteratorNotFound.get());
    4892 
    4893     emitJump(asyncIteratorFound.get());
    4894     emitLabel(asyncIteratorNotFound.get());
    4895 
    4896     RefPtr<RegisterID> commonIterator = emitGetIterator(argument, node);
    4897     move(iterator.get(), commonIterator.get());
    4898 
    4899     RefPtr<RegisterID> nextMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().next);
    4900 
    4901     auto varCreateAsyncFromSyncIterator = variable(propertyNames().builtinNames().createAsyncFromSyncIteratorPrivateName());
    4902     RefPtr<RegisterID> scope = newTemporary();
    4903     move(scope.get(), emitResolveScope(scope.get(), varCreateAsyncFromSyncIterator));
    4904     RefPtr<RegisterID> createAsyncFromSyncIterator = emitGetFromScope(newTemporary(), scope.get(), varCreateAsyncFromSyncIterator, ThrowIfNotFound);
    4905 
    4906     CallArguments args(*this, nullptr, 2);
    4907     emitLoad(args.thisRegister(), jsUndefined());
    4908 
    4909     move(args.argumentRegister(0), iterator.get());
    4910     move(args.argumentRegister(1), nextMethod.get());
    4911 
    4912     JSTextPosition divot(m_scopeNode->firstLine(), m_scopeNode->startOffset(), m_scopeNode->lineStartOffset());
    4913     emitCall(iterator.get(), createAsyncFromSyncIterator.get(), NoExpectedFunction, args, divot, divot, divot, DebuggableCall::No);
    4914 
    4915     emitJump(iteratorReceived.get());
    4916 
    4917     emitLabel(asyncIteratorFound.get());
    4918     emitCallIterator(iterator.get(), argument, node);
    4919     emitLabel(iteratorReceived.get());
    4920 
    4921     return iterator.get();
    4922 }
    4923 
    4924 RegisterID* BytecodeGenerator::emitDelegateYield(RegisterID* argument, ThrowableExpressionData* node)
    4925 {
    4926     RefPtr<RegisterID> value = newTemporary();
    4927     {
    4928         RefPtr<RegisterID> iterator = parseMode() == SourceParseMode::AsyncGeneratorBodyMode ? emitGetAsyncIterator(argument, node) : emitGetIterator(argument, node);
    4929         RefPtr<RegisterID> nextMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().next);
    4930 
    4931         Ref<Label> loopDone = newLabel();
    4932         {
    4933             Ref<Label> nextElement = newLabel();
    4934             emitLoad(value.get(), jsUndefined());
    4935 
    4936             emitJump(nextElement.get());
    4937 
    4938             Ref<Label> loopStart = newLabel();
    4939             emitLabel(loopStart.get());
    4940             emitLoopHint();
    4941 
    4942             Ref<Label> branchOnResult = newLabel();
    4943             {
    4944                 emitYieldPoint(value.get(), JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason::Yield);
    4945 
    4946                 Ref<Label> normalLabel = newLabel();
    4947                 Ref<Label> returnLabel = newLabel();
    4948                 {
    4949                     RefPtr<RegisterID> condition = newTemporary();
    4950                     emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode))));
    4951                     emitJumpIfTrue(condition.get(), normalLabel.get());
    4952 
    4953                     emitEqualityOp(op_stricteq, condition.get(), generatorResumeModeRegister(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ReturnMode))));
    4954                     emitJumpIfTrue(condition.get(), returnLabel.get());
    4955 
    4956                     // Fallthrough to ThrowMode.
    4957                 }
    4958 
    4959                 // Throw.
    4960                 {
    4961                     Ref<Label> throwMethodFound = newLabel();
    4962                     RefPtr<RegisterID> throwMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().throwKeyword);
    4963                     emitJumpIfFalse(emitIsUndefined(newTemporary(), throwMethod.get()), throwMethodFound.get());
    4964 
    4965                     EmitAwait emitAwaitInIteratorClose = parseMode() == SourceParseMode::AsyncGeneratorBodyMode ? EmitAwait::Yes : EmitAwait::No;
    4966                     emitIteratorClose(iterator.get(), node, emitAwaitInIteratorClose);
    4967 
    4968                     emitThrowTypeError("Delegated generator does not have a 'throw' method."_s);
    4969 
    4970                     emitLabel(throwMethodFound.get());
    4971                     CallArguments throwArguments(*this, nullptr, 1);
    4972                     move(throwArguments.thisRegister(), iterator.get());
    4973                     move(throwArguments.argumentRegister(0), generatorValueRegister());
    4974                     emitCall(value.get(), throwMethod.get(), NoExpectedFunction, throwArguments, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
    4975 
    4976                     emitJump(branchOnResult.get());
    4977                 }
    4978 
    4979                 // Return.
    4980                 emitLabel(returnLabel.get());
    4981                 {
    4982                     Ref<Label> returnMethodFound = newLabel();
    4983                     RefPtr<RegisterID> returnMethod = emitGetById(newTemporary(), iterator.get(), propertyNames().returnKeyword);
    4984                     emitJumpIfFalse(emitIsUndefined(newTemporary(), returnMethod.get()), returnMethodFound.get());
    4985 
    4986                     move(value.get(), generatorValueRegister());
    4987 
    4988                     Ref<Label> returnSequence = newLabel();
    4989                     emitJump(returnSequence.get());
    4990 
    4991                     emitLabel(returnMethodFound.get());
    4992                     CallArguments returnArguments(*this, nullptr, 1);
    4993                     move(returnArguments.thisRegister(), iterator.get());
    4994                     move(returnArguments.argumentRegister(0), generatorValueRegister());
    4995                     emitCall(value.get(), returnMethod.get(), NoExpectedFunction, returnArguments, node->divot(), node->divotStart(), node->divotEnd(), DebuggableCall::No);
    4996 
    4997                     if (parseMode() == SourceParseMode::AsyncGeneratorBodyMode)
    4998                         emitAwait(value.get());
    4999 
    5000                     Ref<Label> returnIteratorResultIsObject = newLabel();
    5001                     emitJumpIfTrue(emitIsObject(newTemporary(), value.get()), returnIteratorResultIsObject.get());
    5002                     emitThrowTypeError("Iterator result interface is not an object."_s);
    5003 
    5004                     emitLabel(returnIteratorResultIsObject.get());
    5005 
    5006                     Ref<Label> returnFromGenerator = newLabel();
    5007                     emitJumpIfTrue(emitGetById(newTemporary(), value.get(), propertyNames().done), returnFromGenerator.get());
    5008 
    5009                     emitGetById(value.get(), value.get(), propertyNames().value);
    5010                     emitJump(loopStart.get());
    5011 
    5012                     emitLabel(returnFromGenerator.get());
    5013                     emitGetById(value.get(), value.get(), propertyNames().value);
    5014 
    5015                     emitLabel(returnSequence.get());
    5016                     bool hasFinally = emitReturnViaFinallyIfNeeded(value.get());
    5017                     if (!hasFinally)
    5018                         emitReturn(value.get());
    5019                 }
    5020 
    5021                 // Normal.
    5022                 emitLabel(normalLabel.get());
    5023                 move(value.get(), generatorValueRegister());
    5024             }
    5025 
    5026             emitLabel(nextElement.get());
    5027             emitIteratorNextWithValue(value.get(), nextMethod.get(), iterator.get(), value.get(), node);
    5028 
    5029             emitLabel(branchOnResult.get());
    5030 
    5031             if (parseMode() == SourceParseMode::AsyncGeneratorBodyMode)
    5032                 emitAwait(value.get());
    5033 
    5034             Ref<Label> iteratorValueIsObject = newLabel();
    5035             emitJumpIfTrue(emitIsObject(newTemporary(), value.get()), iteratorValueIsObject.get());
    5036             emitThrowTypeError("Iterator result interface is not an object."_s);
    5037             emitLabel(iteratorValueIsObject.get());
    5038 
    5039             emitJumpIfTrue(emitGetById(newTemporary(), value.get(), propertyNames().done), loopDone.get());
    5040             emitGetById(value.get(), value.get(), propertyNames().value);
    5041 
    5042             emitJump(loopStart.get());
    5043         }
    5044         emitLabel(loopDone.get());
    5045     }
    5046 
    5047     emitGetById(value.get(), value.get(), propertyNames().value);
    5048     return value.get();
    5049 }
    5050 
    5051 
    5052 void BytecodeGenerator::emitGeneratorStateChange(int32_t state)
    5053 {
    5054     RegisterID* completedState = emitLoad(nullptr, jsNumber(state));
    5055     emitPutById(generatorRegister(), propertyNames().builtinNames().generatorStatePrivateName(), completedState);
    5056 }
    5057 
    5058 bool BytecodeGenerator::emitJumpViaFinallyIfNeeded(int targetLabelScopeDepth, Label& jumpTarget)
    5059 {
    5060     ASSERT(labelScopeDepth() - targetLabelScopeDepth >= 0);
    5061     size_t numberOfScopesToCheckForFinally = labelScopeDepth() - targetLabelScopeDepth;
    5062     ASSERT(numberOfScopesToCheckForFinally <= m_controlFlowScopeStack.size());
    5063     if (!numberOfScopesToCheckForFinally)
    5064         return false;
    5065 
    5066     FinallyContext* innermostFinallyContext = nullptr;
    5067     FinallyContext* outermostFinallyContext = nullptr;
    5068     size_t scopeIndex = m_controlFlowScopeStack.size() - 1;
    5069     while (numberOfScopesToCheckForFinally--) {
    5070         ControlFlowScope* scope = &m_controlFlowScopeStack[scopeIndex--];
    5071         if (scope->isFinallyScope()) {
    5072             FinallyContext* finallyContext = &scope->finallyContext;
    5073             if (!innermostFinallyContext)
    5074                 innermostFinallyContext = finallyContext;
    5075             outermostFinallyContext = finallyContext;
    5076             finallyContext->incNumberOfBreaksOrContinues();
    5077         }
    5078     }
    5079     if (!outermostFinallyContext)
    5080         return false; // No finallys to thread through.
    5081 
    5082     auto jumpID = bytecodeOffsetToJumpID(instructions().size());
    5083     int lexicalScopeIndex = labelScopeDepthToLexicalScopeIndex(targetLabelScopeDepth);
    5084     outermostFinallyContext->registerJump(jumpID, lexicalScopeIndex, jumpTarget);
    5085 
    5086     emitSetCompletionType(jumpID);
    5087     emitJump(*innermostFinallyContext->finallyLabel());
    5088     return true; // We'll be jumping to a finally block.
    5089 }
    5090 
    5091 bool BytecodeGenerator::emitReturnViaFinallyIfNeeded(RegisterID* returnRegister)
    5092 {
    5093     size_t numberOfScopesToCheckForFinally = m_controlFlowScopeStack.size();
    5094     if (!numberOfScopesToCheckForFinally)
    5095         return false;
    5096 
    5097     FinallyContext* innermostFinallyContext = nullptr;
    5098     while (numberOfScopesToCheckForFinally) {
    5099         size_t scopeIndex = --numberOfScopesToCheckForFinally;
    5100         ControlFlowScope* scope = &m_controlFlowScopeStack[scopeIndex];
    5101         if (scope->isFinallyScope()) {
    5102             FinallyContext* finallyContext = &scope->finallyContext;
    5103             if (!innermostFinallyContext)
    5104                 innermostFinallyContext = finallyContext;
    5105             finallyContext->setHandlesReturns();
    5106         }
    5107     }
    5108     if (!innermostFinallyContext)
    5109         return false; // No finallys to thread through.
    5110 
    5111     emitSetCompletionType(CompletionType::Return);
    5112     emitSetCompletionValue(returnRegister);
    5113     emitJump(*innermostFinallyContext->finallyLabel());
    5114     return true; // We'll be jumping to a finally block.
    5115 }
    5116 
    5117 void BytecodeGenerator::emitFinallyCompletion(FinallyContext& context, RegisterID* completionTypeRegister, Label& normalCompletionLabel)
    5118 {
    5119     if (context.numberOfBreaksOrContinues() || context.handlesReturns()) {
    5120         emitJumpIf(op_stricteq, completionTypeRegister, CompletionType::Normal, normalCompletionLabel);
    5121 
    5122         FinallyContext* outerContext = context.outerContext();
    5123 
    5124         size_t numberOfJumps = context.numberOfJumps();
    5125         ASSERT(outerContext || numberOfJumps == context.numberOfBreaksOrContinues());
    5126 
    5127         for (size_t i = 0; i < numberOfJumps; i++) {
    5128             Ref<Label> nextLabel = newLabel();
    5129             auto& jump = context.jumps(i);
    5130             emitJumpIf(op_nstricteq, completionTypeRegister, jump.jumpID, nextLabel.get());
    5131 
    5132             restoreScopeRegister(jump.targetLexicalScopeIndex);
    5133             emitSetCompletionType(CompletionType::Normal);
    5134             emitJump(jump.targetLabel.get());
    5135 
    5136             emitLabel(nextLabel.get());
    5137         }
    5138 
    5139         if (outerContext) {
    5140             // We are not the outermost finally.
    5141             bool hasBreaksOrContinuesNotCoveredByJumps = context.numberOfBreaksOrContinues() > numberOfJumps;
    5142             if (hasBreaksOrContinuesNotCoveredByJumps || context.handlesReturns())
    5143                 emitJumpIf(op_nstricteq, completionTypeRegister, CompletionType::Throw, *outerContext->finallyLabel());
    5144 
    5145         } else {
    5146             // We are the outermost finally.
    5147             if (context.handlesReturns()) {
    5148                 Ref<Label> notReturnLabel = newLabel();
    5149                 emitJumpIf(op_nstricteq, completionTypeRegister, CompletionType::Return, notReturnLabel.get());
    5150 
    5151                 emitWillLeaveCallFrameDebugHook();
    5152                 emitReturn(completionValueRegister(), ReturnFrom::Finally);
    5153                
    5154                 emitLabel(notReturnLabel.get());
    5155             }
    5156         }
    5157     }
    5158     emitJumpIf(op_nstricteq, completionTypeRegister, CompletionType::Throw, normalCompletionLabel);
    5159     emitThrow(completionValueRegister());
    5160 }
    5161 
    5162 bool BytecodeGenerator::allocateCompletionRecordRegisters()
    5163 {
    5164     if (m_completionTypeRegister)
    5165         return false;
    5166 
    5167     ASSERT(!m_completionValueRegister);
    5168     m_completionTypeRegister = newTemporary();
    5169     m_completionValueRegister = newTemporary();
    5170 
    5171     emitSetCompletionType(CompletionType::Normal);
    5172     moveEmptyValue(m_completionValueRegister.get());
    5173     return true;
    5174 }
    5175 
    5176 void BytecodeGenerator::releaseCompletionRecordRegisters()
    5177 {
    5178     ASSERT(m_completionTypeRegister && m_completionValueRegister);
    5179     m_completionTypeRegister = nullptr;
    5180     m_completionValueRegister = nullptr;
    5181 }
    5182 
    5183 void BytecodeGenerator::emitJumpIf(OpcodeID compareOpcode, RegisterID* completionTypeRegister, CompletionType type, Label& jumpTarget)
    5184 {
    5185     RefPtr<RegisterID> tempRegister = newTemporary();
    5186     RegisterID* valueConstant = addConstantValue(jsNumber(static_cast<int>(type)));
    5187     OperandTypes operandTypes = OperandTypes(ResultType::numberTypeIsInt32(), ResultType::unknownType());
    5188 
    5189     auto equivalenceResult = emitBinaryOp(compareOpcode, tempRegister.get(), valueConstant, completionTypeRegister, operandTypes);
    5190     emitJumpIfTrue(equivalenceResult, jumpTarget);
    5191 }
    5192 
    5193 void StructureForInContext::finalize(BytecodeGenerator& generator)
    5194 {
     5202        offset += opcodeLength;
     5203    }
     5204}
     5205
     5206void StructureForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlock* codeBlock, unsigned bodyBytecodeEndOffset)
     5207{
     5208    Base::finalize(generator, codeBlock, bodyBytecodeEndOffset);
    51955209    if (isValid())
    51965210        return;
     
    52205234}
    52215235
    5222 void IndexedForInContext::finalize(BytecodeGenerator& generator)
    5223 {
     5236void IndexedForInContext::finalize(BytecodeGenerator& generator, UnlinkedCodeBlock* codeBlock, unsigned bodyBytecodeEndOffset)
     5237{
     5238    Base::finalize(generator, codeBlock, bodyBytecodeEndOffset);
    52245239    if (isValid())
    52255240        return;
  • releases/WebKitGTK/webkit-2.22/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r238988 r238989  
    212212
    213213    protected:
    214         ForInContext(RegisterID* localRegister, Type type)
     214        ForInContext(RegisterID* localRegister, Type type, unsigned bodyBytecodeStartOffset)
    215215            : m_localRegister(localRegister)
    216216            , m_type(type)
     217            , m_bodyBytecodeStartOffset(bodyBytecodeStartOffset)
    217218        { }
     219
     220        unsigned bodyBytecodeStartOffset() const { return m_bodyBytecodeStartOffset; }
     221
     222        void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset);
    218223
    219224    private:
     
    221226        bool m_isValid { true };
    222227        Type m_type;
     228        unsigned m_bodyBytecodeStartOffset;
    223229    };
    224230
    225231    class StructureForInContext : public ForInContext {
     232        using Base = ForInContext;
    226233    public:
    227234        using GetInst = std::tuple<unsigned, int, UnlinkedValueProfile>;
    228235
    229         StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister)
    230             : ForInContext(localRegister, Type::StructureForIn)
     236        StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister, unsigned bodyBytecodeStartOffset)
     237            : ForInContext(localRegister, Type::StructureForIn, bodyBytecodeStartOffset)
    231238            , m_indexRegister(indexRegister)
    232239            , m_propertyRegister(propertyRegister)
     
    244251        }
    245252
    246         void finalize(BytecodeGenerator&);
     253        void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset);
    247254
    248255    private:
     
    254261
    255262    class IndexedForInContext : public ForInContext {
     263        using Base = ForInContext;
    256264    public:
    257         IndexedForInContext(RegisterID* localRegister, RegisterID* indexRegister)
    258             : ForInContext(localRegister, Type::IndexedForIn)
     265        IndexedForInContext(RegisterID* localRegister, RegisterID* indexRegister, unsigned bodyBytecodeStartOffset)
     266            : ForInContext(localRegister, Type::IndexedForIn, bodyBytecodeStartOffset)
    259267            , m_indexRegister(indexRegister)
    260268        {
     
    263271        RegisterID* index() const { return m_indexRegister.get(); }
    264272
    265         void finalize(BytecodeGenerator&);
     273        void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset);
    266274        void addGetInst(unsigned instIndex, int propertyIndex) { m_getInsts.append({ instIndex, propertyIndex }); }
    267275
     
    939947        void pushStructureForInScope(RegisterID* local, RegisterID* index, RegisterID* property, RegisterID* enumerator);
    940948        void popStructureForInScope(RegisterID* local);
    941         void invalidateForInContextForLocal(RegisterID* local);
    942949
    943950        LabelScope* breakTarget(const Identifier&);
  • releases/WebKitGTK/webkit-2.22/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r238986 r238989  
    15571557            localReg = generator.move(generator.tempDestination(dst), local);
    15581558        }
    1559         generator.invalidateForInContextForLocal(local);
    15601559        RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator);
    15611560        generator.emitProfileType(localReg.get(), var, divotStart(), divotEnd());
     
    17701769            localReg = generator.move(generator.tempDestination(dst), localReg.get());
    17711770        } else if (generator.vm()->typeProfiler()) {
    1772             generator.invalidateForInContextForLocal(local);
    17731771            RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
    17741772            generator.move(tempDst.get(), localReg.get());
     
    17781776            return generator.move(dst, tempDst.get());
    17791777        }
    1780         generator.invalidateForInContextForLocal(local);
    17811778        emitIncOrDec(generator, localReg.get(), m_operator);
    17821779        return generator.move(dst, localReg.get());
     
    24422439            emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
    24432440            generator.move(local, result.get());
    2444             generator.invalidateForInContextForLocal(local);
    24452441            generator.emitProfileType(local, divotStart(), divotEnd());
    24462442            return generator.move(dst, result.get());
     
    24482444       
    24492445        RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
    2450         generator.invalidateForInContextForLocal(local);
    24512446        generator.emitProfileType(result, divotStart(), divotEnd());
    24522447        return generator.move(dst, result);
     
    25062501            generator.move(local, tempDst.get());
    25072502            generator.emitProfileType(local, var, divotStart(), divotEnd());
    2508             generator.invalidateForInContextForLocal(local);
    25092503            result = generator.move(dst, tempDst.get());
    25102504        } else {
    25112505            RegisterID* right = generator.emitNode(local, m_right);
    25122506            generator.emitProfileType(right, var, divotStart(), divotEnd());
    2513             generator.invalidateForInContextForLocal(local);
    25142507            result = generator.move(dst, right);
    25152508        }
     
    27532746    if (RegisterID* local = var.local()) {
    27542747        generator.emitLoad(local, jsUndefined());
    2755         generator.invalidateForInContextForLocal(local);
    27562748        generator.emitProfileType(local, var, position(), JSTextPosition(-1, position().offset + m_ident.length(), -1));
    27572749    } else {
     
    29672959                generator.emitReadOnlyExceptionIfNeeded(var);
    29682960            generator.move(local, propertyName);
    2969             generator.invalidateForInContextForLocal(local);
    29702961        } else {
    29712962            if (generator.isStrictMode())
     
    30353026        }
    30363027        generator.move(var.local(), propertyName);
    3037         generator.invalidateForInContextForLocal(var.local());
    30383028        generator.emitProfileType(propertyName, var, simpleBinding->divotStart(), simpleBinding->divotEnd());
    30393029        return;
     
    32263216                    generator.emitReadOnlyExceptionIfNeeded(var);
    32273217                generator.move(local, value);
    3228                 generator.invalidateForInContextForLocal(local);
    32293218            } else {
    32303219                if (generator.isStrictMode())
     
    44004389        }
    44014390        generator.move(local, value);
    4402         generator.invalidateForInContextForLocal(local);
    44034391        generator.emitProfileType(local, var, divotStart(), divotEnd());
    44044392        if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement)
     
    44494437                generator.emitReadOnlyExceptionIfNeeded(var);
    44504438            else {
    4451                 generator.invalidateForInContextForLocal(local);
    44524439                generator.move(local, value);
    44534440                generator.emitProfileType(local, divotStart(), divotEnd());
  • releases/WebKitGTK/webkit-2.22/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r238986 r238989  
    811811    CHECK_EXCEPTION();
    812812    JSValue property = OP(3).jsValue();
     813    ASSERT(property.isString());
    813814    JSString* string = asString(property);
    814815    auto propertyName = string->toIdentifier(exec);
     
    822823    JSValue baseValue = OP_C(2).jsValue();
    823824    JSValue property = OP(3).jsValue();
     825    ASSERT(property.isString());
    824826    JSString* string = asString(property);
    825827    auto propertyName = string->toIdentifier(exec);
Note: See TracChangeset for help on using the changeset viewer.