#define cCApiHandleQfalse         ((VALUE)(0x00))
#define cCApiHandleQtrue ((VALUE)(0x22))
#define cCApiHandleQnil ((VALUE)(0x42))
#define cCApiHandleQundef ((VALUE)(0x62))

#define CAPI_BOOL_MASK 0x7f

#define CAPI_FALSE_P(v) ((VALUE)(v) == cCApiHandleQfalse)
#define CAPI_TRUE_P(v) (((VALUE)(v) & CAPI_BOOL_MASK) == cCApiHandleQtrue)
#define CAPI_NIL_P(v) (((VALUE)(v) & CAPI_BOOL_MASK) == cCApiHandleQnil)
#define CAPI_UNDEF_P(v) (((VALUE)(v) & CAPI_BOOL_MASK) == cCApiHandleQundef)

#define CAPI_REFERENCE_TAG 0x0a
#define CAPI_REFERENCE_MASK 0x0f
#define CAPI_GLOBAL_HANDLE_TAG 0x0a
#define CAPI_GLOBAL_HANDLE_MASK 0x1f
#define CAPI_LOCAL_HANDLE_TAG 0x1a
#define CAPI_REFERENCE_SHIFT 5

#define CAPI_REFERENCE_P(v) (((VALUE)(v) & CAPI_REFERENCE_MASK) == CAPI_REFERENCE_TAG)
#define CAPI_GLOBAL_HANDLE_P(v) \
(((VALUE)(v) & CAPI_GLOBAL_HANDLE_MASK) == CAPI_GLOBAL_HANDLE_TAG)

#define CAPI_APPLY_GLOBAL_TAG(v) \
((VALUE)(((VALUE)(v) << CAPI_REFERENCE_SHIFT) | CAPI_GLOBAL_HANDLE_TAG))
#define CAPI_STRIP_GLOBAL_TAG(v) ((VALUE)((VALUE)(v) >> CAPI_REFERENCE_SHIFT))

#define CAPI_APPLY_LOCAL_TAG(v) \
((VALUE)(((VALUE)(v) << CAPI_REFERENCE_SHIFT) | CAPI_LOCAL_HANDLE_TAG))
#define CAPI_STRIP_LOCAL_TAG(v) ((VALUE)((VALUE)(v) >> CAPI_REFERENCE_SHIFT))

## nativemethod.cpp
Handle NativeMethodEnvironment::get_handle(Object* obj) {
if(obj->reference_p()) {
return current_native_frame_->get_handle(state_, obj);
} else if(obj->fixnum_p()) {
return reinterpret_cast<VALUE>(obj);
} else if(obj->symbol_p()) {
return reinterpret_cast<ID>(obj);
} else if(obj->nil_p()) {
return cCApiHandleQnil;
} else if(obj->false_p()) {
return cCApiHandleQfalse;
} else if(obj->true_p()) {
return cCApiHandleQtrue;
} else if(obj->undef_p()) {
return cCApiHandleQundef;
} else {
capi_raise_runtime_error("handle requested for unknown object type");
}
return 0; // keep compiler happy
}

Handle NativeMethodEnvironment::get_handle_global(Object* obj) {
Handles& global_handles = state_->shared.global_handles();
Handle handle = CAPI_APPLY_GLOBAL_TAG(global_handles.size());
global_handles.push_back(new RootHandle(state_, obj));
return handle;
}

Object* NativeMethodEnvironment::get_object(Handle handle) {
if(CAPI_REFERENCE_P(handle)) {
if(CAPI_GLOBAL_HANDLE_P(handle)) {
Handles& global_handles = state_->shared.global_handles();
RootHandle* root = global_handles[CAPI_STRIP_GLOBAL_TAG(handle)];
if(!root) {
capi_raise_runtime_error("Attempted to use deleted NativeMethod global handle");
}

/* No Ruby object should ever be NULL, so if it is, likely an
* exception occurred that was not caught correctly. Rather
* than letting it propogate to mysterious corners of the code,
* we raise an exception here. @see NativeMethodFrame::get_object()
*/
Object* obj = root->get();
if(!obj) {
capi_raise_runtime_error("NativeMethod global handle refers to NULL object");
}
return obj;
} else {
current_native_frame_->get_object(handle);
}
} else if(FIXNUM_P(handle) || SYMBOL_P(handle)) {
return reinterpret_cast<Object*>(handle);
} else if(CAPI_FALSE_P(handle)) {
return Qfalse;
} else if(CAPI_TRUE_P(handle)) {
return Qtrue;
} else if(CAPI_NIL_P(handle)) {
return Qnil;
} else if(CAPI_UNDEF_P(handle)) {
return Qundef;
} else {
capi_raise_runtime_error("requested Object for unknown handle type");
}
return Qnil; // keep compiler happy
}