summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/bytecode/BytecodeRewriter.h
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/bytecode/BytecodeRewriter.h
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/bytecode/BytecodeRewriter.h')
-rw-r--r--Source/JavaScriptCore/bytecode/BytecodeRewriter.h235
1 files changed, 235 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/bytecode/BytecodeRewriter.h b/Source/JavaScriptCore/bytecode/BytecodeRewriter.h
new file mode 100644
index 000000000..035f900a7
--- /dev/null
+++ b/Source/JavaScriptCore/bytecode/BytecodeRewriter.h
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "BytecodeGraph.h"
+#include "Bytecodes.h"
+#include "Opcode.h"
+#include "UnlinkedCodeBlock.h"
+#include <wtf/Insertion.h>
+
+namespace JSC {
+
+// BytecodeRewriter offers the ability to insert and remove the bytecodes including jump operations.
+//
+// We use the original bytecode offsets as labels. When you emit some jumps, you can specify the jump target by
+// using the original bytecode offsets. These bytecode offsets are later converted appropriate values by the
+// rewriter. And we also use the labels to represents the position the new bytecodes inserted.
+//
+// | [bytecode] | [bytecode] |
+// offsets A B C
+//
+// We can use the above "A", "B", and "C" offsets as labels. And the rewriter has the ability to insert bytecode fragments
+// before and after the label. For example, if you insert the fragment after "B", the layout becomes like this.
+//
+// | [bytecode] | [fragment] [bytecode] |
+// offsets A B C
+//
+// And even if you remove some original bytecodes, the offset remains as labels. For example, when you remove the A's bytecode,
+// the layout becomes like this.
+//
+// | | [bytecode] |
+// offsets A B C
+//
+// And still you can insert fragments before and after "A".
+//
+// | [fragment] | [bytecode] |
+// offsets A B C
+//
+// We can insert bytecode fragments "Before" and "After" the labels. This inserted position, either "Before" and "After",
+// has effect when the label is involved with jumps. For example, when you have jump to the position "B",
+//
+// | [bytecode] | [bytecode] |
+// offsets A B C
+// ^
+// jump to here.
+//
+// and you insert the bytecode before/after "B",
+//
+// | [bytecode] [before] | [after] [bytecode] |
+// offsets A B C
+// ^
+// jump to here.
+//
+// as you can see, the execution jumping into "B" does not execute [before] code.
+class BytecodeRewriter {
+WTF_MAKE_NONCOPYABLE(BytecodeRewriter);
+public:
+ enum class Position : int8_t {
+ EntryPoint = -2,
+ Before = -1,
+ LabelPoint = 0,
+ After = 1,
+ OriginalBytecodePoint = 2,
+ };
+
+ enum class IncludeBranch : uint8_t {
+ No = 0,
+ Yes = 1,
+ };
+
+ struct InsertionPoint {
+ int bytecodeOffset;
+ Position position;
+
+ InsertionPoint(int offset, Position pos)
+ : bytecodeOffset(offset)
+ , position(pos)
+ {
+ }
+
+ bool operator<(const InsertionPoint& other) const
+ {
+ if (bytecodeOffset == other.bytecodeOffset)
+ return position < other.position;
+ return bytecodeOffset < other.bytecodeOffset;
+ }
+
+ bool operator==(const InsertionPoint& other) const
+ {
+ return bytecodeOffset == other.bytecodeOffset && position == other.position;
+ }
+ };
+
+private:
+ struct Insertion {
+ enum class Type : uint8_t { Insert = 0, Remove = 1, };
+
+ size_t length() const
+ {
+ if (type == Type::Remove)
+ return removeLength;
+ return instructions.size();
+ }
+
+ InsertionPoint index;
+ Type type;
+ IncludeBranch includeBranch;
+ size_t removeLength;
+ Vector<UnlinkedInstruction> instructions;
+ };
+
+public:
+ class Fragment {
+ WTF_MAKE_NONCOPYABLE(Fragment);
+ public:
+ Fragment(Vector<UnlinkedInstruction>& fragment, IncludeBranch& includeBranch)
+ : m_fragment(fragment)
+ , m_includeBranch(includeBranch)
+ {
+ }
+
+ template<class... Args>
+ void appendInstruction(OpcodeID opcodeID, Args... args)
+ {
+ if (isBranch(opcodeID))
+ m_includeBranch = IncludeBranch::Yes;
+
+ UnlinkedInstruction instructions[sizeof...(args) + 1] = {
+ UnlinkedInstruction(opcodeID),
+ UnlinkedInstruction(args)...
+ };
+ m_fragment.append(instructions, sizeof...(args) + 1);
+ }
+
+ private:
+ Vector<UnlinkedInstruction>& m_fragment;
+ IncludeBranch& m_includeBranch;
+ };
+
+ BytecodeRewriter(BytecodeGraph<UnlinkedCodeBlock>& graph)
+ : m_graph(graph)
+ {
+ }
+
+ template<class Function>
+ void insertFragmentBefore(unsigned bytecodeOffset, Function function)
+ {
+ IncludeBranch includeBranch = IncludeBranch::No;
+ Vector<UnlinkedInstruction> instructions;
+ Fragment fragment(instructions, includeBranch);
+ function(fragment);
+ insertImpl(InsertionPoint(bytecodeOffset, Position::Before), includeBranch, WTFMove(instructions));
+ }
+
+ template<class Function>
+ void insertFragmentAfter(unsigned bytecodeOffset, Function function)
+ {
+ IncludeBranch includeBranch = IncludeBranch::No;
+ Vector<UnlinkedInstruction> instructions;
+ Fragment fragment(instructions, includeBranch);
+ function(fragment);
+ insertImpl(InsertionPoint(bytecodeOffset, Position::After), includeBranch, WTFMove(instructions));
+ }
+
+ void removeBytecode(unsigned bytecodeOffset)
+ {
+ m_insertions.append(Insertion { InsertionPoint(bytecodeOffset, Position::OriginalBytecodePoint), Insertion::Type::Remove, IncludeBranch::No, opcodeLength(m_graph.instructions()[bytecodeOffset].u.opcode), { } });
+ }
+
+ void execute();
+
+ BytecodeGraph<UnlinkedCodeBlock>& graph() { return m_graph; }
+
+ int adjustAbsoluteOffset(int absoluteOffset)
+ {
+ return adjustJumpTarget(InsertionPoint(0, Position::EntryPoint), InsertionPoint(absoluteOffset, Position::LabelPoint));
+ }
+
+ int adjustJumpTarget(int originalBytecodeOffset, int originalJumpTarget)
+ {
+ return adjustJumpTarget(InsertionPoint(originalBytecodeOffset, Position::LabelPoint), InsertionPoint(originalJumpTarget, Position::LabelPoint));
+ }
+
+private:
+ void insertImpl(InsertionPoint, IncludeBranch, Vector<UnlinkedInstruction>&& fragment);
+
+ friend class UnlinkedCodeBlock;
+ void applyModification();
+ void adjustJumpTargetsInFragment(unsigned finalOffset, Insertion&);
+
+ int adjustJumpTarget(InsertionPoint startPoint, InsertionPoint jumpTargetPoint);
+ template<typename Iterator> int calculateDifference(Iterator begin, Iterator end);
+
+ BytecodeGraph<UnlinkedCodeBlock>& m_graph;
+ Vector<Insertion, 8> m_insertions;
+};
+
+template<typename Iterator>
+inline int BytecodeRewriter::calculateDifference(Iterator begin, Iterator end)
+{
+ int result = 0;
+ for (; begin != end; ++begin) {
+ if (begin->type == Insertion::Type::Remove)
+ result -= begin->length();
+ else
+ result += begin->length();
+ }
+ return result;
+}
+
+} // namespace JSC