Title: [237933] trunk/Source/_javascript_Core
Revision
237933
Author
[email protected]
Date
2018-11-07 11:38:14 -0800 (Wed, 07 Nov 2018)

Log Message

Align wide opcodes in the instruction stream
https://bugs.webkit.org/show_bug.cgi?id=191254

Reviewed by Keith Miller.

Pad the bytecode with nops to ensure that wide opcodes are 4-byte
aligned on platforms that don't like unaligned memory access.

For that, add a new type to represent jump targets, BoundLabel, which
delays computing the offset in case we need to emit nops for padding.
Extra padding is also emitted before op_yield and at the of each
BytecodeWriter fragment, to ensure that the bytecode remains aligned
after the rewriting.

As a side effect, we can longer guarantee that the point immediately
before emitting an opcode is the start of that opcode, since nops
might be emitted in between if the opcode needs to be wide. To fix
that, we only take the offset of opcodes after they have been emitted,
using `m_lastInstruction.offset()`.

* bytecode/BytecodeDumper.h:
(JSC::BytecodeDumper::dumpValue):
* bytecode/BytecodeGeneratorification.cpp:
(JSC::BytecodeGeneratorification::run):
* bytecode/BytecodeList.rb:
* bytecode/BytecodeRewriter.h:
(JSC::BytecodeRewriter::Fragment::align):
(JSC::BytecodeRewriter::insertFragmentBefore):
(JSC::BytecodeRewriter::insertFragmentAfter):
* bytecode/Fits.h:
* bytecode/InstructionStream.h:
(JSC::InstructionStreamWriter::ref):
* bytecode/PreciseJumpTargetsInlines.h:
(JSC::updateStoredJumpTargetsForInstruction):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::Label::setLocation):
(JSC::BoundLabel::target):
(JSC::BoundLabel::saveTarget):
(JSC::BoundLabel::commitTarget):
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::recordOpcode):
(JSC::BytecodeGenerator::alignWideOpcode):
(JSC::BytecodeGenerator::emitProfileControlFlow):
(JSC::BytecodeGenerator::emitResolveScope):
(JSC::BytecodeGenerator::emitGetFromScope):
(JSC::BytecodeGenerator::emitPutToScope):
(JSC::BytecodeGenerator::emitGetById):
(JSC::BytecodeGenerator::emitDirectGetById):
(JSC::BytecodeGenerator::emitPutById):
(JSC::BytecodeGenerator::emitDirectPutById):
(JSC::BytecodeGenerator::emitGetByVal):
(JSC::BytecodeGenerator::emitCreateThis):
(JSC::BytecodeGenerator::beginSwitch):
(JSC::BytecodeGenerator::endSwitch):
(JSC::BytecodeGenerator::emitRequireObjectCoercible):
(JSC::BytecodeGenerator::emitYieldPoint):
(JSC::BytecodeGenerator::emitToThis):
(JSC::Label::bind): Deleted.
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::recordOpcode): Deleted.
* bytecompiler/Label.h:
(JSC::BoundLabel::BoundLabel):
(JSC::BoundLabel::operator int):
(JSC::Label::bind):
* generator/Opcode.rb:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (237932 => 237933)


--- trunk/Source/_javascript_Core/ChangeLog	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-11-07 19:38:14 UTC (rev 237933)
@@ -1,5 +1,73 @@
 2018-11-07  Tadeu Zagallo  <[email protected]>
 
