Zephir\Backends\ZendEngine2\FcallManager::genFcallCode PHP Method

genFcallCode() public method

public genFcallCode ( )
    public function genFcallCode()
    {
        $codePrinter = new CodePrinter();
        $codePrinter->output('#ifndef ZEPHIR_KERNEL_FCALL_INTERNAL_H');
        $codePrinter->output('#define ZEPHIR_KERNEL_FCALL_INTERNAL_H');
        $codePrinter->increaseLevel();
        ksort($this->requiredMacros);
        foreach ($this->requiredMacros as $name => $info) {
            list($scope, $mode, $paramCount) = $info;
            $paramsStr = '';
            $retParam = '';
            $retValueUsed = '0';
            $params = array();
            $zvals = array();
            $initStatements = array();
            $postStatements = array();
            for ($i = 0; $i < $paramCount; ++$i) {
                $params[] = 'p' . $i;
            }
            if ($paramCount) {
                $paramsStr = ', ' . implode(', ', $params);
            }
            if ($mode == 'CALL_INTERNAL_METHOD_P') {
                $retValueUsed = '1';
                $retParam = 'return_value_ptr';
                $initStatements[] = 'ZEPHIR_INIT_NVAR(*(return_value_ptr)); \\';
            }
            $objParam = $scope ? 'scope_ce, ' : 'object, ';
            $macroName = $name . '(' . ($retParam ? $retParam . ', ' : '') . $objParam . 'method' . $paramsStr . ')';
            $codePrinter->output('#define ' . $macroName . ' \\');
            if (!$retParam) {
                $retParam = 'return_value';
            }
            $codePrinter->increaseLevel();
            $codePrinter->output('do { \\');
            $codePrinter->increaseLevel();
            if ($mode == 'CALL_INTERNAL_METHOD_NORETURN_P') {
                $codePrinter->output('zval *rv = NULL; \\');
                $codePrinter->output('zval **rvp = &rv; \\');
                $codePrinter->output('ALLOC_INIT_ZVAL(rv); \\');
                $retParam = 'rvp';
            }
            $codePrinter->output('ZEPHIR_BACKUP_SCOPE() \\');
            $codePrinter->output('ZEPHIR_BACKUP_THIS_PTR() \\');
            if (!$scope) {
                $codePrinter->output('ZEPHIR_SET_THIS(object); \\');
                $codePrinter->output('ZEPHIR_SET_SCOPE((Z_TYPE_P(object) == IS_OBJECT ? Z_OBJCE_P(object) : NULL), (Z_TYPE_P(object) == IS_OBJECT ? Z_OBJCE_P(object) : NULL)); \\');
            } else {
                $codePrinter->output('ZEPHIR_SET_THIS(NULL); \\');
                $codePrinter->output('ZEPHIR_SET_SCOPE(scope_ce, scope_ce); \\');
            }
            /* Create new zval's for parameters */
            for ($i = 0; $i < $paramCount; ++$i) {
                //$zv = '_' . $params[$i];
                //$zvals[] = $zv;
                //$initStatements[] = 'ALLOC_ZVAL(' . $zv . '); \\';
                //$initStatements[] = 'INIT_PZVAL_COPY(' . $zv . ', ' . $params[$i] . '); \\';
                //$postStatements[] = 'zval_ptr_dtor(&' . $zv . '); \\';
                $zv = $params[$i];
                $zvals[] = $zv;
                $initStatements[] = 'Z_ADDREF_P(' . $zv . '); \\';
                $postStatements[] = 'Z_DELREF_P(' . $zv . '); \\';
            }
            if ($i) {
                //$codePrinter->output('zval *' . implode(', *', $zvals) . '; \\');
            }
            foreach ($initStatements as $statement) {
                $codePrinter->output($statement);
            }
            $zvalStr = $i ? ', ' . implode(', ', $zvals) : '';
            $retExpr = '';
            if ($retParam) {
                if ($retParam == 'return_value') {
                    $retExpr = ', return_value, return_value_ptr';
                } else {
                    $retExpr = ', *' . $retParam . ', ' . $retParam;
                }
            }
            $codePrinter->output('method(0' . $retExpr . ', ' . ($scope ? 'NULL, ' : $objParam) . $retValueUsed . $zvalStr . ' TSRMLS_CC); \\');
            if ($mode == 'CALL_INTERNAL_METHOD_NORETURN_P') {
                $postStatements[] = 'zval_ptr_dtor(rvp); \\';
            }
            foreach ($postStatements as $statement) {
                $codePrinter->output($statement);
            }
            $codePrinter->output('ZEPHIR_LAST_CALL_STATUS = EG(exception) ? FAILURE : SUCCESS; \\');
            $codePrinter->output('ZEPHIR_RESTORE_THIS_PTR(); \\');
            $codePrinter->output('ZEPHIR_RESTORE_SCOPE(); \\');
            $codePrinter->decreaseLevel();
            $codePrinter->output('} while (0)');
            $codePrinter->decreaseLevel();
            $codePrinter->output('');
        }
        $codePrinter->decreaseLevel();
        $codePrinter->output("#endif");
        Utils::checkAndWriteIfNeeded($codePrinter->getOutput(), 'ext/kernel/fcall_internal.h');
    }

