Logo Search packages:      
Sourcecode: falconpl version File versions  Download package

bool Falcon::VMachine::callItem ( const Item callable,
int32  paramCount,
e_callMode  mode = e_callNormal 
)

Calls an item. The item may contain any valid callable object:

  • An external (C/C++) function.
  • A falcon function.
  • A method
  • A class

External functions are immediately called, the flow of the VM being interrupted.

Falcon function and method calls prepare this vm to execute the first instruction of the item, pushing a stack frame that allows RET and similar pcodes to return to the VM instruction after the one that was currently being executed. Control may or may not return immediately to the caller; if e_callNormal, e_callInst or e_callPassIn modes are used, the function returns only after the called item returns, else the function returns immediately and the vm is readied to continue execution from the new position.

Class calls actually searches for the class constructor, and call that one. If the called class has no constructor, the function returns true but actually does nothing.

Before calling this function, enough parameters must be pushed in the stack using pushParameter() method.

The paramCount parameter must be smaller or equal to the size of the stack, or an unblockable error will be raised.

Parameters:
callable the item to be called.
paramCount the number of elements in the stack to be considered parameters.
mode the item call mode.
Returns:
false if the item is not callable, true if the item is called.

Definition at line 1142 of file vm.cpp.

References Falcon::Item::asArray(), Falcon::Item::asClass(), Falcon::Item::asFunction(), Falcon::Item::asMethodFunction(), Falcon::Item::asMethodObject(), Falcon::Item::asModule(), Falcon::Item::asObject(), Falcon::CoreArray::at(), Falcon::ExtFuncDef::call(), Falcon::Item::callBom(), callReturn(), Falcon::Module::code(), Falcon::CoreClass::constructor(), Falcon::CoreClass::createInstance(), e_callFrame, e_callInst, e_callInstFrame, e_callNormal, Falcon::Symbol::getExtFuncDef(), Falcon::Symbol::getFuncDef(), Falcon::LiveModule::globals(), Falcon::LiveModule::isAlive(), Falcon::Item::isCallable(), Falcon::Item::isClass(), Falcon::Item::isFbom(), Falcon::Symbol::isFunction(), Falcon::Item::isFunction(), Falcon::Item::isMethod(), Falcon::Item::isNil(), Falcon::CoreArray::length(), Falcon::FuncDef::locals(), m_bomParams, m_code, m_currentGlobals, m_currentModule, m_event, m_pc, m_pc_next, m_stack, m_stackBase, m_symbol, m_tryFrame, Falcon::Symbol::module(), Falcon::FuncDef::offset(), Falcon::FuncDef::params(), raiseError(), run(), Falcon::Item::setNil(), Falcon::Item::setObject(), and Falcon::Item::type.

Referenced by callItemAtomic(), callItemPassIn(), and link().

