summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/b3/air/AirDumpAsJS.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/b3/air/AirDumpAsJS.cpp')
-rw-r--r--Source/JavaScriptCore/b3/air/AirDumpAsJS.cpp245
1 files changed, 245 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/b3/air/AirDumpAsJS.cpp b/Source/JavaScriptCore/b3/air/AirDumpAsJS.cpp
new file mode 100644
index 000000000..3d8d6fb41
--- /dev/null
+++ b/Source/JavaScriptCore/b3/air/AirDumpAsJS.cpp
@@ -0,0 +1,245 @@
+/*
+ * 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. ``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
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AirDumpAsJS.h"
+
+#if ENABLE(B3_JIT)
+
+#include "AirCode.h"
+#include "AirInstInlines.h"
+
+namespace JSC { namespace B3 { namespace Air {
+
+namespace {
+
+CString varNameForBlockAtIndex(unsigned index)
+{
+ return toCString("bb", index);
+}
+
+CString varName(BasicBlock* block)
+{
+ return varNameForBlockAtIndex(block->index());
+}
+
+CString varNameForStackSlotAtIndex(unsigned index)
+{
+ return toCString("slot", index);
+}
+
+CString varName(StackSlot* slot)
+{
+ return varNameForStackSlotAtIndex(slot->index());
+}
+
+CString varName(Reg reg)
+{
+ return toCString("Reg.", reg.debugName());
+}
+
+CString varNameForTmpWithTypeAndIndex(Arg::Type type, unsigned index)
+{
+ return toCString(type == Arg::FP ? "f" : "", "tmp", index);
+}
+
+CString varName(Tmp tmp)
+{
+ if (tmp.isReg())
+ return varName(tmp.reg());
+ return varNameForTmpWithTypeAndIndex(Arg(tmp).type(), tmp.tmpIndex());
+}
+
+} // anonymous namespace
+
+void dumpAsJS(Code& code, PrintStream& out)
+{
+ out.println("let code = new Code();");
+
+ for (unsigned i = 0; i < code.size(); ++i)
+ out.println("let ", varNameForBlockAtIndex(i), " = code.addBlock();");
+
+ out.println("let hash;");
+
+ for (unsigned i = 0; i < code.stackSlots().size(); ++i) {
+ StackSlot* slot = code.stackSlots()[i];
+ if (slot) {
+ out.println("let ", varName(slot), " = code.addStackSlot(", slot->byteSize(), ", ", slot->kind(), ");");
+ if (slot->offsetFromFP())
+ out.println(varName(slot), ".setOffsetFromFP(", slot->offsetFromFP(), ");");
+ out.println("hash = ", varName(slot), ".hash();");
+ out.println("if (hash != ", slot->jsHash(), ")");
+ out.println(" throw new Error(\"Bad hash: \" + hash);");
+ } else
+ out.println("code.addStackSlot(1, Spill);");
+ }
+
+ Arg::forEachType(
+ [&] (Arg::Type type) {
+ for (unsigned i = code.numTmps(type); i--;) {
+ out.println(
+ "let ", varNameForTmpWithTypeAndIndex(type, i), " = code.newTmp(", type, ");");
+ }
+ });
+
+ out.println("let inst;");
+ out.println("let arg;");
+
+ for (BasicBlock* block : code) {
+ for (FrequentedBlock successor : block->successors()) {
+ out.println(
+ varName(block), ".successors.push(new FrequentedBlock(",
+ varName(successor.block()), ", ", successor.frequency(), "));");
+ }
+
+ for (BasicBlock* predecessor : block->predecessors())
+ out.println(varName(block), ".predecessors.push(", varName(predecessor), ");");
+
+ for (Inst& inst : *block) {
+ // FIXME: This should do something for flags.
+ // https://bugs.webkit.org/show_bug.cgi?id=162751
+ out.println("inst = new Inst(", inst.kind.opcode, ");");
+
+ inst.forEachArg(
+ [&] (Arg& arg, Arg::Role, Arg::Type, Arg::Width) {
+ switch (arg.kind()) {
+ case Arg::Invalid:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+
+ case Arg::Tmp:
+ out.println("arg = Arg.createTmp(", varName(arg.tmp()), ");");
+ break;
+
+ case Arg::Imm:
+ out.println("arg = Arg.createImm(", arg.value(), ");");
+ break;
+
+ case Arg::BigImm:
+ out.println(
+ "arg = Arg.createBigImm(",
+ static_cast<int32_t>(arg.value()), ", ",
+ static_cast<int32_t>(arg.value() >> 32), ");");
+ break;
+
+ case Arg::BitImm:
+ out.println("arg = Arg.createBitImm(", arg.value(), ");");
+ break;
+
+ case Arg::BitImm64:
+ out.println(
+ "arg = Arg.createBitImm64(",
+ static_cast<int32_t>(arg.value()), ", ",
+ static_cast<int32_t>(arg.value() >> 32), ");");
+ break;
+
+ case Arg::Addr:
+ out.println(
+ "arg = Arg.createAddr(", varName(arg.base()), ", ", arg.offset(), ");");
+ break;
+
+ case Arg::Stack:
+ out.println(
+ "arg = Arg.createStack(", varName(arg.stackSlot()), ", ", arg.offset(), ");");
+ break;
+
+ case Arg::CallArg:
+ out.println("arg = Arg.createCallArg(", arg.offset(), ");");
+ break;
+
+ case Arg::Index:
+ out.println(
+ "arg = Arg.createIndex(", varName(arg.base()), ", ",
+ varName(arg.index()), ", ", arg.scale(), ", ", arg.offset(), ");");
+ break;
+
+ case Arg::RelCond:
+ out.println("arg = Arg.createRelCond(", arg.asRelationalCondition(), ");");
+ break;
+
+ case Arg::ResCond:
+ out.println("arg = Arg.createResCond(", arg.asResultCondition(), ");");
+ break;
+
+ case Arg::DoubleCond:
+ out.println("arg = Arg.createDoubleCond(", arg.asDoubleCondition(), ");");
+ break;
+
+ case Arg::Special:
+ out.println("arg = Arg.createSpecial();");
+ break;
+
+ case Arg::WidthArg:
+ out.println("arg = Arg.createWidthArg(", arg.width(), ");");
+ break;
+ }
+
+ out.println("inst.args.push(arg);");
+ });
+
+ if (inst.kind.opcode == Patch) {
+ if (inst.hasNonArgEffects())
+ out.println("inst.patchHasNonArgEffects = true;");
+
+ out.println("inst.extraEarlyClobberedRegs = new Set();");
+ out.println("inst.extraClobberedRegs = new Set();");
+ inst.extraEarlyClobberedRegs().forEach(
+ [&] (Reg reg) {
+ out.println("inst.extraEarlyClobberedRegs.add(", varName(reg), ");");
+ });
+ inst.extraClobberedRegs().forEach(
+ [&] (Reg reg) {
+ out.println("inst.extraClobberedRegs.add(", varName(reg), ");");
+ });
+
+ out.println("inst.patchArgData = [];");
+ inst.forEachArg(
+ [&] (Arg&, Arg::Role role, Arg::Type type, Arg::Width width) {
+ out.println(
+ "inst.patchArgData.push({role: Arg.", role, ", type: ", type,
+ ", width: ", width, "});");
+ });
+ }
+
+ if (inst.kind.opcode == CCall || inst.kind.opcode == ColdCCall) {
+ out.println("inst.cCallType = ", inst.origin->type());
+ out.println("inst.cCallArgTypes = [];");
+ for (unsigned i = 1; i < inst.origin->numChildren(); ++i)
+ out.println("inst.cCallArgTypes.push(", inst.origin->child(i)->type(), ");");
+ }
+
+ out.println("hash = inst.hash();");
+ out.println("if (hash != ", inst.jsHash(), ")");
+ out.println(" throw new Error(\"Bad hash: \" + hash);");
+
+ out.println(varName(block), ".append(inst);");
+ }
+ }
+}
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(B3_JIT)
+