+        Align wide opcodes in the instruction stream
+        https://bugs.webkit.org/show_bug.cgi?id=191254
+
+        Reviewed by Keith Miller.
+
+        Pad the bytecode with nops to ensure that wide opcodes are 4-byte
+        aligned on platforms that don't like unaligned memory access.
+
+        For that, add a new type to represent jump targets, BoundLabel, which
+        delays computing the offset in case we need to emit nops for padding.
+        Extra padding is also emitted before op_yield and at the of each
+        BytecodeWriter fragment, to ensure that the bytecode remains aligned
+        after the rewriting.
+
+        As a side effect, we can longer guarantee that the point immediately
+        before emitting an opcode is the start of that opcode, since nops
+        might be emitted in between if the opcode needs to be wide. To fix
+        that, we only take the offset of opcodes after they have been emitted,
+        using `m_lastInstruction.offset()`.
+
+        * bytecode/BytecodeDumper.h:
+        (JSC::BytecodeDumper::dumpValue):
+        * bytecode/BytecodeGeneratorification.cpp:
+        (JSC::BytecodeGeneratorification::run):
+        * bytecode/BytecodeList.rb:
+        * bytecode/BytecodeRewriter.h:
+        (JSC::BytecodeRewriter::Fragment::align):
+        (JSC::BytecodeRewriter::insertFragmentBefore):
+        (JSC::BytecodeRewriter::insertFragmentAfter):
+        * bytecode/Fits.h:
+        * bytecode/InstructionStream.h:
+        (JSC::InstructionStreamWriter::ref):
+        * bytecode/PreciseJumpTargetsInlines.h:
+        (JSC::updateStoredJumpTargetsForInstruction):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::Label::setLocation):
+        (JSC::BoundLabel::target):
+        (JSC::BoundLabel::saveTarget):
+        (JSC::BoundLabel::commitTarget):
+        (JSC::BytecodeGenerator::generate):
+        (JSC::BytecodeGenerator::recordOpcode):
+        (JSC::BytecodeGenerator::alignWideOpcode):
+        (JSC::BytecodeGenerator::emitProfileControlFlow):
+        (JSC::BytecodeGenerator::emitResolveScope):
+        (JSC::BytecodeGenerator::emitGetFromScope):
+        (JSC::BytecodeGenerator::emitPutToScope):
+        (JSC::BytecodeGenerator::emitGetById):
+        (JSC::BytecodeGenerator::emitDirectGetById):
+        (JSC::BytecodeGenerator::emitPutById):
+        (JSC::BytecodeGenerator::emitDirectPutById):
+        (JSC::BytecodeGenerator::emitGetByVal):
+        (JSC::BytecodeGenerator::emitCreateThis):
+        (JSC::BytecodeGenerator::beginSwitch):
+        (JSC::BytecodeGenerator::endSwitch):
+        (JSC::BytecodeGenerator::emitRequireObjectCoercible):
+        (JSC::BytecodeGenerator::emitYieldPoint):
+        (JSC::BytecodeGenerator::emitToThis):
+        (JSC::Label::bind): Deleted.
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::recordOpcode): Deleted.
+        * bytecompiler/Label.h:
+        (JSC::BoundLabel::BoundLabel):
+        (JSC::BoundLabel::operator int):
+        (JSC::Label::bind):
+        * generator/Opcode.rb:
+
+2018-11-07  Tadeu Zagallo  <[email protected]>
+
         REGRESSION(r237547): Test failures on 32-bit JSC since the JIT was disabled
         https://bugs.webkit.org/show_bug.cgi?id=191184
 

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeDumper.h (237932 => 237933)


--- trunk/Source/_javascript_Core/bytecode/BytecodeDumper.h	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeDumper.h	2018-11-07 19:38:14 UTC (rev 237933)
@@ -29,6 +29,7 @@
 #include "CallLinkInfo.h"
 #include "ICStatusMap.h"
 #include "InstructionStream.h"
+#include "Label.h"
 #include "StructureStubInfo.h"
 
 namespace JSC {
@@ -52,6 +53,7 @@
     }
 
     void dumpValue(VirtualRegister reg) { m_out.printf("%s", registerName(reg.offset()).data()); }
+    void dumpValue(BoundLabel label) { m_out.print(label.target()); }
     template<typename T>
     void dumpValue(T v) { m_out.print(v); }
 

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeGeneratorification.cpp (237932 => 237933)


--- trunk/Source/_javascript_Core/bytecode/BytecodeGeneratorification.cpp	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeGeneratorification.cpp	2018-11-07 19:38:14 UTC (rev 237933)
@@ -37,6 +37,7 @@
 #include "JSCInlines.h"
 #include "JSCJSValueInlines.h"
 #include "JSGeneratorFunction.h"
+#include "Label.h"
 #include "StrongInlines.h"
 #include "UnlinkedCodeBlock.h"
 #include "UnlinkedMetadataTableInlines.h"
@@ -205,7 +206,7 @@
             jumpTable.add(i + 1, m_yields[i].point);
 
         rewriter.insertFragmentBefore(nextToEnterPoint, [&](BytecodeRewriter::Fragment& fragment) {
-            fragment.appendInstruction<OpSwitchImm>(switchTableIndex, nextToEnterPoint.offset(), state);
+            fragment.appendInstruction<OpSwitchImm>(switchTableIndex, BoundLabel(nextToEnterPoint.offset()), state);
         });
     }
 

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeList.rb (237932 => 237933)


--- trunk/Source/_javascript_Core/bytecode/BytecodeList.rb	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeList.rb	2018-11-07 19:38:14 UTC (rev 237933)
@@ -25,6 +25,7 @@
     :VirtualRegister,
 
     :BasicBlockLocation,
