When I learned MIPS assembly a few months ago, a question popped into my head that I forgot to ask then, so I thought I'd ask it now:
Is it possible to implement polymorphism without indirect jump instructions? If so, how?
(Indirect jumps are the "jump register" instructions, e.g. jr $t0 in MIPS or jmp EAX in x86.)
One such solution I came up with is self-modifying code, but I'm curious as to whether polymorphism (and so OOP) would be possible by any other means.
The simplest answer to your question would be to write your program (and possible assembler) in such a way that all method calls can be resolved at runtime thus negating the need for a lookup table. I'm going to assume you're talking about passing a subclass to a function that was designed for a superclass and it is therefore impossible to implement this optimization.
Eliminating the lookup, I think, is outside the scope of your question so I'm going to suggest replacements for the jmp <reg> instruction (sorry, I only know x86).
You can execute a call <mem> on a memory
address (isn't this how you would do
it using a lookup table?)
You can execute a call <reg> on a register
(not entirely different from the jmp
, but does answer your question)
You can jmp <mem> if you wanted, but
that's not all that different from jmp <reg>
All of these are possible and solve your problem, but are all alike. I guess this illustrates my confusion on why you would want to do what you're asking. You have to have some way to choose which method to call (the vtable) and some way to transfer execution to the method (using jmp or call).
The only other possible way to do this would be to fiddle with the register that is used to point to the next command in the execution chain (EIP in x86). Whether you can or should is another question. I suppose if you were intimately knowledgeable of the architecture and weren't worried about it changing you could do that.
Yes
You may want to consider changing your question however
Consider this C++ code where Derived is obviously polymorphic (yes, I didn't delete the object):
class Base
{
public: int foo(){ return 1; }
};
class Derived: public Base
{
public: int foo(){ return 2; };
};
int main()
{
Base* b = new Derived();
return b->foo(); //Returns 1
}
The assembly generated by gcc is
main:
.LFB2:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
movl $1, %ecx
call _Znwm
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rcx
call _ZN4Base3fooEv
addq $48, %rsp
popq %rbp
ret
As you can see there is no indirect jump/call.
That's because polymorphism is not the point here (though it is necessary), virtual methods are.
Then the answer becames
No
If by indirect jump/call you means every technique that use a runtime value for computing the target of the jump/call (so including things like ret, call [], call reg, jr, jalr).
Consider this source
#include <iostream>
class Base
{
public: virtual int foo(){ return 1; }
};
class Derived: public Base
{
public: int foo(){ return 2; };
};
class Derived2: public Base
{
public: int foo(){ return 3; };
};
int main()
{
int a;
Base* b = 0; //don't remember the header for std::nullptr right now...
std::cin >> a;
if (a > 241)
b = new Derived();
else
b = new Derived2();
return b->foo(); //Returns what?
}
The result depends on the user input, an archetypal runtime value, so must be the called routine and no static address would do.
Note that in this case the compiler could use a jump toward calls with static address (as either Derived2::foo or Derived::foo is called) but this is not in general possible (you may have multiple object files without the source, you may have an aliasing pointer, the pointer b could be set by an external library, and so on).
Related
These are the ways I know of to create singletons in Rust:
#[macro_use]
extern crate lazy_static;
use std::sync::{Mutex, Once, ONCE_INIT};
#[derive(Debug)]
struct A(usize);
impl Drop for A {
fn drop(&mut self) {
// This is never executed automatically.
println!(
"Dropping {:?} - Important stuff such as release file-handles etc.",
*self
);
}
}
// ------------------ METHOD 0 -------------------
static PLAIN_OBJ: A = A(0);
// ------------------ METHOD 1 -------------------
lazy_static! {
static ref OBJ: Mutex<A> = Mutex::new(A(1));
}
// ------------------ METHOD 2 -------------------
fn get() -> &'static Mutex<A> {
static mut OBJ: *const Mutex<A> = 0 as *const Mutex<A>;
static ONCE: Once = ONCE_INIT;
ONCE.call_once(|| unsafe {
OBJ = Box::into_raw(Box::new(Mutex::new(A(2))));
});
unsafe { &*OBJ }
}
fn main() {
println!("Obj = {:?}", PLAIN_OBJ); // A(0)
println!("Obj = {:?}", *OBJ.lock().unwrap()); // A(1)
println!("Obj = {:?}", *get().lock().unwrap()); // A(2)
}
None of these call A's destructor (drop()) at program exit. This is expected behaviour for Method 2 (which is heap allocated), but I hadn't looked into the implementation of lazy_static! to know it was going to be similar.
There is no RAII here. I could achieve that behaviour of an RAII singleton in C++ (I used to code in C++ until a year a back, so most of my comparisons relate to it - I don't know many other languages) using function local statics:
A& get() {
static A obj; // thread-safe creation with C++11 guarantees
return obj;
}
This is probably allocated/created (lazily) in implementation defined area and is valid for the lifetime of the program. When the program terminates, the destructor is deterministically run. We need to avoid accessing it from destructors of other statics, but I have never run into that.
I might need to release resources and I want drop() to be run. Right now, I end up doing it manually just before program termination (towards the end of main after all threads have joined etc.).
I don't even know how to do this using lazy_static! so I have avoided using it and only go for Method 2 where I can manually destroy it at the end.
I don't want to do this; is there a way I can have such a RAII behaved singleton in Rust?
Singletons in particular, and global constructors/destructors in general, are a bane (especially in language such as C++).
I would say the main (functional) issues they cause are known respectively as static initialization (resp. destruction) order fiasco. That is, it is easy to accidentally create a dependency cycle between those globals, and even without such a cycle it is not immediately clear to compiler in which order they should be built/destroyed.
They may also cause other issues: slower start-up, accidentally shared memory, ...
In Rust, the attitude adopted has been No life before/after main. As such, attempting to get the C++ behavior is probably not going to work as expected.
You will get much greater language support if you:
drop the global aspect
drop the attempt at having a single instance
(and as a bonus, it'll be so much easier to test in parallel, too)
My recommendation, thus, is to simply stick with local variables. Instantiate it in main, pass it by value/reference down the call-stack, and not only do you avoid those tricky initialization order issue, you also get destruction.
I'm making a program for the game 15 puzzle.
My function headers look like this:
void leftSlide(vector< vector<int> >& puzzle);
void rightSlide(vector< vector<int> >& puzzle);
void upSlide(vector< vector<int> >& puzzle);
void downSlide(vector< vector<int> >& puzzle);
my main function also has a vector< vector<int> > puzzle. Am I allowed to do this, or will this cause problems?
The scope of a variable is within the enclosing curly braces. For example,
void foo()
{
int x; // variable x is not known outside of foo
}
This scoping rule applies even for variables in the argument list. For example,
void boo (int y)
{
// variable y in not known outside of boo
}
Therefore, in your case, the variables will be passed from the main driver to the individual functions by reference. So, yes, you can have variables of the same name in different scopes.
simply yes
The potential scope of a variable introduced by a declaration in a block (compound statement) begins at the point of declaration and ends at the end of the block. Actual scope is the same as potential scope unless there is a nested block with a declaration that introduces identical name (in which case, the entire potential scope of the nested declaration is excluded from the scope of the outer declaration)
I have to use dlopen() and access functions from shared object in my code. Do I need to include headers of corresponding functions of shared object ?
Because of the way dlopen() and dlsym() operate, I don't see how that would accomplish anything. Very roughly speaking, dlopen() copies the library binary into your program space and adds the addresses of its exported symbols (i.e. global functions & variables) to your program's symbol table.
Because the library was not linked to your program at compile-time, there's no way your code could possibly know the instruction addresses of these new functions tacked on at run-time. The only way to access a run-time dynamically linked symbol is via a pointer obtained from dlsym().
You have to create a function pointer for each and every library definition that you want to use. If you want to call them like regular functions, in C-language you can manually typedef type definitions for the function pointers, specifying their parameters and return values, then you can call the pointers just like regular functions. But note that you have to define all of these manually. Including the library header doesn't help.
In C++ I think there are issues with storing dlsym() output in a typedef'd pointer due to stricter standards, but this should work in C:
addlib.c (libaddlib.dylib):
int add(int x, int y) {
return x+y;
}
myprogram.c:
#include <stdio.h>
#include <dlfcn.h>
typedef int (*add_t)(int, int);
int main() {
void *lib_handle;
add_t add; // call this anything you want...it's a pointer, it doesn't care
lib_handle = dlopen("libaddlib.dylib", RTLD_NOW);
if (lib_handle == NULL) {
// error handling
}
add = (add_t)dlsym(lib_handle, "add");
if (add == NULL) {
// error handling
}
printf("Sum is %d\n", add(17, 23));
dlclose(lib_handle); // remove library from address space
return 0;
}
(Update: I compiled the dylib and myprogram...it works as expected.)
Go uses both dynamic and static binding. From my understanding, if you need to use a type assertion then it's dynamic. I want to validate my assumptions.
type Xer interface {
X()
}
type XYer interface {
Xer
Y()
}
type Foo struct{}
func (Foo) X() { println("Foo#X()") }
func (Foo) Y() { println("Foo#Y()") }
Assumptions:
foo := Foo{}
// static: Foo -> XYer
var xy XYer = foo
// static: XYer -> Xer
var x Xer = xy
// static: Xer -> interface{}
var empty interface{} = x
// dynamic: interface{} -> XYer
xy2 := empty.(XYer)
// dynamic: XYer -> Foo
foo2 := xy2.(Foo)
So when converting from type A -> interface B, if A satisfies B then you don't need an assertion and the itable can be generated at compile time. What about a case where you use an assertion where it's not needed:
var x Xer = Foo{}
empty := x.(interface{})
what happens in this case? If someone could clarify this for me that would great.
To extend on jnml's answer, 6g generates a type assertion nevertheless.
empty := x.(interface{})
is expanded to:
0034 (dumb.go:19) MOVQ $type.interface {}+0(SB),(SP)
0035 (dumb.go:19) LEAQ 8(SP),BX
0036 (dumb.go:19) MOVQ x+-32(SP),BP
0037 (dumb.go:19) MOVQ BP,(BX)
0038 (dumb.go:19) MOVQ x+-24(SP),BP
0039 (dumb.go:19) MOVQ BP,8(BX)
0040 (dumb.go:19) CALL ,runtime.assertI2E+0(SB)
0041 (dumb.go:19) MOVQ 24(SP),BX
0042 (dumb.go:19) MOVQ BX,empty+-16(SP)
0043 (dumb.go:19) MOVQ 32(SP),BX
0044 (dumb.go:19) MOVQ BX,empty+-8(SP)
To clarify what is happening here, in line 34 the InterfaceType of interface{} is loaded to the
first value of the stack. Line 35-36 and 37-38 put the tab and data values of x
onto the stack. The stack is then ready for runtime.assertI2E to be called,
which simply assigns the underlying type and data to the return value. The compiler knows that
you're assigning to an empty interface, hence the call to assertI2E: I2E stands for Interface to Eface (Empty Interface), so no check for methods is necessary. The only restriction assertI2E enforces is that
the asserted value must be an interface.
If however, you're doing x.(Xer), runtime.assertI2I would've been called, which then checks if
the methods implement the interface.
I don't know what is static binding of interfaces or dynamic binding of interfaces. The language specification never mentions such terms. Let me assume you mean type checking at compile time and type checking at run time. With this assumptions, all of your examples are, AFAICS, correct. It boils down to a simple schema (a condensed version of the relevant language specification parts):
All assignments are type checked at compile time.
All type assertions (.(T)) are type checked at run time.
Which also answers the "what happens in this case?".
That said, the compiler is free to optimize cases where it can prove at compile time that the type is known and assignment compatible. But that's only an implementation detail which one cannot rely on - as it may not be the case of other, specification conforming implementation(s).
Actually the gc compiler has (IINM) such optimizations and even in the opposite sense. It can say 'impossible type assertion' where it can prove at compile time that the type assertion will fail.
I have a C++/CLI wrapper around native .lib and .h files. I use the AutoPtr class pretty extensively in the wrapper class to manage the unmanaged objects I create for wrapping. I have hit a roadblock with the copy constructor/assignment operator.
Using the AutoPtr class from Mr. Kerr: http://weblogs.asp.net/kennykerr/archive/2007/03/26/AutoPtr.aspx
He suggests the following(in the comments) to recreate the behavior of the assignment operator:
SomeManagedClass->NativePointer.Reset(new NativeType);
Which I believe is true. But when I compile my code:
ByteMessageWrap (const ByteMessageWrap% rhs)
{
AutoPtr<ByteMessage> m_NativeByteMessage(rhs.m_NativeByteMessage.GetPointer());
};
ByteMessageWrap% operator=(const ByteMessageWrap% rhs)
{
//SomeManagedClass->NativePointer.Reset(new NativeType);
if (this == %rhs) // prevent assignment to self
return *this;
this->m_NativeByteMessage.Reset(rhs.m_NativeByteMessage.GetPointer());
return *this;
};
-- I get the following errors:
error C2662:
'WrapTest::AutoPtr::GetPointer' :
cannot convert 'this' pointer from
'const WrapTest::AutoPtr' to
'WrapTest::AutoPtr %'
Has anyone experienced similar issues?
For further background on the answer, I removed the "const" keyword from the signature. I know that is not smiled upon in terms of code correctness for a copy ctor, but the CLR doesn't like it at all -- sort of belies the CLR at its core with memory management.
I wonder if it's possible to leave the const in the signature and then use GCHandle or pin_ptr to make sure memory doesn't move on you while performing the copy?
Looking at Kenny Kerr's AutoPtr, it transfers ownership in its constructor -- essentially a "move" constructor rather than a copy constructor. This is analogous with std::auto_ptr.
If you really want to transfer ownership from rhs to this (i.e. leave rhs without it NativeByteMessage), you need to change your copy ctor into a move ctor.
Also, you need to use initialization syntax;
// warning - code below doesn't work
ByteMessageWrap (ByteMessageWrap% rhs)
: m_NativeByteMessage(rhs.m_NativeByteMessage); // take ownership
{
}
ByteMessageWrap% operator=(ByteMessageWrap% rhs)
{
//SomeManagedClass->NativePointer.Reset(new NativeType);
if (this == %rhs) // prevent assignment to self
return *this;
m_NativeByteMessage.Reset(rhs.m_NativeByteMessage.Release());
return *this;
}