diff --git a/src/builtin.cpp b/src/builtin.cpp
index 4307107f15..479d721407 100644
--- a/src/builtin.cpp
+++ b/src/builtin.cpp
@@ -163,16 +163,7 @@ Class_primitiveClass(Thread* t, jclass, jchar name)
 void
 Class_initialize(Thread* t, jobject this_)
 {
-  acquire(t, t->vm->classLock);
-  object c = *this_;
-  if (classVmFlags(t, c) & NeedInitFlag
-      and (classVmFlags(t, c) & InitFlag) == 0)
-  {
-    classVmFlags(t, c) |= InitFlag;
-    run(t, classInitializer(t, c), 0);
-  } else {
-    release(t, t->vm->classLock);
-  }
+  initClass(t, *this_);
 }
 
 jboolean
diff --git a/src/machine.h b/src/machine.h
index 07af002c86..ba8e475d2c 100644
--- a/src/machine.h
+++ b/src/machine.h
@@ -1131,6 +1131,9 @@ class Machine {
   unsigned heapPoolIndex;
 };
 
+object
+run(Thread* t, object method, object this_, ...);
+
 object
 run(Thread* t, const char* className, const char* methodName,
     const char* methodSpec, object this_, ...);
@@ -2111,6 +2114,20 @@ resolveClass(Thread* t, object spec);
 object
 resolveObjectArrayClass(Thread* t, object elementSpec);
 
+inline void
+initClass(Thread* t, object c)
+{
+  acquire(t, t->vm->classLock);
+  if (classVmFlags(t, c) & NeedInitFlag
+      and (classVmFlags(t, c) & InitFlag) == 0)
+  {
+    classVmFlags(t, c) |= InitFlag;
+    run(t, classInitializer(t, c), 0);
+  } else {
+    release(t, t->vm->classLock);
+  }
+}
+
 object
 makeObjectArray(Thread* t, object elementClass, unsigned count, bool clear);
 
diff --git a/src/run.cpp b/src/run.cpp
index 0509a92ef3..89effc597d 100644
--- a/src/run.cpp
+++ b/src/run.cpp
@@ -85,10 +85,10 @@ popFrame(Thread* t)
 }
 
 object
-findInterfaceMethod(Thread* t, object method, object o)
+findInterfaceMethod(Thread* t, object method, object class_)
 {
   object interface = methodClass(t, method);
-  object itable = classInterfaceTable(t, objectClass(t, o));
+  object itable = classInterfaceTable(t, class_);
   for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
     if (arrayBody(t, itable, i) == interface) {
       return arrayBody(t, arrayBody(t, itable, i + 1),
@@ -1594,9 +1594,7 @@ run(Thread* t)
     unsigned parameterFootprint = methodParameterFootprint(t, method);
     if (LIKELY(peekObject(t, sp - parameterFootprint))) {
       code = findInterfaceMethod
-        (t, method, peekObject(t, sp - parameterFootprint));
-      if (UNLIKELY(exception)) goto throw_;
-
+        (t, method, objectClass(t, peekObject(t, sp - parameterFootprint)));
       goto invoke;
     } else {
       exception = makeNullPointerException(t);
@@ -1669,7 +1667,7 @@ run(Thread* t)
         if (UNLIKELY(classInit(t, class_, 3))) goto invoke;
       }
 
-      code = findMethod(t, method, class_);      
+      code = findMethod(t, method, class_);
       goto invoke;
     } else {
       exception = makeNullPointerException(t);
@@ -2575,6 +2573,31 @@ pushArguments(Thread* t, object this_, const char* spec, object a)
 object
 invoke(Thread* t, object method)
 {
+  PROTECT(t, method);
+
+  object class_;
+  PROTECT(t, class_);
+
+  if (methodFlags(t, method) & ACC_STATIC) {
+    class_ = methodClass(t, method);
+  } else {
+    unsigned parameterFootprint = methodParameterFootprint(t, method);
+    class_ = objectClass(t, peekObject(t, t->sp - parameterFootprint));
+
+    if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) {
+      method = findInterfaceMethod(t, method, class_);
+    } else {
+      if (classVirtualTable(t, class_) == 0) {
+        resolveClass(t, className(t, class_));
+        if (UNLIKELY(t->exception)) return 0;
+      }
+
+      method = findMethod(t, method, class_);
+    }
+  }
+
+  initClass(t, class_);
+
   object result = 0;
 
   if (methodFlags(t, method) & ACC_NATIVE) {