+    :BoundLabel,
     :DebugHookType,
     :ErrorType,
     :GetByIdMode,
@@ -591,31 +592,31 @@
 
 op :jmp,
     args: {
-        target: int,
+        target: BoundLabel,
     }
 
 op :jtrue,
     args: {
         condition: VirtualRegister,
-        target: int,
+        target: BoundLabel,
     }
 
 op :jfalse,
     args: {
         condition: VirtualRegister,
-        target: int,
+        target: BoundLabel,
     }
 
 op :jeq_null,
     args: {
         value: VirtualRegister,
-        target: int,
+        target: BoundLabel,
     }
 
 op :jneq_null,
     args: {
         value: VirtualRegister,
-        target: int,
+        target: BoundLabel,
     }
 
 op :jneq_ptr,
@@ -622,7 +623,7 @@
     args: {
         value: VirtualRegister,
         specialPointer: Special::Pointer,
-        target: int,
+        target: BoundLabel,
     },
     metadata: {
         hasJumped: bool,
@@ -648,7 +649,7 @@
     args: {
         lhs: VirtualRegister,
         rhs: VirtualRegister,
-        target: int,
+        target: BoundLabel,
     }
 
 op :loop_hint
@@ -661,7 +662,7 @@
     ],
     args: {
         tableIndex: unsigned,
-        defaultOffset: int,
+        defaultOffset: BoundLabel,
         scrutinee: VirtualRegister,
     }
 

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeRewriter.h (237932 => 237933)


--- trunk/Source/_javascript_Core/bytecode/BytecodeRewriter.h	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeRewriter.h	2018-11-07 19:38:14 UTC (rev 237933)
@@ -28,6 +28,7 @@
 
 #include "BytecodeGenerator.h"
 #include "BytecodeGraph.h"
+#include "BytecodeStructs.h"
 #include "Bytecodes.h"
 #include "Opcode.h"
 #include "UnlinkedCodeBlock.h"
@@ -156,6 +157,16 @@
             });
         }
 
+        void align()
+        {
+#if CPU(NEEDS_ALIGNED_ACCESS)
+            m_bytecodeGenerator.withWriter(m_writer, [&] {
+                while (m_bytecodeGenerator.instructions().size() % OpcodeSize::Wide)
+                    OpNop::emit<OpcodeSize::Narrow>(&m_bytecodeGenerator);
+            });
+#endif
+        }
+
     private:
         BytecodeGenerator& m_bytecodeGenerator;
         InstructionStreamWriter& m_writer;
@@ -177,6 +188,7 @@
         InstructionStreamWriter writer;
         Fragment fragment(m_bytecodeGenerator, writer, includeBranch);
         function(fragment);
+        fragment.align();
         insertImpl(InsertionPoint(instruction.offset(), Position::Before), includeBranch, WTFMove(writer));
     }
 
@@ -187,6 +199,7 @@
         InstructionStreamWriter writer;
         Fragment fragment(m_bytecodeGenerator, writer, includeBranch);
         function(fragment);
+        fragment.align();
         insertImpl(InsertionPoint(instruction.offset(), Position::After), includeBranch, WTFMove(writer));
     }
 

Modified: trunk/Source/_javascript_Core/bytecode/Fits.h (237932 => 237933)


--- trunk/Source/_javascript_Core/bytecode/Fits.h	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/bytecode/Fits.h	2018-11-07 19:38:14 UTC (rev 237933)
@@ -27,6 +27,7 @@
 
 #include "GetPutInfo.h"
 #include "Interpreter.h"
+#include "Label.h"
 #include "OpcodeSize.h"
 #include "ProfileTypeBytecodeFlag.h"
 #include "ResultType.h"
@@ -293,4 +294,30 @@
     }
 };
 
+template<OpcodeSize size>
+struct Fits<BoundLabel, size> : Fits<int, size> {
+    // This is a bit hacky: we need to delay computing jump targets, since we
+    // might have to emit `nop`s to align the instructions stream. Additionally,
+    // we have to compute the target before we start writing to the instruction
+    // stream, since the offset is computed from the start of the bytecode. We
+    // achieve this by computing the target when we `check` and saving it, then
+    // later we use the saved target when we call convert.
+
+    using Base = Fits<int, size>;
+    static bool check(BoundLabel& label)
+    {
+        return Base::check(label.saveTarget());
+    }
+
+    static typename TypeBySize<size>::type convert(BoundLabel& label)
+    {
+        return Base::convert(label.commitTarget());
+    }
+
+    static BoundLabel convert(typename TypeBySize<size>::type target)
+    {
+        return BoundLabel(Base::convert(target));
+    }
+};
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/bytecode/InstructionStream.h (237932 => 237933)


