Example #1
0
bool UnaryOpExpression::preCompute(CVarRef value, Variant &result) {
  bool ret = true;
  try {
    g_context->setThrowAllErrors(true);
    switch(m_op) {
      case '!':
        result = (!toBoolean(value)); break;
      case '+':
        cellSet(cellAdd(make_tv<KindOfInt64>(0), *value.asCell()),
                *result.asCell());
        break;
      case '-':
        cellSet(cellSub(make_tv<KindOfInt64>(0), *value.asCell()),
                *result.asCell());
        break;
      case '~':
        tvSet(*value.asCell(), *result.asTypedValue());
        cellBitNot(*result.asCell());
        break;
      case '@':
        result = value;
        break;
      case T_INT_CAST:
        result = value.toInt64();
        break;
      case T_DOUBLE_CAST:
        result = toDouble(value);
        break;
      case T_STRING_CAST:
        result = toString(value);
        break;
      case T_BOOL_CAST:
        result = toBoolean(value);
        break;
      case T_EMPTY:
        result = !toBoolean(value);
        break;
      case T_ISSET:
        result = is_not_null(value);
        break;
      case T_INC:
      case T_DEC:
        assert(false);
      default:
        ret = false;
        break;
    }
  } catch (...) {
    ret = false;
  }
  g_context->setThrowAllErrors(false);
  return ret;
}
Example #2
0
File: apc.cpp Project: 191919/hhvm
TEST(APC, SetOverwrite) {
  auto store = new_store();

  store->set(s_key, Variant(s_value1), 1500);
  Variant got;
  EXPECT_EQ(store->get(s_key, got), true);
  EXPECT_TRUE(cellSame(*got.asCell(),
              make_tv<KindOfStaticString>(s_value1.get())));
  store->set(s_key, Variant(s_value2), 1500);
  EXPECT_EQ(store->get(s_key, got), true);
  EXPECT_TRUE(cellSame(*got.asCell(),
              make_tv<KindOfStaticString>(s_value2.get())));
}
Example #3
0
Variant f_max(int _argc, const Variant& value,
              const Variant& second /* = null_variant */,
              const Array& _argv /* = null_array */) {
  if (_argc == 1) {
    const auto& cell_value = *value.asCell();
    if (UNLIKELY(!isContainer(cell_value))) {
      return value;
    }

    ArrayIter iter(cell_value);
    if (!iter) {
      return uninit_null();
    }
    Variant ret = iter.secondRefPlus();
    ++iter;
    for (; iter; ++iter) {
      Variant currVal = iter.secondRefPlus();
      if (more(currVal, ret)) {
        ret = currVal;
      }
    }
    return ret;
  } else if (_argc == 2) {
    return more(second, value) ? second : value;
  }

  Variant ret = more(second, value) ? second : value;
  for (ArrayIter iter(_argv); iter; ++iter) {
    Variant currVal = iter.secondRef();
    if (more(currVal, ret)) {
      ret = currVal;
    }
  }
  return ret;
}
Example #4
0
bool objOffsetIsset(TypedValue& tvRef, ObjectData* base, const Variant& 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.
  TypedValue tvResult;
  tvWriteUninit(&tvResult);

  // 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 method =
    SystemLib::s_ArrayObjectClass->lookupMethod(s_offsetGet.get());
  assert(method != nullptr);
  g_context->invokeFuncFew(&tvResult, method, base, nullptr, 1,
                           offset.asCell());
  auto const result = !IS_NULL_TYPE(tvResult.m_type);
  tvRefcountedDecRef(&tvResult);
  return result;
}
Example #5
0
bool same(const Variant& v1, int64_t v2) {
  auto const cell = v1.asCell();
  if (isIntType(cell->m_type)) {
    return v2 == cell->m_data.num;
  }
  return false;
}
Example #6
0
bool HHVM_FUNCTION(define, const String& name, const Variant& value,
              bool case_insensitive /* = false */) {
  if (case_insensitive) {
    raise_warning(Strings::CONSTANTS_CASE_SENSITIVE);
  }
  return Unit::defCns(name.get(), value.asCell());
}
Example #7
0
void StringBuffer::append(const Variant& v) {
  auto const cell = v.asCell();
  switch (cell->m_type) {
    case KindOfInt64:
      append(cell->m_data.num);
      break;
    case KindOfPersistentString:
    case KindOfString:
      append(cell->m_data.pstr);
      break;
    case KindOfUninit:
    case KindOfNull:
    case KindOfBoolean:
    case KindOfDouble:
    case KindOfPersistentVec:
    case KindOfVec:
    case KindOfPersistentDict:
    case KindOfDict:
    case KindOfPersistentKeyset:
    case KindOfKeyset:
    case KindOfPersistentArray:
    case KindOfArray:
    case KindOfObject:
    case KindOfResource:
    case KindOfRef:
      append(v.toString());
  }
}
Example #8
0
void objOffsetUnset(ObjectData* base, const Variant& offset) {
  objArrayAccess(base);
  assert(!base->isCollection());
  const Func* method = base->methodNamed(s_offsetUnset.get());
  assert(method != nullptr);
  TypedValue tv;
  tvWriteUninit(&tv);
  g_context->invokeFuncFew(&tv, method, base, nullptr, 1, offset.asCell());
  tvRefcountedDecRef(&tv);
}
Example #9
0
AutoloadHandler::Result AutoloadHandler::loadFromMap(const String& name,
                                                     const String& kind,
                                                     bool toLower,
                                                     const T &checkExists) {
  assert(!m_map.isNull());
  while (true) {
    const Variant& type_map = m_map.get()->get(kind);
    auto const typeMapCell = type_map.asCell();
    if (typeMapCell->m_type != KindOfArray) return Failure;
    String canonicalName = toLower ? f_strtolower(name) : name;
    const Variant& file = typeMapCell->m_data.parr->get(canonicalName);
    bool ok = false;
    if (file.isString()) {
      String fName = file.toCStrRef().get();
      if (fName.get()->data()[0] != '/') {
        if (!m_map_root.empty()) {
          fName = m_map_root + fName;
        }
      }
      try {
        JIT::VMRegAnchor _;
        bool initial;
        auto const ec = g_context.getNoCheck();
        Unit* u = ec->evalInclude(fName.get(), nullptr, &initial);
        if (u) {
          if (initial) {
            TypedValue retval;
            ec->invokeFunc(&retval, u->getMain(), init_null_variant,
                           nullptr, nullptr, nullptr, nullptr,
                           ExecutionContext::InvokePseudoMain);
            tvRefcountedDecRef(&retval);
          }
          ok = true;
        }
      } catch (...) {}
    }
    if (ok && checkExists(name)) {
      return Success;
    }
    const Variant& func = m_map.get()->get(s_failure);
    if (func.isNull()) return Failure;
    // can throw, otherwise
    //  - true means the map was updated. try again
    //  - false means we should stop applying autoloaders (only affects classes)
    //  - anything else means keep going
    Variant action = vm_call_user_func(func, make_packed_array(kind, name));
    auto const actionCell = action.asCell();
    if (actionCell->m_type == KindOfBoolean) {
      if (actionCell->m_data.num) continue;
      return StopAutoloading;
    }
    return ContinueAutoloading;
  }
}
void c_ConditionWaitHandle::t_succeed(const Variant& result) {
  if (isFinished()) {
    failAlreadyFinished();
  }

  assert(getState() == STATE_BLOCKED);
  auto parentChain = getParentChain();
  setState(STATE_SUCCEEDED);
  cellDup(*result.asCell(), m_resultOrException);
  parentChain.unblock();
}
Example #11
0
File: apc.cpp Project: 191919/hhvm
TEST(APC, Basic) {
  auto store = new_store();

  EXPECT_EQ(store->add(s_key, Variant(s_value1), 1500), true);
  EXPECT_EQ(store->exists(s_key), true);
  Variant got;
  EXPECT_EQ(store->get(s_key, got), true);
  EXPECT_TRUE(cellSame(*got.asCell(),
    make_tv<KindOfStaticString>(s_value1.get())));
  EXPECT_EQ(store->erase(s_key), true);
  EXPECT_EQ(store->get(s_key, got), false);
}
Example #12
0
bool EventHook::RunInterceptHandler(ActRec* ar) {
  const Func* func = ar->m_func;
  if (LIKELY(func->maybeIntercepted() == 0)) return true;

  // Intercept only original generator / async function calls, not resumption.
  if (ar->inGenerator()) return true;

  Variant *h = get_intercept_handler(func->fullNameRef(),
                                     &func->maybeIntercepted());
  if (!h) return true;

  JIT::VMRegAnchor _;

  PC savePc = g_context->m_pc;

  Variant doneFlag = true;
  Variant called_on;

  if (ar->hasThis()) {
    called_on = Variant(ar->getThis());
  } else if (ar->hasClass()) {
    // For static methods, give handler the name of called class
    called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
  }
  Variant intArgs =
    PackedArrayInit(5)
      .append(ar->m_func->fullNameRef())
      .append(called_on)
      .append(get_frame_args_with_ref(ar))
      .append(h->asCArrRef()[1])
      .appendRef(doneFlag)
      .toArray();

  Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
  if (doneFlag.toBoolean()) {
    Offset pcOff;
    ActRec* outer = g_context->getPrevVMState(ar, &pcOff);

    frame_free_locals_inl_no_hook<true>(ar, ar->m_func->numLocals());
    Stack& stack = g_context->getStack();
    stack.top() = (Cell*)(ar + 1);
    cellDup(*ret.asCell(), *stack.allocTV());

    g_context->m_fp = outer;
    g_context->m_pc = outer ? outer->m_func->unit()->at(pcOff) : nullptr;

    return false;
  }
  g_context->m_fp = ar;
  g_context->m_pc = savePc;

  return true;
}
void HHVM_METHOD(ConditionWaitHandle, succeed, const Variant& result) {
  auto obj = wait_handle<c_ConditionWaitHandle>(this_);
  if (obj->isFinished()) {
    failAlreadyFinished();
  }

  assert(obj->getState() == c_ConditionWaitHandle::STATE_BLOCKED);
  auto parentChain = obj->getParentChain();
  obj->setState(c_ConditionWaitHandle::STATE_SUCCEEDED);
  cellDup(*result.asCell(), obj->m_resultOrException);
  parentChain.unblock();
}
void SourceRootInfo::setServerVariables(Variant &server) const {
  if (!sandboxOn()) return;
  for (map<string, string>::const_iterator it =
         RuntimeOption::SandboxServerVariables.begin();
       it != RuntimeOption::SandboxServerVariables.end(); ++it) {
    server.set(String(it->first),
               String(parseSandboxServerVariable(it->second)));
  }

  if (!m_serverVars.empty()) {
    cellAddEq(*server.asCell(), make_tv<KindOfArray>(m_serverVars.get()));
  }
}
Example #15
0
void throw_invalid_object_type(const Variant& p) {
  auto tv = p.asCell();
  switch (tv->m_type) {
    case KindOfNull:
    case KindOfUninit:
      throw_null_pointer_exception();
    case KindOfObject:
      throw_invalid_object_type(tv->m_data.pobj->getClassName().c_str());
    case KindOfResource:
      throw_invalid_object_type(tv->m_data.pres->o_getClassName().c_str());
    default:
      throw_invalid_object_type(tname(tv->m_type).c_str());
  }
}
Example #16
0
void objOffsetSet(ObjectData* base, const Variant& offset, TypedValue* val,
                  bool validate /* = true */) {
  if (validate) {
    objArrayAccess(base);
  }
  assert(!base->isCollection());
  const Func* method = base->methodNamed(s_offsetSet.get());
  assert(method != nullptr);
  TypedValue tvResult;
  tvWriteUninit(&tvResult);
  TypedValue args[2] = { *offset.asCell(), *tvToCell(val) };
  g_context->invokeFuncFew(&tvResult, method, base, nullptr, 2, args);
  tvRefcountedDecRef(&tvResult);
}
Example #17
0
void StringBuffer::append(const Variant& v) {
  auto const cell = v.asCell();
  switch (cell->m_type) {
  case KindOfStaticString:
  case KindOfString:
    append(cell->m_data.pstr);
    break;
  case KindOfInt64:
    append(cell->m_data.num);
    break;
  default:
    append(v.toString());
  }
}
Example #18
0
static OffsetExistsResult objOffsetExists(ObjectData* base,
                                          const Variant& offset) {
  objArrayAccess(base);
  TypedValue tvResult;
  tvWriteUninit(&tvResult);
  assert(!base->isCollection());
  const Func* method = base->methodNamed(s_offsetExists.get());
  assert(method != nullptr);
  g_context->invokeFuncFew(&tvResult, method, base, nullptr, 1,
                             offset.asCell());
  tvCastToBooleanInPlace(&tvResult);
  if (!tvResult.m_data.num) return OffsetExistsResult::DoesNotExist;
  return method->cls() == SystemLib::s_ArrayObjectClass ?
    OffsetExistsResult::IssetIfNonNull : OffsetExistsResult::DefinitelyExists;
}
Example #19
0
bool EventHook::RunInterceptHandler(ActRec* ar) {
  const Func* func = ar->m_func;
  if (LIKELY(func->maybeIntercepted() == 0)) return true;

  Variant *h = get_intercept_handler(func->fullNameRef(),
                                     &func->maybeIntercepted());
  if (!h) return true;

  Transl::VMRegAnchor _;

  PC savePc = g_vmContext->m_pc;

  Variant doneFlag = true;
  Variant called_on;

  if (ar->hasThis()) {
    called_on = Variant(ar->getThis());
  } else if (ar->hasClass()) {
    // For static methods, give handler the name of called class
    called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
  }
  Array intArgs =
    CREATE_VECTOR5(ar->m_func->fullNameRef(),
                   called_on,
                   get_frame_args_with_ref(ar),
                   h->asCArrRef()[1],
                   ref(doneFlag));

  Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
  if (doneFlag.toBoolean()) {
    Offset pcOff;
    ActRec* outer = g_vmContext->getPrevVMState(ar, &pcOff);

    frame_free_locals_inl_no_hook<true>(ar, ar->m_func->numLocals());
    Stack& stack = g_vmContext->getStack();
    stack.top() = (Cell*)(ar + 1);
    cellDup(*ret.asCell(), *stack.allocTV());

    g_vmContext->m_fp = outer;
    g_vmContext->m_pc = outer ? outer->m_func->unit()->at(pcOff) : nullptr;

    return false;
  }
  g_vmContext->m_fp = ar;
  g_vmContext->m_pc = savePc;

  return true;
}
Example #20
0
bool UnaryOpExpression::preCompute(const Variant& value, Variant &result) {
  bool ret = true;
  try {
    ThrowAllErrorsSetter taes;
    auto add = RuntimeOption::IntsOverflowToInts ? cellAdd : cellAddO;
    auto sub = RuntimeOption::IntsOverflowToInts ? cellSub : cellSubO;

    switch(m_op) {
      case '!':
        result = (!toBoolean(value)); break;
      case '+':
        cellSet(add(make_tv<KindOfInt64>(0), *value.asCell()),
                *result.asCell());
        break;
      case '-':
        cellSet(sub(make_tv<KindOfInt64>(0), *value.asCell()),
                *result.asCell());
        break;
      case '~':
        tvSet(*value.asCell(), *result.asTypedValue());
        cellBitNot(*result.asCell());
        break;
      case '@':
        result = value;
        break;
      case T_INT_CAST:
        result = value.toInt64();
        break;
      case T_DOUBLE_CAST:
        result = toDouble(value);
        break;
      case T_STRING_CAST:
        result = toString(value);
        break;
      case T_BOOL_CAST:
        result = toBoolean(value);
        break;
      case T_EMPTY:
        result = !toBoolean(value);
        break;
      case T_ISSET:
        result = is_not_null(value);
        break;
      case T_INC:
      case T_DEC:
        assert(false);
      default:
        ret = false;
        break;
    }
  } catch (...) {
    ret = false;
  }
  return ret;
}
Example #21
0
File: apc.cpp Project: 191919/hhvm
TEST(APC, BasicPrimeStuff) {
  auto store = new_primed_store();
  Variant val;

  EXPECT_TRUE(store->get("int_2", val));
  EXPECT_TRUE(cellSame(*val.asCell(), make_tv<KindOfInt64>(2)));

  bool found = false;
  EXPECT_EQ(store->inc("int_3", 1, found), 4);
  EXPECT_TRUE(found);
  EXPECT_FALSE(store->get("int_200", val));

  EXPECT_EQ(store->cas("obj_1", 1, 2), true); // stdclass converts to 1
  EXPECT_EQ(store->cas("obj_2", 4, 5), false);
  EXPECT_EQ(store->cas("int_4", 4, 5), true);
  EXPECT_EQ(store->cas("int_5", 4, 5), false);
}
Example #22
0
bool contains(ObjectData* obj, const Variant& offset) {
  auto* key = offset.asCell();
  switch (obj->collectionType()) {
    case CollectionType::Vector:
    case CollectionType::ImmVector:
      return BaseVector::OffsetContains(obj, key);
    case CollectionType::Map:
    case CollectionType::ImmMap:
      return BaseMap::OffsetContains(obj, key);
    case CollectionType::Set:
    case CollectionType::ImmSet:
      return BaseSet::OffsetContains(obj, key);
    case CollectionType::Pair:
      return c_Pair::OffsetContains(obj, key);
  }
  not_reached();
}
Example #23
0
void HHVM_FUNCTION(set_frame_metadata, const Variant& metadata) {
  VMRegAnchor _;
  auto fp = vmfp();
  if (fp && fp->skipFrame()) fp = g_context->getPrevVMState(fp);
  if (UNLIKELY(!fp)) return;

  if (LIKELY(!(fp->func()->attrs() & AttrMayUseVV)) ||
      LIKELY(!fp->hasVarEnv())) {
    auto const local = fp->func()->lookupVarId(s_86metadata.get());
    if (LIKELY(local != kInvalidId)) {
      cellSet(*metadata.asCell(), *tvAssertCell(frame_local(fp, local)));
    } else {
      SystemLib::throwInvalidArgumentExceptionObject(
        "Unsupported dynamic call of set_frame_metadata()");
    }
  } else {
    fp->getVarEnv()->set(s_86metadata.get(), metadata.asTypedValue());
  }
}
void c_ConditionWaitHandle::t_fail(const Variant& exception) {
  auto const cell = exception.asCell();
  if (UNLIKELY(
    cell->m_type != KindOfObject ||
    !cell->m_data.pobj->instanceof(SystemLib::s_ExceptionClass)
  )) {
    SystemLib::throwInvalidArgumentExceptionObject(
      "Expected exception to be an instance of Exception");
  }

  if (isFinished()) {
    failAlreadyFinished();
  }

  assert(getState() == STATE_BLOCKED);
  auto parentChain = getParentChain();
  setState(STATE_FAILED);
  cellDup(make_tv<KindOfObject>(cell->m_data.pobj), m_resultOrException);
  parentChain.unblock();
}
Object c_ConditionWaitHandle::ti_create(const Variant& child) {
  // Child not a WaitHandle?
  auto const child_wh = c_WaitHandle::fromCell(child.asCell());
  if (UNLIKELY(!child_wh)) {
    SystemLib::throwInvalidArgumentExceptionObject(
      "Expected child to be an instance of WaitHandle");
  }

  // Child finished before notification?
  if (UNLIKELY(child_wh->isFinished())) {
    throwNotNotifiedException();
  }

  assert(child_wh->instanceof(c_WaitableWaitHandle::classof()));
  auto const child_wwh = static_cast<c_WaitableWaitHandle*>(child_wh);

  auto wh = req::make<c_ConditionWaitHandle>();
  wh->initialize(child_wwh);
  return Object(std::move(wh));
}
Example #26
0
void StringBuffer::append(const Variant& v) {
  auto const cell = v.asCell();
  switch (cell->m_type) {
    case KindOfInt64:
      append(cell->m_data.num);
      break;
    case KindOfStaticString:
    case KindOfString:
      append(cell->m_data.pstr);
      break;
    case KindOfUninit:
    case KindOfNull:
    case KindOfBoolean:
    case KindOfDouble:
    case KindOfArray:
    case KindOfObject:
    case KindOfResource:
    case KindOfRef:
    case KindOfClass:
      append(v.toString());
  }
}
Example #27
0
ALWAYS_INLINE
typename std::enable_if<
  std::is_base_of<BaseMap, TMap>::value, Object>::type
