Exemplo n.º 1
0
void BuiltinSymbols::ImportExtFunctions(AnalysisResultPtr ar,
                                        StringToFunctionScopePtrMap &map,
                                        ClassInfo *cls) {
  const ClassInfo::MethodVec &methods = cls->getMethodsVec();
  for (auto it = methods.begin(); it != methods.end(); ++it) {
    FunctionScopePtr f = ImportFunctionScopePtr(ar, cls, *it);
    assert(!map[f->getName()]);
    map[f->getName()] = f;
  }
}
Exemplo n.º 2
0
void BuiltinSymbols::ParseExtFunctions(AnalysisResultPtr ar, const char **p,
                                       bool sep) {
    while (*p) {
        FunctionScopePtr f = ParseExtFunction(ar, p);
        if (sep) {
            f->setSepExtension();
        }
        assert(!s_functions[f->getName()]);
        s_functions[f->getName()] = f;
    }
}
Exemplo n.º 3
0
void StatementList::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  FunctionScopePtr func = getFunctionScope();

  for (unsigned int i = 0; i < m_stmts.size(); i++) {
    StatementPtr stmt = m_stmts[i];
    stmt->outputCPP(cg, ar);
    if (stmt->is(Statement::KindOfMethodStatement)) {
      MethodStatementPtr methodStmt =
        dynamic_pointer_cast<MethodStatement>(stmt);
      std::string methodName = methodStmt->getName();
      if (methodName == "offsetget") {
        ClassScopePtr cls = getClassScope();
        std::string arrayAccess("arrayaccess");
        if (cls->derivesFrom(ar, arrayAccess, false, false)) {
          FunctionScopePtr funcScope = methodStmt->getFunctionScope();
          std::string name = funcScope->getName();
          funcScope->setName("__offsetget_lval");
          methodStmt->setName("__offsetget_lval");
          methodStmt->outputCPP(cg, ar);
          funcScope->setName(name);
          methodStmt->setName("offsetget");
        }
      }
    }
  }
}
Exemplo n.º 4
0
void StatementList::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  FunctionScopePtr func = getFunctionScope();
  bool inPseudoMain = func && func->inPseudoMain();
  std::vector<bool> isDeclaration;

  if (inPseudoMain) {
    // We need these declarations to go first, because PHP allows top level
    // function and class declarations to appear after usage.
    for (unsigned int i = 0; i < m_stmts.size(); i++) {
      StatementPtr stmt = m_stmts[i];
      bool isDecl = false;
      if (stmt->is(Statement::KindOfFunctionStatement)) {
        isDecl = true;
      } else if (stmt->is(Statement::KindOfClassStatement) ||
                 stmt->is(Statement::KindOfInterfaceStatement)) {
        ClassScopePtr cls =
          (dynamic_pointer_cast<InterfaceStatement>(stmt))->getClassScope();
        isDecl = cls->isBaseClass() || !cls->isVolatile();
      }
      if (isDecl) stmt->outputCPP(cg,ar);
      isDeclaration.push_back(isDecl);
    }
  }

  for (unsigned int i = 0; i < m_stmts.size(); i++) {
    StatementPtr stmt = m_stmts[i];
    if (stmt->is(Statement::KindOfClassStatement)) {
      if (!inPseudoMain || !isDeclaration[i]) stmt->outputCPP(cg, ar);
    } else if (!(stmt->is(Statement::KindOfFunctionStatement) ||
                 stmt->is(Statement::KindOfInterfaceStatement)) ||
               (!inPseudoMain || !isDeclaration[i])) {
      stmt->outputCPP(cg, ar);
      if (stmt->is(Statement::KindOfMethodStatement)) {
        MethodStatementPtr methodStmt =
          dynamic_pointer_cast<MethodStatement>(stmt);
        std::string methodName = methodStmt->getName();
        if (methodName == "offsetget") {
          ClassScopePtr cls = getClassScope();
          std::string arrayAccess("arrayaccess");
          if (cls->derivesFrom(ar, arrayAccess, false, false)) {
            FunctionScopePtr funcScope = methodStmt->getFunctionScope();
            std::string name = funcScope->getName();
            funcScope->setName("__offsetget_lval");
            methodStmt->setName("__offsetget_lval");
            methodStmt->outputCPP(cg, ar);
            funcScope->setName(name);
            methodStmt->setName("offsetget");
          }
        }
      }
    }
  }
}
Exemplo n.º 5
0
bool ClassScope::addFunction(AnalysisResultConstPtr ar,
                             FunctionScopePtr funcScope) {
  FunctionScopePtr &func = m_functions[funcScope->getName()];
  if (func) {
    func->getStmt()->parseTimeFatal(Compiler::DeclaredMethodTwice,
                                    "Redeclared method %s::%s",
                                    getOriginalName().c_str(),
                                    func->getOriginalName().c_str());
  }
  func = funcScope;
  m_functionsVec.push_back(funcScope);
  return true;
}
Exemplo n.º 6
0
void ParameterExpression::analyzeProgram(AnalysisResultPtr ar) {
  if (!m_type.empty()) addUserClass(ar, m_type);

  if (m_defaultValue) m_defaultValue->analyzeProgram(ar);

  if (ar->isFirstPass()) {
    // Have to use non const ref params for magic methods
    FunctionScopePtr fs = ar->getFunctionScope();
    if (fs->isMagicMethod() || fs->getName() == "offsetget") {
      fs->getVariables()->addLvalParam(m_name);
    }
  }
}
Exemplo n.º 7
0
bool FileScope::addFunction(AnalysisResultConstPtr ar,
                            FunctionScopePtr funcScope) {
  if (ar->declareFunction(funcScope)) {
    FunctionScopePtr &fs = m_functions[funcScope->getName()];
    if (fs) {
      if (!m_redeclaredFunctions) {
        m_redeclaredFunctions = new StringToFunctionScopePtrVecMap;
      }
      FunctionScopePtrVec &funcVec =
        (*m_redeclaredFunctions)[funcScope->getName()];
      if (!funcVec.size()) {
        fs->setLocalRedeclaring();
        funcVec.push_back(fs);
      }
      funcScope->setLocalRedeclaring();
      funcVec.push_back(funcScope);
    } else {
      fs = funcScope;
    }
    return true;
  }
  return false;
}
Exemplo n.º 8
0
void MethodStatement::outputCPPTypeCheckWrapper(CodeGenerator &cg,
                                                AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = getFunctionScope();
  TypePtr type = funcScope->getReturnType();
  bool isMethod = getClassScope();
  string fname = isMethod ? funcScope->getName() : funcScope->getId(cg);

  funcScope->outputCPP(cg, ar);
  cg_printf("%s%s%s(", type ? "return " : "",
            (isMethod ? (m_modifiers->isStatic() ?
                         Option::TypedMethodImplPrefix :
                         Option::TypedMethodPrefix) :
             Option::TypedFunctionPrefix),
            fname.c_str());
  if (getClassScope() && m_modifiers->isStatic()) {
    cg_printf("cls, ");
  }
  if (funcScope->isVariableArgument()) {
    cg_printf("num_args, ");
  }

  assert(m_params);

  for (int i = 0; i < m_params->getCount(); i++) {
    ParameterExpressionPtr param =
      dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
    ASSERT(param);
    if (i) cg_printf(", ");
    cg_printf("%s%s", Option::VariablePrefix,
              param->getName().c_str());
    if (TypePtr spec = funcScope->getParamTypeSpec(i)) {
      if (Type::SameType(spec, funcScope->getParamType(i))) {
        if (spec->is(Type::KindOfArray)) {
          cg_printf(".getArrayData()");
        } else {
          ClassScopePtr cls = ar->findClass(spec->getName());
          assert(cls && !cls->isRedeclaring());
          cg_printf(".getObjectData()");
        }
      }
    }
  }

  if (funcScope->isVariableArgument()) {
    cg_printf(", args");
  }
  cg_printf(");\n");
}
Exemplo n.º 9
0
bool AnalysisResult::declareFunction(FunctionScopePtr funcScope) const {
  assert(m_phase < AnalyzeAll);

  string fname = funcScope->getName();
  // System functions override
  auto it = m_functions.find(fname);
  if (it != m_functions.end()) {
    if (!it->second->allowOverride()) {
      // we need someone to hold on to a reference to it
      // even though we're not going to do anything with it
      this->lock()->m_ignoredScopes.push_back(funcScope);
      return false;
    }
  }

  return true;
}
Exemplo n.º 10
0
bool BuiltinSymbols::Load(AnalysisResultPtr ar, bool extOnly /* = false */) {
  if (Loaded) return true;
  Loaded = true;

  // Build function scopes for some of the runtime helper functions
  // declared in "runtime/base/builtin_functions.h"
  const char **helper = HelperFunctions;
  while (*helper) {
    FunctionScopePtr f = ParseHelperFunction(ar, helper);
    ASSERT(!s_helperFunctions[f->getName()]);
    s_helperFunctions[f->getName()] = f;
  }

  // load extension functions first, so system/classes may call them
  ParseExtFunctions(ar, ExtensionFunctions, false);
  AnalysisResultPtr ar2;

  // parse all PHP files under system/classes
  if (!extOnly) {
    ar = AnalysisResultPtr(new AnalysisResult());
    ar->loadBuiltinFunctions();
    for (const char **cls = SystemClasses; *cls; cls++) {
      string phpBaseName = "/system/classes/";
      phpBaseName += *cls;
      phpBaseName += ".php";
      string phpFileName = Option::GetSystemRoot() + phpBaseName;
      const char *baseName = s_strings.add(phpBaseName.c_str());
      const char *fileName = s_strings.add(phpFileName.c_str());
      try {
        Scanner scanner(fileName, Option::ScannerType);
        Compiler::Parser parser(scanner, baseName, ar);
        if (!parser.parse()) {
          Logger::Error("Unable to parse file %s: %s", fileName,
                        parser.getMessage().c_str());
          ASSERT(false);
        }
      } catch (FileOpenException &e) {
        Logger::Error("%s", e.getMessage().c_str());
      }
    }
    ar->analyzeProgram(true);
    ar->inferTypes();
    const StringToFileScopePtrMap &files = ar->getAllFiles();
    for (StringToFileScopePtrMap::const_iterator iterFile = files.begin();
         iterFile != files.end(); iterFile++) {
      const StringToClassScopePtrVecMap &classes =
        iterFile->second->getClasses();
      for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin();
           iter != classes.end(); ++iter) {
        ASSERT(iter->second.size() == 1);
        iter->second[0]->setSystem();
        ASSERT(!s_classes[iter->first]);
        s_classes[iter->first] = iter->second[0];
      }
    }

    // parse globals/variables.php and globals/constants.php
    NoSuperGlobals = true;
    s_variables = LoadGlobalSymbols("symbols.php")->getVariables();
    ar2 = LoadGlobalSymbols("constants.php");
    const FileScopePtrVec &fileScopes = ar2->getAllFilesVector();
    if (!fileScopes.empty()) {
      s_constants = fileScopes[0]->getConstants();
    } else {
      Logger::Error("Couldn't load constants.php");
      return false;
    }
    NoSuperGlobals = false;
  } else {
    ar2 = AnalysisResultPtr(new AnalysisResult());
    s_variables = VariableTablePtr(new VariableTable(*ar2.get()));
    s_constants = ConstantTablePtr(new ConstantTable(*ar2.get()));
    NoSuperGlobals = true;
  }
  s_constants->setDynamic(ar, "SID", true);

  // load extension constants, classes and dynamics
  ParseExtConsts(ar, ExtensionConsts, false);
  ParseExtClasses(ar, ExtensionClasses, false);
  for (unsigned int i = 0; i < Option::SepExtensions.size(); i++) {
    Option::SepExtensionOptions &options = Option::SepExtensions[i];
    string soname = options.soname;
    if (soname.empty()) {
      soname = string("lib") + options.name + ".so";
    }
    if (!options.lib_path.empty()) {
      soname = options.lib_path + "/" + soname;
    }
    if (!LoadSepExtensionSymbols(ar, options.name, soname)) {
      return false;
    }
  }

  return true;
}
Exemplo n.º 11
0
void MethodStatement::outputCPPFFIStub(CodeGenerator &cg,
                                       AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  ClassScopePtr clsScope = getClassScope();
  bool varArgs = funcScope->isVariableArgument();
  bool ret = funcScope->getReturnType();
  string fname = funcScope->getId(cg);
  bool inClass = !m_className.empty();
  bool isStatic = !inClass || m_modifiers->isStatic();

  if (inClass && m_modifiers->isAbstract()) {
    return;
  }

  if (funcScope->getName() == "__offsetget_lval") {
    return;
  }

  if (ret) {
    cg_printf("int");
  } else {
    cg_printf("void");
  }
  cg_printf(" %s%s%s(", Option::FFIFnPrefix,
            (inClass ? (m_className + "_cls_").c_str() : ""), fname.c_str());
  if (ret) {
    cg_printf("void** res");
  }

  bool first = !ret;

  if (!isStatic) {
    // instance methods need one additional parameter for the target
    if (first) {
      first = false;
    }
    else {
      cg_printf(", ");
    }
    cg_printf("Variant *target");
  }

  int ac = funcScope->getMaxParamCount();
  for (int i = 0; i < ac; ++i) {
    if (first) {
      first = false;
    } else {
      cg_printf(", ");
    }
    cg_printf("Variant *a%d", i);
  }
  if (varArgs) {
    if (!first) {
      cg_printf(", ");
    }
    cg_printf("Variant *va");
  }
  cg_printf(")");
  if (cg.getContext() == CodeGenerator::CppFFIDecl) {
    cg_printf(";\n");
  } else {
    cg_indentBegin(" {\n");
    if (ret) {
      cg_printf("return hphp_ffi_exportVariant(");
    }

    if (!inClass) {
      // simple function call
      cg_printf("%s%s(", Option::FunctionPrefix, fname.c_str());
    } else if (isStatic) {
      // static method call
      cg_printf("%s%s::%s%s(", Option::ClassPrefix,
                clsScope->getId(cg).c_str(),
                Option::MethodPrefix, funcScope->getName().c_str());
    } else {
      // instance method call
      cg_printf("dynamic_cast<%s%s *>(target->getObjectData())->",
                Option::ClassPrefix, clsScope->getId(cg).c_str());
      cg_printf("%s%s(", Option::MethodPrefix, funcScope->getName().c_str());
    }

    first = true;
    if (varArgs) {
      cg_printf("%d + (va->isNull() ? 0 : va->getArrayData()->size())", ac);
      first = false;
    }

    for (int i = 0; i < ac; ++i) {
      if (first) {
        first = false;
      } else {
        cg_printf(", ");
      }
      cg_printf("*a%d", i);
    }
    if (varArgs) {
      cg_printf(", va->toArray()");
    }
    if (ret) {
      cg_printf("), res");
    }
    cg_printf(");\n");
    cg_indentEnd("}\n");
    cg.printImplSplitter();
  }
  return;
}
Exemplo n.º 12
0
void MethodStatement::outputJavaFFICPPStub(CodeGenerator &cg,
                                           AnalysisResultPtr ar) {
  // TODO translate PHP namespace once that is supported
  string packageName = Option::JavaFFIRootPackage;

  FunctionScopePtr funcScope = m_funcScope.lock();
  bool varArgs = funcScope->isVariableArgument();
  bool ret = funcScope->getReturnType();
  bool inClass = !m_className.empty();
  bool isStatic = !inClass || m_modifiers->isStatic();
  string fname = funcScope->getId(cg);
  int ac = funcScope->getMaxParamCount();
  bool exposeNative = !(ac > 0 || varArgs || !isStatic || !ret && inClass);

  if (inClass && m_modifiers->isAbstract()) {
    // skip all the abstract methods, because hphp doesn't generate code
    // for them
    return;
  }

  if (funcScope->getName() == "__offsetget_lval") return;

  const char *clsName;
  if (inClass) {
    // uses capitalized original class name
    ClassScopePtr cls = ar->findClass(m_className);
    clsName = cls->getOriginalName().c_str();
  } else {
    clsName = "HphpMain";
  }
  string mangledName = "Java." + packageName + "." + clsName + "." + fname
    + (exposeNative ? "" : "_native");
  // all the existing "_" are replaced as "_1"
  Util::replaceAll(mangledName, "_", "_1");
  Util::replaceAll(mangledName, ".", "_");

  cg_printf("JNIEXPORT %s JNICALL\n", ret ? "jobject" : "void");
  cg_printf("%s(JNIEnv *env, %s target", mangledName.c_str(),
            (isStatic ? "jclass" : "jobject"));

  ostringstream args;
  bool first = true;
  if (!isStatic) {
    // instance method also gets an additional argument, which is a Variant
    // pointer to the target, encoded in int64
    first = false;
    cg_printf(", jlong targetPtr");
    args << "(Variant *)targetPtr";
  }
  for (int i = 0; i < ac; i++) {
    cg_printf(", jlong a%d", i);
    if (first) first = false;
    else args << ", ";
    args << "(Variant *)a" << i;
  }
  if (varArgs) {
    cg_printf(", jlong va");
    if (!first) args << ", ";
    args << "(Variant *)va";
  }

  if (cg.getContext() == CodeGenerator::JavaFFICppDecl) {
    // java_stubs.h
    cg_printf(");\n\n");
    return;
  }

  cg_indentBegin(") {\n");

  // support static/instance methods
  if (ret) {
    cg_printf("void *result;\n");
    cg_printf("int kind = ");
    cg_printf("%s%s%s(&result",
              Option::FFIFnPrefix,
              (inClass ? (m_className + "_cls_").c_str() : ""), fname.c_str());
    if (!isStatic || ac > 0 || varArgs) cg_printf(", ");
  } else {
    cg_printf("%s%s%s(", Option::FFIFnPrefix,
                         (inClass ? (m_className + "_cls_").c_str() : ""),
                         fname.c_str());
  }
  cg_printf("%s);\n", args.str().c_str());
  if (ret) {
    if (!inClass) {
      // HphpMain extends hphp.Hphp.
      cg_printf("jclass hphp = env->GetSuperclass(target);\n");
    }
    else {
      cg_printf("jclass hphp = env->FindClass(\"hphp/Hphp\");\n");
    }
    cg_printf("return exportVariantToJava(env, hphp, result, kind);\n");
  }

  cg_indentEnd("}\n");
  cg.printImplSplitter();
}
Exemplo n.º 13
0
void SimpleFunctionCall::outputCPPImpl(CodeGenerator &cg,
                                       AnalysisResultPtr ar) {
  bool linemap = outputLineMap(cg, ar, true);

  if (!m_lambda.empty()) {
    cg.printf("\"%s\"", m_lambda.c_str());
    if (linemap) cg.printf(")");
    return;
  }

  if (m_className.empty()) {
    if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) {
      ScalarExpressionPtr name =
        dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
      string varName;
      if (name) {
        varName = name->getIdentifier();
        ExpressionPtr value = (*m_params)[1];
        if (varName.empty()) {
          cg.printf("throw_fatal(\"bad define\")");
        } else if (m_dynamicConstant) {
          cg.printf("g->declareConstant(\"%s\", g->%s%s, ",
                    varName.c_str(), Option::ConstantPrefix,
                    varName.c_str());
          value->outputCPP(cg, ar);
          cg.printf(")");
        } else {
          bool needAssignment = true;
          bool isSystem = ar->getConstants()->isSystem(varName);
          if (isSystem ||
              ((!ar->isConstantRedeclared(varName)) && value->isScalar())) {
            needAssignment = false;
          }
          if (needAssignment) {
            cg.printf("%s%s = ", Option::ConstantPrefix, varName.c_str());
            value->outputCPP(cg, ar);
          }
        }
      } else {
        cg.printf("throw_fatal(\"bad define\")");
      }
      if (linemap) cg.printf(")");
      return;
    }
    if (m_name == "func_num_args") {
      cg.printf("num_args");
      if (linemap) cg.printf(")");
      return;
    }

    switch (m_type) {
    case VariableArgumentFunction:
      {
        FunctionScopePtr func =
          dynamic_pointer_cast<FunctionScope>(ar->getScope());
        if (func) {
          cg.printf("%s(", m_name.c_str());
          func->outputCPPParamsCall(cg, ar, true);
          if (m_params) {
            cg.printf(",");
            m_params->outputCPP(cg, ar);
          }
          cg.printf(")");
          if (linemap) cg.printf(")");
          return;
        }
      }
      break;
    case FunctionExistsFunction:
    case ClassExistsFunction:
    case InterfaceExistsFunction:
      {
        bool literalString = false;
        string symbol;
        if (m_params && m_params->getCount() == 1) {
          ExpressionPtr value = (*m_params)[0];
          if (value->isScalar()) {
            ScalarExpressionPtr name =
              dynamic_pointer_cast<ScalarExpression>(value);
            if (name && name->isLiteralString()) {
              literalString = true;
              symbol = name->getLiteralString();
            }
          }
        }
        if (literalString) {
          switch (m_type) {
          case FunctionExistsFunction:
            {
              const std::string &lname = Util::toLower(symbol);
              bool dynInvoke = Option::DynamicInvokeFunctions.find(lname) !=
                Option::DynamicInvokeFunctions.end();
              if (!dynInvoke) {
                FunctionScopePtr func = ar->findFunction(lname);
                if (func) {
                  if (!func->isDynamic()) {
                    if (func->isRedeclaring()) {
                      const char *name = func->getName().c_str();
                      cg.printf("(%s->%s%s != invoke_failed_%s)",
                                cg.getGlobals(ar), Option::InvokePrefix,
                                name, name);
                      break;
                    }
                    cg.printf("true");
                    break;
                  }
                } else {
                  cg.printf("false");
                  break;
                }
              }
              cg.printf("f_function_exists(\"%s\")", lname.c_str());
            }
            break;
          case ClassExistsFunction:
            {
              ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
              if (cls && !cls->isInterface()) {
                const char *name = cls->getName().c_str();
                cg.printf("f_class_exists(\"%s\")", name);
              } else {
                cg.printf("false");
              }
            }
            break;
          case InterfaceExistsFunction:
            {
              ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
              if (cls && cls->isInterface()) {
                const char *name = cls->getName().c_str();
                cg.printf("f_interface_exists(\"%s\")", name);
              } else {
                cg.printf("false");
              }
            }
            break;
          default:
            break;
          }
          if (linemap) cg.printf(")");
          return;
        }
      }
      break;
    case GetDefinedVarsFunction:
      cg.printf("get_defined_vars(variables)");
      if (linemap) cg.printf(")");
      return;
    default:
      break;
    }
  }

  outputCPPParamOrderControlled(cg, ar);
  if (linemap) cg.printf(")");
}
Exemplo n.º 14
0
void SimpleFunctionCall::outputCPPParamOrderControlled(CodeGenerator &cg,
                                                       AnalysisResultPtr ar) {
  if (m_className.empty()) {
    switch (m_type) {
    case ExtractFunction:
      cg.printf("extract(variables, ");
      FunctionScope::outputCPPArguments(m_params, cg, ar, 0, false);
      cg.printf(")");
      return;
    case CompactFunction:
      cg.printf("compact(variables, ");
      FunctionScope::outputCPPArguments(m_params, cg, ar, -1, true);
      cg.printf(")");
      return;
    default:
      break;
    }
  }
  bool volatileCheck = false;
  ClassScopePtr cls;
  if (!m_className.empty()) {
    cls = ar->findClass(m_className);
    if (cls && !ar->checkClassPresent(m_origClassName)) {
      volatileCheck = true;
      cls->outputVolatileCheckBegin(cg, ar, cls->getOriginalName());
    }
  }
  if (m_valid) {
    bool tooManyArgs =
      (m_params && m_params->outputCPPTooManyArgsPre(cg, ar, m_name));
    if (!m_className.empty()) {
      cg.printf("%s%s::", Option::ClassPrefix, m_className.c_str());
      if (m_name == "__construct" && cls) {
        FunctionScopePtr func = cls->findConstructor(ar, true);
        cg.printf("%s%s(", Option::MethodPrefix, func->getName().c_str());
      } else {
        cg.printf("%s%s(", Option::MethodPrefix, m_name.c_str());
      }
    } else {
      int paramCount = m_params ? m_params->getCount() : 0;
      if (m_name == "get_class" && ar->getClassScope() && paramCount == 0) {
        cg.printf("(\"%s\"", ar->getClassScope()->getOriginalName());
      } else if (m_name == "get_parent_class" && ar->getClassScope() &&
                 paramCount == 0) {
        const std::string parentClass = ar->getClassScope()->getParent();
        if (!parentClass.empty()) {
          cg.printf("(\"%s\"", ar->getClassScope()->getParent().c_str());
        } else {
          cg.printf("(false");
        }
      } else {
        if (m_noPrefix) {
          cg.printf("%s(", m_name.c_str());
        }
        else {
         cg.printf("%s%s(", m_builtinFunction ? Option::BuiltinFunctionPrefix :
                   Option::FunctionPrefix, m_name.c_str());
        }
      }
    }
    FunctionScope::outputCPPArguments(m_params, cg, ar, m_extraArg,
                                      m_variableArgument, m_argArrayId);
    cg.printf(")");
    if (tooManyArgs) {
      m_params->outputCPPTooManyArgsPost(cg, ar, m_voidReturn);
    }
  } else {
    if (m_className.empty()) {
      if (m_redeclared && !m_dynamicInvoke) {
        if (canInvokeFewArgs()) {
          cg.printf("%s->%s%s_few_args(", cg.getGlobals(ar),
                    Option::InvokePrefix, m_name.c_str());
          int left = Option::InvokeFewArgsCount;
          if (m_params && m_params->getCount()) {
            left -= m_params->getCount();
            cg.printf("%d, ", m_params->getCount());
            FunctionScope::outputCPPArguments(m_params, cg, ar, 0, false);
          } else {
            cg.printf("0");
          }
          for (int i = 0; i < left; i++) {
            cg.printf(", null_variant");
          }
          cg.printf(")");
          return;
        } else {
          cg.printf("%s->%s%s(", cg.getGlobals(ar), Option::InvokePrefix,
                    m_name.c_str());
        }
      } else {
        cg.printf("invoke(\"%s\", ", m_name.c_str());
      }
    } else {
      bool inObj = m_parentClass && ar->getClassScope() &&
        !dynamic_pointer_cast<FunctionScope>(ar->getScope())->isStatic();
      if (m_redeclaredClass) {
        if (inObj) {  // parent is redeclared
          cg.printf("parent->%sinvoke(\"%s\",", Option::ObjectPrefix,
                    m_name.c_str());
        } else {
          cg.printf("%s->%s%s->%sinvoke(\"%s\", \"%s\",",
                    cg.getGlobals(ar),
                    Option::ClassStaticsObjectPrefix,
                    m_className.c_str(), Option::ObjectStaticPrefix,
                    m_className.c_str(),
                    m_name.c_str());
        }
      } else if (m_validClass) {
        if (inObj) {
          cg.printf("%s%s::%sinvoke(\"%s\",",
                    Option::ClassPrefix, m_className.c_str(),
                    Option::ObjectPrefix, m_name.c_str());
        } else {
          cg.printf("%s%s::%sinvoke(\"%s\", \"%s\",",
                    Option::ClassPrefix, m_className.c_str(),
                    Option::ObjectStaticPrefix,
                    m_className.c_str(),
                    m_name.c_str());
        }
      } else {
        cg.printf("invoke_static_method(\"%s\", \"%s\",",
                  m_className.c_str(), m_name.c_str());
      }
    }
    if ((!m_params) || (m_params->getCount() == 0)) {
      cg.printf("Array()");
    } else {
      FunctionScope::outputCPPArguments(m_params, cg, ar, -1, false);
    }
    bool needHash = true;
    if (m_className.empty()) {
      needHash = !(m_redeclared && !m_dynamicInvoke);
    } else {
      needHash = m_validClass || m_redeclaredClass;
    }
    if (!needHash) {
      cg.printf(")");
    } else {
      cg.printf(", 0x%.16lXLL)", hash_string_i(m_name.data(), m_name.size()));
    }
  }
  if (volatileCheck) {
    cls->outputVolatileCheckEnd(cg);
  }
}
Exemplo n.º 15
0
void AnalysisResult::analyzeProgram(bool system /* = false */) {
  AnalysisResultPtr ar = shared_from_this();

  getVariables()->forceVariants(ar, VariableTable::AnyVars);
  getVariables()->setAttribute(VariableTable::ContainsLDynamicVariable);
  getVariables()->setAttribute(VariableTable::ContainsExtract);
  getVariables()->setAttribute(VariableTable::ForceGlobal);

  // Analyze Includes
  Logger::Verbose("Analyzing Includes");
  sort(m_fileScopes.begin(), m_fileScopes.end(), by_filename); // fixed order
  unsigned int i = 0;
  for (i = 0; i < m_fileScopes.size(); i++) {
    collectFunctionsAndClasses(m_fileScopes[i]);
  }

  // Keep generated code identical without randomness
  canonicalizeSymbolOrder();

  markRedeclaringClasses();

  // Analyze some special cases
  for (set<string>::const_iterator it = Option::VolatileClasses.begin();
       it != Option::VolatileClasses.end(); ++it) {
    ClassScopePtr cls = findClass(toLower(*it));
    if (cls && cls->isUserClass()) {
      cls->setVolatile();
    }
  }

  checkClassDerivations();
  resolveNSFallbackFuncs();

  // Analyze All
  Logger::Verbose("Analyzing All");
  setPhase(AnalysisResult::AnalyzeAll);
  for (i = 0; i < m_fileScopes.size(); i++) {
    m_fileScopes[i]->analyzeProgram(ar);
  }

  /*
    Note that cls->collectMethods() can add entries to m_classDecs,
    which can invalidate iterators. So we have to create an array
    and then iterate over that.
    The new entries added to m_classDecs are always empty, so it
    doesnt matter that we dont include them in the iteration
  */
  std::vector<ClassScopePtr> classes;
  classes.reserve(m_classDecs.size());
  for (StringToClassScopePtrVecMap::const_iterator iter = m_classDecs.begin();
       iter != m_classDecs.end(); ++iter) {
    for (ClassScopePtr cls: iter->second) {
      classes.push_back(cls);
    }
  }

  // Collect methods
  for (ClassScopePtr cls: classes) {
    if (cls->isRedeclaring()) {
      cls->setStaticDynamic(ar);
    }
    StringToFunctionScopePtrMap methods;
    cls->collectMethods(ar, methods, true /* include privates */);
    bool needAbstractMethodImpl =
      (!cls->isAbstract() && !cls->isInterface() &&
       cls->derivesFromRedeclaring() == Derivation::Normal &&
       !cls->getAttribute(ClassScope::UsesUnknownTrait));
    for (StringToFunctionScopePtrMap::const_iterator iterMethod =
           methods.begin(); iterMethod != methods.end(); ++iterMethod) {
      FunctionScopePtr func = iterMethod->second;
      if (Option::WholeProgram && !func->hasImpl() && needAbstractMethodImpl) {
        FunctionScopePtr tmpFunc =
          cls->findFunction(ar, func->getName(), true, true);
        always_assert(!tmpFunc || !tmpFunc->hasImpl());
        Compiler::Error(Compiler::MissingAbstractMethodImpl,
                        func->getStmt(), cls->getStmt());
      }
      m_methodToClassDecs[iterMethod->first].push_back(cls);
    }
  }

  ClassScopePtr cls;
  string cname;
  for (auto& sysclass_cls: m_systemClasses) {
    tie(cname, cls) = sysclass_cls;
    StringToFunctionScopePtrMap methods;
    cls->collectMethods(ar, methods, true /* include privates */);
    for (StringToFunctionScopePtrMap::const_iterator iterMethod =
           methods.begin(); iterMethod != methods.end(); ++iterMethod) {
      m_methodToClassDecs[iterMethod->first].push_back(cls);
    }
  }
}