--- trunk/Source/_javascript_Core/bytecode/InstructionStream.h	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/bytecode/InstructionStream.h	2018-11-07 19:38:14 UTC (rev 237933)
@@ -238,7 +238,7 @@
 
     MutableRef ref()
     {
-        return MutableRef { m_instructions, m_instructions.size() };
+        return MutableRef { m_instructions, m_position };
     }
 
     void swap(InstructionStreamWriter& other)

Modified: trunk/Source/_javascript_Core/bytecode/PreciseJumpTargetsInlines.h (237932 => 237933)


--- trunk/Source/_javascript_Core/bytecode/PreciseJumpTargetsInlines.h	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/bytecode/PreciseJumpTargetsInlines.h	2018-11-07 19:38:14 UTC (rev 237933)
@@ -140,9 +140,9 @@
         int32_t target = jumpTargetForInstruction<__op>(codeBlockOrHashMap, instruction); \
         int32_t newTarget = function(target); \
         if (newTarget != target || finalOffset) { \
-            instruction->cast<__op>()->setTarget(newTarget, [&]() { \
+            instruction->cast<__op>()->setTarget(BoundLabel(newTarget), [&]() { \
                 codeBlock->addOutOfLineJumpTarget(finalOffset + instruction.offset(), newTarget); \
-                return 0; \
+                return BoundLabel(); \
             }); \
         } \
         break; \
@@ -161,9 +161,9 @@
         int32_t target = jumpTargetForInstruction(codeBlockOrHashMap, instruction, bytecode.defaultOffset); \
         int32_t newTarget = function(target); \
         if (newTarget != target || finalOffset) { \
-            instruction->cast<__op>()->setDefaultOffset(newTarget, [&]() { \
+            instruction->cast<__op>()->setDefaultOffset(BoundLabel(newTarget), [&]() { \
                 codeBlock->addOutOfLineJumpTarget(finalOffset + instruction.offset(), newTarget); \
-                return 0; \
+                return BoundLabel(); \
             }); \
         } \
     } while (false)

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (237932 => 237933)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2018-11-07 19:38:14 UTC (rev 237933)
@@ -102,9 +102,9 @@
 
 #define CASE(__op) \
     case __op::opcodeID:  \
-        instruction->cast<__op>()->setTarget(target, [&]() { \
+        instruction->cast<__op>()->setTarget(BoundLabel(target), [&]() { \
             generator.m_codeBlock->addOutOfLineJumpTarget(instruction.offset(), target); \
-            return 0; \
+            return BoundLabel(); \
         }); \
         break;
 
@@ -136,11 +136,41 @@
     }
 }
 
-int Label::bind(BytecodeGenerator* generator)
+int BoundLabel::target()
 {
-    return bind(generator->instructions().size());
+    switch (m_type) {
+    case Offset:
+        return m_target;
+    case GeneratorBackward:
+        return m_target - m_generator->m_writer.position();
+    case GeneratorForward:
+        return 0;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
 }
 
+int BoundLabel::saveTarget()
+{
+    if (m_type == GeneratorForward) {
+        m_savedTarget = m_generator->m_writer.position();
+        return 0;
+    }
+
+    m_savedTarget = target();
+    return m_savedTarget;
+}
+
+int BoundLabel::commitTarget()
+{
+    if (m_type == GeneratorForward) {
+        m_label->m_unresolvedJumps.append(m_savedTarget);
+        return 0;
+    }
+
+    return m_savedTarget;
+}
+
 void Variable::dump(PrintStream& out) const
 {
     out.print(
@@ -216,9 +246,12 @@
     }
 
     for (auto& tuple : m_catchesToEmit) {
-        Ref<Label> realCatchTarget = newEmittedLabel();
+        Ref<Label> realCatchTarget = newLabel();
         OpCatch::emit(this, std::get<1>(tuple), std::get<2>(tuple));
+        realCatchTarget->setLocation(*this, m_lastInstruction.offset());
+        m_codeBlock->addJumpTarget(m_lastInstruction.offset());
 
+
         TryData* tryData = std::get<0>(tuple);
         emitJump(tryData->target.get());
         tryData->target = WTFMove(realCatchTarget);
@@ -1280,6 +1313,24 @@
     return label;
 }
 
+void BytecodeGenerator::recordOpcode(OpcodeID opcodeID)
+{
+    ASSERT(m_lastOpcodeID == op_end || (m_lastOpcodeID == m_lastInstruction->opcodeID() && m_writer.position() == m_lastInstruction.offset() + m_lastInstruction->size()));
+    m_lastInstruction = m_writer.ref();
+    m_lastOpcodeID = opcodeID;
+}
+
+void BytecodeGenerator::alignWideOpcode()
+{
+#if CPU(NEEDS_ALIGNED_ACCESS)
+    OpcodeID lastOpcodeID = m_lastOpcodeID;
+    m_lastOpcodeID = op_end;
+    while ((m_writer.position() + 1) % OpcodeSize::Wide)
+        OpNop::emit<OpcodeSize::Narrow>(this);
+    recordOpcode(lastOpcodeID);
+#endif
+}
+
 void BytecodeGenerator::emitLabel(Label& l0)
 {
     unsigned newLabelIndex = instructions().size();
@@ -1778,10 +1829,9 @@
 {
     if (vm()->controlFlowProfiler()) {
         RELEASE_ASSERT(textOffset >= 0);
-        size_t bytecodeOffset = instructions().size();
-        m_codeBlock->addOpProfileControlFlowBytecodeOffset(bytecodeOffset);
 
         OpProfileControlFlow::emit(this, textOffset);
+        m_codeBlock->addOpProfileControlFlowBytecodeOffset(m_lastInstruction.offset());
     }
 }
 
@@ -2395,11 +2445,9 @@
     case VarKind::Invalid:
         // Indicates non-local resolution.
         
-        m_codeBlock->addPropertyAccessInstruction(instructions().size());
-        
-        // resolve_scope dst, id, ResolveType, depth
         dst = tempDestination(dst);
         OpResolveScope::emit(this, kill(dst), scopeRegister(), addConstant(variable.ident()), resolveType(), localScopeDepth());
+        m_codeBlock->addPropertyAccessInstruction(m_lastInstruction.offset());
         return dst;
     }
     
@@ -2420,9 +2468,6 @@
         
     case VarKind::Scope:
     case VarKind::Invalid: {
-        m_codeBlock->addPropertyAccessInstruction(instructions().size());
-        
-        // get_from_scope dst, scope, id, GetPutInfo, Structure, Operand
         OpGetFromScope::emit(
             this,
             kill(dst),
@@ -2431,6 +2476,7 @@
             GetPutInfo(resolveMode, variable.offset().isScope() ? LocalClosureVar : resolveType(), InitializationMode::NotInitialization),
             localScopeDepth(),
             variable.offset().isScope() ? variable.offset().scopeOffset().offset() : 0);
+        m_codeBlock->addPropertyAccessInstruction(m_lastInstruction.offset());
         return dst;
     } }
     
@@ -2450,9 +2496,6 @@
         
     case VarKind::Scope:
     case VarKind::Invalid: {
-        m_codeBlock->addPropertyAccessInstruction(instructions().size());
-        
-        // put_to_scope scope, id, value, GetPutInfo, Structure, Operand
         GetPutInfo getPutInfo(0);
         int scopeDepth;
         ScopeOffset offset;
@@ -2466,6 +2509,7 @@
             scopeDepth = localScopeDepth();
         }
         OpPutToScope::emit(this, scope, addConstant(variable.ident()), value, getPutInfo, scopeDepth, !!offset ? offset.offset() : 0);
+        m_codeBlock->addPropertyAccessInstruction(m_lastInstruction.offset());
         return value;
     } }
     
@@ -2515,9 +2559,8 @@
 {
     ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties should be handled with get_by_val.");
 
-    m_codeBlock->addPropertyAccessInstruction(instructions().size());
-
     OpGetById::emit(this, kill(dst), base, addConstant(property));
+    m_codeBlock->addPropertyAccessInstruction(m_lastInstruction.offset());
     return dst;
 }
 
@@ -2533,9 +2576,8 @@
 {
     ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties should be handled with get_by_val_direct.");
 
-    m_codeBlock->addPropertyAccessInstruction(instructions().size());
-
     OpGetByIdDirect::emit(this, kill(dst), base, addConstant(property));
+    m_codeBlock->addPropertyAccessInstruction(m_lastInstruction.offset());
     return dst;
 }
 
@@ -2547,9 +2589,8 @@
 
     m_staticPropertyAnalyzer.putById(base, propertyIndex);
 
-    m_codeBlock->addPropertyAccessInstruction(instructions().size());
-
     OpPutById::emit(this, base, propertyIndex, value, PutByIdNone); // is not direct
+    m_codeBlock->addPropertyAccessInstruction(m_lastInstruction.offset());
 
     return value;
 }
@@ -2573,10 +2614,9 @@
 
     m_staticPropertyAnalyzer.putById(base, propertyIndex);
 
-    m_codeBlock->addPropertyAccessInstruction(instructions().size());
-    
     PutByIdFlags type = (putType == PropertyNode::KnownDirect || property != m_vm->propertyNames->underscoreProto) ? PutByIdIsDirect : PutByIdNone;
     OpPutById::emit(this, base, propertyIndex, value, type);
+    m_codeBlock->addPropertyAccessInstruction(m_lastInstruction.offset());
     return value;
 }
 
