Changeset 242614 in webkit


Ignore:
Timestamp:
Mar 7, 2019 3:01:18 PM (5 years ago)
Author:
mark.lam@apple.com
Message:

Follow up refactoring in try-finally code after r242591.
https://bugs.webkit.org/show_bug.cgi?id=195428

Reviewed by Saam Barati.

  1. Added some comments in emitFinallyCompletion() to describe each completion case.
  2. Converted CatchEntry into a struct.
  3. Renamed variable hasBreaksOrContinuesNotCoveredByJumps to hasBreaksOrContinuesThatEscapeCurrentFinally to be more clear about its purpose.
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::emitOutOfLineExceptionHandler):
(JSC::BytecodeGenerator::emitFinallyCompletion):

  • bytecompiler/BytecodeGenerator.h:
Location:
trunk/Source/JavaScriptCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r242613 r242614  
     12019-03-07  Mark Lam  <mark.lam@apple.com>
     2
     3        Follow up refactoring in try-finally code after r242591.
     4        https://bugs.webkit.org/show_bug.cgi?id=195428
     5
     6        Reviewed by Saam Barati.
     7
     8        1. Added some comments in emitFinallyCompletion() to describe each completion case.
     9        2. Converted CatchEntry into a struct.
     10        3. Renamed variable hasBreaksOrContinuesNotCoveredByJumps to hasBreaksOrContinuesThatEscapeCurrentFinally
     11           to be more clear about its purpose.
     12
     13        * bytecompiler/BytecodeGenerator.cpp:
     14        (JSC::BytecodeGenerator::generate):
     15        (JSC::BytecodeGenerator::emitOutOfLineExceptionHandler):
     16        (JSC::BytecodeGenerator::emitFinallyCompletion):
     17        * bytecompiler/BytecodeGenerator.h:
     18
    1192019-03-07  Saam Barati  <sbarati@apple.com>
    220
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r242591 r242614  
    257257    }
    258258
    259     for (auto& tuple : m_exceptionHandlersToEmit) {
     259    for (auto& handler : m_exceptionHandlersToEmit) {
    260260        Ref<Label> realCatchTarget = newLabel();
    261         TryData* tryData = std::get<0>(tuple);
    262 
    263         OpCatch::emit(this, std::get<1>(tuple), std::get<2>(tuple));
     261        TryData* tryData = handler.tryData;
     262
     263        OpCatch::emit(this, handler.exceptionRegister, handler.thrownValueRegister);
    264264        realCatchTarget->setLocation(*this, m_lastInstruction.offset());
    265         if (std::get<3>(tuple).isValid()) {
    266             RegisterID completionTypeRegister { std::get<3>(tuple) };
     265        if (handler.completionTypeRegister.isValid()) {
     266            RegisterID completionTypeRegister { handler.completionTypeRegister };
    267267            CompletionType completionType =
    268268                tryData->handlerType == HandlerType::Finally || tryData->handlerType == HandlerType::SynthesizedFinally
     
    36773677{
    36783678    VirtualRegister completionTypeVirtualRegister = completionTypeRegister ? completionTypeRegister : VirtualRegister();
    3679     m_exceptionHandlersToEmit.append(CatchEntry { data, exceptionRegister, thrownValueRegister, completionTypeVirtualRegister });
     3679    m_exceptionHandlersToEmit.append({ data, exceptionRegister, thrownValueRegister, completionTypeVirtualRegister });
    36803680}
    36813681
     
    47774777            emitJumpIf<OpNstricteq>(context.completionTypeRegister(), jump.jumpID, nextLabel.get());
    47784778
    4779             // After a Break or Continue, we resume execution and may eventually complete with
    4780             // Normal completion (unless abruptly completed again). So, pre-emptively set the
    4781             // completion type to Normal. We can also set the completion value to undefined,
    4782             // but it will never be used for normal completion anyway. So, we'll skip setting it.
     4779            // This case is for Break / Continue completions from an inner finally context
     4780            // with a jump target that is not beyond the next outer finally context:
     4781            //
     4782            //     try {
     4783            //         for (... stuff ...) {
     4784            //             try {
     4785            //                 continue; // Sets completionType to jumpID of top of the for loop.
     4786            //             } finally {
     4787            //             } // Jump to top of the for loop on completion.
     4788            //         }
     4789            //     } finally {
     4790            //     }
     4791            //
     4792            // Since the jumpID is targetting a label that is inside the outer finally context,
     4793            // we can jump to it directly on completion of this finally context: there is no intermediate
     4794            // finally blocks to run. After the Break / Continue, we will contnue execution as normal.
     4795            // So, we'll set the completionType to Normal (on behalf of the target) before we jump.
     4796            // We can also set the completion value to undefined, but it will never be used for normal
     4797            // completion anyway. So, we'll skip setting it.
     4798
    47834799            restoreScopeRegister(jump.targetLexicalScopeIndex);
    47844800            emitLoad(context.completionTypeRegister(), CompletionType::Normal);
     
    47944810                emitJumpIf<OpNstricteq>(context.completionTypeRegister(), CompletionType::Return, isNotReturnLabel.get());
    47954811
    4796                 // For Return completion, we need to pass the completion type and value to
    4797                 // the outer finally so that it can return when it's done (unless interrupted
    4798                 // by another abrupt completion).
     4812                // This case is for Return completion from an inner finally context:
     4813                //
     4814                //     try {
     4815                //         try {
     4816                //             return result; // Sets completionType to Return, and completionValue to result.
     4817                //         } finally {
     4818                //         } // Jump to outer finally on completion.
     4819                //     } finally {
     4820                //     }
     4821                //
     4822                // Since we know there's at least one outer finally context (beyond the current context),
     4823                // we cannot actually return from here. Instead, we pass the completionType and completionValue
     4824                // on to the next outer finally, and let it decide what to do next on its completion. The
     4825                // outer finally may or may not actual return depending on whether it encounters an abrupt
     4826                // completion in its body that overrrides this Return completion.
     4827
    47994828                move(outerContext->completionTypeRegister(), context.completionTypeRegister());
    48004829                move(outerContext->completionValueRegister(), context.completionValueRegister());
     
    48044833            }
    48054834
    4806             bool hasBreaksOrContinuesNotCoveredByJumps = context.numberOfBreaksOrContinues() > numberOfJumps;
    4807             if (hasBreaksOrContinuesNotCoveredByJumps) {
     4835            bool hasBreaksOrContinuesThatEscapeCurrentFinally = context.numberOfBreaksOrContinues() > numberOfJumps;
     4836            if (hasBreaksOrContinuesThatEscapeCurrentFinally) {
    48084837                Ref<Label> isThrowOrNormalLabel = newLabel();
    48094838                emitJumpIf<OpBeloweq>(context.completionTypeRegister(), CompletionType::Throw, isThrowOrNormalLabel.get());
     4839
     4840                // A completionType above Throw means we have a Break or Continue encoded as a jumpID.
     4841                // We already ruled out Return above.
    48104842                static_assert(CompletionType::Throw < CompletionType::Return && CompletionType::Throw < CompletionType::Return, "jumpIDs are above CompletionType::Return");
    48114843
    4812                 // Not Throw means we have a Break or Continue that should be handled by the outer context.
    4813                 // These are for Break or Continue completions that have not reached their jump targets
    4814                 // yet. The outer context needs to run its finally, and resume the jump outwards (unless
    4815                 // interrupted by another abrupt completion). So, we need to pass the completion type to
    4816                 // the outer finally. Again, we can skip the completion value because it's not used for
    4817                 // Break nor Continue.
     4844                // This case is for Break / Continue completions in an inner finally context:
     4845                //
     4846                // 10: label:
     4847                // 11: try {
     4848                // 12:     try {
     4849                // 13:         for (... stuff ...)
     4850                // 14:             break label; // Sets completionType to jumpID of label.
     4851                // 15:     } finally {
     4852                // 16:     } // Jumps to outer finally on completion.
     4853                // 17:  } finally {
     4854                // 18:  }
     4855                //
     4856                // The break (line 14) says to continue execution at the label at line 10. Before we can
     4857                // goto line 10, the inner context's finally (line 15) needs to be run, followed by the
     4858                // outer context's finally (line 17). 'outerContext' being non-null above tells us that
     4859                // there is at least one outer finally context that we need to run after we complete the
     4860                // current finally. Note that unless the body of the outer finally abruptly completes in a
     4861                // different way, that outer finally also needs to complete with a Break / Continue to
     4862                // the same target label. Hence, we need to pass the jumpID in this finally's completionTypeRegister
     4863                // to the outer finally. The completion value for Break and Continue according to the spec
     4864                // is undefined, but it won't ever be used. So, we'll skip setting it.
     4865                //
     4866                // Note that all we're doing here is passing the Break / Continue completion to the next
     4867                // outer finally context. We don't worry about finally contexts beyond that. It is the
     4868                // responsibility of the next outer finally to determine what to do next at its completion,
     4869                // and pass on to the next outer context if present and needed.
     4870
    48184871                move(outerContext->completionTypeRegister(), context.completionTypeRegister());
    48194872                emitJump(*outerContext->finallyLabel());
     
    48284881                emitJumpIf<OpNstricteq>(context.completionTypeRegister(), CompletionType::Return, notReturnLabel.get());
    48294882
     4883                // This case is for Return completion from the outermost finally context:
     4884                //
     4885                //     try {
     4886                //         return result; // Sets completionType to Return, and completionValue to result.
     4887                //     } finally {
     4888                //     } // Executes the return of the completionValue.
     4889                //
     4890                // Since we know there's no outer finally context (beyond the current context) to run,
     4891                // we can actually execute a return for this Return completion. The value to return
     4892                // is whatever is in the completionValueRegister.
     4893
    48304894                emitWillLeaveCallFrameDebugHook();
    48314895                emitReturn(context.completionValueRegister(), ReturnFrom::Finally);
     
    48364900    }
    48374901
    4838     // Handle Throw or Normal completions.
     4902    // By now, we've rule out all Break / Continue / Return completions above. The only remaining
     4903    // possibilities are Normal or Throw.
     4904
    48394905    emitJumpIf<OpNstricteq>(context.completionTypeRegister(), CompletionType::Throw, normalCompletionLabel);
    48404906
    4841     // For Throw, we just re-throw the previously caught exception captured in the completion value.
    4842     // The exception handler will set the completion type to Throw, and re-capture the completion
    4843     // value if needed (i.e. if the exception handler is for a finally). Hence, no need to set the
    4844     // completion type and value here.
     4907    // We get here because we entered this finally context with Throw completionType (i.e. we have
     4908    // an exception that we need to rethrow), and we didn't encounter a different abrupt completion
     4909    // that overrides that incoming completionType. All we have to do here is re-throw the exception
     4910    // captured in the completionValue.
     4911    //
     4912    // Note that unlike for Break / Continue / Return, we don't need to worry about outer finally
     4913    // contexts. This is because any outer finally context (if present) will have its own exception
     4914    // handler, which will take care of receiving the Throw completion, and re-capturing the exception
     4915    // in its completionValue.
     4916
    48454917    emitThrow(context.completionValueRegister());
    48464918}
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r242591 r242614  
    12791279        CompactVariableMap::Handle m_cachedVariablesUnderTDZ;
    12801280
    1281         using CatchEntry = std::tuple<TryData*, VirtualRegister, VirtualRegister, VirtualRegister>;
     1281        struct CatchEntry {
     1282            TryData* tryData;
     1283            VirtualRegister exceptionRegister;
     1284            VirtualRegister thrownValueRegister;
     1285            VirtualRegister completionTypeRegister;
     1286        };
    12821287        Vector<CatchEntry> m_exceptionHandlersToEmit;
    12831288    };
Note: See TracChangeset for help on using the changeset viewer.