BaseMap::FromItems(const Class*, const Variant& iterable) {
  if (iterable.isNull()) return Object{req::make<TMap>()};
  VMRegGuard _;

  size_t sz;
  ArrayIter iter = getArrayIterHelper(iterable, sz);
  auto target = req::make<TMap>();
  target->reserve(sz);
  for (; iter; ++iter) {
    Variant v = iter.second();
    TypedValue* tv = v.asCell();
    if (UNLIKELY(tv->m_type != KindOfObject ||
                 tv->m_data.pobj->getVMClass() != c_Pair::classof())) {
      SystemLib::throwInvalidArgumentExceptionObject(
                 "Parameter must be an instance of Iterable<Pair>");
    }
    auto pair = static_cast<c_Pair*>(tv->m_data.pobj);
    target->setRaw(&pair->elm0, &pair->elm1);
  }
  return Object{std::move(target)};
}
Example #28
0
bool EventHook::RunInterceptHandler(ActRec* ar) {
  const Func* func = ar->func();
  if (LIKELY(func->maybeIntercepted() == 0)) return true;

  // Intercept only original generator / async function calls, not resumption.
  if (ar->resumed()) return true;

  Variant* h = get_intercept_handler(func->fullNameStr(),
                                     &func->maybeIntercepted());
  if (!h) return true;

  /*
   * In production mode, only functions that we have assumed can be
   * intercepted during static analysis should actually be
   * intercepted.
   */
  if (RuntimeOption::RepoAuthoritative &&
      !RuntimeOption::EvalJitEnableRenameFunction) {
    if (!(func->attrs() & AttrInterceptable)) {
      raise_error("fb_intercept was used on a non-interceptable function (%s) "
                  "in RepoAuthoritative mode", func->fullName()->data());
    }
  }

  VMRegAnchor _;

  PC savePc = vmpc();

  Variant doneFlag = true;
  Variant called_on;

  if (ar->hasThis()) {
    called_on = Variant(ar->getThis());
  } else if (ar->hasClass()) {
    // For static methods, give handler the name of called class
    called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
  }
  Variant intArgs =
    PackedArrayInit(5)
      .append(VarNR(ar->func()->fullName()))
      .append(called_on)
      .append(get_frame_args_with_ref(ar))
      .append(h->asCArrRef()[1])
      .appendRef(doneFlag)
      .toArray();

  Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
  if (doneFlag.toBoolean()) {
    Offset pcOff;
    ActRec* outer = g_context->getPrevVMState(ar, &pcOff);

    frame_free_locals_inl_no_hook<true>(ar, ar->func()->numLocals());
    Stack& stack = vmStack();
    stack.top() = (Cell*)(ar + 1);
    cellDup(*ret.asCell(), *stack.allocTV());

    vmfp() = outer;
    vmpc() = outer ? outer->func()->unit()->at(pcOff) : nullptr;

    return false;
  }
  vmfp() = ar;
  vmpc() = savePc;

  return true;
}
Example #29
0
// foldConst() is callable from the parse phase as well as the analysis phase.
// We take advantage of this during the parse phase to reduce very simple
// expressions down to a single scalar and keep the parse tree smaller,
// especially in cases of long chains of binary operators. However, we limit
// the effectivness of this during parse to ensure that we eliminate only
// very simple scalars that don't require analysis in later phases. For now,
// that's just simply scalar values.
ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
  ExpressionPtr optExp;
  Variant v1;
  Variant v2;

  if (!m_exp2->getScalarValue(v2)) {
    if ((ar->getPhase() != AnalysisResult::ParseAllFiles) &&
        m_exp1->isScalar() && m_exp1->getScalarValue(v1)) {
      switch (m_op) {
        case T_IS_IDENTICAL:
        case T_IS_NOT_IDENTICAL:
          if (v1.isNull()) {
            return makeIsNull(ar, getLocation(), m_exp2,
                              m_op == T_IS_NOT_IDENTICAL);
          }
          break;
        case T_LOGICAL_AND:
        case T_BOOLEAN_AND:
        case T_LOGICAL_OR:
        case T_BOOLEAN_OR: {
          ExpressionPtr rep =
            v1.toBoolean() == (m_op == T_LOGICAL_AND ||
                               m_op == T_BOOLEAN_AND) ? m_exp2 : m_exp1;
          rep = ExpressionPtr(
              new UnaryOpExpression(
                getScope(), getLocation(),
                rep, T_BOOL_CAST, true));
          rep->setActualType(Type::Boolean);
          return replaceValue(rep);
        }
        case '+':
        case '.':
        case '*':
        case '&':
        case '|':
        case '^':
          if (m_exp2->is(KindOfBinaryOpExpression)) {
            BinaryOpExpressionPtr binOpExp =
              dynamic_pointer_cast<BinaryOpExpression>(m_exp2);
            if (binOpExp->m_op == m_op && binOpExp->m_exp1->isScalar()) {
              ExpressionPtr aExp = m_exp1;
              ExpressionPtr bExp = binOpExp->m_exp1;
              ExpressionPtr cExp = binOpExp->m_exp2;
              if (aExp->isArray() || bExp->isArray() || cExp->isArray()) {
                break;
              }
              m_exp1 = binOpExp = Clone(binOpExp);
              m_exp2 = cExp;
              binOpExp->m_exp1 = aExp;
              binOpExp->m_exp2 = bExp;
              if (ExpressionPtr optExp = binOpExp->foldConst(ar)) {
                m_exp1 = optExp;
              }
              return static_pointer_cast<Expression>(shared_from_this());
            }
          }
        break;
        default:
          break;
      }
    }

    return ExpressionPtr();
  }

  if (m_exp1->isScalar()) {
    if (!m_exp1->getScalarValue(v1)) return ExpressionPtr();
    try {
      ScalarExpressionPtr scalar1 =
        dynamic_pointer_cast<ScalarExpression>(m_exp1);
      ScalarExpressionPtr scalar2 =
        dynamic_pointer_cast<ScalarExpression>(m_exp2);
      // Some data, like the values of __CLASS__ and friends, are not available
      // while we're still in the initial parse phase.
      if (ar->getPhase() == AnalysisResult::ParseAllFiles) {
        if ((scalar1 && scalar1->needsTranslation()) ||
            (scalar2 && scalar2->needsTranslation())) {
          return ExpressionPtr();
        }
      }
      if (!Option::WholeProgram || !Option::ParseTimeOpts) {
        // In the VM, don't optimize __CLASS__ if within a trait, since
        // __CLASS__ is not resolved yet.
        ClassScopeRawPtr clsScope = getOriginalClass();
        if (clsScope && clsScope->isTrait()) {
          if ((scalar1 && scalar1->getType() == T_CLASS_C) ||
              (scalar2 && scalar2->getType() == T_CLASS_C)) {
            return ExpressionPtr();
          }
        }
      }
      Variant result;
      switch (m_op) {
        case T_LOGICAL_XOR:
          result = static_cast<bool>(v1.toBoolean() ^ v2.toBoolean());
          break;
        case '|':
          *result.asCell() = cellBitOr(*v1.asCell(), *v2.asCell());
          break;
        case '&':
          *result.asCell() = cellBitAnd(*v1.asCell(), *v2.asCell());
          break;
        case '^':
          *result.asCell() = cellBitXor(*v1.asCell(), *v2.asCell());
          break;
        case '.':
          if (v1.isArray() || v2.isArray()) {
            return ExpressionPtr();
          }
          result = concat(v1.toString(), v2.toString());
          break;
        case T_IS_IDENTICAL:
          result = same(v1, v2);
          break;
        case T_IS_NOT_IDENTICAL:
          result = !same(v1, v2);
          break;
        case T_IS_EQUAL:
          result = equal(v1, v2);
          break;
        case T_IS_NOT_EQUAL:
          result = !equal(v1, v2);
          break;
        case '<':
          result = less(v1, v2);
          break;
        case T_IS_SMALLER_OR_EQUAL:
          result = cellLessOrEqual(*v1.asCell(), *v2.asCell());
          break;
        case '>':
          result = more(v1, v2);
          break;
        case T_IS_GREATER_OR_EQUAL:
          result = cellGreaterOrEqual(*v1.asCell(), *v2.asCell());
          break;
        case '+':
          *result.asCell() = cellAdd(*v1.asCell(), *v2.asCell());
          break;
        case '-':
          *result.asCell() = cellSub(*v1.asCell(), *v2.asCell());
          break;
        case '*':
          *result.asCell() = cellMul(*v1.asCell(), *v2.asCell());
          break;
        case '/':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          *result.asCell() = cellDiv(*v1.asCell(), *v2.asCell());
          break;
        case '%':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          *result.asCell() = cellMod(*v1.asCell(), *v2.asCell());
          break;
        case T_SL:
          result = v1.toInt64() << v2.toInt64();
          break;
        case T_SR:
          result = v1.toInt64() >> v2.toInt64();
          break;
        case T_BOOLEAN_OR:
          result = v1.toBoolean() || v2.toBoolean(); break;
        case T_BOOLEAN_AND:
          result = v1.toBoolean() && v2.toBoolean(); break;
        case T_LOGICAL_OR:
          result = v1.toBoolean() || v2.toBoolean(); break;
        case T_LOGICAL_AND:
          result = v1.toBoolean() && v2.toBoolean(); break;
        case T_INSTANCEOF: {
          if (v2.isString()) {
            if (v1.isArray() &&
                interface_supports_array(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isString() &&
                interface_supports_string(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isInteger() &&
                interface_supports_int(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isDouble() &&
                interface_supports_double(v2.getStringData())) {
              result = true;
              break;
            }
          }
          result = false;
          break;
        }
        default:
          return ExpressionPtr();
      }
      return makeScalarExpression(ar, result);
    } catch (...) {
    }
  } else if (ar->getPhase() != AnalysisResult::ParseAllFiles) {
Example #30
0
bool f_is_callable(const Variant& v, bool syntax /* = false */,
                   VRefParam name /* = null */) {
  bool ret = true;
  if (LIKELY(!syntax)) {
    CallerFrame cf;
    ObjectData* obj = NULL;
    HPHP::Class* cls = NULL;
    StringData* invName = NULL;
    const HPHP::Func* f = vm_decode_function(v, cf(), false, obj, cls,
                                                 invName, false);
    if (f == NULL) {
      ret = false;
    }
    if (invName != NULL) {
      decRefStr(invName);
    }
    if (!name.isReferenced()) return ret;
  }

  auto const tv_func = v.asCell();
  if (IS_STRING_TYPE(tv_func->m_type)) {
    if (name.isReferenced()) name = tv_func->m_data.pstr;
    return ret;
  }

  if (tv_func->m_type == KindOfArray) {
    const Array& arr = Array(tv_func->m_data.parr);
    const Variant& clsname = arr.rvalAtRef(int64_t(0));
    const Variant& mthname = arr.rvalAtRef(int64_t(1));
    if (arr.size() != 2 ||
        &clsname == &null_variant ||
        &mthname == &null_variant) {
      name = String("Array");
      return false;
    }

    auto const tv_meth = mthname.asCell();
    if (!IS_STRING_TYPE(tv_meth->m_type)) {
      if (name.isReferenced()) name = v.toString();
      return false;
    }

    auto const tv_cls = clsname.asCell();
    if (tv_cls->m_type == KindOfObject) {
      name = tv_cls->m_data.pobj->o_getClassName();
    } else if (IS_STRING_TYPE(tv_cls->m_type)) {
      name = tv_cls->m_data.pstr;
    } else {
      name = v.toString();
      return false;
    }

    name = concat3(name, s_colon2, tv_meth->m_data.pstr);
    return ret;
  }

  if (tv_func->m_type == KindOfObject) {
    ObjectData *d = tv_func->m_data.pobj;
    const Func* invoke = d->getVMClass()->lookupMethod(s__invoke.get());
    if (name.isReferenced()) {
      if (d->instanceof(c_Closure::classof())) {
        // Hack to stop the mangled name from showing up
        name = s_Closure__invoke;
      } else {
        name = d->o_getClassName() + "::__invoke";
      }
    }
    return invoke != NULL;
  }

  return false;
}