@@ -2659,33 +2699,26 @@
 
 RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
 {
-    bool forceWide = false;
     for (size_t i = m_forInContextStack.size(); i--; ) {
         ForInContext& context = m_forInContextStack[i].get();
         if (context.local() != property)
             continue;
 
-        unsigned instIndex = instructions().size();
-
         if (context.isIndexedForInContext()) {
             auto& indexedContext = context.asIndexedForInContext();
-            indexedContext.addGetInst(instIndex, property->index());
-            property = indexedContext.index();
-            forceWide = true;
-            break;
+            OpGetByVal::emit<OpcodeSize::Wide>(this, kill(dst), base, indexedContext.index());
+            indexedContext.addGetInst(m_lastInstruction.offset(), property->index());
+            return dst;
         }
 
         StructureForInContext& structureContext = context.asStructureForInContext();
         OpGetDirectPname::emit<OpcodeSize::Wide>(this, kill(dst), base, property, structureContext.index(), structureContext.enumerator());
 
-        structureContext.addGetInst(instIndex, property->index());
+        structureContext.addGetInst(m_lastInstruction.offset(), property->index());
         return dst;
     }
 
-    if (forceWide)
-        OpGetByVal::emit<OpcodeSize::Wide>(this, kill(dst), base, property);
-    else
-        OpGetByVal::emit(this, kill(dst), base, property);
+    OpGetByVal::emit(this, kill(dst), base, property);
     return dst;
 }
 
