bool objCMethodDeclHasActionAttributeImpl( const clang::ObjCMethodDecl *decl, const std::string& action, const CAPA::RuleBase& rule, std::string* comment) { if(decl == nullptr) { return false; } // Check the method directly if(baseDeclHasActionAttributeImpl(decl, action, rule, comment)) { return true; } // That failed, check if it has a property declaration and use that if(decl->isPropertyAccessor() && baseDeclHasActionAttributeImpl(decl->findPropertyDecl(), action, rule, comment)) { return true; } // Check if the method comes from a protocol, because then it doesn't have a class // interface const auto protocol = clang::dyn_cast<clang::ObjCProtocolDecl>(decl->getDeclContext()); if(protocol) { const auto method = protocol->lookupMethod(decl->getSelector(), decl->isInstanceMethod()); return baseDeclHasActionAttributeImpl(method, action, rule, comment); } return objCMethodDeclHasAttributeFromCategory(decl, action, rule, comment); }
bool methodCallPrologue(Thread* t, AbsStack slot, Value self, String* methodName, word numReturns, uword numParams, bool isTailcall) { auto method = lookupMethod(t, self, methodName); // Idea is like this: // If we're calling the real method, the object is moved to the 'this' slot and the method takes its place. // If we're calling opMethod, the object is left where it is (or the custom context is moved to its place), // the method name goes where the context was, and we use callPrologue2 with a closure that's not on the stack. if(method.type != CrocType_Null) { t->stack[slot] = method; t->stack[slot + 1] = self; return callPrologue(t, slot, numReturns, numParams, isTailcall); } else { if(auto mm = getMM(t, self, MM_Method)) { t->stack[slot] = self; t->stack[slot + 1] = Value::from(methodName); return funcCallPrologue(t, mm, slot, numReturns, slot, numParams + 1, isTailcall); } else { pushTypeStringImpl(t, self); return croc_eh_throwStd(*t, "MethodError", "No implementation of method '%s' or %s for type '%s'", methodName->toCString(), MetaNames[MM_Method], croc_getString(*t, -1)); } } }
bool LuaInterface::callMethod(void *o, const char *func, float a, float b) { lookupMethod(o, func); lua_pushnumber(_lua, a); lua_pushnumber(_lua, b); return doCall(2+1); // first parameter is self (aka o) }
int main(int argc, char *argv[]) { Class *array_class, *main_class; Object *system_loader, *array; MethodBlock *mb; InitArgs args; int class_arg; char *cpntr; int status; int i; setDefaultInitArgs(&args); class_arg = parseCommandLine(argc, argv, &args); args.main_stack_base = &array_class; if(!initVM(&args)) { printf("Could not initialise VM. Aborting.\n"); exit(1); } if((system_loader = getSystemClassLoader()) == NULL) goto error; mainThreadSetContextClassLoader(system_loader); for(cpntr = argv[class_arg]; *cpntr; cpntr++) if(*cpntr == '.') *cpntr = '/'; main_class = findClassFromClassLoader(argv[class_arg], system_loader); if(main_class != NULL) initClass(main_class); if(exceptionOccurred()) goto error; mb = lookupMethod(main_class, SYMBOL(main), SYMBOL(_array_java_lang_String__V)); if(mb == NULL || !(mb->access_flags & ACC_STATIC)) { signalException(java_lang_NoSuchMethodError, "main"); goto error; } /* Create the String array holding the command line args */ i = class_arg + 1; if((array_class = findArrayClass(SYMBOL(array_java_lang_String))) && (array = allocArray(array_class, argc - i, sizeof(Object*)))) { Object **args = ARRAY_DATA(array, Object*) - i; for(; i < argc; i++) if(!(args[i] = Cstr2String(argv[i]))) break; /* Call the main method */ if(i == argc) executeStaticMethod(main_class, mb, array); }
void signalChainedExceptionClass(Class *exception, char *message, Object *cause) { Object *exp = allocObject(exception); Object *str = message == NULL ? NULL : Cstr2String(message); MethodBlock *init = lookupMethod(exception, SYMBOL(object_init), SYMBOL(_java_lang_String__V)); if(exp && init) { executeMethod(exp, init, str); if(cause && !exceptionOccurred()) { MethodBlock *mb = lookupMethod(exception, SYMBOL(initCause), SYMBOL(_java_lang_Throwable__java_lang_Throwable)); if(mb) executeMethod(exp, mb, cause); } setException(exp); } }
/* * The CreateCl opcode is specified as not being allowed before the * class it creates exists, and closure classes are always unique. * * This means even if we're not in RepoAuthoritative mode, as long as * this code is reachable it will always use the same closure Class*, * so we can just burn it into the TC without using RDS. */ void emitCreateCl(HTS& env, int32_t numParams, const StringData* clsName) { auto const cls = Unit::lookupClassOrUniqueClass(clsName); auto const invokeFunc = cls->lookupMethod(s_uuinvoke.get()); auto const clonedFunc = invokeFunc->cloneAndSetClass( const_cast<Class*>(curClass(env)) ); assert(cls && (cls->attrs() & AttrUnique)); auto const closure = allocObjFast(env, cls); gen(env, IncRef, closure); auto const ctx = [&]{ if (!curClass(env)) return cns(env, nullptr); auto const ldctx = gen(env, LdCtx, fp(env)); if (invokeFunc->attrs() & AttrStatic) { return gen(env, ConvClsToCctx, gen(env, LdClsCtx, ldctx)); } gen(env, IncRefCtx, ldctx); return ldctx; }(); gen(env, StClosureCtx, closure, ctx); gen(env, StClosureFunc, FuncData(clonedFunc), closure); SSATmp* args[numParams]; for (int32_t i = 0; i < numParams; ++i) { args[numParams - i - 1] = popF(env); } int32_t propId = 0; for (; propId < numParams; ++propId) { gen( env, StClosureArg, PropByteOffset(cls->declPropOffset(propId)), closure, args[propId] ); } // Closure static variables are per instance, and need to start // uninitialized. After numParams use vars, the remaining instance // properties hold any static locals. assert(cls->numDeclProperties() == clonedFunc->numStaticLocals() + numParams); for (int32_t numDeclProperties = cls->numDeclProperties(); propId < numDeclProperties; ++propId) { gen( env, StClosureArg, PropByteOffset(cls->declPropOffset(propId)), closure, cns(env, Type::Uninit) ); } push(env, closure); }
bool LuaInterface::callMethod(void *o, const char *func, void* other) { lookupMethod(o, func); int lty = lua_rawgetp(_lua, LUA_REGISTRYINDEX, other); #ifdef _DEBUG assert(lty == LUA_TUSERDATA); #endif return doCall(1+1); // first parameter is self (aka o) }
/** * Recursively searches the scope hierarchy for the instance of * a method having the given name. */ Method* CodeParser::lookupMethod( Scope* scope, const char* signature ) { // is the scope a class scope? if( scope->getScopeType() == CLASS_SCOPE ) { ScopeContainer* container = (ScopeContainer*)scope; Method* method = container->lookupMethod( signature ); if( method != NULL ) { return method; } } // look for the method via the parent scope Scope* parentScope = scope->getParentSope(); return ( parentScope != NULL ) ? lookupMethod( parentScope, signature ) : NULL; }
void Java_java_lang_Class_newInstance(void) { INSTANCE_CLASS currentClass = getFP()->thisMethod->ofClass; CLASS clazz = topStackAsType(CLASS); if (IS_ARRAY_CLASS(clazz) || ((clazz->accessFlags & (ACC_INTERFACE | ACC_ABSTRACT)) != 0)) { raiseException("java/lang/InstantiationException"); return; } if (classHasAccessToClass(currentClass, clazz)) { METHOD method = lookupMethod(clazz, initNameAndType, currentClass); if ( (method != NULL) && (method->ofClass == (INSTANCE_CLASS)clazz) /* I don't understand why, but we're not allowed access to * a protected <init> method of a superclass. */ && classHasAccessToMember(currentClass, (method->accessFlags & ~ACC_PROTECTED), (INSTANCE_CLASS)clazz, (INSTANCE_CLASS)clazz) ) { START_TEMPORARY_ROOTS DECLARE_TEMPORARY_ROOT(INSTANCE, object, instantiate((INSTANCE_CLASS)clazz)); if (object != NULL) { /* Put the result back on the stack */ topStackAsType(INSTANCE) = object; /* Will get the result */ /* We now need to call the initializer. We'd like to just * push a second copy of the object onto the stack, and then * do pushFrame(method). But we can't, because that would * not necessarily coincide with the stack map of the * current method. */ pushFrame(RunCustomCodeMethod); pushStackAsType(CustomCodeCallbackFunction, newInstanceReturnObject); pushStackAsType(INSTANCE, object); /* pushFrame may signal a stack overflow. */ pushFrame(method); } else { /* We will already have thrown an appropriate error */ } END_TEMPORARY_ROOTS return; } }
UserFSNode::UserFSNode(Class* cls, const Variant& context /*= null */) { VMRegAnchor _; const Func* ctor; m_cls = cls; if (LookupResult::MethodFoundWithThis != g_context->lookupCtorMethod(ctor, m_cls)) { raise_error("Unable to call %s'n constructor", m_cls->name()->data()); } m_obj = ObjectData::newInstance(m_cls); m_obj.o_set("context", context); Variant ret; g_context->invokeFuncFew(ret.asTypedValue(), ctor, m_obj.get()); m_Call = lookupMethod(s_call.get()); }
/** * Parses the method call within an expression */ int CodeParser::parseExpression_MethodCall( const char* methodName, Scope* scope, TokenStack* stack ) { int errorCode = 0; list<Parameter*> params; // parse the method parameters if( ( errorCode = parseMethodParameters( scope, stack, params ) ) ) { return errorCode; } // generate the method signature const char* signature = generateSignature( methodName, params ); // lookup the method Method* method = lookupMethod( scope, signature ); if( method == NULL ) { // generate the error message char* errorMessage = new char[256]; sprintf( errorMessage, "Method '%s' could not be found", signature ); // display the error message SYNTAX_ERROR( errorMessage, stack->last() ); delete errorMessage; return -1; } else { printf( "CodeParser::parseExpression: Method call - [%s]\n", signature ); // get the code buffer CodeBuffer* cb = scope->getCodeBuffer(); // parse the method parameter // setup the method call // instruction: PARAMS methodParams // instruction: INVOKE methodSig OFFSET_T offset1 = cb->putInstruction( PARAMS << A_OP ); OFFSET_T offset2 = cb->putInstruction( INVOKE << A_OP ); // add the parameter and reference data scope->addParameterData( new ParameterData( state->nextParamId(), params, offset1 ) ); scope->addReferenceData( new ReferenceData( state->nextDataRefId(), signature, offset2 ) ); return 0; } }
bool objOffsetIsset( ObjectData* base, TypedValue offset, bool validate /* = true */ ) { auto exists = objOffsetExists(base, offset); // Unless we called ArrayObject::offsetExists, there's nothing more to do. if (exists != OffsetExistsResult::IssetIfNonNull) { return (int)exists; } // For ArrayObject::offsetExists, we need to check the value at `offset`. If // it's null, then we return false. We can't call the offsetGet method on // `base` because users aren't expecting offsetGet to be called for // `isset(...)` expressions, so call the method on the base ArrayObject class. auto const cls = SystemLib::s_ArrayObjectClass; auto const method = cls->lookupMethod(s_offsetGet.get()); assert(method != nullptr); auto result = g_context->invokeMethodV(base, method, InvokeArgs(&offset, 1)); return !result.isNull(); }
void SmalltalkVM::setupVarsForDoesNotUnderstand(hptr<TMethod>& method, hptr<TObjectArray>& arguments, TSymbol* selector, TClass* receiverClass) { // Looking up the #doesNotUnderstand: method: method = newPointer(lookupMethod(globals.badMethodSymbol, receiverClass)); if (method == 0) { // Something goes really wrong. // We could not continue the execution std::fprintf(stderr, "Could not locate #doesNotUnderstand:\n"); //exit(1); } // Protecting the selector pointer because it may be invalidated later hptr<TSymbol> failedSelector = newPointer(selector); // We're replacing the original call arguments with custom one hptr<TObjectArray> errorArguments = newObject<TObjectArray>(2); // Filling in the failed call context information errorArguments[0] = arguments[0]; // receiver object errorArguments[1] = failedSelector; // message selector that failed // Replacing the arguments with newly created one arguments = errorArguments; }
void c_Closure::init(int numArgs, ActRec* ar, TypedValue* sp) { auto const cls = getVMClass(); auto const invokeFunc = cls->lookupMethod(s_uuinvoke.get()); if (ar->hasThis()) { if (invokeFunc->isStatic()) { // Only set the class for static closures. setClass(ar->getThis()->getVMClass()); } else { setThis(ar->m_this); ar->getThis()->incRefCount(); } } else if (ar->hasClass()) { setClass(ar->getClass()); } else { m_ctx = nullptr; } /* * Copy the use vars to instance variables, and initialize any * instance properties that are for static locals to KindOfUninit. */ auto const numDeclProperties = cls->numDeclProperties(); assertx(numDeclProperties - numArgs == getInvokeFunc()->numStaticLocals()); auto beforeCurUseVar = sp + numArgs; auto curProperty = getUseVars(); int i = 0; assertx(numArgs <= numDeclProperties); for (; i < numArgs; i++) { // teleport the references in here so we don't incref tvCopy(*--beforeCurUseVar, *curProperty++); } for (; i < numDeclProperties; ++i) { tvWriteUninit(curProperty++); } }
void SmalltalkVM::doSendMessage(TVMExecutionContext& ec, TSymbol* selector, TObjectArray* arguments, TClass* receiverClass /*= 0*/ ) { hptr<TObjectArray> messageArguments = newPointer(arguments); if (!receiverClass) { TObject* receiver = messageArguments[0]; assert(receiver != 0); receiverClass = isSmallInteger(receiver) ? globals.smallIntClass : receiver->getClass(); assert(receiverClass != 0); } hptr<TMethod> receiverMethod = newPointer(lookupMethod(selector, receiverClass)); // Checking whether we found a method if (receiverMethod == 0) { // Oops. Method was not found. In this case we should send #doesNotUnderstand: message to the receiver setupVarsForDoesNotUnderstand(receiverMethod, messageArguments, selector, receiverClass); // Continuing the execution just as if #doesNotUnderstand: was the actual selector that we wanted to call } // Save stack and opcode pointers ec.storePointers(); // Create a new context for the giving method and arguments hptr<TContext> newContext = newObject<TContext>(); hptr<TObjectArray> newStack = newObject<TObjectArray>(receiverMethod->stackSize); hptr<TObjectArray> newTemps = newObject<TObjectArray>(receiverMethod->temporarySize); newContext->stack = newStack; newContext->temporaries = newTemps; newContext->arguments = messageArguments; newContext->method = receiverMethod; newContext->stackTop = 0; newContext->bytePointer = 0; // Suppose that current send message operation is last operation in the current context. // If it is true then next instruction will be either stackReturn or blockReturn. // // VM will switch to the newContext, perform it and then switch back to the current context // for the single one return instruction. This is pretty dumb to load the whole context // just to exit it immediately. Therefore, we looking one instruction ahead to see if it is // a return instruction. If it is, we may skip our context and set our previousContext as // previousContext for the newContext. In case of blockReturn it will be the previousContext // of the wrapping method context. uint8_t nextInstruction = ec.currentContext->method->byteCodes->getByte(ec.bytePointer); if (nextInstruction == (opcode::doSpecial * 16 + special::stackReturn)) { // Optimizing stack return newContext->previousContext = ec.currentContext->previousContext; } else if (nextInstruction == (opcode::doSpecial * 16 + special::blockReturn) && (ec.currentContext->getClass() == globals.blockClass)) { // Optimizing block return newContext->previousContext = ec.currentContext.cast<TBlock>()->creatingContext->previousContext; } else { newContext->previousContext = ec.currentContext; } // Replace current context with the new one. On the next iteration, // VM will start interpreting instructions from the new context. ec.currentContext = newContext; ec.loadPointers(); m_messagesSent++; }
APCHandle::Pair APCObject::Construct(ObjectData* objectData) { // This function assumes the object and object/array down the tree have no // internal references and do not implement the serializable interface. assert(!objectData->instanceof(SystemLib::s_SerializableClass)); auto cls = objectData->getVMClass(); auto clsOrName = make_class(cls); if (clsOrName.right()) return ConstructSlow(objectData, clsOrName); // We have a persistent Class. Build an array of APCHandle* to mirror the // declared properties in the object. auto const propInfo = cls->declProperties(); auto const hasDynProps = objectData->hasDynProps(); auto const numRealProps = propInfo.size(); auto const numApcProps = numRealProps + hasDynProps; auto size = sizeof(APCObject) + sizeof(APCHandle*) * numApcProps; auto const apcObj = new (malloc_huge(size)) APCObject(clsOrName, numApcProps); apcObj->m_persistent = 1; // Set a few more flags for faster fetching: whether or not the object has a // wakeup method, and whether or not we can use a fast path that avoids // default-initializing properties before setting them to their APC values. if (!cls->lookupMethod(s___wakeup.get())) apcObj->m_no_wakeup = 1; if (!cls->instanceCtor()) { apcObj->m_fast_init = 1; } auto const apcPropVec = apcObj->persistentProps(); auto const objPropVec = objectData->propVec(); const TypedValueAux* propInit = nullptr; for (unsigned i = 0; i < numRealProps; ++i) { auto const attrs = propInfo[i].attrs; assert((attrs & AttrStatic) == 0); const TypedValue* objProp; if (attrs & AttrBuiltin) { // Special properties like the Memoize cache should be set to their // default value, not the current value. if (propInit == nullptr) { propInit = cls->pinitVec().empty() ? &cls->declPropInit()[0] : &(*cls->getPropData())[0]; } objProp = propInit + i; } else { objProp = objPropVec + i; } auto val = APCHandle::Create(tvAsCVarRef(objProp), false, APCHandleLevel::Inner, true); size += val.size; apcPropVec[i] = val.handle; } if (UNLIKELY(hasDynProps)) { auto val = APCHandle::Create(objectData->dynPropArray(), false, APCHandleLevel::Inner, true); size += val.size; apcPropVec[numRealProps] = val.handle; } return {apcObj->getHandle(), size}; }
void detachThread(Thread *thread) { Object *group, *excep; //ExecEnv *ee = thread->ee; //Object *jThread = ee->thread; Object *jThread = thread->thread; Object *vmthread = (Object*)INST_DATA(jThread)[vmthread_offset]; /* Get the thread's group */ group = (Object *)INST_DATA(jThread)[group_offset]; /* If there's an uncaught exception, call uncaughtException on the thread's exception handler, or the thread's group if this is unset */ if((excep = exceptionOccurred())) { FieldBlock *fb = findField(thread_class, SYMBOL(exceptionHandler), SYMBOL(sig_java_lang_Thread_UncaughtExceptionHandler)); Object *thread_handler = fb == NULL ? NULL : (Object *)INST_DATA(jThread)[fb->offset]; Object *handler = thread_handler == NULL ? group : thread_handler; MethodBlock *uncaught_exp = lookupMethod(handler->classobj, SYMBOL(uncaughtException), SYMBOL(_java_lang_Thread_java_lang_Throwable__V)); if(uncaught_exp) { clearException(); DummyFrame dummy; executeMethod(&dummy, handler, uncaught_exp, jThread, excep); } else printException(); } /* remove thread from thread group */ DummyFrame dummy; executeMethod(&dummy, group, (CLASS_CB(group->classobj))->method_table[rmveThrd_mtbl_idx], jThread); /* set VMThread ref in Thread object to null - operations after this point will result in an IllegalThreadStateException */ INST_DATA(jThread)[vmthread_offset] = 0; /* Remove thread from the ID map hash table */ deleteThreadFromHash(thread); /* Disable suspend to protect lock operation */ disableSuspend(thread); /* Grab global lock, and update thread structures protected by it (thread list, thread ID and number of daemon threads) */ pthread_mutex_lock(&lock); /* remove from thread list... */ if((thread->prev->next = thread->next)) thread->next->prev = thread->prev; /* One less live thread */ threads_count--; /* Recycle the thread's thread ID */ freeThreadID(thread->id); /* Handle daemon thread status */ if(!INST_DATA(jThread)[daemon_offset]) non_daemon_thrds--; pthread_mutex_unlock(&lock); /* notify any threads waiting on VMThread object - these are joining this thread */ objectLock(vmthread); objectNotifyAll(vmthread); objectUnlock(vmthread); /* It is safe to free the thread's ExecEnv and stack now as these are only used within the thread. It is _not_ safe to free the native thread structure as another thread may be concurrently accessing it. However, they must have a reference to the VMThread -- therefore, it is safe to free during GC when the VMThread is determined to be no longer reachable. */ // sysFree(ee->stack); //sysFree(ee); /* If no more daemon threads notify the main thread (which may be waiting to exit VM). Note, this is not protected by lock, but main thread checks again */ if(non_daemon_thrds == 0) { /* No need to bother with disabling suspension * around lock, as we're no longer on thread list */ pthread_mutex_lock(&exit_lock); pthread_cond_signal(&exit_cv); pthread_mutex_unlock(&exit_lock); } TRACE("Thread 0x%x id: %d detached from VM\n", thread, thread->id); }
int main(int argc, char *argv[]) { Class *array_class, *main_class; Object *system_loader, *array; MethodBlock *mb; InitArgs args; int class_arg; char *cpntr; int status; int i; setDefaultInitArgs(&args); class_arg = parseCommandLine(argc, argv, &args); args.main_stack_base = &array_class; initVM(&args); if((system_loader = getSystemClassLoader()) == NULL) { printf("Cannot create system class loader\n"); printException(); exitVM(1); } mainThreadSetContextClassLoader(system_loader); for(cpntr = argv[class_arg]; *cpntr; cpntr++) if(*cpntr == '.') *cpntr = '/'; if((main_class = findClassFromClassLoader(argv[class_arg], system_loader)) != NULL) initClass(main_class); if(exceptionOccurred()) { printException(); exitVM(1); } mb = lookupMethod(main_class, SYMBOL(main), SYMBOL(_array_java_lang_String__V)); if(!mb || !(mb->access_flags & ACC_STATIC)) { printf("Static method \"main\" not found in %s\n", argv[class_arg]); exitVM(1); } /* Create the String array holding the command line args */ i = class_arg + 1; if((array_class = findArrayClass(SYMBOL(array_java_lang_String))) && (array = allocArray(array_class, argc - i, sizeof(Object*)))) { Object **args = (Object**)ARRAY_DATA(array) - i; for(; i < argc; i++) if(!(args[i] = Cstr2String(argv[i]))) break; /* Call the main method */ if(i == argc) executeStaticMethod(main_class, mb, array); } /* ExceptionOccurred returns the exception or NULL, which is OK for normal conditionals, but not here... */ if((status = exceptionOccurred() ? 1 : 0)) printException(); /* Wait for all but daemon threads to die */ mainThreadWaitToExitVM(); exitVM(status); }
bool LuaInterface::callMethod(ScriptObject *obj, const char *func, float f) { lookupMethod(obj, func); lua_pushnumber(_lua, f); return doCall(2); }
UserFile::UserFile(Class *cls, CVarRef context /*= null */) : UserFSNode(cls) { m_StreamOpen = lookupMethod(s_stream_open.get()); m_StreamClose = lookupMethod(s_stream_close.get()); m_StreamRead = lookupMethod(s_stream_read.get()); m_StreamWrite = lookupMethod(s_stream_write.get()); m_StreamSeek = lookupMethod(s_stream_seek.get()); m_StreamTell = lookupMethod(s_stream_tell.get()); m_StreamEof = lookupMethod(s_stream_eof.get()); m_StreamFlush = lookupMethod(s_stream_flush.get()); m_StreamTruncate = lookupMethod(s_stream_truncate.get()); m_StreamLock = lookupMethod(s_stream_lock.get()); m_StreamStat = lookupMethod(s_stream_stat.get()); m_UrlStat = lookupMethod(s_url_stat.get()); m_Unlink = lookupMethod(s_unlink.get()); m_Rename = lookupMethod(s_rename.get()); m_Mkdir = lookupMethod(s_mkdir.get()); m_Rmdir = lookupMethod(s_rmdir.get()); m_isLocal = true; // UserFile, to match Zend, should not call stream_close() unless it was ever // opened. This is a bit of a misuse of this field but the API doesn't allow // one direct access to an not-yet-opened stream resource so it should be // safe. m_closed = true; }
bool LuaInterface::callMethod(void *o, const char *func) { lookupMethod(o, func); return doCall(0+1); // first parameter is self (aka o) }
UserFile::UserFile(Class *cls, CVarRef context /*= null */) : UserFSNode(cls), m_opened(false) { m_StreamOpen = lookupMethod(s_stream_open.get()); m_StreamClose = lookupMethod(s_stream_close.get()); m_StreamRead = lookupMethod(s_stream_read.get()); m_StreamWrite = lookupMethod(s_stream_write.get()); m_StreamSeek = lookupMethod(s_stream_seek.get()); m_StreamTell = lookupMethod(s_stream_tell.get()); m_StreamEof = lookupMethod(s_stream_eof.get()); m_StreamFlush = lookupMethod(s_stream_flush.get()); m_StreamTruncate = lookupMethod(s_stream_truncate.get()); m_StreamLock = lookupMethod(s_stream_lock.get()); m_UrlStat = lookupMethod(s_url_stat.get()); m_isLocal = true; }
UserDirectory::UserDirectory(Class* cls) : UserFSNode(cls) { m_DirOpen = lookupMethod(s_dir_opendir.get()); m_DirClose = lookupMethod(s_dir_closedir.get()); m_DirRead = lookupMethod(s_dir_readdir.get()); m_DirRewind = lookupMethod(s_dir_rewinddir.get()); }
bool LuaInterface::callMethod(ScriptObject *obj, const char *func) { lookupMethod(obj, func); return doCall(1); }