From 55e65b46f648eff8e7c1d6a921f9907d26254dc7 Mon Sep 17 00:00:00 2001 From: Dmitry Kashitsyn Date: Mon, 16 May 2016 11:19:19 +0600 Subject: [PATCH] Fixes analyzer and context, adds handling of conditional branches Issue: #17 --- include/inference.h | 32 +++++++++---------- src/TypeAnalyzer.cpp | 74 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 77 insertions(+), 29 deletions(-) diff --git a/include/inference.h b/include/inference.h index 6e5c920..1cf8964 100644 --- a/include/inference.h +++ b/include/inference.h @@ -30,8 +30,8 @@ class Type { std::string toString() const; Type(TKind kind = tkUndefined) : m_kind(kind), m_value(0) {} - Type(TObject* literal) { set(literal); } - Type(TClass* klass) { set(klass); } + Type(TObject* literal, TKind kind = tkLiteral) { set(literal, kind); } + Type(TClass* klass, TKind kind = tkMonotype) { set(klass, kind); } void setKind(TKind kind) { m_kind = kind; } TKind getKind() const { return m_kind; } @@ -65,15 +65,13 @@ class Type { TSubTypes m_subTypes; }; -typedef std::vector TTypeList; +typedef std::size_t TNodeIndex; +typedef std::map TTypeList; class CallContext { public: - CallContext(std::size_t index, const Type& arguments, std::size_t nodeCount) - : m_index(index), m_arguments(arguments) - { - m_instructions.resize(nodeCount); - } + CallContext(std::size_t index, const Type& arguments) + : m_index(index), m_arguments(arguments) {} std::size_t getIndex() const { return m_index; } @@ -86,11 +84,12 @@ class CallContext { return polytype; } const Type& getArguments() const { return m_arguments; } + const TTypeList& getTypeList() const { return m_instructions; } Type& getReturnType() { return m_returnType; } - Type& getInstructionType(std::size_t index) { return m_instructions[index]; } - Type& operator[] (std::size_t index) { return m_instructions[index]; } + Type& getInstructionType(TNodeIndex index) { return m_instructions[index]; } + Type& operator[] (TNodeIndex index) { return m_instructions[index]; } Type& operator[] (const ControlNode& node) { return getInstructionType(node.getIndex()); } private: @@ -110,20 +109,15 @@ class TypeSystem { class TypeAnalyzer { public: TypeAnalyzer(ControlGraph& graph, CallContext& context) - : m_graph(graph), m_context(context) {} + : m_graph(graph), m_context(context), m_walker(*this) {} void run() { if (m_graph.isEmpty()) return; - Walker walker(*this); - walker.run(*m_graph.nodes_begin(), Walker::wdForward); + m_walker.run(*m_graph.nodes_begin(), Walker::wdForward); } -private: - ControlGraph& m_graph; - CallContext& m_context; - private: void processInstruction(const InstructionNode& instruction); void processPhi(const PhiNode& phi); @@ -169,6 +163,10 @@ class TypeAnalyzer { TypeAnalyzer& analyzer; }; +private: + ControlGraph& m_graph; + CallContext& m_context; + Walker m_walker; }; } // namespace type diff --git a/src/TypeAnalyzer.cpp b/src/TypeAnalyzer.cpp index 638c859..6bcd31c 100644 --- a/src/TypeAnalyzer.cpp +++ b/src/TypeAnalyzer.cpp @@ -21,7 +21,11 @@ std::string Type::toString() const { else if (getValue()->getClass() == globals.stringClass) stream << "'" << getValue()->cast()->toString() << "'"; else if (getValue()->getClass() == globals.badMethodSymbol->getClass()) - stream << "'" << getValue()->cast()->toString() << "'"; + stream << "#" << getValue()->cast()->toString(); + else if (getValue()->getClass()->name->toString().find("Meta", 0, 4) != std::string::npos) + stream << getValue()->cast()->name->toString(); + else + stream << "~" << getValue()->getClass()->name->toString(); break; case tkMonotype: @@ -48,6 +52,8 @@ std::string Type::toString() const { } void TypeAnalyzer::processInstruction(const InstructionNode& instruction) { + std::printf("processing %.2u\n", instruction.getIndex()); + const TSmalltalkInstruction::TArgument argument = instruction.getInstruction().getArgument(); switch (instruction.getInstruction().getOpcode()) { @@ -59,13 +65,61 @@ void TypeAnalyzer::processInstruction(const InstructionNode& instruction) { case opcode::pushLiteral: doPushLiteral(instruction); break; case opcode::markArguments: doMarkArguments(instruction); break; + case opcode::sendUnary: doSendUnary(instruction); break; case opcode::sendBinary: doSendBinary(instruction); break; + case opcode::assignTemporary: + m_context[instruction.getTauNode()->getIndex()] = m_context[*instruction.getArgument()]; + break; + case opcode::sendMessage: // For now, treat method call as * m_context[instruction] = Type(Type::tkPolytype); break; + case opcode::doPrimitive: + m_context.getReturnType().addSubType(Type(Type::tkPolytype)); + break; + + case opcode::doSpecial: { + switch (argument) { + case special::branchIfFalse: + case special::branchIfTrue: { + const bool branchIfTrue = (argument == special::branchIfTrue); + + const Type& argType = m_context[*instruction.getArgument()]; + const BranchNode* const branch = instruction.cast(); + + if (argType.getValue() == globals.trueObject || argType.getValue() == globals.trueObject->getClass()) + m_walker.addStopNode(branchIfTrue ? branch->getSkipNode() : branch->getTargetNode()); + else if (argType.getValue() == globals.falseObject || argType.getValue() == globals.falseObject->getClass()) + m_walker.addStopNode(branchIfTrue ? branch->getTargetNode() : branch->getSkipNode()); + + break; + } + + case special::stackReturn: + m_context.getReturnType().addSubType(m_context[*instruction.getArgument()]); + break; + + case special::selfReturn: + m_context.getReturnType().addSubType(m_context.getArgument(0)); + break; + + case special::sendToSuper: + // For now, treat method call as * + m_context[instruction] = Type(Type::tkPolytype); + break; + + case special::duplicate: + m_context[instruction] = m_context[*instruction.getArgument()]; + break; + } + + break; + } + + default: break; } @@ -130,7 +184,7 @@ void TypeAnalyzer::doSendUnary(const InstructionNode& instruction) { default: // * isNil = (Boolean) // * notNil = (Boolean) - result.set(globals.trueObject->getClass()->getClass()); + result.set(globals.trueObject->getClass()->parentClass); } } @@ -142,7 +196,7 @@ void TypeAnalyzer::doSendBinary(const InstructionNode& instruction) { Type& result = m_context[instruction]; - if (isSmallInteger(type1.getValue()) && isSmallInteger(type1.getValue())) { + if (isSmallInteger(type1.getValue()) && isSmallInteger(type2.getValue())) { const int32_t rightOperand = TInteger(type2.getValue()); const int32_t leftOperand = TInteger(type1.getValue()); @@ -175,7 +229,7 @@ void TypeAnalyzer::doSendBinary(const InstructionNode& instruction) { case binaryBuiltIns::operatorLess: case binaryBuiltIns::operatorLessOrEq: // (SmallInt) <= (SmallInt) = (Boolean) - result.set(globals.trueObject->getClass()->getClass()); + result.set(globals.trueObject->getClass()->parentClass); break; case binaryBuiltIns::operatorPlus: @@ -197,17 +251,13 @@ void TypeAnalyzer::doSendBinary(const InstructionNode& instruction) { } void TypeAnalyzer::doMarkArguments(const InstructionNode& instruction) { - const Type& argsType = m_context[*instruction.getArgument()]; Type& result = m_context[instruction]; - if (argsType.getKind() == Type::tkUndefined || argsType.getKind() == Type::tkPolytype) { - result.set(globals.arrayClass); - return; + for (std::size_t index = 0; index < instruction.getArgumentsCount(); index++) { + const Type& argsType = m_context[*instruction.getArgument(index)]; + result.addSubType(argsType); } - for (std::size_t index = 0; index < argsType.getSubTypes().size(); index++) - result.addSubType(argsType[index]); - result.set(globals.arrayClass, Type::tkArray); } @@ -228,5 +278,5 @@ void TypeAnalyzer::processTau(const TauNode& tau) { } void TypeAnalyzer::walkComplete() { - + std::printf("walk complete\n"); }