Exemplo n.º 1
0
    shared_ptr<MethodBody> ContextBuilder::buildMethod(
        const shared_ptr<MethodDeclaration> &method) {
        std::map< PropertyName, ClassName > args;
        for (auto elem : method->getArgs()) {
            args[PropertyName(elem.first)] = ClassName(elem.second);
        }
        MethodName methodName(method->getName());

        auto term = buildMethodBody(method->getBodyTerm());

        return std::make_shared< MethodBody >(
            methodName,
            term,
            args
        );
    }
Exemplo n.º 2
0
JavaScriptObject::JavaScriptObject(JavaTypeMap& typeMap, JNIEnv* env, duk_context* context,
                                   jstring name, jobjectArray methods)
    : m_name(JString(env, name).str())
    , m_context(context)
    , m_instance(nullptr)
    , m_nextFinalizer(nullptr) {
    CHECK_STACK(m_context);
    duk_push_global_object(m_context);
    if (!duk_get_prop_string(m_context, -1, m_name.c_str())) {
        duk_pop_2(m_context);
        throw std::invalid_argument("A global JavaScript object called " + m_name + " was not found");
    }

    m_instance = duk_get_heapptr(m_context, -1);
    if (m_instance == nullptr) {
        duk_pop_2(m_context);
        throw std::invalid_argument("JavaScript global called " + m_name + " is not an object");
    }

    // Make sure that the object has all of the methods we want.
    jmethodID getName = nullptr;
    const jsize numArgs = env->GetArrayLength(methods);
    for (jsize i = 0; i < numArgs; ++i) {
        auto method = env->GetObjectArrayElement(methods, i);
        if (getName == nullptr) {
            jclass methodClass = env->GetObjectClass(method);
            getName = env->GetMethodID(methodClass, "getName", "()Ljava/lang/String;");
        }

        // Sanity check that as of right now, the object we're proxying has a function with this name.
        const JString methodName(env, static_cast<jstring>(env->CallObjectMethod(method, getName)));
        if (!duk_get_prop_string(m_context, -1, methodName)) {
            duk_pop_3(m_context);
            throw std::runtime_error("JavaScript global " + m_name + " has no method called " +
                                     methodName.str());
        } else if (!duk_is_callable(m_context, -1)) {
            duk_pop_3(m_context);
            throw std::runtime_error("JavaScript property " + m_name + "." + methodName.str() +
                                     " not callable");
        }

        try {
            // Build a call wrapper that handles marshalling the arguments and return value.
            m_methods.emplace(std::make_pair(env->FromReflectedMethod(method),
                                             buildMethodBody(typeMap, env, method, methodName.str())));
        } catch (const std::invalid_argument& e) {
            duk_pop_3(m_context);
            throw std::invalid_argument("In proxied method \"" + m_name + "." + methodName.str() +
                                        "\": " + e.what());
        }

        // Pop the method property.
        duk_pop(m_context);
    }

    // Keep track of any previously registered finalizer.
    duk_get_finalizer(m_context, -1);
    m_nextFinalizer = duk_is_c_function(m_context, -1)
                      ? duk_get_c_function(m_context, -1)
                      : nullptr;
    duk_pop(m_context);
    duk_push_c_function(m_context, JavaScriptObject::finalizer, 1);
    duk_set_finalizer(m_context, -2);

    // Add 'this' to the list of pointers attached to the proxied instance.
    // TODO: don't use an array here, just use a separate hidden property for each proxy.
    if (!duk_has_prop_string(m_context, -1, WRAPPER_THIS_PROP_NAME)) {
        duk_push_array(m_context);
    } else {
        duk_get_prop_string(m_context, -1, WRAPPER_THIS_PROP_NAME);
    }

    const duk_size_t length = duk_get_length(m_context, -1);
    duk_push_pointer(m_context, this);
    duk_put_prop_index(m_context, -2, static_cast<duk_uarridx_t>(length));
    // Add the array (back) to the instance.
    duk_put_prop_string(m_context, -2, WRAPPER_THIS_PROP_NAME);

    // Pop the global and our instance.
    duk_pop_2(m_context);
}