@@ -2750,8 +2783,8 @@
 {
     m_staticPropertyAnalyzer.createThis(dst, m_writer.ref());
 
-    m_codeBlock->addPropertyAccessInstruction(instructions().size());
     OpCreateThis::emit(this, dst, dst, 0);
+    m_codeBlock->addPropertyAccessInstruction(m_lastInstruction.offset());
     return dst;
 }
 
@@ -3762,24 +3795,23 @@
 
 void BytecodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type)
 {
-    SwitchInfo info = { static_cast<uint32_t>(instructions().size()), type };
     switch (type) {
     case SwitchInfo::SwitchImmediate: {
         size_t tableIndex = m_codeBlock->numberOfSwitchJumpTables();
         m_codeBlock->addSwitchJumpTable();
-        OpSwitchImm::emit(this, tableIndex, 0, scrutineeRegister);
+        OpSwitchImm::emit(this, tableIndex, BoundLabel(), scrutineeRegister);
         break;
     }
     case SwitchInfo::SwitchCharacter: {
         size_t tableIndex = m_codeBlock->numberOfSwitchJumpTables();
         m_codeBlock->addSwitchJumpTable();
-        OpSwitchChar::emit(this, tableIndex, 0, scrutineeRegister);
+        OpSwitchChar::emit(this, tableIndex, BoundLabel(), scrutineeRegister);
         break;
     }
     case SwitchInfo::SwitchString: {
         size_t tableIndex = m_codeBlock->numberOfStringSwitchJumpTables();
         m_codeBlock->addStringSwitchJumpTable();
-        OpSwitchString::emit(this, tableIndex, 0, scrutineeRegister);
+        OpSwitchString::emit(this, tableIndex, BoundLabel(), scrutineeRegister);
         break;
     }
     default:
@@ -3786,6 +3818,7 @@
         RELEASE_ASSERT_NOT_REACHED();
     }
 
+    SwitchInfo info = { m_lastInstruction.offset(), type };
     m_switchContextStack.append(info);
 }
 
@@ -3848,11 +3881,11 @@
     SwitchInfo switchInfo = m_switchContextStack.last();
     m_switchContextStack.removeLast();
 
