Report abuse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  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
  }