bool RuntimeObject::getOwnPropertyDescriptor(JSObject* object, ExecState *exec, PropertyName propertyName, PropertyDescriptor& descriptor) { RuntimeObject* thisObject = jsCast<RuntimeObject*>(object); if (!thisObject->m_instance) { throwInvalidAccessError(exec); return false; } RefPtr<Instance> instance = thisObject->m_instance; instance->begin(); Class *aClass = instance->getClass(); if (aClass) { // See if the instance has a field with the specified name. Field *aField = aClass->fieldNamed(propertyName, instance.get()); if (aField) { PropertySlot slot; slot.setCustom(thisObject, fieldGetter); instance->end(); descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete); return true; } else { // Now check if a method with specified name exists, if so return a function object for // that method. MethodList methodList = aClass->methodsNamed(propertyName, instance.get()); if (methodList.size() > 0) { PropertySlot slot; slot.setCustom(thisObject, methodGetter); instance->end(); descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly); return true; } } // Try a fallback object. if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) { PropertySlot slot; slot.setCustom(thisObject, fallbackObjectGetter); instance->end(); descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum); return true; } } instance->end(); return instance->getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); }
bool JavaNPObjectInvoke(NPObject* obj, NPIdentifier identifier, const NPVariant* args, uint32_t argCount, NPVariant* result) { JavaInstance* instance = ExtractJavaInstance(obj); if (!instance) return false; NPUTF8* name = _NPN_UTF8FromIdentifier(identifier); if (!name) return false; instance->begin(); MethodList methodList = instance->getClass()->methodsNamed(name); // TODO: use NPN_MemFree free(name); // Try to find a good match for the overloaded method. The // fundamental problem is that JavaScript doesn't have the // notion of method overloading and Java does. We could // get a bit more sophisticated and attempt to do some // type checking as well as checking the number of parameters. size_t numMethods = methodList.size(); JavaMethod* aMethod; JavaMethod* jMethod = 0; for (size_t methodIndex = 0; methodIndex < numMethods; methodIndex++) { aMethod = methodList[methodIndex]; if (aMethod->numParameters() == static_cast<int>(argCount)) { jMethod = aMethod; break; } } if (!jMethod) { instance->end(); return false; } JavaValue* jArgs = new JavaValue[argCount]; for (unsigned int i = 0; i < argCount; i++) jArgs[i] = convertNPVariantToJavaValue(args[i], jMethod->parameterAt(i)); JavaValue jResult = instance->invokeMethod(jMethod, jArgs); instance->end(); delete[] jArgs; VOID_TO_NPVARIANT(*result); convertJavaValueToNPVariant(jResult, result); return true; }
bool RuntimeObject::getOwnPropertySlot(JSCell* cell, ExecState *exec, const Identifier& propertyName, PropertySlot& slot) { RuntimeObject* thisObject = static_cast<RuntimeObject*>(cell); if (!thisObject->m_instance) { throwInvalidAccessError(exec); return false; } RefPtr<Instance> instance = thisObject->m_instance; instance->begin(); Class *aClass = instance->getClass(); if (aClass) { // See if the instance has a field with the specified name. Field *aField = aClass->fieldNamed(propertyName, instance.get()); if (aField) { slot.setCustom(thisObject, thisObject->fieldGetter); instance->end(); return true; } else { // Now check if a method with specified name exists, if so return a function object for // that method. MethodList methodList = aClass->methodsNamed(propertyName, instance.get()); if (methodList.size() > 0) { slot.setCustom(thisObject, thisObject->methodGetter); instance->end(); return true; } } // Try a fallback object. if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) { slot.setCustom(thisObject, thisObject->fallbackObjectGetter); instance->end(); return true; } } instance->end(); return instance->getOwnPropertySlot(thisObject, exec, propertyName, slot); }
bool RuntimeObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) { if (!instance) { throwInvalidAccessError(exec); return false; } instance->begin(); Class *aClass = instance->getClass(); if (aClass) { // See if the instance has a field with the specified name. Field *aField = aClass->fieldNamed(propertyName, instance.get()); if (aField) { slot.setCustom(this, fieldGetter); instance->end(); return true; } else { // Now check if a method with specified name exists, if so return a function object for // that method. MethodList methodList = aClass->methodsNamed(propertyName, instance.get()); if (methodList.size() > 0) { slot.setCustom(this, methodGetter); instance->end(); return true; } } // Try a fallback object. if (!aClass->fallbackObject(exec, instance.get(), propertyName)->isUndefined()) { slot.setCustom(this, fallbackObjectGetter); instance->end(); return true; } } instance->end(); // don't call superclass, because runtime objects can't have custom properties or a prototype return false; }
LuaExportMethodDescriptor* LuaExportTypeDescriptor::filterMethod(std::string const& methodName, LuaArgumentList arguments, bool isStatic) { MethodList methodList; if (isStatic) { MethodMap::iterator mapIt = _classMethods.find(methodName); if (mapIt != _classMethods.end()) { methodList = mapIt -> second; } } else { MethodMap::iterator mapIt = _instanceMethods.find(methodName); if (mapIt != _instanceMethods.end()) { methodList = mapIt -> second; } } if (methodList.size() > 1) { LuaExportMethodDescriptor *targetMethod = NULL; int startIndex = isStatic ? 0 : 1; if (arguments.size() > startIndex) { //带参数 std::deque<std::string> signList; std::string signListStr; std::string signStrRegexp; for (LuaArgumentList::iterator it = arguments.begin() + startIndex; it != arguments.end(); it++) { LuaValue *value = *it; switch (value -> getType()) { case LuaValueTypeNumber: signList.push_back("N"); signListStr += "N"; signStrRegexp += "[fdcislqCISLQB@]"; break; case LuaValueTypeBoolean: signList.push_back("B"); signListStr += "B"; signStrRegexp += "[BcislqCISLQfd@]"; break; case LuaValueTypeInteger: signList.push_back("I"); signListStr += "I"; signStrRegexp += "[cislqCISLQfdB@]"; break; default: signList.push_back("O"); signListStr += "O"; signStrRegexp += "@"; break; } } std::string luaMethodSignStr = methodName + "_" + signListStr; MappingMethodMap::iterator methodIt = _methodsMapping.find(luaMethodSignStr); if (methodIt == _methodsMapping.end()) { //映射表无该方法,查找匹配方法 MethodList matchMethods; std::regex regExp(signStrRegexp); for (MethodList::iterator methodIt = methodList.begin(); methodIt != methodList.end(); methodIt ++) { LuaExportMethodDescriptor *methodDesc = *methodIt; if (std::regex_match(methodDesc -> methodSignature(), regExp)) { matchMethods.push_back(methodDesc); } } if (matchMethods.size() > 0) { //选择最匹配的方法 //备选方法,如果没有最匹配的情况下使用 LuaExportMethodDescriptor *alternateMethod = NULL; for (MethodList::iterator methodIt = matchMethods.begin(); methodIt != matchMethods.end(); methodIt ++) { LuaExportMethodDescriptor *methodDesc = *methodIt; bool hasMatch = true; bool hasAlternate = false; for (int i = 0; i < methodDesc -> methodSignature().length(); i++) { if (i < signList.size()) { std::string luaSign = signList[i]; char nativeSign = methodDesc -> methodSignature()[i]; if (luaSign == "N" && nativeSign != 'f' && nativeSign != 'd') { hasAlternate = true; luaSign = "I"; } if (luaSign == "B" && nativeSign != 'B') { hasMatch = false; break; } if (luaSign == "I" && nativeSign != 'c' && nativeSign != 'i' && nativeSign != 's' && nativeSign != 'l' && nativeSign != 'q' && nativeSign != 'C' && nativeSign != 'I' && nativeSign != 'S' && nativeSign != 'L' && nativeSign != 'Q') { hasMatch = false; break; } if (luaSign == "O" && nativeSign != '@') { hasMatch = false; break; } } } if (hasMatch) { if (hasAlternate) { //记录备选方法 alternateMethod = methodDesc; } else { //设置匹配方法 targetMethod = methodDesc; break; } } } if (targetMethod == NULL) { if (alternateMethod != NULL) { //使用备选方法 targetMethod = alternateMethod; } else { //没有最匹配则使用第一个方法 targetMethod = *(matchMethods.begin()); } } //设置方法映射 _methodsMapping[luaMethodSignStr] = targetMethod; } } else { targetMethod = methodIt -> second; } } else { //不带参数 for (MethodList::iterator it = methodList.begin(); it != methodList.end(); it++) { LuaExportMethodDescriptor *methodDesc = *it; if (methodDesc -> methodSignature() == "") { targetMethod = methodDesc; break; } } } return targetMethod; } else if (methodList.size() == 1) { return *(methodList.begin()); } return NULL; }
bool JavaInstance::invokeMethod(const char* methodName, const NPVariant* args, uint32_t count, NPVariant* resultValue) { int i; jvalue *jArgs; JavaMethod *method = 0; VOID_TO_NPVARIANT(*resultValue); MethodList methodList = getClass()->methodsNamed(methodName); size_t numMethods = methodList.size(); // Try to find a good match for the overloaded method. The // fundamental problem is that JavaScript doesn have the // notion of method overloading and Java does. We could // get a bit more sophisticated and attempt to does some // type checking as we as checking the number of parameters. JavaMethod *aMethod; for (size_t methodIndex = 0; methodIndex < numMethods; methodIndex++) { aMethod = methodList[methodIndex]; if (aMethod->numParameters() == count) { method = aMethod; break; } } if (method == 0) { LOGW("unable to find an appropiate method\n"); return false; } const JavaMethod *jMethod = static_cast<const JavaMethod*>(method); if (count > 0) { jArgs = (jvalue *)malloc (count * sizeof(jvalue)); } else jArgs = 0; for (i = 0; i < count; i++) { JavaParameter* aParameter = jMethod->parameterAt(i); jArgs[i] = convertNPVariantToJValue(args[i], aParameter->getJNIType(), aParameter->type()); } jvalue result; // The following code can be conditionally removed once we have a Tiger update that // contains the new Java plugin. It is needed for builds prior to Tiger. { jobject obj = getLocalRef(); switch (jMethod->JNIReturnType()){ case void_type: callJNIMethodIDA<void>(obj, jMethod->methodID(obj), jArgs); break; case object_type: result.l = callJNIMethodIDA<jobject>(obj, jMethod->methodID(obj), jArgs); break; case boolean_type: result.z = callJNIMethodIDA<jboolean>(obj, jMethod->methodID(obj), jArgs); break; case byte_type: result.b = callJNIMethodIDA<jbyte>(obj, jMethod->methodID(obj), jArgs); break; case char_type: result.c = callJNIMethodIDA<jchar>(obj, jMethod->methodID(obj), jArgs); break; case short_type: result.s = callJNIMethodIDA<jshort>(obj, jMethod->methodID(obj), jArgs); break; case int_type: result.i = callJNIMethodIDA<jint>(obj, jMethod->methodID(obj), jArgs); break; case long_type: result.j = callJNIMethodIDA<jlong>(obj, jMethod->methodID(obj), jArgs); break; case float_type: result.f = callJNIMethodIDA<jfloat>(obj, jMethod->methodID(obj), jArgs); break; case double_type: result.d = callJNIMethodIDA<jdouble>(obj, jMethod->methodID(obj), jArgs); break; case invalid_type: default: break; } getJNIEnv()->DeleteLocalRef(obj); } convertJValueToNPVariant(result, jMethod->JNIReturnType(), jMethod->returnType(), resultValue); free (jArgs); return true; }
JSValuePtr JavaInstance::invokeMethod (ExecState *exec, const MethodList &methodList, const ArgList &args) { int i, count = args.size(); jvalue *jArgs; JSValuePtr resultValue; Method *method = 0; size_t numMethods = methodList.size(); // Try to find a good match for the overloaded method. The // fundamental problem is that JavaScript doesn have the // notion of method overloading and Java does. We could // get a bit more sophisticated and attempt to does some // type checking as we as checking the number of parameters. Method *aMethod; for (size_t methodIndex = 0; methodIndex < numMethods; methodIndex++) { aMethod = methodList[methodIndex]; if (aMethod->numParameters() == count) { method = aMethod; break; } } if (method == 0) { JS_LOG ("unable to find an appropiate method\n"); return jsUndefined(); } const JavaMethod *jMethod = static_cast<const JavaMethod*>(method); JS_LOG ("call %s %s on %p\n", UString(jMethod->name()).UTF8String().c_str(), jMethod->signature(), _instance->_instance); if (count > 0) { jArgs = (jvalue *)malloc (count * sizeof(jvalue)); } else jArgs = 0; for (i = 0; i < count; i++) { JavaParameter* aParameter = jMethod->parameterAt(i); jArgs[i] = convertValueToJValue(exec, args.at(exec, i), aParameter->getJNIType(), aParameter->type()); JS_LOG("arg[%d] = %s\n", i, args.at(exec, i).toString(exec).ascii()); } jvalue result; // Try to use the JNI abstraction first, otherwise fall back to // nornmal JNI. The JNI dispatch abstraction allows the Java plugin // to dispatch the call on the appropriate internal VM thread. RootObject* rootObject = this->rootObject(); if (!rootObject) return jsUndefined(); bool handled = false; if (rootObject->nativeHandle()) { jobject obj = _instance->_instance; JSValuePtr exceptionDescription = noValue(); const char *callingURL = 0; // FIXME, need to propagate calling URL to Java handled = dispatchJNICall(exec, rootObject->nativeHandle(), obj, jMethod->isStatic(), jMethod->JNIReturnType(), jMethod->methodID(obj), jArgs, result, callingURL, exceptionDescription); if (exceptionDescription) { throwError(exec, GeneralError, exceptionDescription.toString(exec)); free (jArgs); return jsUndefined(); } } // The following code can be conditionally removed once we have a Tiger update that // contains the new Java plugin. It is needed for builds prior to Tiger. if (!handled) { jobject obj = _instance->_instance; switch (jMethod->JNIReturnType()){ case void_type: callJNIMethodIDA<void>(obj, jMethod->methodID(obj), jArgs); break; case object_type: result.l = callJNIMethodIDA<jobject>(obj, jMethod->methodID(obj), jArgs); break; case boolean_type: result.z = callJNIMethodIDA<jboolean>(obj, jMethod->methodID(obj), jArgs); break; case byte_type: result.b = callJNIMethodIDA<jbyte>(obj, jMethod->methodID(obj), jArgs); break; case char_type: result.c = callJNIMethodIDA<jchar>(obj, jMethod->methodID(obj), jArgs); break; case short_type: result.s = callJNIMethodIDA<jshort>(obj, jMethod->methodID(obj), jArgs); break; case int_type: result.i = callJNIMethodIDA<jint>(obj, jMethod->methodID(obj), jArgs); break; case long_type: result.j = callJNIMethodIDA<jlong>(obj, jMethod->methodID(obj), jArgs); break; case float_type: result.f = callJNIMethodIDA<jfloat>(obj, jMethod->methodID(obj), jArgs); break; case double_type: result.d = callJNIMethodIDA<jdouble>(obj, jMethod->methodID(obj), jArgs); break; case invalid_type: default: break; } } switch (jMethod->JNIReturnType()){ case void_type: { resultValue = jsUndefined(); } break; case object_type: { if (result.l != 0) { const char *arrayType = jMethod->returnType(); if (arrayType[0] == '[') { resultValue = JavaArray::convertJObjectToArray(exec, result.l, arrayType, rootObject); } else { resultValue = JavaInstance::create(result.l, rootObject)->createRuntimeObject(exec); } } else { resultValue = jsUndefined(); } } break; case boolean_type: { resultValue = jsBoolean(result.z); } break; case byte_type: { resultValue = jsNumber(exec, result.b); } break; case char_type: { resultValue = jsNumber(exec, result.c); } break; case short_type: { resultValue = jsNumber(exec, result.s); } break; case int_type: { resultValue = jsNumber(exec, result.i); } break; case long_type: { resultValue = jsNumber(exec, result.j); } break; case float_type: { resultValue = jsNumber(exec, result.f); } break; case double_type: { resultValue = jsNumber(exec, result.d); } break; case invalid_type: default: { resultValue = jsUndefined(); } break; } free (jArgs); return resultValue; }