-    int defaultTarget = defaultLabel.bind(switchInfo.bytecodeOffset);
+    BoundLabel defaultTarget = defaultLabel.bind(switchInfo.bytecodeOffset);
     auto handleSwitch = [&](auto* op, auto bytecode) {
         op->setDefaultOffset(defaultTarget, [&]() {
             m_codeBlock->addOutOfLineJumpTarget(switchInfo.bytecodeOffset, defaultTarget);
-            return 0;
+            return BoundLabel();
         });
 
         UnlinkedSimpleJumpTable& jumpTable = m_codeBlock->switchJumpTable(bytecode.tableIndex);
@@ -3877,7 +3910,7 @@
     case SwitchInfo::SwitchString: {
         ref->cast<OpSwitchString>()->setDefaultOffset(defaultTarget, [&]() {
             m_codeBlock->addOutOfLineJumpTarget(switchInfo.bytecodeOffset, defaultTarget);
-            return 0;
+            return BoundLabel();
         });
 
         UnlinkedStringJumpTable& jumpTable = m_codeBlock->stringSwitchJumpTable(ref->as<OpSwitchString>().tableIndex);
@@ -4360,8 +4393,7 @@
     // FIXME: op_jneq_null treats "undetectable" objects as null/undefined. RequireObjectCoercible
     // thus incorrectly throws a TypeError for interfaces like HTMLAllCollection.
     Ref<Label> target = newLabel();
-    size_t begin = instructions().size();
-    OpJneqNull::emit(this, value, target->bind(begin));
+    OpJneqNull::emit(this, value, target->bind(this));
     emitThrowTypeError(error);
     emitLabel(target.get());
 }
@@ -4392,6 +4424,13 @@
     Vector<TryContext> savedTryContextStack;
     m_tryContextStack.swap(savedTryContextStack);
 
+
+#if CPU(NEEDS_ALIGNED_ACCESS)
+    // conservatively align for the bytecode rewriter: it will delete this yield and
+    // append a fragment, so we make sure that the start of the fragments is aligned
+    while (m_writer.position() % OpcodeSize::Wide)
+        OpNop::emit<OpcodeSize::Narrow>(this);
+#endif
     OpYield::emit(this, generatorFrameRegister(), yieldPointIndex, argument);
 
     // Restore the try contexts, which start offset is updated to the merge point.
@@ -4863,8 +4902,8 @@
 
 void BytecodeGenerator::emitToThis()
 {
-    m_codeBlock->addPropertyAccessInstruction(instructions().size());
     OpToThis::emit(this, kill(&m_thisRegister));
+    m_codeBlock->addPropertyAccessInstruction(m_lastInstruction.offset());
 }
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (237932 => 237933)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2018-11-07 19:38:14 UTC (rev 237933)
@@ -363,6 +363,7 @@
         WTF_MAKE_FAST_ALLOCATED;
         WTF_MAKE_NONCOPYABLE(BytecodeGenerator);
 
+        friend class BoundLabel;
         friend class Label;
         friend class IndexedForInContext;
         friend class StructureForInContext;
@@ -506,12 +507,7 @@
             n->emitBytecode(*this, dst);
         }
 
