Permalink
Browse files

Fixes #960

  • Loading branch information...
andresgutierrez committed May 20, 2015
1 parent e8e2618 commit c44abb4d640ed01bc3cbcdc3afff570a1b0058c7
Showing with 76 additions and 59 deletions.
  1. +63 −29 Library/Cache/MethodCache.php
  2. +13 −30 Library/MethodCall.php
@@ -94,18 +94,45 @@ private function isClassCacheable($classDefinition)
* @param ClassMethod $method
* @param Variable $caller
*/
public function get(CompilationContext $compilationContext, $method, Variable $caller)
public function get(CompilationContext $compilationContext, $methodName, Variable $caller)
{
$compiler = $compilationContext->compiler;
if (!is_object($method)) {
/**
* Try to generate a cache based on the fact the variable is not modified within the loop block
*/
$numberPoly = 0;
$classTypes = $caller->getClassTypes();
foreach ($classTypes as $classType) {
if ($compiler->isClass($classType) || $compiler->isInterface($classType) || $compiler->isInternalClass($classType) || $compiler->isInternalInterface($classType)) {
if ($compiler->isInterface($classType)) {
continue;
}
if ($compiler->isClass($classType)) {
$classDefinition = $compiler->getClassDefinition($classType);
} else {
$classDefinition = $compiler->getInternalClassDefinition($classType);
}
if (!$classDefinition) {
continue;
}
if ($classDefinition->hasMethod($methodName) && !$classDefinition->isInterface()) {
$numberPoly++;
$method = $classDefinition->getMethod($methodName);
}
}
}
if (!$numberPoly) {
// Try to generate a cache based on the fact the variable is not modified within the loop block
if ($compilationContext->insideCycle && !$caller->isTemporal()) {
if (count($compilationContext->cycleBlocks) && $caller->getType() == 'variable') {
$currentBlock = $compilationContext->cycleBlocks[count($compilationContext->cycleBlocks) - 1];
if ($currentBlock->getMutateGatherer(true)->getNumberOfMutations($caller->getName()) == 0) {
$functionCache = $compilationContext->symbolTable->getTempVariableForWrite('zephir_fcall_cache_entry', $compilationContext);
$functionCache->setMustInitNull(true);
$functionCache->setReusable(false);
@@ -119,16 +146,14 @@ public function get(CompilationContext $compilationContext, $method, Variable $c
}
if (!($method instanceof \ReflectionMethod)) {
/**
* Avoid generate caches for external classes
*/
if ($method->getClassDefinition()->isExternal()) {
return 'NULL, 0';
}
$completeName = $method->getClassDefinition()->getCompleteName();
if (isset($this->cache[$completeName][$method->getName()])) {
return '&' . $this->cache[$completeName][$method->getName()]->getName() . ', ' . SlotsCache::getExistingMethodSlot($method);
if (isset($this->cache[$completeName][$method->getName()])) {
return $this->cache[$completeName][$method->getName()] . ', ' . SlotsCache::getExistingMethodSlot($method);
}
$gatherer = $this->gatherer;
@@ -139,50 +164,59 @@ public function get(CompilationContext $compilationContext, $method, Variable $c
}
$staticCacheable = !$method->getClassDefinition()->isInterface() && ($compilationContext->currentMethod == $method || $method->getClassDefinition()->isFinal() || $method->isFinal() || $method->isPrivate());
$cacheable = $staticCacheable || $number > 1;
if ($number > 0 || $compilationContext->insideCycle) {
$cacheable = true;
} else {
$cacheable = false;
}
} else {
$staticCacheable = false;
$cacheable = false;
}
// Recursive methods require warm-up
if ($compilationContext->currentMethod == $method) {
if (!$compilationContext->methodWarmUp) {
$compilationContext->methodWarmUp = new MethodCallWarmUp;
}
}
$associatedClass = false;
if (!$compilationContext->insideCycle) {
if ($caller->getName() != 'this_ptr') {
$associatedClass = $caller->getAssociatedClass();
if (!$this->isClassCacheable($associatedClass)) {
$associatedClass = false;
} else {
$staticCacheable = true;
}
if ($caller->getName() != 'this_ptr') {
$associatedClass = $caller->getAssociatedClass();
if ($this->isClassCacheable($associatedClass)) {
$staticCacheable = true;
}
}
if (!$compilationContext->insideCycle && !$cacheable && !$associatedClass) {
return 'NULL, 0';
}
$functionCache = $compilationContext->symbolTable->getTempVariableForWrite('zephir_fcall_cache_entry', $compilationContext);
if (!($method instanceof \ReflectionMethod) && $staticCacheable) {
if ($staticCacheable) {
$cacheSlot = SlotsCache::getMethodSlot($method);
} else {
$cacheSlot = '0';
}
$functionCache->setMustInitNull(true);
$functionCache->setReusable(false);
if ($cacheable) {
$functionCacheVar = $compilationContext->symbolTable->getTempVariableForWrite('zephir_fcall_cache_entry', $compilationContext);
$functionCacheVar->setMustInitNull(true);
$functionCacheVar->setReusable(false);
$functionCache = '&' . $functionCacheVar->getName();
} else {
$functionCache = 'NULL';
}
if (!($method instanceof \ReflectionMethod)) {
$this->cache[$completeName][$method->getName()] = $functionCache;
}
return '&' . $functionCache->getName() . ', ' . $cacheSlot;
/*if ($compilationContext->currentMethod->getName() == "_connect") {
echo $method->getClassDefinition()->getCompleteName(), PHP_EOL;
echo $method->getName(), PHP_EOL;
echo $functionCache, PHP_EOL;
echo $cacheSlot, PHP_EOL;
echo "---", PHP_EOL;
}*/
return $functionCache . ', ' . $cacheSlot;
}
}
@@ -255,7 +255,7 @@ public function compile(Expression $expr, CompilationContext $compilationContext
throw new CompilerException("Cannot locate class definition for class " . $classType, $expression);
}
if (!$classDefinition->hasMethod($expression['name'])) {
if (!$classDefinition->hasMethod($methodName)) {
if (!$classDefinition->isInterface()) {
if (count($classTypes) == 1) {
throw new CompilerException("Class '" . $classType . "' does not implement method: '" . $expression['name'] . "'", $expression);
@@ -283,7 +283,7 @@ public function compile(Expression $expr, CompilationContext $compilationContext
}
/**
* Try to produce an exception if method is called with a wrong number of parameters
* Try to produce an exception if a method is called with a wrong number of parameters
* We only check extension parameters if methods are extension methods
* Internal methods may have invalid Reflection information
*/
@@ -415,9 +415,7 @@ public function compile(Expression $expr, CompilationContext $compilationContext
}
}
/**
* We check here if a correct parameter type is passed to the called method
*/
// We check here if a correct parameter type is passed to the called method
if ($type == self::CALL_NORMAL) {
if (isset($method) && $method instanceof ClassMethod && isset($expression['parameters'])) {
$resolvedTypes = $this->getResolvedTypes();
@@ -524,31 +522,24 @@ public function compile(Expression $expr, CompilationContext $compilationContext
$params = array();
}
/**
* Add the last call status to the current symbol table
*/
// Add the last call status to the current symbol table
$this->addCallStatusFlag($compilationContext);
/**
* Initialize non-temporary variables
*/
// Initialize non-temporary variables
if ($mustInit) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
/**
* Generate the code according to the call type
*/
// Generate the code according to the call type
if ($type == self::CALL_NORMAL || $type == self::CALL_DYNAMIC_STRING) {
/**
* Check if the method call can have an inline cache
*/
// Check if the method call can have an inline cache
$methodCache = $compilationContext->cacheManager->getMethodCache();
$cachePointer = $methodCache->get(
$compilationContext,
isset($method) ? $method : null,
$methodName,
$variableVariable
);
@@ -575,6 +566,7 @@ public function compile(Expression $expr, CompilationContext $compilationContext
}
} else {
if ($type == self::CALL_DYNAMIC) {
switch ($variableMethod->getType()) {
case 'string':
case 'variable':
@@ -583,9 +575,6 @@ public function compile(Expression $expr, CompilationContext $compilationContext
throw new Exception('Cannot use variable type: ' . $variableMethod->getType() . ' as method caller');
}
if ($variableMethod->getType() == 'variable') {
}
$cachePointer = 'NULL, 0';
if (!count($params)) {
@@ -612,23 +601,17 @@ public function compile(Expression $expr, CompilationContext $compilationContext
}
}
/**
* Temporary variables must be copied if they have more than one reference
*/
// Temporary variables must be copied if they have more than one reference
foreach ($this->getMustCheckForCopyVariables() as $checkVariable) {
$codePrinter->output('zephir_check_temp_parameter(' . $checkVariable . ');');
}
/**
* We can mark temporary variables generated as idle
*/
// We can mark temporary variables generated as idle
foreach ($this->getTemporalVariables() as $tempVariable) {
$tempVariable->setIdle(true);
}
/**
* Release parameters marked as references
*/
// Release parameters marked as references
if (isset($expression['parameters'])) {
if (count($references)) {
foreach ($params as $position => $param) {

0 comments on commit c44abb4

Please sign in to comment.