{
   Symbol *target;
   Item oldsender;
   CoreObject *self = 0;
   LiveModule *targetMod;

   if ( ! callable.isCallable() )
      return false;

   switch( callable.type() )
   {
      case FLC_ITEM_FBOM:
      {
         m_bomParams = paramCount;
         bool bomRet = callable.callBom( this );
         m_stack->resize( m_stack->size() - paramCount );
         return bomRet;
      }

      case FLC_ITEM_METHOD:
         self = callable.asMethodObject();
         target = callable.asMethodFunction();
         targetMod = callable.asModule();
      break;

      case FLC_ITEM_FUNC:
         target = callable.asFunction();
         targetMod = callable.asModule();
      break;

      case FLC_ITEM_CLSMETHOD:
      case FLC_ITEM_CLASS:
      {
         CoreClass *cls = callable.asClass();
         if( callMode != e_callNormal && callMode != e_callFrame ) {
            self = m_regS1.asObject();
         }
         else {
            self = cls->createInstance();
         }

         // if the class has not a constructor, we just set the item in A
         // and return
         if ( cls->constructor().isNil() ) {
            m_regA.setObject( self );
            // pop the stack
            m_stack->resize( m_stack->size() - paramCount );
            return true;
         }

         if ( ! cls->constructor().asModule()->isAlive() )
         {
            const_cast<Item *>(&callable)->setNil();
            return false;
         }

         target = cls->constructor().asFunction();
         targetMod = cls->constructor().asModule();
      }
      break;

      case FLC_ITEM_ARRAY:
      {
         CoreArray *arr = callable.asArray();

         if ( arr->length() != 0 )
         {
            const Item &carr = callable.asArray()->at(0);

            if ( carr.isFbom() || carr.isFunction() ||
               carr.isMethod() || carr.isClass() )
            {
               uint32 arraySize = arr->length();
               uint32 sizeNow = m_stack->size();

               // prevent calling too wide arrays.
               if ( paramCount + arraySize > 254 )
               {
                  raiseError( e_too_params, "CALL" );
                  if ( paramCount != 0 )
                     m_stack->resize( sizeNow - paramCount );
                  return false;
               }

               // move parameters beyond array parameters
               arraySize -- ; // first element is the callable item.
               if ( arraySize > 0 )
               {
                  // first array element is the called item.
                  m_stack->resize( sizeNow + arraySize );

                  sizeNow -= paramCount;
                  for ( uint32 j = sizeNow + paramCount; j > sizeNow; j -- )
                  {
                     m_stack->itemAt( j-1 + arraySize ) = m_stack->itemAt( j-1 );
                  }

                  // push array paramers
                  for ( uint32 i = 0; i < arraySize; i ++ )
                  {
                     m_stack->itemAt( i + sizeNow ) = (*arr)[i + 1];
                  }
               }

               return callItem( carr, arraySize + paramCount, callMode );
            }
         }

         if ( paramCount != 0 )
               m_stack->resize( m_stack->size() - paramCount );
         return false;
      }
      break;

      default:
         // non callableitem
         if ( paramCount != 0 )
            m_stack->resize( m_stack->size() - paramCount );
         return false;
   }

   if ( target->isFunction() )
   {
      // manage internal functions
      FuncDef *tg_def = target->getFuncDef();

      // manage an internal function
      // ensure against optional parameters.
      if( paramCount < tg_def->params() )
      {
         m_stack->resize( m_stack->size() + tg_def->params() - paramCount );
         paramCount = tg_def->params();
      }
   }

   // space for frame
   m_stack->resize( m_stack->size() + VM_FRAME_SPACE );
   StackFrame *frame = (StackFrame *) m_stack->at( m_stack->size() - VM_FRAME_SPACE );
   frame->header.type( FLC_ITEM_INVALID );
   frame->m_symbol = m_symbol;
   frame->m_ret_pc = m_pc_next;
   frame->m_call_pc = m_pc;
   frame->m_module = m_currentModule;
   frame->m_globals = m_currentGlobals;
   frame->m_param_count = (byte)paramCount;
   frame->m_stack_base = m_stackBase;
   frame->m_try_base = m_tryFrame;
   frame->m_break = false;
   frame->m_suspend = false;

   // iterative processing support
   frame->m_endFrameFunc = 0;

   // now we can change the stack base
   m_stackBase = m_stack->size();

   // Save the stack frame
   if ( callMode == e_callInst || callMode == e_callInstFrame )
   {
      frame->m_initFrame = true;
   }
   else
   {
      frame->m_initFrame = false;
      frame->m_sender = m_regS2;
      m_regS2 = m_regS1;
      if ( self == 0 )
         m_regS1.setNil();
      else
         m_regS1.setObject( self );
   }

   if ( target->isFunction() )
   {
      // manage internal functions
      FuncDef *tg_def = target->getFuncDef();
      // space for locals
      if ( tg_def->locals() > 0 )
         m_stack->resize( m_stackBase + tg_def->locals() );

      m_code = target->module()->code();
      m_currentModule = target->module();
      m_currentGlobals = &targetMod->globals();
      m_symbol = target;

      //jump
      m_pc_next = tg_def->offset();

      // If the function is not called internally by the VM, another run is issued.
      if( callMode == e_callNormal || callMode == e_callInst )
      {
         // hitting the stack limit forces the RET code to raise a return event,
         // and this forces the machine to exit run().

         m_pc = m_pc_next;
         frame->m_break = true;
         if ( m_event == eventSuspend )
            frame->m_suspend = true;
         run();
      }
   }
   else
   {
      m_symbol = target; // so we can have adequate tracebacks.
      m_currentModule = target->module();
      m_currentGlobals = &targetMod->globals();

      // if we aren't in a frame call, call the item directly
      if( callMode == e_callNormal || callMode == e_callInst )
      {
         regA().setNil(); // clear return value if calling external functions
         target->getExtFuncDef()->call( this );
         if ( callable.isClass() )
            m_regA.setObject( self );
         callReturn();
      }
      //else, ask the  VM to call it by using the fake m_pc
      else {
         if ( callable.isClass() )
         {
            m_regS1 = self;
            m_pc_next = i_pc_call_external_ctor;
         }
         else  {
            m_pc_next = i_pc_call_external;
         }
      }
   }

   return true;
}


Generated by  Doxygen 1.6.0   Back to index