-        void recordOpcode(OpcodeID opcodeID)
-        {
-            ASSERT(m_lastOpcodeID == op_end || m_writer.size() == m_lastInstruction.offset() + m_lastInstruction->size());
-            m_lastInstruction = m_writer.ref();
-            m_lastOpcodeID = opcodeID;
-        }
+        void recordOpcode(OpcodeID);
 
         ALWAYS_INLINE unsigned addMetadataFor(OpcodeID opcodeID)
         {
@@ -1185,6 +1181,7 @@
 
         void write(uint8_t byte) { m_writer.write(byte); }
         void write(uint32_t i) { m_writer.write(i); }
+        void alignWideOpcode();
 
         class PreservedTDZStack {
         private:

Modified: trunk/Source/_javascript_Core/bytecompiler/Label.h (237932 => 237933)


--- trunk/Source/_javascript_Core/bytecompiler/Label.h	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/bytecompiler/Label.h	2018-11-07 19:38:14 UTC (rev 237933)
@@ -35,7 +35,56 @@
 
 namespace JSC {
     class BytecodeGenerator;
+    class Label;
 
+    class BoundLabel {
+    public:
+        BoundLabel()
+            : m_type(Offset)
+            , m_generator(nullptr)
+            , m_target(0)
+        { }
+
+        explicit BoundLabel(int target)
+            : m_type(Offset)
+            , m_generator(nullptr)
+            , m_target(target)
+        { }
+
+        BoundLabel(BytecodeGenerator* generator, Label* label)
+            : m_type(GeneratorForward)
+            , m_generator(generator)
+            , m_label(label)
+        { }
+
+        BoundLabel(BytecodeGenerator* generator, int offset)
+            : m_type(GeneratorBackward)
+            , m_generator(generator)
+            , m_target(offset)
+        { }
+
+        int target();
+        int saveTarget();
+        int commitTarget();
+
+        operator int() { return target(); }
+
+    private:
+        enum Type : uint8_t {
+            Offset,
+            GeneratorForward,
+            GeneratorBackward,
+        };
+
+        Type m_type;
+        int m_savedTarget { 0 };
+        BytecodeGenerator* m_generator;
+        union {
+            Label* m_label;
+            int m_target;
+        };
+    };
+
     class Label {
     WTF_MAKE_NONCOPYABLE(Label);
     public:
@@ -43,18 +92,24 @@
 
         void setLocation(BytecodeGenerator&, unsigned);
 
-        int bind(BytecodeGenerator*);
+        BoundLabel bind(BytecodeGenerator* generator)
+        {
+            m_bound = true;
+            if (!isForward())
+                return BoundLabel(generator, m_location);
+            return BoundLabel(generator, this);
+        }
 
-        int bind(unsigned offset)
+        BoundLabel bind(unsigned offset)
         {
             m_bound = true;
             if (!isForward())
-                return m_location - offset;
+                return BoundLabel(m_location - offset);
             m_unresolvedJumps.append(offset);
-            return 0;
+            return BoundLabel();
         }
 
-        int bind()
+        BoundLabel bind()
         {
             ASSERT(!isForward());
             return bind(0u);
@@ -74,6 +129,8 @@
         bool isBound() const { return m_bound; }
 
     private:
+        friend class BoundLabel;
+
         typedef Vector<int, 8> JumpVector;
 
         static const unsigned invalidLocation = UINT_MAX;

Modified: trunk/Source/_javascript_Core/generator/Opcode.rb (237932 => 237933)


--- trunk/Source/_javascript_Core/generator/Opcode.rb	2018-11-07 19:33:54 UTC (rev 237932)
+++ trunk/Source/_javascript_Core/generator/Opcode.rb	2018-11-07 19:38:14 UTC (rev 237933)
@@ -118,7 +118,7 @@
         {
             __generator->recordOpcode(opcodeID);
             #{@metadata.create_emitter_local}
-            emit<OpcodeSize::Narrow, NoAssert>(__generator#{untyped_args}#{metadata_arg}) || emit<OpcodeSize::Wide>(__generator#{untyped_args}#{metadata_arg});
+            emit<OpcodeSize::Narrow, NoAssert, false>(__generator#{untyped_args}#{metadata_arg}) || emit<OpcodeSize::Wide, Assert, false>(__generator#{untyped_args}#{metadata_arg});
         }
 
         #{%{
@@ -125,15 +125,16 @@
         template<OpcodeSize size, FitsAssertion shouldAssert = Assert>
         static bool emit(BytecodeGenerator* __generator#{typed_args})
         {
-            __generator->recordOpcode(opcodeID);
             #{@metadata.create_emitter_local}
             return emit<size, shouldAssert>(__generator#{untyped_args}#{metadata_arg});
         }
         } unless @metadata.empty?}
 
-        template<OpcodeSize size, FitsAssertion shouldAssert = Assert>
+        template<OpcodeSize size, FitsAssertion shouldAssert = Assert, bool recordOpcode = true>
         static bool emit(BytecodeGenerator* __generator#{typed_args}#{metadata_param})
         {
+            if (recordOpcode)
+                __generator->recordOpcode(opcodeID);
             bool didEmit = emitImpl<size>(__generator#{untyped_args}#{metadata_arg});
             if (shouldAssert == Assert)
                 ASSERT(didEmit);
@@ -144,10 +145,11 @@
         template<OpcodeSize size>
         static bool emitImpl(BytecodeGenerator* __generator#{typed_args}#{metadata_param})
         {
+            if (size == OpcodeSize::Wide)
+                __generator->alignWideOpcode();
             if (#{map_fields_with_size("size", &:fits_check).join " && "} && (size == OpcodeSize::Wide ? #{op_wide.fits_check(Size::Narrow)} : true)) {
-                if (size == OpcodeSize::Wide) {
+                if (size == OpcodeSize::Wide)
                     #{op_wide.fits_write Size::Narrow}
-                }
                 #{map_fields_with_size("size", &:fits_write).join "\n"}
                 return true;
             }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to