Skip to content

Commit

Permalink
Merge pull request #2 from fernandezseb/feature/instanceof
Browse files Browse the repository at this point in the history
Implement instanceof instruction
  • Loading branch information
fernandezseb authored Jan 27, 2024
2 parents 958ba14 + c741bd7 commit c705569
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 60 deletions.
14 changes: 13 additions & 1 deletion src/Data/Class.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "Data/Variable.h"

#include <span>
#include <string_view>

class FieldInfo {
public:
Expand Down Expand Up @@ -83,7 +84,18 @@ class ClassInfo {
uint16_t staticFieldsCount; // Total amount of static fields
public:
[[nodiscard]] bool isPublic() const {
return ((accessFlags & ACC_PUBLIC) != 0);
return (accessFlags & ACC_PUBLIC) != 0;
}

[[nodiscard]] bool isInterface() const
{
return (accessFlags & ACC_INTERFACE) != 0;
}

[[nodiscard]] bool isArrayType() const
{
const std::string_view name = getName();
return name.starts_with('[');
}

[[nodiscard]] MethodInfo* findMethodWithNameAndDescriptor(const char* name, const char* descriptor) const
Expand Down
4 changes: 2 additions & 2 deletions src/Library/java/lang/Class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ JCALL void lib_java_lang_Class_getPrimitiveClass(NATIVE_ARGS)
const StackFrame* currentFrame = thread->m_currentFrame;
const Variable var = currentFrame->localVariables[0];
VM->checkType(var, VariableType_REFERENCE, thread);
Object* strObject = heap->getObject(var.data);
const Object* strObject = heap->getObject(var.data);
u4 arrayRefId = strObject->fields[0].data->data;
Array* array = heap->getArray(arrayRefId);
const Array* array = heap->getArray(arrayRefId);
auto typeString = std::string_view{reinterpret_cast<char*>(array->data), array->length};
u4 classRef = 0;
if (typeString == "float")
Expand Down
2 changes: 1 addition & 1 deletion src/Library/java/security/AccessController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ void lib_java_security_AccessController_doPriviliged(NATIVE_ARGS)
{
StackFrame* currentFrame = thread->m_currentFrame;
Variable objectVar = currentFrame->localVariables[0];
Object* method = heap->getObject(currentFrame->localVariables[0].data);
const Object* method = heap->getObject(currentFrame->localVariables[0].data);
MethodInfo* methodInfo = method->classInfo->findMethodWithNameAndDescriptor("run", "()Ljava/lang/Object;");
ClassInfo* classInfo = method->classInfo;

Expand Down
69 changes: 66 additions & 3 deletions src/VM/Instructions/ReferenceInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ void getfield(INSTRUCTION_ARGS)
}
else
{
Object* object = heap->getChildObject(referencePointer.data, targetClass);
const Object* object = heap->getChildObject(referencePointer.data, targetClass);
FieldData* field = object->getField(fieldName, fieldDescr, heap);
if (field == 0)
{
Expand Down Expand Up @@ -143,7 +143,7 @@ void putfield(INSTRUCTION_ARGS)
}
Variable referencePointer = thread->m_currentFrame->popOperand();

Object* targetObject = heap->getChildObject(referencePointer.data, targetClass);
const Object* targetObject = heap->getChildObject(referencePointer.data, targetClass);

FieldData* fieldData = targetObject->getField(fieldName, fieldDescr, heap);

Expand Down Expand Up @@ -185,7 +185,7 @@ static void invokeVirtual(ClassInfo* classInfo, MethodInfo* methodInfo, VMThread
}

// Look for method based on the object
Object* object = heap->getObject(ref.data);
const Object* object = heap->getObject(ref.data);
targetClass = object->classInfo;
MethodInfo* foundMethod = targetClass->findMethodWithNameAndDescriptor(methodInfo->name,
classInfo->constantPool->getString(methodInfo->descriptorIndex));
Expand Down Expand Up @@ -420,6 +420,69 @@ void checkCast(INSTRUCTION_ARGS) {
// TODO: Implement actual type check
}

void instanceof(INSTRUCTION_ARGS)
{
const u2 index = combineBytes(args[0], args[1]);
const CPClassInfo* cpClassInfo = thread->m_currentClass->constantPool->getClassInfo(index);
const std::string_view name = thread->m_currentClass->constantPool->getString(cpClassInfo->nameIndex);

const Variable operand = thread->m_currentFrame->popOperand();
VM->checkType(operand, VariableType_REFERENCE, thread);

i4 returnVal = 0;

if (operand.data == 0)
{
thread->m_currentFrame->pushInt(returnVal);
return;
}

const Reference* reference = heap->getReference(operand.data);

if (reference->type == OBJECT || reference->type == CLASSOBJECT)
{
const Object* object = reference->getObject();
const ClassInfo* classInfo = object->classInfo;
if (classInfo->isInterface())
{
thread->internalError("Instanceof not implemented yet for interfaces");
} else
{
std::string_view objectClassName = classInfo->getName();

const ClassInfo* targetClassInfo = VM->getClass(name.data(), thread);
if (targetClassInfo->isInterface())
{
thread->internalError("Instanceof not implemented yet for interface implementation checking");
} else
// Check if it is a subclass
{
do
{
if (name == objectClassName)
{
returnVal = 1;
break;
}
if (object->superClassObject == 0)
{
break;
}
object = heap->getObject(object->superClassObject);
if (object != nullptr)
{
objectClassName = object->classInfo->getName();
}
} while(object != nullptr);
thread->m_currentFrame->pushInt(returnVal);
}
}
} else
{
thread->internalError("Instanceof not implemented yet for arrays");
}
}

void monitorenter(INSTRUCTION_ARGS)
{
// TODO: Implement when real threading is implemented
Expand Down
1 change: 1 addition & 0 deletions src/VM/Instructions/ReferenceInstructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ void newarray(INSTRUCTION_ARGS);
void anewarray(INSTRUCTION_ARGS);
void arraylength(INSTRUCTION_ARGS);
void checkCast(INSTRUCTION_ARGS);
void instanceof(INSTRUCTION_ARGS);
void monitorenter(INSTRUCTION_ARGS);
void monitorexit(INSTRUCTION_ARGS);
59 changes: 24 additions & 35 deletions src/VM/JavaHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,9 @@ u4 JavaHeap::createObject(ClassInfo* classInfo, VM* VM)
if (classInfo->superClass != 0)
{
const char* superClassName = classInfo->constantPool->getString(classInfo->constantPool->getClassInfo(classInfo->superClass)->nameIndex);
if (strcmp(superClassName, "java/lang/Object") != 0)
{
ClassInfo* superClass = getClassByName(superClassName);
u4 superClassObject = createObject(superClass, VM);
object->superClassObject = superClassObject;
}
ClassInfo* superClass = getClassByName(superClassName);
const u4 superClassObject = createObject(superClass, VM);
object->superClassObject = superClassObject;
}

objects.push_back(object);
Expand Down Expand Up @@ -207,24 +204,26 @@ u4 JavaHeap::createString(const char* utf8String, VM* VM) {
return strObjectId;
}

Object* JavaHeap::getObject(const uint32_t id) const
const Object* JavaHeap::getObject(const uint32_t id) const
{
if (id == 0)
{
// Nullpointer
fprintf(stderr, "Error: Null pointer exception!\n");
Platform::exitProgram(1);
}
Reference* ref = objects[id];
if (ref->type == OBJECT || ref->type == CLASSOBJECT)
{
return static_cast<Object*>(objects[id]);
} else
return objects[id]->getObject();
}

Reference* JavaHeap::getReference(u4 id) const
{
if (id == 0)
{
fprintf(stderr, "Error: Array instead of Object\n");
Platform::exitProgram(22);
// Nullpointer
fprintf(stderr, "Error: Null pointer exception!\n");
Platform::exitProgram(1);
}
return nullptr;
return objects[id];
}

ClassObject* JavaHeap::getClassObject(uint32_t id) const
Expand All @@ -247,41 +246,31 @@ ClassObject* JavaHeap::getClassObject(uint32_t id) const
return nullptr;
}

Object* JavaHeap::getChildObject(uint32_t id, ClassInfo* classInfo)
const Object* JavaHeap::getChildObject(const uint32_t id, ClassInfo* classInfo)
{
Object* o = getObject(id);
if (o == 0 || strcmp(o->classInfo->getName(), classInfo->getName()) != 0)
const Object* o = getObject(id);
if (o == nullptr || strcmp(o->classInfo->getName(), classInfo->getName()) != 0)
{
if (o->superClassObject != 0)
if (o != nullptr && o->superClassObject != 0)
{
return getChildObject(o->superClassObject, classInfo);
} else
{
fprintf(stderr, "Error: Object not found at reference with class: %s\n", classInfo->getName());
Platform::exitProgram(22);
}

fprintf(stderr, "Error: Object not found at reference with class: %s\n", classInfo->getName());
Platform::exitProgram(22);
}
return o;
}

Array* JavaHeap::getArray(const uint32_t id) const
const Array* JavaHeap::getArray(const uint32_t id) const
{
if (id == 0)
{
// Nullpointer
fprintf(stderr, "Error: Null pointer exception!");
Platform::exitProgram(1);
}
Reference* ref = objects[id];
if (ref->type == ARRAY)
{
return static_cast<Array*>(objects[id]);
} else
{
fprintf(stderr, "Error: Array instead of Object");
Platform::exitProgram(22);
}
return nullptr;
return objects[id]->getArray();
}

u4 JavaHeap::getString(const char* utf8String) const
Expand All @@ -293,7 +282,7 @@ u4 JavaHeap::getString(const char* utf8String) const
const Object* obj = static_cast<const Object*>(ref);
if (strcmp(obj->classInfo->getName(), "java/lang/String") == 0) {
Variable charArrRef = obj->fields[0].data[0];
Array* arr = getArray(charArrRef.data);
const Array* arr = getArray(charArrRef.data);
if (strncmp((const char*)arr->data, utf8String,
(arr->length > strlen(utf8String) ? arr->length : strlen(utf8String))) == 0) {
return currentObj;
Expand Down
29 changes: 13 additions & 16 deletions src/VM/JavaHeap.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,21 @@ class Reference {
public:
ReferenceType type;

Array* getArray() {
[[nodiscard]] const Array* getArray() const {
if (type == ARRAY) {
return reinterpret_cast<Array*>(this);
}
else {
fprintf(stderr, "Error: Reference is not of type 'Array'");
Platform::exitProgram(23);
return reinterpret_cast<const Array*>(this);
}
fprintf(stderr, "Error: Reference is not of type 'Array'");
Platform::exitProgram(23);
return nullptr;
};

Object* getObject() {
if (type == OBJECT) {
return reinterpret_cast<Object*>(this);
}
else {
fprintf(stderr, "Error: Reference is not of type 'Object'");
Platform::exitProgram(23);
[[nodiscard]] const Object* getObject() const {
if (type == OBJECT || type == CLASSOBJECT) {
return reinterpret_cast<const Object*>(this);
}
fprintf(stderr, "Error: Reference is not of type 'Object'");
Platform::exitProgram(23);
return nullptr;
};
};
Expand Down Expand Up @@ -100,10 +96,11 @@ class JavaHeap {
u4 createClassObject(ClassInfo* classInfo, VM* VM, std::string_view name);
u4 createString(const char* utf8String, VM* VM);

[[nodiscard]] Object* getObject(uint32_t id) const;
[[nodiscard]] const Object* getObject(uint32_t id) const;
[[nodiscard]] Reference* getReference(u4 id) const;
[[nodiscard]] ClassObject* getClassObject(uint32_t id) const;
[[nodiscard]] Object* getChildObject(uint32_t id, ClassInfo* classInfo);
[[nodiscard]] Array* getArray(u4 id) const;
[[nodiscard]] const Object* getChildObject(uint32_t id, ClassInfo* classInfo);
[[nodiscard]] const Array* getArray(u4 id) const;
[[nodiscard]] u4 getString(const char* utf8String) const;
[[nodiscard]] u4 getClassObjectByName(std::string_view name) const;

Expand Down
3 changes: 2 additions & 1 deletion src/VM/VM.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class VM {
void executeLoop(VMThread* thread);
static void checkType(Variable var, VariableType type, VMThread *thread);
private:
inline static constexpr std::array<Instruction,105> m_instructions{{
inline static constexpr std::array<Instruction,106> m_instructions{{
// Constants
{i_nop, 0, "nop", 0, nop},
{i_aconst_null, 0, "aconst_null", 0, aconst_null},
Expand Down Expand Up @@ -152,6 +152,7 @@ class VM {
{i_anewarray, 0, "anewarray", 0, anewarray},
{i_arraylength, 0, "arraylength", 0, arraylength},
{i_checkcast, 2, "checkcast", 0, checkCast},
{i_instanceof, 2, "instanceof", 0, instanceof},
{i_monitorenter, 0, "monitorenter", 0, monitorenter},
{i_monitorexit, 0, "monitorexit", 0, monitorexit},
// Control
Expand Down
6 changes: 6 additions & 0 deletions src/VM/VMThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ static constexpr std::string_view NoNonNativeStackFrameFound{"Can't return to pr
void VMThread::pushStackFrameWithoutParams(ClassInfo* classInfo, const MethodInfo* methodInfo)
{
StackFrame stackFrame;

if (methodInfo->code == nullptr)
{
internalError(std::string_view("No code found in method"));
}

stackFrame.localVariables.reserve(methodInfo->code->maxLocals);
for (u2 currentLocal = 0; currentLocal < methodInfo->code->maxLocals; ++currentLocal)
{
Expand Down
5 changes: 4 additions & 1 deletion test/e2e/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ set(CMAKE_JAVA_COMPILE_FLAGS "-source" "1.8" "-target" "1.8")
add_jar(e2e
SmokeTest.java
PrivilegedTest.java
InstanceofTest.java
)

get_target_property(_classDir e2e CLASSDIR)

add_test(NAME SmokeTest COMMAND VigurVM "-classpath" "${_classDir}" "SmokeTest" WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_test(NAME PrivilegedTest COMMAND VigurVM "-classpath" "${_classDir}" "PrivilegedTest" WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_test(NAME InstanceofTest COMMAND VigurVM "-classpath" "${_classDir}" "InstanceofTest" WORKING_DIRECTORY ${CMAKE_BINARY_DIR})

set (failRegex "^Error:")
set_property(TEST SmokeTest PROPERTY FAIL_REGULAR_EXPRESSION "${failRegex}")
set_property(TEST PrivilegedTest PROPERTY FAIL_REGULAR_EXPRESSION "${failRegex}")
set_property(TEST PrivilegedTest PROPERTY FAIL_REGULAR_EXPRESSION "${failRegex}")
set_property(TEST InstanceofTest PROPERTY FAIL_REGULAR_EXPRESSION "${failRegex}")
22 changes: 22 additions & 0 deletions test/e2e/InstanceofTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import java.io.Serializable;

public class InstanceofTest {
public static void main(String[] args) {
String brol = "";
Object o = new Object();
Object oNull = null;
// char[] charArr = new char[2];
if (!(brol instanceof String))
throw new RuntimeException();
if (!(brol instanceof Object))
throw new RuntimeException();
if (o instanceof String)
throw new RuntimeException();
if (oNull instanceof String)
throw new RuntimeException();
// if (!(brol instanceof Serializable))
// throw new RuntimeException();
// if (!(charArr instanceof char[]))
// throw new RuntimeException();
}
}

0 comments on commit c705569

Please sign in to comment.