Usage Example

Example #1
0
 /**
  * Generates the C sources from Zephir without compiling them
  *
  * @param CommandInterface $command
  * @return bool
  * @throws Exception
  */
 public function generate(CommandInterface $command)
 {
     /**
      * Get global namespace
      */
     $namespace = $this->checkDirectory();
     /**
      * Check whether there are external dependencies
      */
     $externalDependencies = $this->config->get('external-dependencies');
     if (is_array($externalDependencies)) {
         foreach ($externalDependencies as $dependencyNs => $location) {
             if (!file_exists($location)) {
                 throw new CompilerException('Location of dependency "' . $dependencyNs . '" does not exist. Check the config.json for more information');
             }
             $this->addExternalDependency($dependencyNs, $location);
         }
     }
     /**
      * Check if there are module/request/global destructors
      */
     $destructors = $this->config->get('destructors');
     if (is_array($destructors)) {
         $invokeDestructors = $this->processCodeInjection($destructors);
         $includes = $invokeDestructors[0];
         $destructors = $invokeDestructors[1];
     }
     /**
      * Check if there are module/request/global initializers
      */
     $initializers = $this->config->get('initializers');
     if (is_array($initializers)) {
         $invokeInitializers = $this->processCodeInjection($initializers);
         $includes = $invokeInitializers[0];
         $initializers = $invokeInitializers[1];
     }
     /**
      * Round 1. pre-compile all files in memory
      */
     $this->recursivePreCompile(str_replace('\\', DIRECTORY_SEPARATOR, $namespace));
     if (!count($this->files)) {
         throw new Exception("Zephir files to compile couldn't be found. Did you add a first class to the extension?");
     }
     /**
      * Round 2. Check 'extends' and 'implements' dependencies
      */
     foreach ($this->files as $compileFile) {
         $compileFile->checkDependencies($this);
     }
     /**
      * Sort the files by dependency ranking
      */
     $files = array();
     $rankedFiles = array();
     $this->calculateDependencies($this->files);
     foreach ($this->files as $rankFile) {
         $rank = $rankFile->getClassDefinition()->getDependencyRank();
         $rankedFiles[$rank][] = $rankFile;
     }
     krsort($rankedFiles);
     foreach ($rankedFiles as $rank => $rankFiles) {
         $files = array_merge($files, $rankFiles);
     }
     $this->files = $files;
     /**
      * Convert C-constants into PHP constants
      */
     $constantsSources = $this->config->get('constants-sources');
     if (is_array($constantsSources)) {
         $this->loadConstantsSources($constantsSources);
     }
     /**
      * Set extension globals
      */
     $globals = $this->config->get('globals');
     if (is_array($globals)) {
         $this->setExtensionGlobals($globals);
     }
     /**
      * Load function optimizers
      */
     if (self::$loadedPrototypes === false) {
         FunctionCall::addOptimizerDir(ZEPHIRPATH . 'Library/Optimizers/FunctionCall');
         $optimizerDirs = $this->config->get('optimizer-dirs');
         if (is_array($optimizerDirs)) {
             foreach ($optimizerDirs as $directory) {
                 FunctionCall::addOptimizerDir(realpath($directory));
             }
         }
         if (is_dir(ZEPHIRPATH . 'prototypes') && is_readable(ZEPHIRPATH . 'prototypes')) {
             /**
              * Load additional extension prototypes
              * @var $file \DirectoryIterator
              */
             foreach (new \DirectoryIterator(ZEPHIRPATH . 'prototypes') as $file) {
                 if (!$file->isDir()) {
                     $extension = str_replace('.php', '', $file);
                     if (!extension_loaded($extension)) {
                         require $file->getRealPath();
                     }
                 }
             }
         }
         /**
          * Load customer additional extension prototypes
          */
         $prototypeDirs = $this->config->get('prototype-dir');
         if (is_array($prototypeDirs)) {
             foreach ($prototypeDirs as $prototype => $prototypeDir) {
                 /**
                  * Check if the extension is installed
                  */
                 if (!extension_loaded($prototype)) {
                     $prototypeRealpath = realpath($prototypeDir);
                     if ($prototypeRealpath) {
                         foreach (new \DirectoryIterator($prototypeRealpath) as $file) {
                             if (!$file->isDir()) {
                                 require $file->getRealPath();
                             }
                         }
                     }
                 }
             }
         }
         self::$loadedPrototypes = true;
     }
     /**
      * Round 3. Compile all files to C sources
      */
     $files = array();
     $hash = "";
     foreach ($this->files as $compileFile) {
         /**
          * Only compile classes in the local extension, ignore external classes
          */
         if (!$compileFile->isExternal()) {
             $compileFile->compile($this, $this->stringManager);
             $compiledFile = $compileFile->getCompiledFile();
             $methods = array();
             $classDefinition = $compileFile->getClassDefinition();
             foreach ($classDefinition->getMethods() as $method) {
                 $methods[] = '[' . $method->getName() . ':' . join('-', $method->getVisibility()) . ']';
                 if ($method->isInitializer() && $method->isStatic()) {
                     $this->internalInitializers[] = "\t" . $method->getName() . '(TSRMLS_C);';
                 }
             }
             $files[] = $compiledFile;
             $hash .= '|' . $compiledFile . ':' . $classDefinition->getClassEntry() . '[' . join('|', $methods) . ']';
         }
     }
     /**
      * Round 3.2. Compile anonymous classes
      */
     foreach ($this->anonymousFiles as $compileFile) {
         $compileFile->compile($this, $this->stringManager);
         $compiledFile = $compileFile->getCompiledFile();
         $methods = array();
         $classDefinition = $compileFile->getClassDefinition();
         foreach ($classDefinition->getMethods() as $method) {
             $methods[] = '[' . $method->getName() . ':' . join('-', $method->getVisibility()) . ']';
         }
         $files[] = $compiledFile;
         $hash .= '|' . $compiledFile . ':' . $classDefinition->getClassEntry() . '[' . join('|', $methods) . ']';
     }
     $hash = md5($hash);
     $this->compiledFiles = $files;
     /**
      * Round 3.3. Load extra C-sources
      */
     $extraSources = $this->config->get('extra-sources');
     if (is_array($extraSources)) {
         $this->extraFiles = $extraSources;
     } else {
         $this->extraFiles = array();
     }
     /**
      * Round 3.4. Load extra classes sources
      */
     $extraClasses = $this->config->get('extra-classes');
     if (is_array($extraClasses)) {
         foreach ($extraClasses as $value) {
             if (isset($value['source'])) {
                 $this->extraFiles[] = $value['source'];
             }
         }
     }
     /**
      * Round 4. Create config.m4 and config.w32 files / Create project.c and project.h files
      */
     $namespace = str_replace('\\', '_', $namespace);
     $extensionName = $this->config->get('extension-name');
     if (empty($extensionName) || !is_string($extensionName)) {
         $extensionName = $namespace;
     }
     $needConfigure = $this->createConfigFiles($extensionName);
     $needConfigure |= $this->createProjectFiles($extensionName);
     $needConfigure |= $this->checkIfPhpized();
     $version = self::getCurrentVersion();
     /**
      * When a new file is added or removed we need to run configure again
      */
     if (!$command instanceof CommandGenerate) {
         if (!$this->fileSystem->exists($version . '/compiled-files-sum')) {
             $needConfigure = true;
             $this->fileSystem->write($version . '/compiled-files-sum', $hash);
         } else {
             if ($this->fileSystem->read($version . '/compiled-files-sum') != $hash) {
                 $needConfigure = true;
                 $this->fileSystem->write($version . '/compiled-files-sum', $hash);
             }
         }
     }
     /**
      * Round 5. Generate concatenation functions
      */
     $this->stringManager->genConcatCode();
     $this->fcallManager->genFcallCode();
     if ($this->config->get('stubs-run-after-generate', 'stubs')) {
         $this->stubs($command, true);
     }
     return $needConfigure;
 }