Esempio n. 1
0
void StandardExtension::initMisc() {
    HHVM_FALIAS(HH\\server_warmup_status, server_warmup_status);
    HHVM_FE(connection_aborted);
    HHVM_FE(connection_status);
    HHVM_FE(connection_timeout);
    HHVM_FE(constant);
    HHVM_FE(define);
    HHVM_FE(defined);
    HHVM_FE(ignore_user_abort);
    HHVM_FE(pack);
    HHVM_FE(sleep);
    HHVM_FE(usleep);
    HHVM_FE(time_nanosleep);
    HHVM_FE(time_sleep_until);
    HHVM_FE(uniqid);
    HHVM_FE(unpack);
    HHVM_FE(sys_getloadavg);
    HHVM_FE(token_get_all);
    HHVM_FE(token_name);
    HHVM_FE(hphp_to_string);
    HHVM_FALIAS(__SystemLib\\max2, SystemLib_max2);
    HHVM_FALIAS(__SystemLib\\min2, SystemLib_min2);
    Native::registerConstant<KindOfDouble>(makeStaticString("INF"), k_INF);
    Native::registerConstant<KindOfDouble>(makeStaticString("NAN"), k_NAN);
    Native::registerConstant<KindOfInt64>(
        makeStaticString("PHP_MAXPATHLEN"), MAXPATHLEN);
    Native::registerConstant<KindOfBoolean>(makeStaticString("PHP_DEBUG"),
      #if DEBUG
        true
      #else
        false
      #endif
     );
    bindTokenConstants();
    Native::registerConstant<KindOfInt64>(s_T_PAAMAYIM_NEKUDOTAYIM.get(),
                                          get_user_token_id(T_DOUBLE_COLON));

    HHVM_RC_STR(PHP_BINARY, current_executable_path());
    HHVM_RC_STR(PHP_BINDIR, current_executable_directory());
    HHVM_RC_STR(PHP_OS, HHVM_FN(php_uname)("s").toString().toCppString());
    HHVM_RC_STR(PHP_SAPI, RuntimeOption::ExecutionMode);

    HHVM_RC_INT(PHP_INT_SIZE, sizeof(int64_t));
    HHVM_RC_INT(PHP_INT_MIN, k_PHP_INT_MIN);
    HHVM_RC_INT(PHP_INT_MAX, k_PHP_INT_MAX);

    HHVM_RC_INT_SAME(PHP_MAJOR_VERSION);
    HHVM_RC_INT_SAME(PHP_MINOR_VERSION);
    HHVM_RC_INT_SAME(PHP_RELEASE_VERSION);
    HHVM_RC_STR_SAME(PHP_EXTRA_VERSION);
    HHVM_RC_STR_SAME(PHP_VERSION);
    HHVM_RC_INT_SAME(PHP_VERSION_ID);

    // FIXME: These values are hardcoded from their previous IDL values
    // Grab their correct values from the system as appropriate
    HHVM_RC_STR(PHP_EOL, "\n");
    HHVM_RC_STR(PHP_CONFIG_FILE_PATH, "");
    HHVM_RC_STR(PHP_CONFIG_FILE_SCAN_DIR, "");
    HHVM_RC_STR(PHP_DATADIR, "");
    HHVM_RC_STR(PHP_EXTENSION_DIR, "");
    HHVM_RC_STR(PHP_LIBDIR, "");
    HHVM_RC_STR(PHP_LOCALSTATEDIR, "");
    HHVM_RC_STR(PHP_PREFIX, "");
    HHVM_RC_STR(PHP_SHLIB_SUFFIX, "so");
    HHVM_RC_STR(PHP_SYSCONFDIR, "");
    HHVM_RC_STR(PEAR_EXTENSION_DIR, "");
    HHVM_RC_STR(PEAR_INSTALL_DIR, "");

    loadSystemlib("std_misc");
  }
Esempio n. 2
0
namespace HPHP { namespace HHBBC {

//////////////////////////////////////////////////////////////////////

const StaticString s_reified_generics_var("0ReifiedGenerics");

//////////////////////////////////////////////////////////////////////

uint32_t closure_num_use_vars(const php::Func* f) {
  // Properties on the closure object are use vars.
  return f->cls->properties.size();
}

bool is_pseudomain(const php::Func* f) {
  return f->unit->pseudomain.get() == f;
}

bool is_methcaller(const StringData* name) {
  return Func::isMethCallerName(name);
}

bool is_volatile_local(const php::Func* func, LocalId lid) {
  auto const& l = func->locals[lid];
  if (!l.name) return false;

  // Named pseudomain locals are bound to $GLOBALS.
  if (is_pseudomain(func)) return true;

  return (RuntimeOption::EnableArgsInBacktraces &&
          l.name->same(s_reified_generics_var.get())) ||
         l.name->same(s_86metadata.get());
}

SString memoize_impl_name(const php::Func* func) {
  always_assert(func->isMemoizeWrapper);
  return Func::genMemoizeImplName(func->name);
}

bool check_nargs_in_range(const php::Func* func, uint32_t nArgs) {
  while (nArgs < func->dvEntries.size()) {
    if (func->dvEntries[nArgs++] == NoBlockId) return false;
  }
  return true;
}

//////////////////////////////////////////////////////////////////////

namespace {

using ExnNode = php::ExnNode;

void copy_into(php::FuncBase* dst, const php::FuncBase& other) {
  hphp_fast_map<ExnNode*, ExnNode*> processed;

  BlockId delta = dst->blocks.size();
  always_assert(!dst->exnNodes.size() || !other.exnNodes.size());
  dst->exnNodes.reserve(dst->exnNodes.size() + other.exnNodes.size());
  for (auto en : other.exnNodes) {
    en.region.catchEntry += delta;
    dst->exnNodes.push_back(std::move(en));
  }
  for (auto theirs : other.blocks) {
    if (delta) {
      auto const ours = theirs.mutate();
      if (ours->fallthrough != NoBlockId) ours->fallthrough += delta;
      if (ours->throwExit != NoBlockId) ours->throwExit += delta;
      for (auto& bc : ours->hhbcs) {
        // When merging functions (used for 86xints) we have to drop
        // the src info, because it might reference a different unit
        // (and as a generated function, the src info isn't very
        // meaningful anyway).
        bc.srcLoc = -1;
        bc.forEachTarget([&] (BlockId& b) { b += delta; });
      }
    }
    dst->blocks.push_back(std::move(theirs));
  }
}

//////////////////////////////////////////////////////////////////////

}

//////////////////////////////////////////////////////////////////////

bool append_func(php::Func* dst, const php::Func& src) {
  if (src.numIters || src.locals.size()) return false;
  if (src.exnNodes.size() && dst->exnNodes.size()) return false;

  bool ok = false;
  for (auto& b : dst->blocks) {
    if (b->hhbcs.back().op != Op::RetC) continue;
    auto const blk = b.mutate();
    blk->hhbcs.back() = bc::PopC {};
    blk->fallthrough = dst->blocks.size();
    ok = true;
  }
  if (!ok) return false;
  copy_into(dst, src);
  return true;
}

php::FuncBase::FuncBase(const FuncBase& other) {
  copy_into(this, other);

  assertx(!other.nativeInfo);
}

//////////////////////////////////////////////////////////////////////

}}
Esempio n. 3
0
  void moduleInit() override {
    SOCK_CONST(AF_UNIX);
    SOCK_CONST(AF_INET);
    SOCK_CONST(AF_INET6);
    SOCK_CONST(SOCK_STREAM);
    SOCK_CONST(SOCK_DGRAM);
    SOCK_CONST(SOCK_RAW);
    SOCK_CONST(SOCK_SEQPACKET);
    SOCK_CONST(SOCK_RDM);

    SOCK_CONST(MSG_OOB);
    SOCK_CONST(MSG_WAITALL);
    SOCK_CONST(MSG_CTRUNC);
    SOCK_CONST(MSG_TRUNC);
    SOCK_CONST(MSG_PEEK);
    SOCK_CONST(MSG_DONTROUTE);
#ifdef MSG_EOR
    SOCK_CONST(MSG_EOR);
#endif
#ifdef MSG_EOF
    SOCK_CONST(MSG_EOF);
#endif
#ifdef MSG_CONFIRM
    SOCK_CONST(MSG_CONFIRM);
#endif
#ifdef MSG_ERRQUEUE
    SOCK_CONST(MSG_ERRQUEUE);
#endif
#ifdef MSG_NOSIGNAL
    SOCK_CONST(MSG_NOSIGNAL);
#endif
#ifdef MSG_DONTWAIT
    SOCK_CONST(MSG_DONTWAIT);
#endif
#ifdef MSG_MORE
    SOCK_CONST(MSG_MORE);
#endif
#ifdef MSG_WAITFORONE
    SOCK_CONST(MSG_WAITFORONE);
#endif
#ifdef MSG_CMSG_CLOEXEC
    SOCK_CONST(MSG_CMSG_CLOEXEC);
#endif

    SOCK_CONST(SO_DEBUG);
    SOCK_CONST(SO_REUSEADDR);
#ifdef SO_REUSEPORT
    SOCK_CONST(SO_REUSEPORT);
#endif
    SOCK_CONST(SO_KEEPALIVE);
    SOCK_CONST(SO_DONTROUTE);
    SOCK_CONST(SO_LINGER);
    SOCK_CONST(SO_BROADCAST);
    SOCK_CONST(SO_OOBINLINE);
    SOCK_CONST(SO_SNDBUF);
    SOCK_CONST(SO_RCVBUF);
    SOCK_CONST(SO_SNDLOWAT);
    SOCK_CONST(SO_RCVLOWAT);
    SOCK_CONST(SO_SNDTIMEO);
    SOCK_CONST(SO_RCVTIMEO);
    SOCK_CONST(SO_TYPE);
#ifdef SO_FAMILY
    SOCK_CONST(SO_FAMILY);
#endif
    SOCK_CONST(SO_ERROR);
#ifdef SO_BINDTODEVICE
    SOCK_CONST(SO_BINDTODEVICE);
#endif
    SOCK_CONST(SOL_SOCKET);
    SOCK_CONST(SOMAXCONN);
#ifdef TCP_NODELAY
    SOCK_CONST(TCP_NODELAY);
#endif
    SOCK_CONST(PHP_NORMAL_READ);
    SOCK_CONST(PHP_BINARY_READ);

    /* TODO: MCAST_* constants and logic to handle them */

    SOCK_CONST(IP_MULTICAST_IF);
    SOCK_CONST(IP_MULTICAST_TTL);
    SOCK_CONST(IP_MULTICAST_LOOP);
    SOCK_CONST(IPV6_MULTICAST_IF);
    SOCK_CONST(IPV6_MULTICAST_HOPS);
    SOCK_CONST(IPV6_MULTICAST_LOOP);
    SOCK_CONST(IPPROTO_IP);
    SOCK_CONST(IPPROTO_IPV6);

    Native::registerConstant<KindOfInt64>(s_SOL_TCP.get(), IPPROTO_TCP);
    Native::registerConstant<KindOfInt64>(s_SOL_UDP.get(), IPPROTO_UDP);

    SOCK_CONST(IPV6_UNICAST_HOPS);

    HHVM_FE(socket_create);
    HHVM_FE(socket_create_listen);
    HHVM_FE(socket_create_pair);
    HHVM_FE(socket_get_option);
    HHVM_FE(socket_getpeername);
    HHVM_FE(socket_getsockname);
    HHVM_FE(socket_set_block);
    HHVM_FE(socket_set_nonblock);
    HHVM_FE(socket_set_option);
    HHVM_FE(socket_connect);
    HHVM_FE(socket_bind);
    HHVM_FE(socket_listen);
    HHVM_FE(socket_select);
    HHVM_FE(socket_server);
    HHVM_FE(socket_accept);
    HHVM_FE(socket_read);
    HHVM_FE(socket_write);
    HHVM_FE(socket_send);
    HHVM_FE(socket_sendto);
    HHVM_FE(socket_recv);
    HHVM_FE(socket_recvfrom);
    HHVM_FE(socket_shutdown);
    HHVM_FE(socket_close);
    HHVM_FE(socket_strerror);
    HHVM_FE(socket_last_error);
    HHVM_FE(socket_clear_error);
    HHVM_FE(getaddrinfo);

    loadSystemlib();
  }
Esempio n. 4
0
string
toHex(const StaticString &data) {
	string result(data.size() * 2, '\0');
	toHex(data, (char *) result.data());
	return result;
}
Esempio n. 5
0
void c_Continuation::call_next() {
  const HPHP::Func* func = m_cls->lookupMethod(s_next.get());
  g_vmContext->invokeContFunc(func, this);
}
Esempio n. 6
0
namespace HPHP { namespace HHBBC {

//////////////////////////////////////////////////////////////////////

const StaticString s_Vector("HH\\Vector");
const StaticString s_Map("HH\\Map");
const StaticString s_Set("HH\\Set");

const StaticString s_add("add");
const StaticString s_addall("addall");
const StaticString s_append("append");
const StaticString s_clear("clear");
const StaticString s_remove("remove");
const StaticString s_removeall("removeall");
const StaticString s_removekey("removekey");
const StaticString s_set("set");
const StaticString s_setall("setall");

//////////////////////////////////////////////////////////////////////

bool is_collection_method_returning_this(const php::Class* cls,
                                         const php::Func* func) {
  if (!cls) return false;

  if (cls->name->isame(s_Vector.get())) {
    return
      func->name->isame(s_add.get()) ||
      func->name->isame(s_addall.get()) ||
      func->name->isame(s_append.get()) ||
      func->name->isame(s_clear.get()) ||
      func->name->isame(s_removekey.get()) ||
      func->name->isame(s_set.get()) ||
      func->name->isame(s_setall.get());
  }

  if (cls->name->isame(s_Map.get())) {
    return
      func->name->isame(s_add.get()) ||
      func->name->isame(s_addall.get()) ||
      func->name->isame(s_clear.get()) ||
      func->name->isame(s_remove.get()) ||
      func->name->isame(s_set.get()) ||
      func->name->isame(s_setall.get());
  }

  if (cls->name->isame(s_Set.get())) {
    return
      func->name->isame(s_add.get()) ||
      func->name->isame(s_addall.get()) ||
      func->name->isame(s_clear.get()) ||
      func->name->isame(s_remove.get()) ||
      func->name->isame(s_removeall.get());
  }

  return false;
}

Type native_function_return_type(const php::Func* f,
                                 bool include_coercion_failures) {
  assert(f->nativeInfo);

  // If the function returns by ref, we can't say much about it. It can be a ref
  // or null.
  if (f->attrs & AttrReference) {
    return union_of(TRef, TInitNull);
  }

  // Infer the type from the HNI declaration
  auto t = [&]{
    auto const hni = f->nativeInfo->returnType;
    return hni ? from_DataType(*hni) : TInitCell;
  }();
  if (t.subtypeOf(BArr)) {
    if (f->retTypeConstraint.isVArray()) {
      assertx(!RuntimeOption::EvalHackArrDVArrs);
      t = TVArr;
    } else if (f->retTypeConstraint.isDArray()) {
      assertx(!RuntimeOption::EvalHackArrDVArrs);
      t = TDArr;
    } else if (f->retTypeConstraint.isArray()) {
      t = TPArr;
    }
  }

  // Non-simple types (ones that are represented by pointers) can always
  // possibly be null.
  if (t.subtypeOfAny(TStr, TArr, TVec, TDict,
                     TKeyset, TObj, TRes)) {
    t |= TInitNull;
  } else {
    // Otherwise it should be a simple type or possibly everything.
    assert(t == TInitCell || t.subtypeOfAny(TBool, TInt, TDbl, TNull));
  }

  if (include_coercion_failures) {
    // If parameter coercion fails, we can also get null or false depending on
    // the function.
    if (f->attrs & AttrParamCoerceModeNull) {
      t |= TInitNull;
    }
    if (f->attrs & AttrParamCoerceModeFalse) {
      t |= TFalse;
    }
  }

  return remove_uninit(t);
}

}}
Esempio n. 7
0
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////

const StaticString
  s_unknown_type("unknown type"),
  s_boolean("boolean"),
  s_bool("bool"),
  s_integer("integer"),
  s_int("int"),
  s_float("float"),
  s_double("double"),
  s_string("string"),
  s_object("object"),
  s_array("array"),
  s_dict("dict"),
  s_vec("vec"),
  s_keyset("keyset"),
  s_NULL("NULL"),
  s_null("null");

String HHVM_FUNCTION(gettype, const Variant& v) {
  if (v.getType() == KindOfResource && v.toCResRef().isInvalid()) {
    return s_unknown_type;
  }
  /* Although getDataTypeString also handles the null type, it returns "null"
   * (lower case). Unfortunately, PHP returns "NULL" (upper case) for
   * gettype(). So we make an exception here. */
  if (v.isNull()) {
    return s_NULL;
  }
  if (v.isArray()) {
    if (v.toArray()->isDict()) return s_dict;
    if (v.toArray()->isVecArray()) return s_vec;
    if (v.toArray()->isKeyset()) return s_keyset;
  }
  return getDataTypeString(v.getType());
}

String HHVM_FUNCTION(get_resource_type, const Resource& handle) {
  return handle->o_getResourceName();
}

bool HHVM_FUNCTION(boolval, const Variant& v) {
  return v.toBoolean();
}

int64_t HHVM_FUNCTION(intval, const Variant& v, int64_t base /* = 10 */) {
  return v.toInt64(base);
}

double HHVM_FUNCTION(floatval, const Variant& v) {
  return v.toDouble();
}

String HHVM_FUNCTION(strval, const Variant& v) {
  return v.toString();
}

bool HHVM_FUNCTION(settype, VRefParam var, const String& type) {
  Variant val;
  if      (type == s_boolean) val = var.toBoolean();
  else if (type == s_bool   ) val = var.toBoolean();
  else if (type == s_integer) val = var.toInt64();
  else if (type == s_int    ) val = var.toInt64();
  else if (type == s_float  ) val = var.toDouble();
  else if (type == s_double ) val = var.toDouble();
  else if (type == s_string ) val = var.toString();
  else if (type == s_array  ) val = var.toArray();
  else if (type == s_object ) val = var.toObject();
  else if (type == s_null   ) val = uninit_null();
  else return false;
  var.assignIfRef(val);
  return true;
}

bool HHVM_FUNCTION(is_null, const Variant& v) {
  return is_null(v);
}

bool HHVM_FUNCTION(is_bool, const Variant& v) {
  return is_bool(v);
}

bool HHVM_FUNCTION(is_int, const Variant& v) {
  return is_int(v);
}

bool HHVM_FUNCTION(is_float, const Variant& v) {
  return is_double(v);
}

bool HHVM_FUNCTION(is_numeric, const Variant& v) {
  return v.isNumeric(true);
}

bool HHVM_FUNCTION(is_string, const Variant& v) {
  return is_string(v);
}

bool HHVM_FUNCTION(is_scalar, const Variant& v) {
  return v.isScalar();
}

bool HHVM_FUNCTION(is_array, const Variant& v) {
  return is_array(v);
}

bool HHVM_FUNCTION(HH_is_vec, const Variant& v) {
  return is_vec(v);
}

bool HHVM_FUNCTION(HH_is_dict, const Variant& v) {
  return is_dict(v);
}

bool HHVM_FUNCTION(HH_is_keyset, const Variant& v) {
  return is_keyset(v);
}

bool HHVM_FUNCTION(is_object, const Variant& v) {
  return is_object(v);
}

bool HHVM_FUNCTION(is_resource, const Variant& v) {
  return (v.getType() == KindOfResource && !v.toCResRef().isInvalid());
}

///////////////////////////////////////////////////////////////////////////////
// input/output

Variant HHVM_FUNCTION(print_r, const Variant& expression,
                               bool ret /* = false */) {
  Variant res;
  try {
    VariableSerializer vs(VariableSerializer::Type::PrintR);
    if (ret) {
      res = vs.serialize(expression, ret);
    } else {
      vs.serialize(expression, ret);
      res = true;
    }
  } catch (StringBufferLimitException &e) {
    raise_notice("print_r() exceeded max bytes limit");
    res = e.m_result;
  }
  return res;
}

Variant HHVM_FUNCTION(var_export, const Variant& expression,
                                  bool ret /* = false */) {
  Variant res;
  try {
    VariableSerializer vs(VariableSerializer::Type::VarExport);
    if (ret) {
      res = vs.serialize(expression, ret);
    } else {
      vs.serialize(expression, ret);
      res = true;
    }
  } catch (StringBufferLimitException &e) {
    raise_notice("var_export() exceeded max bytes limit");
  }
  return res;
}

static ALWAYS_INLINE void do_var_dump(VariableSerializer vs,
                                      const Variant& expression) {
  // manipulate maxCount to match PHP behavior
  if (!expression.isObject()) {
    vs.incMaxCount();
  }
  vs.serialize(expression, false);
}

void HHVM_FUNCTION(var_dump, const Variant& expression,
                             const Array& _argv /*=null_array */) {
#ifdef ENABLE_EXTENSION_XDEBUG
  if (UNLIKELY(XDEBUG_GLOBAL(OverloadVarDump) &&
               XDEBUG_GLOBAL(DefaultEnable))) {
    HHVM_FN(xdebug_var_dump)(expression, _argv);
    return;
  }
#endif

  VariableSerializer vs(VariableSerializer::Type::VarDump, 0, 2);
  do_var_dump(vs, expression);

  auto sz = _argv.size();
  for (int i = 0; i < sz; i++) {
    do_var_dump(vs, _argv[i]);
  }
}

void HHVM_FUNCTION(debug_zval_dump, const Variant& variable) {
  VariableSerializer vs(VariableSerializer::Type::DebugDump);
  vs.serialize(variable, false);
}

const StaticString
  s_Null("N;"),
  s_True("b:1;"),
  s_False("b:0;"),
  s_Res("i:0;"),
  s_EmptyArray("a:0:{}"),
  s_EmptyVecArray("v:0:{}"),
  s_EmptyDictArray("D:0:{}");

String HHVM_FUNCTION(serialize, const Variant& value) {
  switch (value.getType()) {
    case KindOfUninit:
    case KindOfNull:
      return s_Null;
    case KindOfBoolean:
      return value.getBoolean() ? s_True : s_False;
    case KindOfInt64: {
      StringBuffer sb;
      sb.append("i:");
      sb.append(value.getInt64());
      sb.append(';');
      return sb.detach();
    }
    case KindOfPersistentString:
    case KindOfString: {
      StringData *str = value.getStringData();
      StringBuffer sb;
      sb.append("s:");
      sb.append(str->size());
      sb.append(":\"");
      sb.append(str->data(), str->size());
      sb.append("\";");
      return sb.detach();
    }
    case KindOfResource:
      return s_Res;
    case KindOfPersistentArray:
    case KindOfArray: {
      ArrayData *arr = value.getArrayData();
      if (arr->empty()) {
        if (arr->isVecArray()) return s_EmptyVecArray;
        if (arr->isDict()) return s_EmptyDictArray;
        return s_EmptyArray;
      }
      // fall-through
    }
    case KindOfDouble:
    case KindOfObject: {
      VariableSerializer vs(VariableSerializer::Type::Serialize);
      return vs.serialize(value, true);
    }
    case KindOfRef:
    case KindOfClass:
      break;
  }
  not_reached();
}

Variant HHVM_FUNCTION(unserialize, const String& str,
                                   const Array& options /* =[] */) {
  return unserialize_from_string(str, options);
}

///////////////////////////////////////////////////////////////////////////////
// variable table

ALWAYS_INLINE
static Array get_defined_vars() {
  VarEnv* v = g_context->getOrCreateVarEnv();
  return v ? v->getDefinedVariables() : empty_array();
}

Array HHVM_FUNCTION(get_defined_vars) {
  raise_disallowed_dynamic_call("get_defined_vars should not be "
    "called dynamically");
  return get_defined_vars();
}

// accessible as __SystemLib\\get_defined_vars
Array HHVM_FUNCTION(SystemLib_get_defined_vars) {
  return get_defined_vars();
}

const StaticString
  s_GLOBALS("GLOBALS"),
  s_this("this");

static const Func* arGetContextFunc(const ActRec* ar) {
  if (ar == nullptr) {
    return nullptr;
  }
  if (ar->m_func->isPseudoMain() || ar->m_func->isBuiltin()) {
    // Pseudomains inherit the context of their caller
    auto const context = g_context.getNoCheck();
    ar = context->getPrevVMState(ar);
    while (ar != nullptr &&
             (ar->m_func->isPseudoMain() || ar->m_func->isBuiltin())) {
      ar = context->getPrevVMState(ar);
    }
    if (ar == nullptr) {
      return nullptr;
    }
  }
  return ar->m_func;
}

static bool modify_extract_name(VarEnv* v,
                                String& name,
                                int64_t extract_type,
                                const String& prefix) {
  switch (extract_type) {
  case EXTR_SKIP:
    if (v->lookup(name.get()) != nullptr) {
      return false;
    }
    break;
  case EXTR_IF_EXISTS:
    if (v->lookup(name.get()) == nullptr) {
      return false;
    } else {
      goto namechecks;
    }
    break;
  case EXTR_PREFIX_SAME:
    if (v->lookup(name.get()) != nullptr) {
      name = prefix + "_" + name;
    } else {
      goto namechecks;
    }
    break;
  case EXTR_PREFIX_ALL:
    name = prefix + "_" + name;
    break;
  case EXTR_PREFIX_INVALID:
    if (!is_valid_var_name(name.get()->data(), name.size())) {
      name = prefix + "_" + name;
    } else {
      goto namechecks;
    }
    break;
  case EXTR_PREFIX_IF_EXISTS:
    if (v->lookup(name.get()) == nullptr) {
      return false;
    }
    name = prefix + "_" + name;
    break;
  case EXTR_OVERWRITE:
    namechecks:
    if (name == s_GLOBALS) {
      return false;
    }
    if (name == s_this) {
      // Only disallow $this when inside a non-static method, or a static method
      // that has defined $this (matches Zend)
      auto const func = arGetContextFunc(GetCallerFrame());

      if (func && func->isMethod() && v->lookup(s_this.get()) != nullptr) {
        return false;
      }
    }
  default:
    break;
  }

  // skip invalid variable names, as in PHP
  return is_valid_var_name(name.get()->data(), name.size());
}

ALWAYS_INLINE static
int64_t extract_impl(VRefParam vref_array,
                     int extract_type /* = EXTR_OVERWRITE */,
                     const String& prefix /* = "" */) {
  auto arrByRef = false;
  auto arr_tv = vref_array.wrapped().asTypedValue();
  if (arr_tv->m_type == KindOfRef) {
    arr_tv = arr_tv->m_data.pref->tv();
    arrByRef = true;
  }
  if (!isArrayType(arr_tv->m_type)) {
    raise_warning("extract() expects parameter 1 to be array");
    return 0;
  }

  bool reference = extract_type & EXTR_REFS;
  extract_type &= ~EXTR_REFS;

  VMRegAnchor _;
  auto const varEnv = g_context->getOrCreateVarEnv();
  if (!varEnv) return 0;

  auto& carr = tvAsCVarRef(arr_tv).asCArrRef();
  if (UNLIKELY(reference)) {
    auto extr_refs = [&](Array& arr) {
      if (arr.size() > 0) {
        // force arr to escalate (if necessary) by getting an lvalue to the
        // first element.
        ArrayData* ad = arr.get();
        auto const& first_key = ad->getKey(ad->iter_begin());
        arr.lvalAt(first_key);
      }
      int count = 0;
      for (ArrayIter iter(arr); iter; ++iter) {
        auto name = iter.first().toString();
        if (!modify_extract_name(varEnv, name, extract_type, prefix)) continue;
        // The const_cast is safe because we escalated the array.  We can't use
        // arr.lvalAt(name), because arr may have been modified as a side
        // effect of an earlier iteration.
        auto& ref = const_cast<Variant&>(iter.secondRef());
        g_context->bindVar(name.get(), ref.asTypedValue());
        ++count;
      }
      return count;
    };

    if (arrByRef) {
      return extr_refs(tvAsVariant(vref_array.getRefData()->tv()).asArrRef());
    }
    Array tmp = carr;
    return extr_refs(tmp);
  }

  int count = 0;
  for (ArrayIter iter(carr); iter; ++iter) {
    auto name = iter.first().toString();
    if (!modify_extract_name(varEnv, name, extract_type, prefix)) continue;
    g_context->setVar(name.get(), iter.secondRef().asTypedValue());
    ++count;
  }
  return count;
}

int64_t HHVM_FUNCTION(extract, VRefParam vref_array,
                      int64_t extract_type /* = EXTR_OVERWRITE */,
                      const String& prefix /* = "" */) {
  raise_disallowed_dynamic_call("extract should not be called dynamically");
  return extract_impl(vref_array, extract_type, prefix);
}

int64_t HHVM_FUNCTION(SystemLib_extract,
                      VRefParam vref_array,
                      int64_t extract_type = EXTR_OVERWRITE,
                      const String& prefix = "") {
  return extract_impl(vref_array, extract_type, prefix);
}

static void parse_str_impl(const String& str, VRefParam arr) {
  Array result = Array::Create();
  HttpProtocol::DecodeParameters(result, str.data(), str.size());
  if (!arr.isReferenced()) {
    HHVM_FN(SystemLib_extract)(result);
    return;
  }
  arr.assignIfRef(result);
}

void HHVM_FUNCTION(parse_str,
                   const String& str,
                   VRefParam arr /* = null */) {
  raise_disallowed_dynamic_call("parse_str should not be called dynamically");
  parse_str_impl(str, arr);
}

void HHVM_FUNCTION(SystemLib_parse_str,
                   const String& str,
                   VRefParam arr /* = null */) {
  parse_str_impl(str, arr);
}

/////////////////////////////////////////////////////////////////////////////

void StandardExtension::initVariable() {
  HHVM_RC_INT_SAME(EXTR_IF_EXISTS);
  HHVM_RC_INT_SAME(EXTR_OVERWRITE);
  HHVM_RC_INT_SAME(EXTR_PREFIX_ALL);
  HHVM_RC_INT_SAME(EXTR_PREFIX_IF_EXISTS);
  HHVM_RC_INT_SAME(EXTR_PREFIX_INVALID);
  HHVM_RC_INT_SAME(EXTR_PREFIX_SAME);
  HHVM_RC_INT_SAME(EXTR_REFS);
  HHVM_RC_INT_SAME(EXTR_SKIP);

  HHVM_FE(is_null);
  HHVM_FE(is_bool);
  HHVM_FE(is_int);
  HHVM_FALIAS(is_integer, is_int);
  HHVM_FALIAS(is_long, is_int);
  HHVM_FE(is_float);
  HHVM_FALIAS(is_double, is_float);
  HHVM_FALIAS(is_real, is_float);
  HHVM_FE(is_numeric);
  HHVM_FE(is_string);
  HHVM_FE(is_scalar);
  HHVM_FE(is_array);
  HHVM_FALIAS(HH\\is_vec, HH_is_vec);
  HHVM_FALIAS(HH\\is_dict, HH_is_dict);
  HHVM_FALIAS(HH\\is_keyset, HH_is_keyset);
  HHVM_FE(is_object);
  HHVM_FE(is_resource);
  HHVM_FE(boolval);
  HHVM_FE(intval);
  HHVM_FE(floatval);
  HHVM_FALIAS(doubleval, floatval);
  HHVM_FE(strval);
  HHVM_FE(gettype);
  HHVM_FE(get_resource_type);
  HHVM_FE(settype);
  HHVM_FE(print_r);
  HHVM_FE(var_export);
  HHVM_FE(debug_zval_dump);
  HHVM_FE(var_dump);
  HHVM_FE(serialize);
  HHVM_FE(unserialize);
  HHVM_FE(get_defined_vars);
  HHVM_FALIAS(__SystemLib\\get_defined_vars, SystemLib_get_defined_vars);
  HHVM_FE(extract);
  HHVM_FE(parse_str);
  HHVM_FALIAS(__SystemLib\\extract, SystemLib_extract);
  HHVM_FALIAS(__SystemLib\\parse_str, SystemLib_parse_str);

  loadSystemlib("std_variable");
}

///////////////////////////////////////////////////////////////////////////////
} // namespace HPHP
Esempio n. 8
0
namespace HPHP {

///////////////////////////////////////////////////////////////////////////////
// json_encode() options
const int64_t k_JSON_HEX_TAG                 = 1<<0;
const int64_t k_JSON_HEX_AMP                 = 1<<1;
const int64_t k_JSON_HEX_APOS                = 1<<2;
const int64_t k_JSON_HEX_QUOT                = 1<<3;
const int64_t k_JSON_FORCE_OBJECT            = 1<<4;
const int64_t k_JSON_NUMERIC_CHECK           = 1<<5;
const int64_t k_JSON_UNESCAPED_SLASHES       = 1<<6;
const int64_t k_JSON_PRETTY_PRINT            = 1<<7;
const int64_t k_JSON_UNESCAPED_UNICODE       = 1<<8;
const int64_t k_JSON_PARTIAL_OUTPUT_ON_ERROR = 1<<9;

// json_decode() options
const int64_t k_JSON_BIGINT_AS_STRING  = 1<<0;

// FB json_decode() options
// intentionally higher so when PHP adds more options we're fine
const int64_t k_JSON_FB_LOOSE          = 1<<20;
const int64_t k_JSON_FB_UNLIMITED      = 1<<21;
const int64_t k_JSON_FB_EXTRA_ESCAPES  = 1<<22;
const int64_t k_JSON_FB_COLLECTIONS    = 1<<23;
const int64_t k_JSON_FB_STABLE_MAPS    = 1<<24;

const int64_t k_JSON_ERROR_NONE
  = json_error_codes::JSON_ERROR_NONE;
const int64_t k_JSON_ERROR_DEPTH
  = json_error_codes::JSON_ERROR_DEPTH;
const int64_t k_JSON_ERROR_STATE_MISMATCH
  = json_error_codes::JSON_ERROR_STATE_MISMATCH;
const int64_t k_JSON_ERROR_CTRL_CHAR
  = json_error_codes::JSON_ERROR_CTRL_CHAR;
const int64_t k_JSON_ERROR_SYNTAX
  = json_error_codes::JSON_ERROR_SYNTAX;
const int64_t k_JSON_ERROR_UTF8
  = json_error_codes::JSON_ERROR_UTF8;
const int64_t k_JSON_ERROR_RECURSION
  = json_error_codes::JSON_ERROR_RECURSION;
const int64_t k_JSON_ERROR_INF_OR_NAN
  = json_error_codes::JSON_ERROR_INF_OR_NAN;
const int64_t k_JSON_ERROR_UNSUPPORTED_TYPE
  = json_error_codes::JSON_ERROR_UNSUPPORTED_TYPE;

///////////////////////////////////////////////////////////////////////////////
int64_t HHVM_FUNCTION(json_last_error) {
  return (int) json_get_last_error_code();
}

String HHVM_FUNCTION(json_last_error_msg) {
  return json_get_last_error_msg();
}

Variant HHVM_FUNCTION(json_encode, const Variant& value,
                                   int64_t options /* = 0 */,
                                   int64_t depth /* = 512 */) {
  // Special case for resource since VariableSerializer does not take care of it
  if (value.isResource()) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_UNSUPPORTED_TYPE);

    if (options & k_JSON_PARTIAL_OUTPUT_ON_ERROR) {
      return "null";
    }

    return false;
  }

  json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
  VariableSerializer vs(VariableSerializer::Type::JSON, options);
  vs.setDepthLimit(depth);

  String json = vs.serializeValue(value, !(options & k_JSON_FB_UNLIMITED));

  if ((json_get_last_error_code() != json_error_codes::JSON_ERROR_NONE) &&
      !(options & k_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
    return false;
  }

  return json;
}

Variant HHVM_FUNCTION(json_decode, const String& json, bool assoc /* = false */,
                      int64_t depth /* = 512 */, int64_t options /* = 0 */) {

  json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);

  if (json.empty()) {
    return init_null();
  }

  const int64_t supported_options =
    k_JSON_FB_LOOSE |
    k_JSON_FB_COLLECTIONS |
    k_JSON_FB_STABLE_MAPS |
    k_JSON_BIGINT_AS_STRING;
  int64_t parser_options = options & supported_options;
  Variant z;
  if (JSON_parser(z, json.data(), json.size(), assoc, depth, parser_options)) {
    return z;
  }

  String trimmed = f_trim(json, "\t\n\r ");

  if (trimmed.size() == 4) {
    if (!strcasecmp(trimmed.data(), "null")) {
      json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
      return init_null();
    }
    if (!strcasecmp(trimmed.data(), "true")) {
      json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
      return true;
    }
  } else if (trimmed.size() == 5 && !strcasecmp(trimmed.data(), "false")) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return false;
  }

  int64_t p;
  double d;
  DataType type = json.get()->isNumericWithVal(p, d, 0);
  if (type == KindOfInt64) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return p;
  } else if (type == KindOfDouble) {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    if ((options & k_JSON_BIGINT_AS_STRING) &&
        (json.toInt64() == LLONG_MAX || json.toInt64() == LLONG_MIN)
        && errno == ERANGE) { // Overflow
      bool is_float = false;
      for (int i = (trimmed[0] == '-' ? 1 : 0); i < trimmed.size(); ++i) {
        if (trimmed[i] < '0' || trimmed[i] > '9') {
          is_float = true;
          break;
        }
      }
      if (!is_float) {
        return trimmed;
      }
    }
    return d;
  }

  char ch0 = json.charAt(0);
  if (json.size() > 1 && ch0 == '"' && json.charAt(json.size() - 1) == '"') {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);

    // Wrap the string in an array to allow the JSON_parser to handle
    // things like unicode escape sequences, then unwrap to get result
    String wrapped("[");
    wrapped += json + "]";
    // Stick to a normal hhvm array for the wrapper
    const int64_t mask = ~(k_JSON_FB_COLLECTIONS | k_JSON_FB_STABLE_MAPS);
    if (JSON_parser(z, wrapped.data(), wrapped.size(), false, depth,
                    parser_options & mask) && z.isArray()) {
      Array arr = z.toArray();
      if ((arr.size() == 1) && arr.exists(0)) {
        return arr[0];
      }
      // The input string could be something like: "foo","bar"
      // Which will parse inside the [] wrapper, but be invalid
      json_set_last_error_code(json_error_codes::JSON_ERROR_SYNTAX);
    }
  }

  if ((options & k_JSON_FB_LOOSE) && json.size() > 1 &&
      ch0 == '\'' && json.charAt(json.size() - 1) == '\'') {
    json_set_last_error_code(json_error_codes::JSON_ERROR_NONE);
    return json.substr(1, json.size() - 2);
  }

  assert(json_get_last_error_code() != json_error_codes::JSON_ERROR_NONE);
  return init_null();
}

///////////////////////////////////////////////////////////////////////////////

const StaticString
  s_JSON_HEX_TAG("JSON_HEX_TAG"),
  s_JSON_HEX_AMP("JSON_HEX_AMP"),
  s_JSON_HEX_APOS("JSON_HEX_APOS"),
  s_JSON_HEX_QUOT("JSON_HEX_QUOT"),
  s_JSON_FORCE_OBJECT("JSON_FORCE_OBJECT"),
  s_JSON_NUMERIC_CHECK("JSON_NUMERIC_CHECK"),
  s_JSON_UNESCAPED_SLASHES("JSON_UNESCAPED_SLASHES"),
  s_JSON_PRETTY_PRINT("JSON_PRETTY_PRINT"),
  s_JSON_UNESCAPED_UNICODE("JSON_UNESCAPED_UNICODE"),
  s_JSON_PARTIAL_OUTPUT_ON_ERROR("JSON_PARTIAL_OUTPUT_ON_ERROR"),
  s_JSON_BIGINT_AS_STRING("JSON_BIGINT_AS_STRING"),
  s_JSON_FB_LOOSE("JSON_FB_LOOSE"),
  s_JSON_FB_UNLIMITED("JSON_FB_UNLIMITED"),
  s_JSON_FB_EXTRA_ESCAPES("JSON_FB_EXTRA_ESCAPES"),
  s_JSON_FB_COLLECTIONS("JSON_FB_COLLECTIONS"),
  s_JSON_FB_STABLE_MAPS("JSON_FB_STABLE_MAPS"),
  s_JSON_ERROR_NONE("JSON_ERROR_NONE"),
  s_JSON_ERROR_DEPTH("JSON_ERROR_DEPTH"),
  s_JSON_ERROR_STATE_MISMATCH("JSON_ERROR_STATE_MISMATCH"),
  s_JSON_ERROR_CTRL_CHAR("JSON_ERROR_CTRL_CHAR"),
  s_JSON_ERROR_SYNTAX("JSON_ERROR_SYNTAX"),
  s_JSON_ERROR_UTF8("JSON_ERROR_UTF8"),
  s_JSON_ERROR_RECURSION("JSON_ERROR_RECURSION"),
  s_JSON_ERROR_INF_OR_NAN("JSON_ERROR_INF_OR_NAN"),
  s_JSON_ERROR_UNSUPPORTED_TYPE("JSON_ERROR_UNSUPPORTED_TYPE");

class JsonExtension : public Extension {
 public:
  JsonExtension() : Extension("json", "1.2.1") {}
  virtual void moduleInit() {
    Native::registerConstant<KindOfInt64>(
      s_JSON_HEX_TAG.get(), k_JSON_HEX_TAG
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_HEX_AMP.get(), k_JSON_HEX_AMP
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_HEX_APOS.get(), k_JSON_HEX_APOS
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_HEX_QUOT.get(), k_JSON_HEX_QUOT
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FORCE_OBJECT.get(), k_JSON_FORCE_OBJECT
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_NUMERIC_CHECK.get(), k_JSON_NUMERIC_CHECK
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_UNESCAPED_SLASHES.get(), k_JSON_UNESCAPED_SLASHES
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_PRETTY_PRINT.get(), k_JSON_PRETTY_PRINT
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_UNESCAPED_UNICODE.get(), k_JSON_UNESCAPED_UNICODE
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_PARTIAL_OUTPUT_ON_ERROR.get(), k_JSON_PARTIAL_OUTPUT_ON_ERROR
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_BIGINT_AS_STRING.get(), k_JSON_BIGINT_AS_STRING
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FB_LOOSE.get(), k_JSON_FB_LOOSE
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FB_UNLIMITED.get(), k_JSON_FB_UNLIMITED
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FB_EXTRA_ESCAPES.get(), k_JSON_FB_EXTRA_ESCAPES
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FB_COLLECTIONS.get(), k_JSON_FB_COLLECTIONS
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FB_STABLE_MAPS.get(), k_JSON_FB_STABLE_MAPS
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_NONE.get(), k_JSON_ERROR_NONE
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_DEPTH.get(), k_JSON_ERROR_DEPTH
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_STATE_MISMATCH.get(), k_JSON_ERROR_STATE_MISMATCH
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_CTRL_CHAR.get(), k_JSON_ERROR_CTRL_CHAR
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_SYNTAX.get(), k_JSON_ERROR_SYNTAX
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_UTF8.get(), k_JSON_ERROR_UTF8
    );
  Native::registerConstant<KindOfInt64>(
    s_JSON_ERROR_RECURSION.get(), k_JSON_ERROR_RECURSION
  );
  Native::registerConstant<KindOfInt64>(
    s_JSON_ERROR_INF_OR_NAN.get(), k_JSON_ERROR_INF_OR_NAN
  );
  Native::registerConstant<KindOfInt64>(
    s_JSON_ERROR_UNSUPPORTED_TYPE.get(), k_JSON_ERROR_UNSUPPORTED_TYPE
  );

    HHVM_FE(json_last_error);
    HHVM_FE(json_last_error_msg);
    HHVM_FE(json_encode);
    HHVM_FE(json_decode);

    loadSystemlib();
  }
} s_json_extension;

}
Esempio n. 9
0
  virtual void moduleInit() {
    Native::registerConstant<KindOfInt64>(
      s_JSON_HEX_TAG.get(), k_JSON_HEX_TAG
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_HEX_AMP.get(), k_JSON_HEX_AMP
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_HEX_APOS.get(), k_JSON_HEX_APOS
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_HEX_QUOT.get(), k_JSON_HEX_QUOT
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FORCE_OBJECT.get(), k_JSON_FORCE_OBJECT
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_NUMERIC_CHECK.get(), k_JSON_NUMERIC_CHECK
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_UNESCAPED_SLASHES.get(), k_JSON_UNESCAPED_SLASHES
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_PRETTY_PRINT.get(), k_JSON_PRETTY_PRINT
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_UNESCAPED_UNICODE.get(), k_JSON_UNESCAPED_UNICODE
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_PARTIAL_OUTPUT_ON_ERROR.get(), k_JSON_PARTIAL_OUTPUT_ON_ERROR
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_BIGINT_AS_STRING.get(), k_JSON_BIGINT_AS_STRING
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FB_LOOSE.get(), k_JSON_FB_LOOSE
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FB_UNLIMITED.get(), k_JSON_FB_UNLIMITED
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FB_EXTRA_ESCAPES.get(), k_JSON_FB_EXTRA_ESCAPES
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FB_COLLECTIONS.get(), k_JSON_FB_COLLECTIONS
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_FB_STABLE_MAPS.get(), k_JSON_FB_STABLE_MAPS
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_NONE.get(), k_JSON_ERROR_NONE
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_DEPTH.get(), k_JSON_ERROR_DEPTH
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_STATE_MISMATCH.get(), k_JSON_ERROR_STATE_MISMATCH
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_CTRL_CHAR.get(), k_JSON_ERROR_CTRL_CHAR
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_SYNTAX.get(), k_JSON_ERROR_SYNTAX
    );
    Native::registerConstant<KindOfInt64>(
      s_JSON_ERROR_UTF8.get(), k_JSON_ERROR_UTF8
    );
  Native::registerConstant<KindOfInt64>(
    s_JSON_ERROR_RECURSION.get(), k_JSON_ERROR_RECURSION
  );
  Native::registerConstant<KindOfInt64>(
    s_JSON_ERROR_INF_OR_NAN.get(), k_JSON_ERROR_INF_OR_NAN
  );
  Native::registerConstant<KindOfInt64>(
    s_JSON_ERROR_UNSUPPORTED_TYPE.get(), k_JSON_ERROR_UNSUPPORTED_TYPE
  );

    HHVM_FE(json_last_error);
    HHVM_FE(json_last_error_msg);
    HHVM_FE(json_encode);
    HHVM_FE(json_decode);

    loadSystemlib();
  }
Esempio n. 10
0
namespace HPHP {

StaticString s_call("__call");

UserFSNode::UserFSNode(Class* cls, const Variant& context /*= null */) {
  JIT::VMRegAnchor _;
  const Func* ctor;
  m_cls = cls;
  if (LookupResult::MethodFoundWithThis !=
      g_context->lookupCtorMethod(ctor, m_cls)) {
    throw InvalidArgumentException(0, "Unable to call %s's constructor",
                                   m_cls->name()->data());
  }

  m_obj = ObjectData::newInstance(m_cls);
  m_obj.o_set("context", context);
  Variant ret;
  g_context->invokeFuncFew(ret.asTypedValue(), ctor, m_obj.get());

  m_Call = lookupMethod(s_call.get());
}

Variant UserFSNode::invoke(const Func* func, const String& name,
                           const Array& args, bool& invoked) {
  JIT::VMRegAnchor _;

  // Assume failure
  invoked = false;

  // Public method, no private ancestor, no need for further checks (common)
  if (func &&
      !(func->attrs() & (AttrPrivate|AttrProtected|AttrAbstract)) &&
      !func->hasPrivateAncestor()) {
    Variant ret;
    g_context->invokeFunc(ret.asTypedValue(), func, args, m_obj.get());
    invoked = true;
    return ret;
  }

  // No explicitly defined function, no __call() magic method
  // Give up.
  if (!func && !m_Call) {
    return uninit_null();
  }

  HPHP::JIT::CallerFrame cf;
  Class* ctx = arGetContextClass(cf());
  switch(g_context->lookupObjMethod(func, m_cls, name.get(), ctx)) {
    case LookupResult::MethodFoundWithThis:
    {
      Variant ret;
      g_context->invokeFunc(ret.asTypedValue(), func, args, m_obj.get());
      invoked = true;
      return ret;
    }

    case LookupResult::MagicCallFound:
    {
      Variant ret;
      g_context->invokeFunc(ret.asTypedValue(), func,
                              make_packed_array(name, args), m_obj.get());
      invoked = true;
      return ret;
    }

    case LookupResult::MethodNotFound:
      // There's a method somewhere in the hierarchy, but none
      // which are accessible.
      /* fallthrough */
    case LookupResult::MagicCallStaticFound:
      // We're not calling statically, so this result is unhelpful
      // Also, it's never produced by lookupObjMethod, so it'll
      // never happen, but we must handle all enums
      return uninit_null();

    case LookupResult::MethodFoundNoThis:
      // Should never happen (Attr::Static check in ctor)
      assert(false);
      raise_error("%s::%s() must not be declared static",
                  m_cls->name()->data(), name.data());
      return uninit_null();
  }

  NOT_REACHED();
  return uninit_null();
}

const Func* UserFSNode::lookupMethod(const StringData* name) {
  const Func* f = m_cls->lookupMethod(name);
  if (!f) return nullptr;

  if (f->attrs() & AttrStatic) {
    throw InvalidArgumentException(0, "%s::%s() must not be declared static",
                                   m_cls->name()->data(), name->data());
  }
  return f;
}

}
Esempio n. 11
0
void
DeviceListWidget::OnPaintItem(Canvas &canvas, const PixelRect rc, unsigned idx)
{
  assert(idx < NUMDEV);

  const DeviceConfig &config =
    CommonInterface::SetSystemSettings().devices[idx];
  const Flags flags(*items[idx]);

  const UPixelScalar margin = Layout::GetTextPadding();

  TCHAR port_name_buffer[128];
  const TCHAR *port_name =
    config.GetPortName(port_name_buffer, ARRAY_SIZE(port_name_buffer));

  StaticString<256> text(_T("A: "));
  text[0u] += idx;

  if (config.UsesDriver()) {
    const TCHAR *driver_name = FindDriverDisplayName(config.driver_name);

    text.AppendFormat(_("%s on %s"), driver_name, port_name);
  } else {
    text.append(port_name);
  }

  canvas.Select(*look.list.font);
  canvas.DrawText(rc.left + margin, rc.top + margin, text);

  /* show a list of features that are available in the second row */

  StaticString<256> buffer;
  const TCHAR *status;
  if (flags.alive) {
    if (flags.location) {
      buffer = _("GPS fix");
    } else if (flags.gps) {
      /* device sends GPGGA, but no valid location */
      buffer = _("Bad GPS");
    } else {
      buffer = _("Connected");
    }

    if (flags.baro) {
      buffer.append(_T("; "));
      buffer.append(_("Baro"));
    }

    if (flags.airspeed) {
      buffer.append(_T("; "));
      buffer.append(_("Airspeed"));
    }

    if (flags.vario) {
      buffer.append(_T("; "));
      buffer.append(_("Vario"));
    }

    if (flags.traffic)
      buffer.append(_T("; FLARM"));

    status = buffer;
  } else if (config.IsDisabled()) {
    status = _("Disabled");
  } else if (is_simulator() || !config.IsAvailable()) {
    status = _("N/A");
  } else if (flags.open) {
    status = _("No data");
#ifdef ANDROID
  } else if ((config.port_type == DeviceConfig::PortType::RFCOMM ||
              config.port_type == DeviceConfig::PortType::RFCOMM_SERVER) &&
             !BluetoothHelper::isEnabled(Java::GetEnv())) {
    status = _("Bluetooth is disabled");
#endif
  } else if (flags.error) {
    status = _("Error");
  } else {
    status = _("Not connected");
  }

  canvas.Select(*look.small_font);
  canvas.DrawText(rc.left + margin, rc.top + 2 * margin + font_height,
                  status);
}
Esempio n. 12
0
 void Clear() {
   bssid.clear();
   ssid.clear();
 }
Esempio n. 13
0
 void ClearName() {
   name.clear();
 }
Esempio n. 14
0
namespace HPHP {

IMPLEMENT_THREAD_LOCAL(std::string, s_misc_highlight_default_string);
IMPLEMENT_THREAD_LOCAL(std::string, s_misc_highlight_default_comment);
IMPLEMENT_THREAD_LOCAL(std::string, s_misc_highlight_default_keyword);
IMPLEMENT_THREAD_LOCAL(std::string, s_misc_highlight_default_default);
IMPLEMENT_THREAD_LOCAL(std::string, s_misc_highlight_default_html);
IMPLEMENT_THREAD_LOCAL(std::string, s_misc_display_errors);

const std::string s_1("1"), s_2("2"), s_stdout("stdout"), s_stderr("stderr");
const double k_INF = std::numeric_limits<double>::infinity();
const double k_NAN = std::numeric_limits<double>::quiet_NaN();

static String HHVM_FUNCTION(server_warmup_status) {
  // Fail if we jitted more than 25kb of code.
  size_t begin, end;
  jit::mcg->codeEmittedThisRequest(begin, end);
  auto const diff = end - begin;
  auto constexpr kMaxTCBytes = 25 << 10;
  if (diff > kMaxTCBytes) {
    return folly::format("Translation cache grew by {} bytes to {} bytes.",
                         diff, begin).str();
  }

  // Fail if we spent more than 0.5ms in the JIT.
  auto const jittime = jit::Timer::CounterValue(jit::Timer::translate);
  auto constexpr kMaxJitTimeNS = 500000;
  if (jittime.total > kMaxJitTimeNS) {
    return folly::format("Spent {}us in the JIT.", jittime.total / 1000).str();
  }

  if (!isStandardRequest()) {
    return "Warmup is still in progress.";
  }

  if (requestCount() <= RuntimeOption::EvalJitProfileRequests) {
    return "PGO profiling translations are still enabled.";
  }

  auto tpc_diff = jit::s_perfCounters[jit::tpc_interp_bb] -
    jit::s_perfCounters[jit::tpc_interp_bb_force];
  if (tpc_diff) {
    return folly::sformat("Interpreted {} non-forced basic blocks.", tpc_diff);
  }

  return empty_string();
}


void StandardExtension::threadInitMisc() {
    IniSetting::Bind(
      this, IniSetting::PHP_INI_ALL,
      "highlight.string", "#DD0000",
      s_misc_highlight_default_string.get()
    );
    IniSetting::Bind(
      this, IniSetting::PHP_INI_ALL,
      "highlight.comment", "#FF8000",
      s_misc_highlight_default_comment.get()
    );
    IniSetting::Bind(
      this, IniSetting::PHP_INI_ALL,
      "highlight.keyword", "#007700",
      s_misc_highlight_default_keyword.get()
    );
    IniSetting::Bind(
      this, IniSetting::PHP_INI_ALL,
      "highlight.default", "#0000BB",
      s_misc_highlight_default_default.get()
    );
    IniSetting::Bind(
      this, IniSetting::PHP_INI_ALL,
      "highlight.html", "#000000",
      s_misc_highlight_default_html.get()
    );
    IniSetting::Bind(
      this, IniSetting::PHP_INI_ALL,
      "display_errors", RuntimeOption::EnableHipHopSyntax ? "stderr" : "1",
      IniSetting::SetAndGet<std::string>(
        [](const std::string& value) {
          if (value == s_1 || value == s_stdout) {
            Logger::SetStandardOut(stdout);
            return true;
          }
          if (value == s_2 || value == s_stderr) {
            Logger::SetStandardOut(stderr);
            return true;
          }
          return false;
        },
        nullptr
      ),
      s_misc_display_errors.get()
    );
  }

static void bindTokenConstants();
static int get_user_token_id(int internal_id);
const StaticString s_T_PAAMAYIM_NEKUDOTAYIM("T_PAAMAYIM_NEKUDOTAYIM");

#define PHP_MAJOR_VERSION 5
#define PHP_MINOR_VERSION 6
#define PHP_RELEASE_VERSION 99
#define PHP_EXTRA_VERSION "hhvm"
#define PHP_VERSION "5.6.99-hhvm"
#define PHP_VERSION_ID 50699

const StaticString k_PHP_VERSION(PHP_VERSION);

void StandardExtension::initMisc() {
    HHVM_FALIAS(HH\\server_warmup_status, server_warmup_status);
    HHVM_FE(connection_aborted);
    HHVM_FE(connection_status);
    HHVM_FE(connection_timeout);
    HHVM_FE(constant);
    HHVM_FE(define);
    HHVM_FE(defined);
    HHVM_FE(ignore_user_abort);
    HHVM_FE(pack);
    HHVM_FE(sleep);
    HHVM_FE(usleep);
    HHVM_FE(time_nanosleep);
    HHVM_FE(time_sleep_until);
    HHVM_FE(uniqid);
    HHVM_FE(unpack);
    HHVM_FE(sys_getloadavg);
    HHVM_FE(token_get_all);
    HHVM_FE(token_name);
    HHVM_FE(hphp_to_string);
    HHVM_FALIAS(__SystemLib\\max2, SystemLib_max2);
    HHVM_FALIAS(__SystemLib\\min2, SystemLib_min2);
    Native::registerConstant<KindOfDouble>(makeStaticString("INF"), k_INF);
    Native::registerConstant<KindOfDouble>(makeStaticString("NAN"), k_NAN);
    Native::registerConstant<KindOfInt64>(
        makeStaticString("PHP_MAXPATHLEN"), MAXPATHLEN);
    Native::registerConstant<KindOfBoolean>(makeStaticString("PHP_DEBUG"),
      #if DEBUG
        true
      #else
        false
      #endif
     );
    bindTokenConstants();
    Native::registerConstant<KindOfInt64>(s_T_PAAMAYIM_NEKUDOTAYIM.get(),
                                          get_user_token_id(T_DOUBLE_COLON));

    HHVM_RC_STR(PHP_BINARY, current_executable_path());
    HHVM_RC_STR(PHP_BINDIR, current_executable_directory());
    HHVM_RC_STR(PHP_OS, HHVM_FN(php_uname)("s").toString().toCppString());
    HHVM_RC_STR(PHP_SAPI, RuntimeOption::ExecutionMode);

    HHVM_RC_INT(PHP_INT_SIZE, sizeof(int64_t));
    HHVM_RC_INT(PHP_INT_MIN, k_PHP_INT_MIN);
    HHVM_RC_INT(PHP_INT_MAX, k_PHP_INT_MAX);

    HHVM_RC_INT_SAME(PHP_MAJOR_VERSION);
    HHVM_RC_INT_SAME(PHP_MINOR_VERSION);
    HHVM_RC_INT_SAME(PHP_RELEASE_VERSION);
    HHVM_RC_STR_SAME(PHP_EXTRA_VERSION);
    HHVM_RC_STR_SAME(PHP_VERSION);
    HHVM_RC_INT_SAME(PHP_VERSION_ID);

    // FIXME: These values are hardcoded from their previous IDL values
    // Grab their correct values from the system as appropriate
    HHVM_RC_STR(PHP_EOL, "\n");
    HHVM_RC_STR(PHP_CONFIG_FILE_PATH, "");
    HHVM_RC_STR(PHP_CONFIG_FILE_SCAN_DIR, "");
    HHVM_RC_STR(PHP_DATADIR, "");
    HHVM_RC_STR(PHP_EXTENSION_DIR, "");
    HHVM_RC_STR(PHP_LIBDIR, "");
    HHVM_RC_STR(PHP_LOCALSTATEDIR, "");
    HHVM_RC_STR(PHP_PREFIX, "");
    HHVM_RC_STR(PHP_SHLIB_SUFFIX, "so");
    HHVM_RC_STR(PHP_SYSCONFDIR, "");
    HHVM_RC_STR(PEAR_EXTENSION_DIR, "");
    HHVM_RC_STR(PEAR_INSTALL_DIR, "");

    loadSystemlib("std_misc");
  }

// Make sure "tokenizer" gets added to the list of extensions
IMPLEMENT_DEFAULT_EXTENSION_VERSION(tokenizer, 0.1);


///////////////////////////////////////////////////////////////////////////////

int64_t HHVM_FUNCTION(connection_aborted) {
  return HHVM_FN(connection_status)() == k_CONNECTION_ABORTED;
}

int64_t HHVM_FUNCTION(connection_status) {
  return k_CONNECTION_NORMAL;
}

int64_t HHVM_FUNCTION(connection_timeout) {
  return HHVM_FN(connection_status)() == k_CONNECTION_TIMEOUT;
}

static Class* getClassByName(const char* name, int len) {
  Class* cls = nullptr;
  // translate "self" or "parent"
  if (len == 4 && !memcmp(name, "self", 4)) {
    cls = g_context->getContextClass();
    if (!cls) {
      throw FatalErrorException("Cannot access self:: "
                                "when no class scope is active");
    }
  } else if (len == 6 && !memcmp(name, "parent", 6)) {
    cls = g_context->getParentContextClass();
    if (!cls) {
      throw FatalErrorException("Cannot access parent");
    }
  } else if (len == 6 && !memcmp(name, "static", 6)) {
    CallerFrame cf;
    auto ar = cf();
    if (ar) {
      if (ar->hasThis()) {
        cls = ar->getThis()->getVMClass();
      } else if (ar->hasClass()) {
        cls = ar->getClass();
      }
    }
    if (!cls) {
      throw FatalErrorException("Cannot access static:: "
                                "when no class scope is active");
    }
  } else {
    String className(name, len, CopyString);
    cls = Unit::loadClass(className.get());
  }
  return cls;
}

Variant HHVM_FUNCTION(constant, const String& name) {
  if (!name.get()) return init_null();
  const char *data = name.data();
  int len = name.length();

  char *colon;
  if ((colon = (char*)memchr(data, ':', len)) && colon[1] == ':') {
    // class constant
    int classNameLen = colon - data;
    char *constantName = colon + 2;
    Class* cls = getClassByName(data, classNameLen);
    if (cls) {
      String cnsName(constantName, data + len - constantName, CopyString);
      Cell cns = cls->clsCnsGet(cnsName.get());
      if (cns.m_type != KindOfUninit) {
        return cellAsCVarRef(cns);
      }
    }
  } else {
    auto const cns = Unit::loadCns(name.get());
    if (cns) return tvAsCVarRef(cns);
  }

  raise_warning("constant(): Couldn't find constant %s", data);
  return init_null();
}

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());
}

bool HHVM_FUNCTION(defined, const String& name, bool autoload /* = true */) {
  if (!name.get()) return false;
  const char *data = name.data();
  int len = name.length();

  char *colon;
  if ((colon = (char*)memchr(data, ':', len)) && colon[1] == ':') {
    // class constant
    int classNameLen = colon - data;
    char *constantName = colon + 2;
    Class* cls = getClassByName(data, classNameLen);
    if (cls) {
      String cnsName(constantName, data + len - constantName, CopyString);
      return cls->clsCnsGet(cnsName.get()).m_type != KindOfUninit;
    }
    return false;
  } else {
    auto* cb = autoload ? Unit::loadCns : Unit::lookupCns;
    return cb(name.get());
  }
}

int64_t HHVM_FUNCTION(ignore_user_abort, bool setting /* = false */) {
  return 0;
}

Variant HHVM_FUNCTION(pack, const String& format, const Array& argv) {
  // pack() returns false if there was an error, String otherwise
  return ZendPack().pack(format, argv);
}

int64_t HHVM_FUNCTION(sleep, int seconds) {
  IOStatusHelper io("sleep");
  Transport *transport = g_context->getTransport();
  if (transport) {
    transport->incSleepTime(seconds);
  }
  sleep(seconds);
  return 0;
}

void HHVM_FUNCTION(usleep, int micro_seconds) {
  IOStatusHelper io("usleep");
  Transport *transport = g_context->getTransport();
  if (transport) {
    transport->incuSleepTime(micro_seconds);
  }
  usleep(micro_seconds);
}

static void recordNanosleepTime(
  const struct timespec &req,
  const struct timespec *rem
) {
  Transport *transport = g_context->getTransport();
  if (transport) {
    int64_t req_s = req.tv_sec;
    int32_t req_n = req.tv_nsec;
    int64_t rem_s = 0;
    int32_t rem_n = 0;

    if (rem) {
      rem_s = rem->tv_sec;
      rem_n = rem->tv_nsec;
    }

    int32_t nanos = req_n - rem_n;
    int64_t seconds = req_s - rem_s;
    if (nanos < 0) {
      nanos += 1000000000;
      seconds--;
    }

    transport->incnSleepTime(seconds, nanos);
  }
}

const StaticString
  s_seconds("seconds"),
  s_nanoseconds("nanoseconds");

Variant HHVM_FUNCTION(time_nanosleep, int seconds, int nanoseconds) {
  if (seconds < 0) {
    throw_invalid_argument("seconds: cannot be negative");
    return false;
  }
  if (nanoseconds < 0 || nanoseconds > 999999999) {
    throw_invalid_argument("nanoseconds: has to be 0 to 999999999");
    return false;
  }

  struct timespec req, rem;
  req.tv_sec = (time_t)seconds;
  req.tv_nsec = nanoseconds;

  IOStatusHelper io("nanosleep");
  if (!nanosleep(&req, &rem)) {
    recordNanosleepTime(req, nullptr);
    return true;
  }

  recordNanosleepTime(req, &rem);
  if (errno == EINTR) {
    return make_map_array(s_seconds, (int64_t)rem.tv_sec,
                          s_nanoseconds, (int64_t)rem.tv_nsec);
  }
  return false;
}

bool HHVM_FUNCTION(time_sleep_until, double timestamp) {
  struct timeval tm;
  if (gettimeofday((struct timeval *)&tm, NULL) != 0) {
    return false;
  }

  double c_ts = (double)(timestamp - tm.tv_sec - tm.tv_usec / 1000000.0);
  if (c_ts < 0) {
    throw_invalid_argument
      ("timestamp: Sleep until to time is less than current time");
    return false;
  }

  struct timespec req, rem;
  req.tv_sec = (time_t)c_ts;
  req.tv_nsec = (long)((c_ts - req.tv_sec) * 1000000000.0);

  IOStatusHelper io("nanosleep");
  while (nanosleep(&req, &rem)) {
    recordNanosleepTime(req, &rem);
    if (errno != EINTR) return false;
    req.tv_sec = rem.tv_sec;
    req.tv_nsec = rem.tv_nsec;
  }
  recordNanosleepTime(req, nullptr);
  return true;
}

String HHVM_FUNCTION(uniqid, const String& prefix /* = null_string */,
                     bool more_entropy /* = false */) {
  if (!more_entropy) {
    Transport *transport = g_context->getTransport();
    if (transport) {
      transport->incuSleepTime(1);
    }
    usleep(1);
  }

  struct timeval tv;
  gettimeofday((struct timeval *)&tv, NULL);
  int sec = (int)tv.tv_sec;
  int usec = (int)(tv.tv_usec % 0x100000);

  String uniqid(prefix.size() + 64, ReserveString);
  auto ptr = uniqid.mutableData();
  // StringData::capacity() returns the buffer size without the null
  // terminator. snprintf expects a the buffer capacity including room
  // for the null terminator, writes the null termintor, and returns
  // the full length not counting the null terminator.
  auto capacity = uniqid.capacity() + 1;
  int64_t len;
  if (more_entropy) {
    len = snprintf(ptr, capacity, "%s%08x%05x%.8F",
                   prefix.c_str(), sec, usec, math_combined_lcg() * 10);
  } else {
    len = snprintf(ptr, capacity, "%s%08x%05x",
                   prefix.c_str(), sec, usec);
  }
  uniqid.setSize(len);
  return uniqid;
}

Variant HHVM_FUNCTION(unpack, const String& format, const String& data) {
  return ZendPack().unpack(format, data);
}

Array HHVM_FUNCTION(sys_getloadavg) {
#if (defined(__CYGWIN__) || defined(__MINGW__) || defined(_MSC_VER))
  return make_packed_array(0, 0, 0);
#else
  double load[3];
  getloadavg(load, 3);
  return make_packed_array(load[0], load[1], load[2]);
#endif
}

// We want token IDs to remain stable regardless of how we change the
// internals of the parser. Thus, we maintain a mapping from internal
// token IDs to stable "user token IDs" and only expose the user token
// IDs to the PHP application.

const int UserTokenId_T_REQUIRE_ONCE = 258;
const int UserTokenId_T_REQUIRE = 259;
const int UserTokenId_T_EVAL = 260;
const int UserTokenId_T_INCLUDE_ONCE = 261;
const int UserTokenId_T_INCLUDE = 262;
const int UserTokenId_T_LOGICAL_OR = 263;
const int UserTokenId_T_LOGICAL_XOR = 264;
const int UserTokenId_T_LOGICAL_AND = 265;
const int UserTokenId_T_PRINT = 266;
const int UserTokenId_T_SR_EQUAL = 267;
const int UserTokenId_T_SL_EQUAL = 268;
const int UserTokenId_T_XOR_EQUAL = 269;
const int UserTokenId_T_OR_EQUAL = 270;
const int UserTokenId_T_AND_EQUAL = 271;
const int UserTokenId_T_MOD_EQUAL = 272;
const int UserTokenId_T_CONCAT_EQUAL = 273;
const int UserTokenId_T_DIV_EQUAL = 274;
const int UserTokenId_T_MUL_EQUAL = 275;
const int UserTokenId_T_MINUS_EQUAL = 276;
const int UserTokenId_T_PLUS_EQUAL = 277;
const int UserTokenId_T_BOOLEAN_OR = 278;
const int UserTokenId_T_BOOLEAN_AND = 279;
const int UserTokenId_T_IS_NOT_IDENTICAL = 280;
const int UserTokenId_T_IS_IDENTICAL = 281;
const int UserTokenId_T_IS_NOT_EQUAL = 282;
const int UserTokenId_T_IS_EQUAL = 283;
const int UserTokenId_T_IS_GREATER_OR_EQUAL = 284;
const int UserTokenId_T_IS_SMALLER_OR_EQUAL = 285;
const int UserTokenId_T_SR = 286;
const int UserTokenId_T_SL = 287;
const int UserTokenId_T_INSTANCEOF = 288;
const int UserTokenId_T_UNSET_CAST = 289;
const int UserTokenId_T_BOOL_CAST = 290;
const int UserTokenId_T_OBJECT_CAST = 291;
const int UserTokenId_T_ARRAY_CAST = 292;
const int UserTokenId_T_STRING_CAST = 293;
const int UserTokenId_T_DOUBLE_CAST = 294;
const int UserTokenId_T_INT_CAST = 295;
const int UserTokenId_T_DEC = 296;
const int UserTokenId_T_INC = 297;
const int UserTokenId_T_CLONE = 298;
const int UserTokenId_T_NEW = 299;
const int UserTokenId_T_EXIT = 300;
const int UserTokenId_T_IF = 301;
const int UserTokenId_T_ELSEIF = 302;
const int UserTokenId_T_ELSE = 303;
const int UserTokenId_T_ENDIF = 304;
const int UserTokenId_T_LNUMBER = 305;
const int UserTokenId_T_DNUMBER = 306;
const int UserTokenId_T_STRING = 307;
const int UserTokenId_T_STRING_VARNAME = 308;
const int UserTokenId_T_VARIABLE = 309;
const int UserTokenId_T_NUM_STRING = 310;
const int UserTokenId_T_INLINE_HTML = 311;
const int UserTokenId_T_CHARACTER = 312;
const int UserTokenId_T_BAD_CHARACTER = 313;
const int UserTokenId_T_ENCAPSED_AND_WHITESPACE = 314;
const int UserTokenId_T_CONSTANT_ENCAPSED_STRING = 315;
const int UserTokenId_T_ECHO = 316;
const int UserTokenId_T_DO = 317;
const int UserTokenId_T_WHILE = 318;
const int UserTokenId_T_ENDWHILE = 319;
const int UserTokenId_T_FOR = 320;
const int UserTokenId_T_ENDFOR = 321;
const int UserTokenId_T_FOREACH = 322;
const int UserTokenId_T_ENDFOREACH = 323;
const int UserTokenId_T_DECLARE = 324;
const int UserTokenId_T_ENDDECLARE = 325;
const int UserTokenId_T_AS = 326;
const int UserTokenId_T_SWITCH = 327;
const int UserTokenId_T_ENDSWITCH = 328;
const int UserTokenId_T_CASE = 329;
const int UserTokenId_T_DEFAULT = 330;
const int UserTokenId_T_BREAK = 331;
const int UserTokenId_T_GOTO = 332;
const int UserTokenId_T_CONTINUE = 333;
const int UserTokenId_T_FUNCTION = 334;
const int UserTokenId_T_CONST = 335;
const int UserTokenId_T_RETURN = 336;
const int UserTokenId_T_TRY = 337;
const int UserTokenId_T_CATCH = 338;
const int UserTokenId_T_THROW = 339;
const int UserTokenId_T_USE = 340;
const int UserTokenId_T_GLOBAL = 341;
const int UserTokenId_T_PUBLIC = 342;
const int UserTokenId_T_PROTECTED = 343;
const int UserTokenId_T_PRIVATE = 344;
const int UserTokenId_T_FINAL = 345;
const int UserTokenId_T_ABSTRACT = 346;
const int UserTokenId_T_STATIC = 347;
const int UserTokenId_T_VAR = 348;
const int UserTokenId_T_UNSET = 349;
const int UserTokenId_T_ISSET = 350;
const int UserTokenId_T_EMPTY = 351;
const int UserTokenId_T_HALT_COMPILER = 352;
const int UserTokenId_T_CLASS = 353;
const int UserTokenId_T_INTERFACE = 354;
const int UserTokenId_T_EXTENDS = 355;
const int UserTokenId_T_IMPLEMENTS = 356;
const int UserTokenId_T_OBJECT_OPERATOR = 357;
const int UserTokenId_T_DOUBLE_ARROW = 358;
const int UserTokenId_T_LIST = 359;
const int UserTokenId_T_ARRAY = 360;
const int UserTokenId_T_CLASS_C = 361;
const int UserTokenId_T_METHOD_C = 362;
const int UserTokenId_T_FUNC_C = 363;
const int UserTokenId_T_LINE = 364;
const int UserTokenId_T_FILE = 365;
const int UserTokenId_T_COMMENT = 366;
const int UserTokenId_T_DOC_COMMENT = 367;
const int UserTokenId_T_OPEN_TAG = 368;
const int UserTokenId_T_OPEN_TAG_WITH_ECHO = 369;
const int UserTokenId_T_CLOSE_TAG = 370;
const int UserTokenId_T_WHITESPACE = 371;
const int UserTokenId_T_START_HEREDOC = 372;
const int UserTokenId_T_END_HEREDOC = 373;
const int UserTokenId_T_DOLLAR_OPEN_CURLY_BRACES = 374;
const int UserTokenId_T_CURLY_OPEN = 375;
const int UserTokenId_T_PAAMAYIM_NEKUDOTAYIM UNUSED = 376;
const int UserTokenId_T_NAMESPACE = 377;
const int UserTokenId_T_NS_C = 378;
const int UserTokenId_T_DIR = 379;
const int UserTokenId_T_NS_SEPARATOR = 380;
const int UserTokenId_T_YIELD = 381;
const int UserTokenId_T_XHP_LABEL = 382;
const int UserTokenId_T_XHP_TEXT = 383;
const int UserTokenId_T_XHP_ATTRIBUTE = 384;
const int UserTokenId_T_XHP_CATEGORY = 385;
const int UserTokenId_T_XHP_CATEGORY_LABEL = 386;
const int UserTokenId_T_XHP_CHILDREN = 387;
const int UserTokenId_T_ENUM = 388;
const int UserTokenId_T_XHP_REQUIRED = 389;
const int UserTokenId_T_TRAIT = 390;
const int UserTokenId_T_INSTEADOF = 391;
const int UserTokenId_T_TRAIT_C = 392;
const int UserTokenId_T_ELLIPSIS = 393;
const int UserTokenId_T_HH_ERROR = 394;
const int UserTokenId_T_FINALLY = 395;
const int UserTokenId_T_XHP_TAG_LT = 396;
const int UserTokenId_T_XHP_TAG_GT = 397;
const int UserTokenId_T_TYPELIST_LT = 398;
const int UserTokenId_T_TYPELIST_GT = 399;
const int UserTokenId_T_UNRESOLVED_LT = 400;
const int UserTokenId_T_COLLECTION = 401;
const int UserTokenId_T_SHAPE = 402;
const int UserTokenId_T_TYPE = 403;
const int UserTokenId_T_UNRESOLVED_TYPE = 404;
const int UserTokenId_T_NEWTYPE = 405;
const int UserTokenId_T_UNRESOLVED_NEWTYPE = 406;
const int UserTokenId_T_COMPILER_HALT_OFFSET = 407;
const int UserTokenId_T_AWAIT = 408;
const int UserTokenId_T_ASYNC = 409;
const int UserTokenId_T_FROM = 411;
const int UserTokenId_T_WHERE = 412;
const int UserTokenId_T_JOIN = 413;
const int UserTokenId_T_IN = 414;
const int UserTokenId_T_ON = 415;
const int UserTokenId_T_EQUALS = 416;
const int UserTokenId_T_INTO = 417;
const int UserTokenId_T_LET = 418;
const int UserTokenId_T_ORDERBY = 419;
const int UserTokenId_T_ASCENDING = 420;
const int UserTokenId_T_DESCENDING = 421;
const int UserTokenId_T_SELECT = 422;
const int UserTokenId_T_GROUP = 423;
const int UserTokenId_T_BY = 424;
const int UserTokenId_T_LAMBDA_ARROW = 425;
const int UserTokenId_T_DOUBLE_COLON = 426;
const int UserTokenId_T_LAMBDA_OP = 427;
const int UserTokenId_T_LAMBDA_CP = 428;
const int UserTokenId_T_UNRESOLVED_OP = 429;
const int UserTokenId_T_CALLABLE = 430;
const int UserTokenId_T_ONUMBER = 431;
const int UserTokenId_T_POW = 432;
const int UserTokenId_T_POW_EQUAL = 433;
const int UserTokenId_T_NULLSAFE_OBJECT_OPERATOR = 434;
const int UserTokenId_T_HASHBANG = 435;
const int UserTokenId_T_SUPER = 436;
const int UserTokenId_T_SPACESHIP = 437;
const int MaxUserTokenId = 438; // Marker, not a real user token ID

#undef YYTOKENTYPE
#undef YYTOKEN_MAP
#undef YYTOKEN
#define YYTOKEN(num, name) UserTokenId_##name,
#define YYTOKEN_MAP static const int user_token_ids[] =
#include "hphp/parser/hphp.tab.hpp"
#undef YYTOKEN_MAP
#undef YYTOKEN

// Converts an internal token ID to a user token ID
static int get_user_token_id(int internal_id) {
  assert(internal_id >= 0);
  if (internal_id < 256) {
    return internal_id;
  }
  if (internal_id >= YYTOKEN_MIN && internal_id <= YYTOKEN_MAX) {
    return user_token_ids[internal_id - YYTOKEN_MIN];
  }
  return MaxUserTokenId;
}

/**
 * We cheat slightly in the lexer by turning
 * T_ELSE T_WHITESPACE T_IF into T_ELSEIF
 *
 * This makes the AST flatter and avoids bugs like
 * https://github.com/facebook/hhvm/issues/2699
 */
static String token_get_all_fix_elseif(Array& res,
                                       int& tokVal,
                                       const std::string& tokText,
                                       Location& loc) {
  if (!strcasecmp(tokText.c_str(), "elseif")) {
    // Actual T_ELSEIF, continue on.
    return String(tokText);
  }

  // Otherwise, it's a fake elseif made from "else\s+if"
  auto tokCStr = tokText.c_str();
  auto tokCEnd = tokCStr + tokText.size();

  const auto DEBUG_ONLY checkWhitespace =
  [](const char* s, const char* e) {
    while (s < e) { if (!isspace(*(s++))) return false; }
    return true;
  };

  assert(tokText.size() > strlen("elseif"));
  assert(!strncasecmp(tokCStr, "else", strlen("else")));
  assert(checkWhitespace(tokCStr + strlen("else"), tokCEnd - strlen("if")));
  assert(!strcasecmp(tokCEnd - strlen("if"), "if"));

  // Shove in the T_ELSE and T_WHITESPACE, then return the remaining T_IF
  res.append(make_packed_array(
    UserTokenId_T_ELSE,
    String(tokCStr, strlen("else"), CopyString),
    loc.r.line0
  ));

  res.append(make_packed_array(
    UserTokenId_T_WHITESPACE,
    String(tokCStr + strlen("else"), tokText.size() - strlen("elseif"),
           CopyString),
    loc.r.line0
  ));

  tokVal = UserTokenId_T_IF;

  // To account for newlines in the T_WHITESPACE
  loc.r.line0 = loc.r.line1;

  return String(tokCEnd - strlen("if"), CopyString);
}

Array HHVM_FUNCTION(token_get_all, const String& source) {
  Scanner scanner(source.data(), source.size(),
                  RuntimeOption::GetScannerType() | Scanner::ReturnAllTokens);
  ScannerToken tok;
  Location loc;
  int tokid;
  Array res = Array::Create();
  while ((tokid = scanner.getNextToken(tok, loc))) {
loop_start: // For after seeing a T_INLINE_HTML, see below
    if (tokid < 256) {
      res.append(String::FromChar((char)tokid));
    } else {
      String value;
      int tokVal = get_user_token_id(tokid);
      switch (tokVal) {
        case UserTokenId_T_XHP_LABEL:
          value = String(":" + tok.text());
          break;
        case UserTokenId_T_XHP_CATEGORY_LABEL:
          value = String("%" + tok.text());
          break;
        case UserTokenId_T_ELSEIF:
          value = token_get_all_fix_elseif(res, tokVal, tok.text(), loc);
          break;
        case UserTokenId_T_HASHBANG:
          // Convert T_HASHBANG to T_INLINE_HTML for Zend compatibility
          tokVal = UserTokenId_T_INLINE_HTML;
          // Fall through to merge it with following T_INLINE_HTML tokens
        case UserTokenId_T_INLINE_HTML:
        {
          // Consecutive T_INLINE_HTML tokens should be merged together to
          // match Zend behaviour.
          value = String(tok.text());
          int line = loc.r.line0;
          tokid = scanner.getNextToken(tok, loc);
          while (tokid == T_INLINE_HTML) {
            value += String(tok.text());
            tokid = scanner.getNextToken(tok, loc);
          }
          Array p = make_packed_array(
            tokVal,
            value,
            line
          );
          res.append(p);

          if (tokid) {
            // We have a new token to deal with, jump to the beginning
            // of the loop, but don't fetch the next token, hence the
            // goto.
            goto loop_start;
          } else {
            // Break out otherwise we end up appending an empty token to
            // the end of the array
            return res;
          }
          break;
        }
        default:
          value = String(tok.text());
          break;
      }

      Array p = make_packed_array(
        tokVal,
        value,
        loc.r.line0
      );
      res.append(p);
    }
  }
  return res;
}

// User token ID => Token name mapping
static const char** getTokenNameTable() {
  static const char* table[MaxUserTokenId+1];
  for (int i = 0; i <= MaxUserTokenId; ++i) {
    table[i] = "UNKNOWN";
  }
#undef YYTOKENTYPE
#undef YYTOKEN_MAP
#undef YYTOKEN
#define YYTOKEN(num, name) table[get_user_token_id(num)] = #name;
#define YYTOKEN_MAP
#include "hphp/parser/hphp.tab.hpp" // nolint
#undef YYTOKEN_MAP
#undef YYTOKEN
  return table;
}

// Converts a user token ID to a token name
String HHVM_FUNCTION(token_name, int64_t token) {
  static const char** table = getTokenNameTable();
  if (token >= 0 && token < MaxUserTokenId) {
    return table[token];
  }
  return "UNKNOWN";
}

String HHVM_FUNCTION(hphp_to_string, const Variant& v) {
  return v.toString();
}

// Adds an optimized FCallBuiltin for max with 2 operands to SystemLib
Variant HHVM_FUNCTION(SystemLib_max2, const Variant& value1,
                      const Variant& value2) {
  return less(value1, value2) ? value2 : value1;
}

// Adds an optimized FCallBuiltin for min with 2 operands to SystemLib
Variant HHVM_FUNCTION(SystemLib_min2, const Variant& value1,
                      const Variant& value2) {
  return more(value1, value2) ? value2 : value1;
}

#undef YYTOKENTYPE
#undef YYTOKEN_MAP
#undef YYTOKEN
#define YYTOKEN_MAP static void bindTokenConstants()
#define YYTOKEN(num, name) Native::registerConstant<KindOfInt64> \
  (makeStaticString(#name), get_user_token_id(num));

#include "hphp/parser/hphp.tab.hpp" // nolint

#undef YYTOKEN_MAP
#undef YYTOKEN

///////////////////////////////////////////////////////////////////////////////
}
Esempio n. 15
0
void
TrackingConfigPanel::Prepare(ContainerWindow &parent, const PixelRect &rc)
{
  const TrackingSettings &settings =
    CommonInterface::GetComputerSettings().tracking;

  RowFormWidget::Prepare(parent, rc);

#ifdef HAVE_SKYLINES_TRACKING
  AddBoolean(_T("SkyLines"), nullptr, settings.skylines.enabled, this);
#ifdef HAVE_NET_STATE_ROAMING
  AddBoolean(_T("Roaming"), nullptr, settings.skylines.roaming, this);
#endif
  AddEnum(_("Tracking Interval"), nullptr, tracking_intervals,
          settings.skylines.interval);

  AddBoolean(_("Track friends"),
             _("Download the position of your friends live from the SkyLines server."),
             settings.skylines.traffic_enabled, this);

  AddBoolean(_("Show nearby traffic"),
             _("Download the position of your nearby traffic live from the SkyLines server."),
             settings.skylines.near_traffic_enabled, this);

  StaticString<64> buffer;
  if (settings.skylines.key != 0)
    buffer.UnsafeFormat(_T("%llX"), (unsigned long long)settings.skylines.key);
  else
    buffer.clear();
  AddText(_T("Key"), nullptr, buffer);
#endif

#if defined(HAVE_SKYLINES_TRACKING) && defined(HAVE_LIVETRACK24)
  AddSpacer();
#endif

#ifdef HAVE_LIVETRACK24
  AddBoolean(_T("LiveTrack24"),  _T(""), settings.livetrack24.enabled, this);

  AddTime(_("Tracking Interval"), _T(""), 5, 3600, 5, settings.interval);

  AddEnum(_("Vehicle Type"), _("Type of vehicle used."), vehicle_type_list,
          (unsigned) settings.vehicleType);
  AddText(_("Vehicle Name"), _T("Name of vehicle used."),
          settings.vehicle_name);

  WndProperty *edit = AddEnum(_("Server"), _T(""), server_list, 0);
  ((DataFieldEnum *)edit->GetDataField())->Set(settings.livetrack24.server);
  edit->RefreshDisplay();

  AddText(_("Username"), _T(""), settings.livetrack24.username);
  AddPassword(_("Password"), _T(""), settings.livetrack24.password);
#endif

#ifdef HAVE_SKYLINES_TRACKING
  SetSkyLinesEnabled(settings.skylines.enabled);
#endif

#ifdef HAVE_LIVETRACK24
  SetEnabled(settings.livetrack24.enabled);
#endif
}
Esempio n. 16
0
void
writeExact(int fd, const StaticString &data, unsigned long long *timeout) {
	const char * restrict data_ptr = data.data();
	writeExact(fd, data_ptr, data.size(), timeout);
}
Esempio n. 17
0
namespace HPHP {
//////////////////////////////////////////////////////////////////////////////
// class Locale

#define ULOC_CHECK(err, ret) \
  if (U_FAILURE(err)) { \
    s_intl_error->set(err, "%s", u_errorName(err)); \
    return ret; \
  }

#define ULOC_DEFAULT(loc) (loc.empty() ? Intl::GetDefaultLocale() : loc)

#define MAX_LOCALE_LEN 80

/*returns TRUE if a is an ID separator FALSE otherwise*/
#define isIDSeparator(a) (a == '_' || a == '-')
#define isKeywordSeparator(a) (a == '@' )
#define isEndOfTag(a) (a == '\0' )

#define isPrefixLetter(a) ((a=='x')||(a=='X')||(a=='i')||(a=='I'))

/*returns TRUE if one of the special prefixes is here (s=string)
 *   'x-' or 'i-' */
#define isIDPrefix(s) (isPrefixLetter(s[0])&&isIDSeparator(s[1]))
#define isKeywordPrefix(s) ( isKeywordSeparator(s[0]) )

/* Dot terminates it because of POSIX form  where dot precedes the codepage
 *  * except for variant */
#define isTerminator(a)  ((a==0)||(a=='.')||(a=='@'))

static std::vector<std::string> g_grandfathered = {
  "art-lojban", "i-klingon", "i-lux", "i-navajo", "no-bok", "no-nyn",
  "cel-gaulish", "en-GB-oed", "i-ami", "i-bnn", "i-default", "i-enochian",
  "i-mingo", "i-pwn", "i-tao", "i-tay", "i-tsu", "sgn-BE-fr", "sgn-BE-nl",
  "sgn-CH-de", "zh-cmn", "zh-cmn-Hans", "zh-cmn-Hant", "zh-gan", "zh-guoyu",
  "zh-hakka", "zh-min", "zh-min-nan", "zh-wuu", "zh-xiang", "zh-yue"
};

/* Preferred locale codes for the first N entries of g_grandfathered
 * Must be kept in sync with above.
 */
static std::vector<std::string> g_grandfathered_preferred = {
  "jbo", "tlh", "lb", "nv", "nb", "nn"
};

static int getGrandfatheredOffset(const String& locale) {
  auto it = std::find(g_grandfathered.begin(),
                      g_grandfathered.end(), locale.data());
  if (it == g_grandfathered.end()) return -1;
  return (it - g_grandfathered.begin());
}

static String getGrandfatheredPreferred(int ofs) {
  if ((ofs < 0) || (ofs >= g_grandfathered.size())) {
    return null_string;
  }
  if (ofs < g_grandfathered_preferred.size()) {
    return g_grandfathered_preferred[ofs];
  }
  return g_grandfathered[ofs];
}

enum LocaleTag {
  LOC_SCRIPT,
  LOC_LANG,
  LOC_REGION,
  LOC_VARIANT,
  LOC_CANONICALIZE,
  LOC_PRIVATE,
  LOC_DISPLAY,
  LOC_EXTLANG,
};

const StaticString
  s_DEFAULT_LOCALE("DEFAULT_LOCALE"),
  s_LANG_TAG("LANG_TAG"),
  s_EXTLANG_TAG("EXTLANG_TAG"),
  s_SCRIPT_TAG("SCRIPT_TAG"),
  s_REGION_TAG("REGION_TAG"),
  s_VARIANT_TAG("VARIANT_TAG"),
  s_GRANDFATHERED_LANG_TAG("GRANDFATHERED_LANG_TAG"),
  s_PRIVATE_TAG("PRIVATE_TAG"),
  s_LOC_SCRIPT("script"),
  s_LOC_LANG("language"),
  s_LOC_REGION("region"),
  s_LOC_VARIANT("variant"),
  s_LOC_CANONICALIZE("canonicalize"),
  s_LOC_PRIVATE("private"),
  s_LOC_DISPLAY("display"),
  s_LOC_EXTLANG("extlang"),
  s_GRANDFATHERED("grandfathered"),
  s_SEPARATOR("_"),
  s_SEPARATOR_x("_x");

static const StaticString LocaleName(LocaleTag tag) {
  switch (tag) {
    case LOC_SCRIPT:       return s_LOC_SCRIPT;
    case LOC_LANG:         return s_LOC_LANG;
    case LOC_REGION:       return s_LOC_REGION;
    case LOC_VARIANT:      return s_LOC_VARIANT;
    case LOC_CANONICALIZE: return s_LOC_CANONICALIZE;
    case LOC_PRIVATE:      return s_LOC_PRIVATE;
    case LOC_DISPLAY:      return s_LOC_DISPLAY;
    case LOC_EXTLANG:      return s_LOC_EXTLANG;
  }
  not_reached();
}

static int singleton_pos(const String& str) {
  auto len = str.size();
  for (int i = 0; i < (len - 2); ++i) {
    if (!isIDSeparator(str[i])) continue;
    if (i == 1) return 0;
    if (isIDSeparator(str[i+2])) return i+1;
  }
  return -1;
}


static Variant get_icu_value(const String &locale, LocaleTag tag,
                             bool fromParseLocale = false) {
  String locale_name(locale);
  if (tag != LOC_CANONICALIZE) {
    if (getGrandfatheredOffset(locale) >= 0) {
      if (tag == LOC_LANG) {
        return locale;
      }
      return false;
    }
    if (fromParseLocale) {
      auto localecstr = locale.c_str();
      if (tag == LOC_LANG && locale.size() > 1 && isIDPrefix(localecstr)) {
        return locale;
      }
      int pos = singleton_pos(locale);
      if (pos == 0) {
        return null_string;
      } else if (pos > 0) {
        locale_name = f_substr(locale, 0, pos - 1);
      }
    }
  }

  int32_t (*ulocfunc)(const char *loc, char *val, int32_t len, UErrorCode *err);
  switch (tag) {
    case LOC_SCRIPT:       ulocfunc = uloc_getScript;    break;
    case LOC_LANG:         ulocfunc = uloc_getLanguage;  break;
    case LOC_REGION:       ulocfunc = uloc_getCountry;   break;
    case LOC_VARIANT:      ulocfunc = uloc_getVariant;   break;
    case LOC_CANONICALIZE: ulocfunc = uloc_canonicalize; break;
    default:
      assert(false);
  }

  String buf(64, ReserveString);
  do {
    UErrorCode error = U_ZERO_ERROR;
    int32_t len = ulocfunc(locale_name.c_str(),
                           buf->mutableData(), buf->capacity(), &error);
    if (error != U_BUFFER_OVERFLOW_ERROR &&
        error != U_STRING_NOT_TERMINATED_WARNING) {
      if (U_FAILURE(error)) {
        s_intl_error->set(error, "unable to get locale info");
        return false;
      }
      buf.setSize(len);
      return buf;
    }
    if (len <= buf->capacity()) {
      // Avoid infinite loop
      s_intl_error->set(U_INTERNAL_PROGRAM_ERROR,
                        "Got invalid response from ICU");
      return false;
    }
    buf = String(len, ReserveString);
  } while (true);

  not_reached();
  return false;
}

static Variant get_icu_display_value(const String &locale,
                                     const String &disp_locale,
                                     LocaleTag tag) {
  String locname(locale);
  if (tag != LOC_DISPLAY) {
    int ofs = getGrandfatheredOffset(locale);
    if (ofs >= 0) {
      if (tag == LOC_LANG) {
        locname = getGrandfatheredPreferred(ofs);
      } else {
        return false;
      }
    }
  }

  int32_t (*ulocfunc)(const char *loc, const char *dloc,
                      UChar *dest, int32_t destcap, UErrorCode *err);
  switch (tag) {
    case LOC_LANG:     ulocfunc = uloc_getDisplayLanguage; break;
    case LOC_SCRIPT:   ulocfunc = uloc_getDisplayScript;   break;
    case LOC_REGION:   ulocfunc = uloc_getDisplayCountry;  break;
    case LOC_VARIANT:  ulocfunc = uloc_getDisplayVariant;  break;
    case LOC_DISPLAY:  ulocfunc = uloc_getDisplayName;     break;
    default:
      assert(false);
  }

  String buf(64 * sizeof(UChar), ReserveString);
  do {
    UErrorCode error = U_ZERO_ERROR;
    int32_t len = ulocfunc(locname.c_str(), disp_locale.c_str(),
                           (UChar*)buf->mutableData(),
                           buf->capacity() / sizeof(UChar),
                           &error);
    if (error != U_BUFFER_OVERFLOW_ERROR &&
        error != U_STRING_NOT_TERMINATED_WARNING) {
      if (U_FAILURE(error)) {
        s_intl_error->set(error, "locale_get_display_%s : unable to "
                                 "get locale %s",
                                 LocaleName(tag).c_str(),
                                 LocaleName(tag).c_str());
        return false;
      }
      buf.setSize(len * sizeof(UChar));

      error = U_ZERO_ERROR;
      String out(Intl::u8(buf, error));
      if (U_FAILURE(error)) {
        s_intl_error->set(error, "Unable to convert result from "
                                 "locale_get_display_%s to UTF-8",
                                 LocaleName(tag).c_str());
        return false;
      }
      return out;
    }
    if (len <= (buf->capacity() / sizeof(UChar))) {
      // Avoid infinite loop
      s_intl_error->set(U_INTERNAL_PROGRAM_ERROR,
                        "Got invalid response from ICU");
      return false;
    }
    buf = String(len * sizeof(UChar), ReserveString);
  } while (true);

  not_reached();
  return false;
}

static Variant HHVM_STATIC_METHOD(Locale, acceptFromHttp,
                                  const String& header) {
  UErrorCode error = U_ZERO_ERROR;
  UEnumeration *avail = ures_openAvailableLocales(nullptr, &error);
  ULOC_CHECK(error, false);
  char out[MAX_LOCALE_LEN];
  UAcceptResult result;
  error = U_ZERO_ERROR;
  int len = uloc_acceptLanguageFromHTTP(out, sizeof(out), &result,
                                        header.c_str(), avail, &error);
  uenum_close(avail);
  ULOC_CHECK(error, false);
  if (len < 0 || result == ULOC_ACCEPT_FAILED) {
    return false;
  }
  return String(out, len, CopyString);
}

static Variant HHVM_STATIC_METHOD(Locale, canonicalize, const String& locale) {
  return get_icu_value(ULOC_DEFAULT(locale), LOC_CANONICALIZE);
}

inline void element_not_string() {
  s_intl_error->set(U_ILLEGAL_ARGUMENT_ERROR,
                    "locale_compose: parameter array element is not a string: "
                    "U_ILLEGAL_ARGUMENT_ERROR");
}

static bool append_key_value(String& ret,
                             CArrRef subtags,
                             LocaleTag tag) {
  auto name = LocaleName(tag);
  if (!subtags.exists(name)) return true;
  auto val = subtags[name];
  if (!val.isString()) {
    element_not_string();
    return false;
  }
  ret += s_SEPARATOR + val.toString();
  return true;
}

static bool append_multiple_key_values(String& ret,
                                       CArrRef subtags,
                                       LocaleTag tag) {
  auto name = LocaleName(tag);
  if (subtags.exists(name)) {
    // Sane version: [tag] => string, [tag] => array<tring>
    auto val = subtags[name];
    if (val.isString()) {
      if (tag == LOC_PRIVATE) {
        ret += s_SEPARATOR_x;
      }
      ret += s_SEPARATOR + val.toString();
      return true;
    }
    if (!val.isArray()) {
      return false;
    }
    bool first = true;
    for (ArrayIter it(val.toArray()); it; ++it) {
      auto v = it.second();
      if (!v.isString()) {
        element_not_string();
        return false;
      }
      if (first) {
        if (tag == LOC_PRIVATE) {
          ret += s_SEPARATOR + "x";
        }
        first = false;
      }
      ret += s_SEPARATOR + v.toString();
    }
    return true;
  }

  // clowny version [tag$n] => string
  // Only extlang, variant, and private
  if (tag != LOC_EXTLANG &&
      tag != LOC_VARIANT &&
      tag != LOC_PRIVATE) {
    return true;
  }

  int max = (tag == LOC_EXTLANG) ? 3 : 15;
  bool first = true;
  for (int i = 0; i < max; ++i) {
    auto namenum = name + String(i, CopyString);
    if (!subtags.exists(namenum)) continue;
    auto val = subtags[namenum];
    if (!val.isString()) {
      element_not_string();
      return false;
    }
    if (first) {
      if (tag == LOC_PRIVATE) {
        ret += s_SEPARATOR + "x";
      }
      first = false;
    }
    ret += s_SEPARATOR + val.toString();
  }
  return true;
}

static Variant HHVM_STATIC_METHOD(Locale, composeLocale, CArrRef subtags) {
  s_intl_error->clear();

  if (subtags.exists(s_GRANDFATHERED)) {
    auto val = subtags[s_GRANDFATHERED];
    if (val.isString()) {
      return val;
    }
  }

  if (!subtags.exists(s_LOC_LANG)) {
    s_intl_error->set(U_ILLEGAL_ARGUMENT_ERROR, "locale_compose: "
                      "parameter array does not contain 'language' tag.: "
                      "U_ILLEGAL_ARGUMENT_ERROR");
    return false;
  }
  String ret(subtags[s_LOC_LANG].toString());
  if (!append_multiple_key_values(ret, subtags, LOC_EXTLANG) ||
      !append_key_value(ret, subtags, LOC_SCRIPT) ||
      !append_key_value(ret, subtags, LOC_REGION) ||
      !append_multiple_key_values(ret, subtags, LOC_VARIANT) ||
      !append_multiple_key_values(ret, subtags, LOC_PRIVATE)) {
    return false;
  }
  return ret;
}

static Array HHVM_STATIC_METHOD(Locale, getAllVariants, const String& locale) {
  Variant val = get_icu_value(ULOC_DEFAULT(locale), LOC_VARIANT);
  String strval = val.toString();
  if (strval.empty()) {
    return null_array;
  }
  Array ret = Array::Create();
  const char *s = strval.c_str(), *e = s + strval.size(), *p;
  for (p = s; p < e; ++p) {
    if (!isIDSeparator(*p)) continue;
    if ((p - s) <= 1) {
      return ret;
    }
    ret.append(String(s, p - s, CopyString));
    s = p + 1;
  }
  if ((e - s) > 1) {
    ret.append(String(s, e - s, CopyString));
  }
  return ret;
}

static String HHVM_STATIC_METHOD(Locale, getDefault) {
  return Intl::GetDefaultLocale();
}

static String HHVM_STATIC_METHOD(Locale, getDisplayLanguage,
                                 const String& locale,
                                 const String& in_locale) {
  return get_icu_display_value(ULOC_DEFAULT(locale),
                               ULOC_DEFAULT(in_locale), LOC_LANG);
}

static String HHVM_STATIC_METHOD(Locale, getDisplayName,
                                 const String& locale,
                                 const String& in_locale) {
  return get_icu_display_value(ULOC_DEFAULT(locale),
                               ULOC_DEFAULT(in_locale), LOC_DISPLAY);
}

static String HHVM_STATIC_METHOD(Locale, getDisplayRegion,
                                 const String& locale,
                                 const String& in_locale) {
  return get_icu_display_value(ULOC_DEFAULT(locale),
                               ULOC_DEFAULT(in_locale), LOC_REGION);
}

static String HHVM_STATIC_METHOD(Locale, getDisplayScript,
                                 const String& locale,
                                 const String& in_locale) {
  return get_icu_display_value(ULOC_DEFAULT(locale),
                               ULOC_DEFAULT(in_locale), LOC_SCRIPT);
}

static String HHVM_STATIC_METHOD(Locale, getDisplayVariant,
                                 const String& locale,
                                 const String& in_locale) {
  return get_icu_display_value(ULOC_DEFAULT(locale),
                               ULOC_DEFAULT(in_locale), LOC_VARIANT);
}

static Array HHVM_STATIC_METHOD(Locale, getKeywords, const String& locale) {
  UErrorCode error = U_ZERO_ERROR;
  String locname = ULOC_DEFAULT(locale);
  UEnumeration *e = uloc_openKeywords(locname.c_str(), &error);
  if (!e) return null_array;

  Array ret = Array::Create();
  const char *key;
  int key_len;
  String val(128, ReserveString);
  char *ptr = val->mutableData();
  error = U_ZERO_ERROR;
  while ((key = uenum_next(e, &key_len, &error))) {
tryagain:
    error = U_ZERO_ERROR;
    int val_len = uloc_getKeywordValue(locname.c_str(), key,
                                       ptr, val->capacity(), &error);
    if (error == U_BUFFER_OVERFLOW_ERROR) {
      val = String(val_len + 128, ReserveString);
      ptr = val->mutableData();
      goto tryagain;
    }
    if (U_FAILURE(error)) {
      s_intl_error->set(error, "locale_get_keywords: Error encountered while "
                               "getting the keyword  value for the  keyword");
      return null_array;
    }
    ret.set(String(key, key_len, CopyString), String(ptr, val_len, CopyString));
  }
  return ret;
}

static String HHVM_STATIC_METHOD(Locale, getPrimaryLanguage,
                                 const String& locale) {
  return get_icu_value(ULOC_DEFAULT(locale), LOC_LANG);
}

static Variant HHVM_STATIC_METHOD(Locale, getRegion, const String& locale) {
  return get_icu_value(ULOC_DEFAULT(locale), LOC_REGION);
}

static Variant HHVM_STATIC_METHOD(Locale, getScript, const String& locale) {
  return get_icu_value(ULOC_DEFAULT(locale), LOC_SCRIPT);
}

static String locale_suffix_strip(const String& locale) {
  for (int i = locale.size(); i >= 0; --i) {
    if (isIDSeparator(locale[i])) {
      if ((i>=2) && isIDSeparator(locale[i-2])) {
        return f_substr(locale, 0, i - 2);
      } else {
        return f_substr(locale, 0, i);
      }
    }
  }
  return null_string;
}

inline void normalize_for_match(String& v) {
  for (char *ptr = v->mutableData(), *end = ptr + v.size(); ptr < end; ++ptr) {
    if (*ptr == '-') {
      *ptr = '_';
    } else {
      *ptr = tolower(*ptr);
    }
  }
  v->invalidateHash();
}

static String HHVM_STATIC_METHOD(Locale, lookup, CArrRef langtag,
                                 const String& locale,
                                 bool canonicalize, const String& def) {
  String locname(ULOC_DEFAULT(locale), CopyString);
  std::vector<std::pair<String,String>> cur_arr;
  for (ArrayIter iter(langtag); iter; ++iter) {
    auto val = iter.second();
    if (!val.isString()) {
      s_intl_error->set(U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: "
                        "locale array element is not a string");
      return def;
    }
    String normalized(val.toString(), CopyString);
    normalize_for_match(normalized);
    if (canonicalize) {
      normalized = get_icu_value(normalized, LOC_CANONICALIZE);
      if (normalized.isNull()) {
        s_intl_error->set(U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: "
                          "unable to canonicalize lang_tag");
        return def;
      }
      normalize_for_match(normalized);
    }
    cur_arr.push_back(std::make_pair(val,normalized));
  }

  if (canonicalize) {
    locname = get_icu_value(locname, LOC_CANONICALIZE);
    if (locname.isNull()) {
      s_intl_error->set(U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: "
                        "unable to canonicalize loc_range");
      return def;
    }
  }

  normalize_for_match(locname);
  while (locname.size() > 0) {
    for (auto &p : cur_arr) {
      if (locname.same(p.second)) {
        return canonicalize ? p.second : p.first;
      }
    }
    locname = locale_suffix_strip(locname);
  }
  return def;
}

static Variant get_private_subtags(const String& locname) {
  if (locname.empty()) return uninit_null();
  String locale(locname);
  int pos;
  while ((pos = singleton_pos(locale)) >= 0) {
    if ((locale[pos] == 'x') || (locale[pos] == 'X')) {
      if ((pos + 2) == locale.size()) {
        /* loc_name ends with '-x-' */
        return uninit_null();
      }
      return f_substr(locale, pos);
    }
    if ((pos + 1) >= locale.size()) {
      return uninit_null();
    }
    locale = f_substr(locale, pos + 1);
  }
  return uninit_null();
}

static void add_array_entry(Array& ret,
                            const String& locname,
                            LocaleTag tag) {
  Variant val;
  if (tag == LOC_PRIVATE) {
    val = get_private_subtags(locname);
  } else {
    val = get_icu_value(locname, tag, true);
  }
  if (val.isNull()) return;
  String strval = val.toString();
  if (strval.empty()) {
    return;
  }

  auto name = LocaleName(tag);
  if ((tag != LOC_PRIVATE) && (tag != LOC_VARIANT)) {
    ret.set(name, strval);
    return;
  }

  const char *s = strval.c_str(), *e = s + strval.size(), *p;
  int cnt;
  for (cnt = 0, p = s; p < e; ++p) {
    if (!isIDSeparator(*p)) continue;
    if ((p - s) > 1) {
      ret.set(name + String(cnt++), String(s, p - s, CopyString));
    }
    s = p + 1;
  }
  if ((e - s) > 1) {
    ret.set(name + String(cnt++), String(s, e - s, CopyString));
  }
}

static Array HHVM_STATIC_METHOD(Locale, parseLocale, const String& locale) {
  String locname = ULOC_DEFAULT(locale);
  Array ret = Array::Create();
  if (std::find(g_grandfathered.begin(),
                g_grandfathered.end(), locale.data()) !=
                g_grandfathered.end()) {
    ret.set(s_GRANDFATHERED, locname);
    return ret;
  }
  add_array_entry(ret, locname, LOC_LANG);
  add_array_entry(ret, locname, LOC_SCRIPT);
  add_array_entry(ret, locname, LOC_REGION);
  add_array_entry(ret, locname, LOC_VARIANT);
  add_array_entry(ret, locname, LOC_PRIVATE);
  return ret;
}

static bool HHVM_STATIC_METHOD(Locale, setDefault, const String& locale) {
  return Intl::SetDefaultLocale(locale);
}

//////////////////////////////////////////////////////////////////////////////

const StaticString s_Locale("Locale");

void Intl::IntlExtension::initLocale() {
  HHVM_STATIC_ME(Locale, acceptFromHttp);
  HHVM_STATIC_ME(Locale, canonicalize);
  HHVM_STATIC_ME(Locale, composeLocale);
  HHVM_STATIC_ME(Locale, getAllVariants);
  HHVM_STATIC_ME(Locale, getDefault);
  HHVM_STATIC_ME(Locale, getDisplayLanguage);
  HHVM_STATIC_ME(Locale, getDisplayName);
  HHVM_STATIC_ME(Locale, getDisplayRegion);
  HHVM_STATIC_ME(Locale, getDisplayScript);
  HHVM_STATIC_ME(Locale, getDisplayVariant);
  HHVM_STATIC_ME(Locale, getKeywords);
  HHVM_STATIC_ME(Locale, getPrimaryLanguage);
  HHVM_STATIC_ME(Locale, getRegion);
  HHVM_STATIC_ME(Locale, getScript);
  HHVM_STATIC_ME(Locale, lookup);
  HHVM_STATIC_ME(Locale, parseLocale);
  HHVM_STATIC_ME(Locale, setDefault);

#define ULOC_CONST(nm,val) Native::registerClassConstant<KindOfStaticString>\
                               (s_Locale.get(), s_##nm.get(), s_##val.get())

  Native::registerClassConstant<KindOfNull>(s_Locale.get(),
                                            s_DEFAULT_LOCALE.get());
  ULOC_CONST(LANG_TAG,               LOC_LANG);
  ULOC_CONST(EXTLANG_TAG,            LOC_EXTLANG);
  ULOC_CONST(SCRIPT_TAG,             LOC_SCRIPT);
  ULOC_CONST(REGION_TAG,             LOC_REGION);
  ULOC_CONST(VARIANT_TAG,            LOC_VARIANT);
  ULOC_CONST(GRANDFATHERED_LANG_TAG, GRANDFATHERED);
  ULOC_CONST(PRIVATE_TAG,            LOC_PRIVATE);


#undef ULOC_CONST

  loadSystemlib("icu_locale");
}

//////////////////////////////////////////////////////////////////////////////
} // namespace HPHP
Esempio n. 18
0
namespace HPHP {

Class* Generator::s_class = nullptr;
const StaticString Generator::s_className("Generator");

Generator::Generator()
  : m_index(-1LL)
  , m_key(make_tv<KindOfInt64>(-1LL))
  , m_value(make_tv<KindOfNull>())
  , m_delegate(make_tv<KindOfNull>())
{
}

Generator::~Generator() {
  if (LIKELY(getState() == State::Done)) {
    return;
  }

  assert(getState() != State::Running);
  tvRefcountedDecRef(m_key);
  tvRefcountedDecRef(m_value);
  tvRefcountedDecRef(m_delegate);

  // Free locals, but don't trigger the EventHook for FunctionReturn since
  // the generator has already been exited. We don't want redundant calls.
  ActRec* ar = actRec();
  frame_free_locals_inl_no_hook<false>(ar, ar->func()->numLocals());
}

Generator& Generator::operator=(const Generator& other) {
  auto const fp = other.actRec();
  const size_t numSlots = fp->func()->numSlotsInFrame();
  const size_t frameSz = Resumable::getFrameSize(numSlots);
  const size_t genSz = genSize(sizeof(Generator), frameSz);
  resumable()->initialize<true>(fp,
                                other.resumable()->resumeAddr(),
                                other.resumable()->resumeOffset(),
                                frameSz,
                                genSz);
  copyVars(fp);
  setState(other.getState());
  m_index = other.m_index;
  cellSet(other.m_key, m_key);
  cellSet(other.m_value, m_value);
  cellSet(other.m_delegate, m_delegate);
  return *this;
}

void Generator::copyVars(const ActRec* srcFp) {
  const auto dstFp = actRec();
  const auto func = dstFp->func();
  assert(srcFp->func() == dstFp->func());

  for (Id i = 0; i < func->numLocals(); ++i) {
    tvDupFlattenVars(frame_local(srcFp, i), frame_local(dstFp, i));
  }

  if (dstFp->hasThis()) {
    dstFp->getThis()->incRefCount();
  }

  if (LIKELY(!(srcFp->func()->attrs() & AttrMayUseVV))) return;
  if (LIKELY(srcFp->m_varEnv == nullptr)) return;

  if (srcFp->hasExtraArgs()) {
    dstFp->setExtraArgs(srcFp->getExtraArgs()->clone(dstFp));
  } else {
    assert(srcFp->hasVarEnv());
    dstFp->setVarEnv(srcFp->getVarEnv()->clone(dstFp));
  }
}

void Generator::yield(Offset resumeOffset,
                      const Cell* key, const Cell value) {
  assert(isRunning());
  resumable()->setResumeAddr(nullptr, resumeOffset);

  if (key) {
    cellSet(*key, m_key);
    tvRefcountedDecRefNZ(*key);
    if (m_key.m_type == KindOfInt64) {
      int64_t new_index = m_key.m_data.num;
      m_index = new_index > m_index ? new_index : m_index;
    }
  } else {
    cellSet(make_tv<KindOfInt64>(++m_index), m_key);
  }
  cellSet(value, m_value);
  tvRefcountedDecRefNZ(value);

  setState(State::Started);
}

void Generator::done(TypedValue tv) {
  assert(isRunning());
  cellSetNull(m_key);
  cellSet(*tvToCell(&tv), m_value);
  setState(State::Done);
}

bool Generator::successfullyFinishedExecuting() {
  // `getReturn` needs to know whether a generator finished successfully or
  // whether an exception occurred during its execution. For every other use
  // case a failed generator was identical to one that finished executing, but
  // `getReturn` wants to throw an exception if the generator threw an
  // exception. Since we use the same variable to store the yield result and
  // the return value, and since we dont have a separate state to represent a
  // failed generator, we use an unintialized value to flag that the generator
  // failed (rather than NULL, which we use for a successful generator without
  // a return value).
  return getState() == State::Done &&
         m_value.m_type != KindOfUninit;
}

const StaticString s__closure_("{closure}");
String HHVM_METHOD(Generator, getOrigFuncName) {
  Generator* gen = Native::data<Generator>(this_);
  const Func* origFunc = gen->actRec()->func();
  auto const origName = origFunc->isClosureBody() ? s__closure_.get()
                                                  : origFunc->name();
  assert(origName->isStatic());
  return String(const_cast<StringData*>(origName));
}

String HHVM_METHOD(Generator, getCalledClass) {
  Generator* gen = Native::data<Generator>(this_);
  String called_class;

  if (gen->actRec()->hasThis()) {
    called_class =
      gen->actRec()->getThis()->getVMClass()->name()->data();
  } else if (gen->actRec()->hasClass()) {
    called_class = gen->actRec()->getClass()->name()->data();
  } else {
    called_class = empty_string();
  }

  return called_class;
}

///////////////////////////////////////////////////////////////////////////////

class GeneratorExtension final : public Extension {
public:
  GeneratorExtension() : Extension("generator") {}

  void moduleInit() override {
    HHVM_ME(Generator, getOrigFuncName);
    HHVM_ME(Generator, getCalledClass);
    Native::registerNativeDataInfo<Generator>(
      Generator::s_className.get(),
      Native::NDIFlags::NO_SWEEP);
    loadSystemlib("generator");
    Generator::s_class = Unit::lookupClass(Generator::s_className.get());
    assert(Generator::s_class);
  }
};

static GeneratorExtension s_generator_extension;

///////////////////////////////////////////////////////////////////////////////
}
Esempio n. 19
0
bool is_collection_method_returning_this(const php::Class* cls,
                                         const php::Func* func) {
  if (!cls) return false;

  if (cls->name->isame(s_Vector.get())) {
    return
      func->name->isame(s_add.get()) ||
      func->name->isame(s_addall.get()) ||
      func->name->isame(s_append.get()) ||
      func->name->isame(s_clear.get()) ||
      func->name->isame(s_removekey.get()) ||
      func->name->isame(s_set.get()) ||
      func->name->isame(s_setall.get());
  }

  if (cls->name->isame(s_Map.get())) {
    return
      func->name->isame(s_add.get()) ||
      func->name->isame(s_addall.get()) ||
      func->name->isame(s_clear.get()) ||
      func->name->isame(s_remove.get()) ||
      func->name->isame(s_set.get()) ||
      func->name->isame(s_setall.get());
  }

  if (cls->name->isame(s_Set.get())) {
    return
      func->name->isame(s_add.get()) ||
      func->name->isame(s_addall.get()) ||
      func->name->isame(s_clear.get()) ||
      func->name->isame(s_remove.get()) ||
      func->name->isame(s_removeall.get());
  }

  return false;
}
Esempio n. 20
0
bool interface_supports_string(const StringData* s) {
  return s->isame(s_XHPChild.get())
    || s->isame(s_Stringish.get());
}
Esempio n. 21
0
static bool modify_extract_name(VarEnv* v,
                                String& name,
                                int64_t extract_type,
                                const String& prefix) {
  switch (extract_type) {
  case EXTR_SKIP:
    if (v->lookup(name.get()) != nullptr) {
      return false;
    }
    break;
  case EXTR_IF_EXISTS:
    if (v->lookup(name.get()) == nullptr) {
      return false;
    } else {
      goto namechecks;
    }
    break;
  case EXTR_PREFIX_SAME:
    if (v->lookup(name.get()) != nullptr) {
      name = prefix + "_" + name;
    } else {
      goto namechecks;
    }
    break;
  case EXTR_PREFIX_ALL:
    name = prefix + "_" + name;
    break;
  case EXTR_PREFIX_INVALID:
    if (!is_valid_var_name(name.get()->data(), name.size())) {
      name = prefix + "_" + name;
    } else {
      goto namechecks;
    }
    break;
  case EXTR_PREFIX_IF_EXISTS:
    if (v->lookup(name.get()) == nullptr) {
      return false;
    }
    name = prefix + "_" + name;
    break;
  case EXTR_OVERWRITE:
    namechecks:
    if (name == s_GLOBALS) {
      return false;
    }
    if (name == s_this) {
      // Only disallow $this when inside a non-static method, or a static method
      // that has defined $this (matches Zend)
      auto const func = arGetContextFunc(GetCallerFrame());

      if (func && func->isMethod() && v->lookup(s_this.get()) != nullptr) {
        return false;
      }
    }
  default:
    break;
  }

  // skip invalid variable names, as in PHP
  return is_valid_var_name(name.get()->data(), name.size());
}
Esempio n. 22
0
bool interface_supports_double(const StringData* s) {
  return (s->isame(s_XHPChild.get()));
}
Esempio n. 23
0
static void
LoadString(const char *bytes, size_t length, StaticString<size> &dest)
{
  return LoadString(bytes, length, dest.buffer(), dest.MAX_SIZE);
}
Esempio n. 24
0
namespace HPHP {

///////////////////////////////////////////////////////////////////////////////

const StaticString s_filter("filter");
const StaticString s_onCreate("onCreate");
const StaticString s_onClose("onClose");

const StaticString s_bucket_class("__SystemLib\\StreamFilterBucket");

///////////////////////////////////////////////////////////////////////////////

const StaticString s_default_filters_register_func(
  "__SystemLib\\register_default_stream_filters");

class StreamUserFilters : public RequestEventHandler {
 public:
  virtual ~StreamUserFilters() {}
  Array m_registeredFilters;

  bool registerFilter(const String& name, const String& class_name) {
    if (m_registeredFilters.exists(name)) {
      return false;
    }
    m_registeredFilters.add(name, class_name);
    return true;
  }

  Variant prepend(const Resource& stream,
                 const String& filtername,
                 const Variant& readwrite,
                 const Variant& params) {
    return appendOrPrependFilter(stream,
                                 filtername,
                                 readwrite,
                                 params,
                                 /* append = */ false);
  }

  Variant append(const Resource& stream,
                 const String& filtername,
                 const Variant& readwrite,
                 const Variant& params) {
    return appendOrPrependFilter(stream,
                                 filtername,
                                 readwrite,
                                 params,
                                 /* append = */ true);
  }

  virtual void requestInit() {
    vm_call_user_func(s_default_filters_register_func, empty_array_ref);
  }

  virtual void requestShutdown() {
    m_registeredFilters.detach();
  }
private:
  Variant appendOrPrependFilter(const Resource& stream,
                 const String& filtername,
                 const Variant& readwrite,
                 const Variant& params,
                 bool append) {
    const char* func_name =
      append ? "stream_filter_append()" : "stream_filter_prepend()";

    if (!m_registeredFilters.exists(filtername)) {
      raise_warning("%s: unable to locate filter \"%s\"",
                    func_name,
                    filtername.data());
      return false;
    }

    auto file = stream.getTyped<File>();
    assert(file);

    int mode = readwrite.toInt32();
    if (!mode) {
      auto str = file->getMode();
      /* The documentation says a read filter is only created for 'r' and '+'
       * modes, but the implementation will always create one unless
       * STREAM_FILTER_WRITE is passed.
       *
       * This branch is only executed if no STREAM_FILTER* args were passed,
       * so we always create a READ filter.
       */
      mode = k_STREAM_FILTER_READ;
      if (str.find('+') != -1 || str.find('w') != -1 || str.find('a') != -1) {
        mode |= k_STREAM_FILTER_WRITE;
      }
    }
    if (!(mode & k_STREAM_FILTER_ALL)) {
      return false;
    }

    // If it's ALL we create two resources, but only return one - this
    // matches Zend, and is the documented behavior.
    Resource ret;
    if (mode & k_STREAM_FILTER_READ) {
      auto resource = createInstance(func_name,
                                     stream,
                                     filtername,
                                     params);
      if (resource.isNull()) {
        return false;
      }
      ret = resource;
      if (append) {
        file->appendReadFilter(resource);
      } else {
        file->prependReadFilter(resource);
      }
    }
    if (mode & k_STREAM_FILTER_WRITE) {
      auto resource = createInstance(func_name,
                                     stream,
                                     filtername,
                                     params);
      if (resource.isNull()) {
        return false;
      }
      ret = resource;
      if (append) {
        file->appendWriteFilter(resource);
      } else {
        file->prependWriteFilter(resource);
      }
    }
    return ret;
  }

  Resource createInstance(const char* php_func,
                          const Resource& stream,
                          const String& filter,
                          const Variant& params) {
    auto class_name = m_registeredFilters.rvalAt(filter).asCStrRef();
    Class* class_ = Unit::getClass(class_name.get(), true);
    Object obj = Object();

    if (LIKELY(class_ != nullptr)) {
      PackedArrayInit ctor_args(3);
      ctor_args.append(stream);
      ctor_args.append(filter);
      ctor_args.append(params);
      obj = g_context->createObject(class_name.get(), ctor_args.toArray());
      auto created = obj->o_invoke(s_onCreate, Array::Create());
      /* - true: documented value for success
       * - null: undocumented default successful value
       * - false: documented value for failure
       */
      if (!(created.isNull() || created.toBoolean())) {
        obj.reset();
      }
    } else {
      raise_warning("%s: user-filter \"%s\" requires class \"%s\", but that "
                    "class " "is not defined",
                    php_func,
                    filter.data(),
                    class_name.data());
      // Fall through, as to match Zend, the warning below should also be raised
    }

    if (obj.isNull()) {
      raise_warning("%s: unable to create or locate filter \"%s\"",
                    php_func,
                    filter.data());
      return Resource();
    }

    return Resource(newres<StreamFilter>(obj, stream));
  }
};
IMPLEMENT_STATIC_REQUEST_LOCAL(StreamUserFilters, s_stream_user_filters);

///////////////////////////////////////////////////////////////////////////////
// StreamFilter

int64_t StreamFilter::invokeFilter(Resource in,
                                   Resource out,
                                   bool closing) {
  auto consumedTV = make_tv<KindOfInt64>(0);
  auto consumedRef = RefData::Make(consumedTV);

  PackedArrayInit params(4);
  params.append(in);
  params.append(out);
  params.append(consumedRef);
  params.append(closing);
  return m_filter->o_invoke(s_filter, params.toArray()).toInt64();
}

void StreamFilter::invokeOnClose() {
  m_filter->o_invoke(s_onClose, Array::Create());
}

bool StreamFilter::remove() {
  if (m_stream.isNull()) {
    return false;
  }
  auto file = m_stream.getTyped<File>();
  assert(file);
  Resource rthis(this);
  auto ret = file->removeFilter(rthis);
  m_stream.reset();
  return ret;
}

///////////////////////////////////////////////////////////////////////////////
// BucketBrigade

BucketBrigade::BucketBrigade(const String& data) {
  PackedArrayInit ai(2);
  ai.append(data);
  ai.append(data.length());
  auto bucket = g_context->createObject(s_bucket_class.get(), ai.toArray());
  appendBucket(bucket);
}

void BucketBrigade::appendBucket(const Object& bucket) {
  m_buckets.push_back(bucket);
}

void BucketBrigade::prependBucket(const Object& bucket) {
  m_buckets.push_front(bucket);
}

Object BucketBrigade::popFront() {
  if (m_buckets.empty()) {
    return Object();
  }
  auto bucket = m_buckets.front();
  m_buckets.pop_front();
  return bucket;
}

String BucketBrigade::createString() {
  StringBuffer buffer;
  for (auto& bucket_obj: m_buckets) {
    buffer.append(bucket_obj.toString());
  }
  return buffer.detach();
}

///////////////////////////////////////////////////////////////////////////////

bool HHVM_FUNCTION(stream_filter_register,
                   const String& name,
                   const String& classname) {
  return s_stream_user_filters.get()->registerFilter(name, classname);
}

Array HHVM_FUNCTION(stream_get_filters) {
  auto filters = s_stream_user_filters.get()->m_registeredFilters;
  if (UNLIKELY(filters.isNull())) {
    return empty_array();
  }
  return array_keys_helper(filters).toArray();
}

Variant HHVM_FUNCTION(stream_filter_append,
                      const Resource& stream,
                      const String& filtername,
                      const Variant& readwrite,
                      const Variant& params) {
  return s_stream_user_filters.get()->append(stream,
                                             filtername,
                                             readwrite,
                                             params);
}

Variant HHVM_FUNCTION(stream_filter_prepend,
                      const Resource& stream,
                      const String& filtername,
                      const Variant& readwrite,
                      const Variant& params) {
  return s_stream_user_filters.get()->prepend(stream,
                                              filtername,
                                              readwrite,
                                              params);
}

bool HHVM_FUNCTION(stream_filter_remove, const Resource& resource) {
  auto filter = resource.getTyped<StreamFilter>();
  assert(filter);
  return filter->remove();
}

Variant HHVM_FUNCTION(stream_bucket_make_writeable, const Resource& bb_res) {
  auto brigade = bb_res.getTyped<BucketBrigade>();
  assert(brigade);
  auto ret = brigade->popFront();
  return ret;
}

void HHVM_FUNCTION(stream_bucket_append, const Resource& bb_res, const Object& bucket) {
  auto brigade = bb_res.getTyped<BucketBrigade>();
  assert(brigade);
  brigade->appendBucket(bucket);
}

void HHVM_FUNCTION(stream_bucket_prepend, const Resource& bb_res, const Object& bucket) {
  auto brigade = bb_res.getTyped<BucketBrigade>();
  assert(brigade);
  brigade->prependBucket(bucket);
}

const StaticString
  s_STREAM_FILTER_READ("STREAM_FILTER_READ"),
  s_STREAM_FILTER_WRITE("STREAM_FILTER_WRITE"),
  s_STREAM_FILTER_ALL("STREAM_FILTER_ALL");

void StandardExtension::initStreamUserFilters() {
#define SFCNS(v) Native::registerConstant<KindOfInt64> \
                         (s_STREAM_FILTER_##v.get(), k_STREAM_FILTER_##v)
  SFCNS(READ);
  SFCNS(WRITE);
  SFCNS(ALL);
#undef SFCNS

  HHVM_FE(stream_get_filters);
  HHVM_FE(stream_filter_register);
  HHVM_FE(stream_filter_append);
  HHVM_FE(stream_filter_prepend);
  HHVM_FE(stream_filter_remove);
  HHVM_FE(stream_bucket_make_writeable);
  HHVM_FE(stream_bucket_append);
  HHVM_FE(stream_bucket_prepend);

  loadSystemlib("stream-user-filters");
}

///////////////////////////////////////////////////////////////////////////////
}
Esempio n. 25
0
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////

p_Continuation f_hphp_create_continuation(CStrRef clsname,
                                          CStrRef funcname,
                                          CStrRef origFuncName,
                                          CArrRef args /* = null_array */) {
  throw_fatal("Invalid call hphp_create_continuation");
  return NULL;
}

///////////////////////////////////////////////////////////////////////////////

static StaticString s___cont__("__cont__");

c_Continuation::c_Continuation(Class* cb) :
    ExtObjectData(cb),
    m_label(0),
    m_index(-1LL),
    m_value(Variant::NullInit()),
    m_received(Variant::NullInit()),
    m_origFunc(nullptr) {
  o_subclassData.u16 = 0;
}

c_Continuation::~c_Continuation() {
  ActRec* ar = actRec();

  // The first local is the object itself, and it wasn't increffed at creation
  // time (see createContinuation()). Overwrite its type to exempt it from
  // refcounting here.
  TypedValue* contLocal = frame_local(ar, 0);
  assert(contLocal->m_data.pobj == this);
  contLocal->m_type = KindOfNull;

  if (ar->hasVarEnv()) {
    ar->getVarEnv()->detach(ar);
  } else {
    frame_free_locals_inl(ar, ar->m_func->numLocals());
  }
}

void c_Continuation::t___construct() {}

void c_Continuation::t_update(int64_t label, CVarRef value) {
  m_label = label;
  assert(m_label == label); // check m_label for truncation
  m_value.assignVal(value);
}

Object c_Continuation::t_getwaithandle() {
  if (m_waitHandle.isNull()) {
    c_ContinuationWaitHandle::Create(this);
    assert(!m_waitHandle.isNull());
  }
  return m_waitHandle;
}

int64_t c_Continuation::t_getlabel() {
  return m_label;
}

Variant c_Continuation::t_current() {
  const_assert(false);
  return m_value;
}

int64_t c_Continuation::t_key() {
  startedCheck();
  return m_index;
}

bool c_Continuation::php_sleep(Variant &ret) {
  ret = false;
  return true;
}

void c_Continuation::t_next() {
  const_assert(false);
}

static StaticString s_next("next");
void c_Continuation::t_rewind() {
  this->o_invoke_few_args(s_next, 0);
}

bool c_Continuation::t_valid() {
  const_assert(false);
  return !done();
}

void c_Continuation::t_send(CVarRef v) {
  const_assert(false);
}

void c_Continuation::t_raise(CVarRef v) {
  const_assert(false);
}

String c_Continuation::t_getorigfuncname() {
  static auto const closureName = StringData::GetStaticString("{closure}");
  auto const origName = m_origFunc->isClosureBody() ? closureName
                                                    : m_origFunc->name();
  assert(origName->isStatic());
  return String(const_cast<StringData*>(origName));
}

String c_Continuation::t_getcalledclass() {
  String called_class;

  if (actRec()->hasThis()) {
    called_class = actRec()->getThis()->getVMClass()->name()->data();
  } else if (actRec()->hasClass()) {
    called_class = actRec()->getClass()->name()->data();
  } else {
    called_class = empty_string;
  }

  return called_class;
}

Variant c_Continuation::t___clone() {
  throw_fatal(
      "Trying to clone an uncloneable object of class Continuation");
  return uninit_null();
}

namespace {
  StaticString s_send("send");
  StaticString s_raise("raise");
}

void c_Continuation::call_next() {
  const HPHP::Func* func = m_cls->lookupMethod(s_next.get());
  g_vmContext->invokeContFunc(func, this);
}

void c_Continuation::call_send(TypedValue* v) {
  const HPHP::Func* func = m_cls->lookupMethod(s_send.get());
  g_vmContext->invokeContFunc(func, this, v);
}

void c_Continuation::call_raise(ObjectData* e) {
  assert(e);
  assert(e->instanceof(SystemLib::s_ExceptionClass));

  const HPHP::Func* func = m_cls->lookupMethod(s_raise.get());

  TypedValue arg;
  arg.m_type = KindOfObject;
  arg.m_data.pobj = e;

  g_vmContext->invokeContFunc(func, this, &arg);
}

///////////////////////////////////////////////////////////////////////////////

c_DummyContinuation::c_DummyContinuation(Class* cb) :
  ExtObjectData(cb) {
}

c_DummyContinuation::~c_DummyContinuation() {}

void c_DummyContinuation::t___construct() {
}

Variant c_DummyContinuation::t_current() {
  throw_fatal("Tring to use a DummyContinuation");
  return uninit_null();
}

int64_t c_DummyContinuation::t_key() {
  throw_fatal("Tring to use a DummyContinuation");
  return 0;
}

void c_DummyContinuation::t_next() {
  throw_fatal("Tring to use a DummyContinuation");
}

void c_DummyContinuation::t_rewind() {
  throw_fatal("Tring to use a DummyContinuation");
}

bool c_DummyContinuation::t_valid() {
  throw_fatal("Tring to use a DummyContinuation");
  return false;
}

///////////////////////////////////////////////////////////////////////////////
}
Esempio n. 26
0
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////

namespace {

size_t getMemSize(const TypedValue* tv) {
  const auto& v = tvAsCVarRef(tv);
  auto type = v.getType();
  if (!IS_REFCOUNTED_TYPE(type)) {
    return sizeof(Variant);
  }
  if (type == KindOfString) {
    return getMemSize(v.getStringData());
  }
  if (type == KindOfArray) {
    return getMemSize(v.getArrayData());
  }
  assert(!"Unsupported Variant type for getMemSize()");
  return 0;
}

}

size_t getMemSize(const APCHandle* handle) {
  auto t = handle->getType();
  if (!IS_REFCOUNTED_TYPE(t)) {
    return sizeof(APCHandle);
  }
  if (t == KindOfString) {
    if (handle->isUncounted()) {
      return sizeof(APCTypedValue) +
             getMemSize(APCTypedValue::fromHandle(handle)->getStringData());
    }
    return getMemSize(APCString::fromHandle(handle));
  }
  if (t == KindOfArray) {
    if (handle->isSerializedArray()) {
      return getMemSize(APCString::fromHandle(handle));
    }
    if (handle->isUncounted()) {
      return sizeof(APCTypedValue) +
             getMemSize(APCTypedValue::fromHandle(handle)->getArrayData());
    }
    return getMemSize(APCArray::fromHandle(handle));
  }
  if (t == KindOfObject) {
    if (handle->isCollection()) {
      return getMemSize(APCCollection::fromHandle(handle));
    }
    if (handle->isObj()) {
      return getMemSize(APCObject::fromHandle(handle));
    }
    return getMemSize(APCString::fromHandle(handle));
  }

  assert(!"Unsupported APCHandle Type in getMemSize");
  return 0;
}

size_t getMemSize(const APCArray* arr) {
  auto memSize = sizeof(APCArray);
  auto size = arr->size();
  if (arr->isPacked()) {
    memSize += sizeof(APCHandle*) * size;
    for (auto i = 0; i < size; i++) {
      memSize += getMemSize(arr->getValue(i));
    }
  } else {
    memSize += sizeof(int) * (arr->m.m_capacity_mask + 1) +
               sizeof(APCArray::Bucket) * size;
    auto b = arr->buckets();
    for (auto i = 0; i < size; i++) {
      memSize += getMemSize(b[i].key);
      memSize += getMemSize(b[i].val);
    }
  }
  return memSize;
}

size_t getMemSize(const APCObject* obj) {
  auto size = sizeof(APCObject) +
              sizeof(APCObject::Prop) * obj->m_propCount;
  auto prop = obj->props();
  auto const propEnd = prop + obj->m_propCount;
  // we don't add property names and class names (or Class*) in Prop
  // assuming that is static data not owned or accounted by the APCObject
  for (; prop != propEnd; ++prop) {
    if (prop->val) size += getMemSize(prop->val);
  }
  return size;
}

inline
size_t getMemSize(const APCCollection* obj) {
  return sizeof(APCCollection) + obj->m_size;
}

size_t getMemSize(const ArrayData* arr) {
  switch (arr->kind()) {
  case ArrayData::ArrayKind::kPackedKind: {
    auto size = sizeof(ArrayData) +
      (packedCodeToCap(arr->m_packedCapCode) - arr->m_size) *
      sizeof(TypedValue);
    auto const values = reinterpret_cast<const TypedValue*>(arr + 1);
    auto const last = values + arr->m_size;
    for (auto ptr = values; ptr != last; ++ptr) {
      size += getMemSize(ptr);
    }
    return size;
  }
  case ArrayData::ArrayKind::kIntMapKind:
  case ArrayData::ArrayKind::kMixedKind: {
    auto const mixed = MixedArray::asMixed(arr);
    auto size = sizeof(MixedArray) +
                sizeof(MixedArray::Elm) * (mixed->m_cap - mixed->m_used);
    auto elms = mixed->data();
    auto last = elms + mixed->m_used;
    for (auto ptr = elms; ptr != last; ++ptr) {
      if (MixedArray::isTombstone(ptr->data.m_type)) {
        size += sizeof(MixedArray::Elm);
        continue;
      }
      size += ptr->hasStrKey() ? getMemSize(ptr->skey) : sizeof(int64_t);
      size += getMemSize(&ptr->data);
    }
    return size;
  }
  case ArrayData::ArrayKind::kEmptyKind:
    return sizeof(ArrayData);
  default:
    assert(!"Unsupported Array type in getMemSize");
  }
  return 0;
}

///////////////////////////////////////////////////////////////////////////////

std::unique_ptr<APCStats> APCStats::s_apcStats = nullptr;

void APCStats::Create() {
  s_apcStats = folly::make_unique<APCStats>();
}

APCStats::APCStats() : m_valueSize(nullptr)
                     , m_keySize(nullptr)
                     , m_inFileSize(nullptr)
                     , m_livePrimedSize(nullptr)
                     , m_pendingDeleteSize(nullptr)
                     , m_entries(nullptr)
                     , m_primedEntries(nullptr)
                     , m_livePrimedEntries(nullptr)
                     , m_detailedStats(nullptr) {
  m_valueSize = ServiceData::createTimeseries(
      "apc.value_size", {ServiceData::StatsType::SUM});
  m_keySize = ServiceData::createTimeseries(
      "apc.key_size", {ServiceData::StatsType::SUM});
  m_inFileSize = ServiceData::createTimeseries(
      "apc.in_file_size", {ServiceData::StatsType::SUM});
  m_livePrimedSize = ServiceData::createTimeseries(
      "apc.primed_live_size", {ServiceData::StatsType::SUM});
  m_pendingDeleteSize = ServiceData::createTimeseries(
      "apc.pending_delete_size", {ServiceData::StatsType::SUM});

  m_entries = ServiceData::createCounter("apc.entries");
  m_primedEntries = ServiceData::createCounter("apc.primed_entries");
  m_livePrimedEntries =
      ServiceData::createCounter("apc.primed_live_entries");
  if (RuntimeOption::EnableAPCStats) {
    m_detailedStats = new APCDetailedStats();
  }
}

APCStats::~APCStats() {
  if (m_detailedStats) delete m_detailedStats;
}

std::string APCStats::getStatsInfo() const {
  std::string info("APC info\nValue size: ");
  info += std::to_string(m_valueSize->getSum()) +
          "\nKey size: " +
          std::to_string(m_keySize->getSum()) +
          "\nMapped to file data size: " +
          std::to_string(m_inFileSize->getSum()) +
          "\nIn memory primed data size: " +
          std::to_string(m_livePrimedSize->getSum()) +
          "\nEntries count: " +
          std::to_string(m_entries->getValue()) +
          "\nPrimed entries count: " +
          std::to_string(m_primedEntries->getValue()) +
          "\nIn memory primed entries count: " +
          std::to_string(m_livePrimedEntries->getValue());
  if (apcExtension::UseUncounted) {
    info += "\nPending deletes via treadmill size: " +
            std::to_string(m_pendingDeleteSize->getSum());
  }
  if (m_detailedStats) {
    info += m_detailedStats->getStatsInfo();
  }
  return info + "\n";
}

const StaticString s_entries("entries");
const StaticString s_primedEntries("primed_entries");
const StaticString s_primedLiveEntries("primed_live_entries");
const StaticString s_valuesSize("values_size");
const StaticString s_keysSize("keys_size");
const StaticString s_primedInFileSize("primed_in_file_size");
const StaticString s_primeLiveSize("primed_live_size");
const StaticString s_pendingDeleteSize("pending_delete_size");

void APCStats::collectStats(std::map<const StringData*, int64_t>& stats) const {
  stats.insert(
      std::pair<const StringData*, int64_t>(s_entries.get(),
                                            m_entries->getValue()));
  stats.insert(
      std::pair<const StringData*, int64_t>(s_primedEntries.get(),
                                            m_primedEntries->getValue()));
  stats.insert(
      std::pair<const StringData*, int64_t>(s_primedLiveEntries.get(),
                                            m_livePrimedEntries->getValue()));
  stats.insert(
      std::pair<const StringData*, int64_t>(s_valuesSize.get(),
                                            m_valueSize->getSum()));
  stats.insert(
      std::pair<const StringData*, int64_t>(s_keysSize.get(),
                                            m_keySize->getSum()));
  stats.insert(
      std::pair<const StringData*, int64_t>(s_primedInFileSize.get(),
                                            m_inFileSize->getSum()));
  stats.insert(
      std::pair<const StringData*, int64_t>(s_primeLiveSize.get(),
                                            m_livePrimedSize->getSum()));
  stats.insert(
      std::pair<const StringData*, int64_t>(s_pendingDeleteSize.get(),
                                            m_pendingDeleteSize->getSum()));
  if (m_detailedStats) {
    m_detailedStats->collectStats(stats);
  }
}

APCDetailedStats::APCDetailedStats() : m_uncounted(nullptr)
                                     , m_apcString(nullptr)
                                     , m_uncString(nullptr)
                                     , m_serArray(nullptr)
                                     , m_apcArray(nullptr)
                                     , m_uncArray(nullptr)
                                     , m_serObject(nullptr)
                                     , m_apcObject(nullptr)
                                     , m_apcColl(nullptr)
                                     , m_setValues(nullptr)
                                     , m_delValues(nullptr)
                                     , m_replValues(nullptr)
                                     , m_expValues(nullptr) {
  m_uncounted = ServiceData::createCounter("apc.type_uncounted");
  m_apcString = ServiceData::createCounter("apc.type_apc_string");
  m_uncString = ServiceData::createCounter("apc.type_unc_string");
  m_serArray = ServiceData::createCounter("apc.type_ser_array");
  m_apcArray = ServiceData::createCounter("apc.type_apc_array");
  m_uncArray = ServiceData::createCounter("apc.type_unc_array");
  m_serObject = ServiceData::createCounter("apc.type_ser_object");
  m_apcObject = ServiceData::createCounter("apc.type_apc_object");
  m_apcColl = ServiceData::createCounter("apc.type_apc_collection");

  m_setValues = ServiceData::createCounter("apc.set_values");
  m_delValues = ServiceData::createCounter("apc.deleted_values");
  m_replValues = ServiceData::createCounter("apc.replaced_values");
  m_expValues = ServiceData::createCounter("apc.expired_values");
}

const StaticString s_typeUncounted("type_uncounted");
const StaticString s_typeAPCString("type_apc_string");
const StaticString s_typeUncountedString("type_unc_string");
const StaticString s_typeSerArray("type_ser_array");
const StaticString s_typeAPCArray("type_apc_array");
const StaticString s_typUncountedArray("type_unc_array");
const StaticString s_typeSerObject("type_ser_object");
const StaticString s_typeAPCObject("type_apc_object");
const StaticString s_setValueCount("set_values_count");
const StaticString s_deleteValuesCount("deleted_values_count");
const StaticString s_replacedValueCount("replaced_values_count");
const StaticString s_expiredValueCount("expired_values_count");

std::string APCDetailedStats::getStatsInfo() const {
  return "\nPrimitve and static strings count: " +
         std::to_string(m_uncounted->getValue()) +
         "\nAPC strings count: " +
         std::to_string(m_apcString->getValue()) +
         "\nUncounted strings count: " +
         std::to_string(m_uncString->getValue()) +
         "\nSerialized array count: " +
         std::to_string(m_serArray->getValue()) +
         "\nAPC array count: " +
         std::to_string(m_apcArray->getValue()) +
         "\nUncounted array count: " +
         std::to_string(m_uncArray->getValue()) +
         "\nSerialized object count: " +
         std::to_string(m_serObject->getValue()) +
         "\nAPC object count: " +
         std::to_string(m_apcObject->getValue()) +
         "\add count: " +
         std::to_string(m_setValues->getValue()) +
         "\ndelete count: " +
         std::to_string(m_delValues->getValue()) +
         "\nreplaced count: " +
         std::to_string(m_replValues->getValue()) +
         "\nexpired count: " +
         std::to_string(m_expValues->getValue()) +
         "\n";
}

void APCDetailedStats::collectStats(
    std::map<const StringData*, int64_t>& stats) const {
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeUncounted.get(),
                                              m_uncounted->getValue()));
  stats.insert(
      std::pair<const StringData*, int64_t>(s_typeAPCString.get(),
                                            m_apcString->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeUncountedString.get(),
                                              m_uncString->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeSerArray.get(),
                                              m_serArray->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeAPCArray.get(),
                                              m_apcArray->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typUncountedArray.get(),
                                              m_uncArray->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeSerObject.get(),
                                              m_serObject->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeAPCObject.get(),
                                              m_apcObject->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_setValueCount.get(),
                                              m_setValues->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_deleteValuesCount.get(),
                                              m_delValues->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_replacedValueCount.get(),
                                              m_replValues->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_expiredValueCount.get(),
                                              m_expValues->getValue()));
}

void APCDetailedStats::addAPCValue(APCHandle* handle) {
  m_setValues->increment();
  addType(handle);
}

void APCDetailedStats::updateAPCValue(APCHandle* handle,
                                      APCHandle* oldHandle,
                                      bool expired) {
  removeType(oldHandle);
  addType(handle);
  if (expired) {
    m_expValues->increment();
  } else {
    m_replValues->increment();
  }
}

void APCDetailedStats::removeAPCValue(APCHandle* handle, bool expired) {
  removeType(handle);
  if (expired) {
    m_expValues->increment();
  } else {
    m_delValues->increment();
  }
}

void APCDetailedStats::addType(APCHandle* handle) {
  DataType type = handle->getType();
  assert(!IS_REFCOUNTED_TYPE(type) ||
         type == KindOfString ||
         type == KindOfArray ||
         type == KindOfObject);
  if (!IS_REFCOUNTED_TYPE(type)) {
    m_uncounted->increment();
    return;
  }
  switch (type) {
  case KindOfString:
    if (handle->isUncounted()) {
      m_uncString->increment();
    } else {
      m_apcString->increment();
    }
    return;
  case KindOfArray:
    if (handle->isUncounted()) {
      m_uncArray->increment();
    } else if (handle->isSerializedArray()) {
      m_serArray->increment();
    } else {
      m_apcArray->increment();
    }
    return;
  case KindOfObject:
    if (handle->isCollection()) {
      m_apcColl->increment();
    } else if (handle->isObj()) {
      m_apcObject->increment();
    } else {
      m_serObject->increment();
    }
    return;
  default:
    return;
  }
}

void APCDetailedStats::removeType(APCHandle* handle) {
  DataType type = handle->getType();
  assert(!IS_REFCOUNTED_TYPE(type) ||
         type == KindOfString ||
         type == KindOfArray ||
         type == KindOfObject);
  if (!IS_REFCOUNTED_TYPE(type)) {
    m_uncounted->decrement();
    return;
  }
  switch (type) {
  case KindOfString:
    if (handle->isUncounted()) {
      m_uncString->decrement();
    } else {
      m_apcString->decrement();
    }
    return;
  case KindOfArray:
    if (handle->isUncounted()) {
      m_uncArray->decrement();
    } else if (handle->isSerializedArray()) {
      m_serArray->decrement();
    } else {
      m_apcArray->decrement();
    }
    return;
  case KindOfObject:
    if (handle->isCollection()) {
      m_apcColl->decrement();
    } else  if (handle->isObj()) {
      m_apcObject->decrement();
    } else {
      m_serObject->decrement();
    }
    return;
  default:
    return;
  }
}

///////////////////////////////////////////////////////////////////////////////

}
Esempio n. 27
0
namespace Transl {

//////////////////////////////////////////////////////////////////////

ArrayData* addElemIntKeyHelper(ArrayData* ad,
                               int64_t key,
                               TypedValue value) {
  // this does not re-enter
  // set will decRef any old value that may have been overwritten
  // if appropriate
  ArrayData* retval = ad->set(key, tvAsCVarRef(&value),
                              ad->getCount() > 1);
  // TODO Task #1970153: It would be great if there were set()
  // methods that didn't bump up the refcount so that we didn't
  // have to decrement it here
  tvRefcountedDecRef(&value);
  return arrayRefShuffle<false>(ad, retval, nullptr);
}

ArrayData* addElemStringKeyHelper(ArrayData* ad,
                                  StringData* key,
                                  TypedValue value) {
  // this does not re-enter
  bool copy = ad->getCount() > 1;
  // set will decRef any old value that may have been overwritten
  // if appropriate
  int64_t intkey;
  ArrayData* retval = UNLIKELY(key->isStrictlyInteger(intkey)) ?
                      ad->set(intkey, tvAsCVarRef(&value), copy) :
                      ad->set(key, tvAsCVarRef(&value), copy);
  // TODO Task #1970153: It would be great if there were set()
  // methods that didn't bump up the refcount so that we didn't
  // have to decrement it here
  tvRefcountedDecRef(&value);
  return arrayRefShuffle<false>(ad, retval, nullptr);
}

ArrayData* array_add(ArrayData* a1, ArrayData* a2) {
  if (!a2->empty()) {
    if (a1->empty()) {
      decRefArr(a1);
      return a2;
    }
    if (a1 != a2) {
      ArrayData *escalated = a1->plus(a2, a1->getCount() > 1);
      if (escalated != a1) {
        escalated->incRefCount();
        decRefArr(a2);
        decRefArr(a1);
        return escalated;
      }
    }
  }
  decRefArr(a2);
  return a1;
}

HOT_FUNC_VM void setNewElem(TypedValue* base, Cell val) {
  SetNewElem<false>(base, &val);
}

HOT_FUNC_VM void setNewElemArray(TypedValue* base, Cell val) {
  SetNewElemArray(base, &val);
}

void bindNewElemIR(TypedValue* base, RefData* val, MInstrState* mis) {
  base = NewElem(mis->tvScratch, mis->tvRef, base);
  if (!(base == &mis->tvScratch && base->m_type == KindOfUninit)) {
    tvBindRef(val, base);
  }
}

// TODO: Kill this #2031980
HOT_FUNC_VM RefData* box_value(TypedValue tv) {
  return tvBoxHelper(tv.m_type, tv.m_data.num);
}

inline int64_t reinterpretDblAsInt(double d) {
  union {
    int64_t intval;
    double dblval;
  } u;
  u.dblval = d;
  return u.intval;
}

inline double reinterpretIntAsDbl(int64_t i) {
  union {
    int64_t intval;
    double dblval;
  } u;
  u.intval = i;
  return u.dblval;
}

ArrayData* convCellToArrHelper(TypedValue tv) {
  // Note: the call sites of this function all assume that
  // no user code will run and no recoverable exceptions will
  // occur while running this code. This seems trivially true
  // in all cases but converting objects to arrays. It also
  // seems true for that case as well, since the resulting array
  // is essentially metadata for the object. If that is not true,
  // you might end up looking at this code in a debugger and now
  // you know why.
  tvCastToArrayInPlace(&tv); // consumes a ref on counted values
  return tv.m_data.parr;
}

int64_t convArrToBoolHelper(const ArrayData* a) {
  return a->size() != 0;
}

int64_t convObjToBoolHelper(const ObjectData* o) {
  return o->o_toBoolean();
}

int64_t convArrToDblHelper(ArrayData* a) {
  return reinterpretDblAsInt(a->empty() ? 0 : 1);
}

int64_t convStrToDblHelper(const StringData* s) {
  return reinterpretDblAsInt(s->toDouble());
}

int64_t convCellToDblHelper(TypedValue tv) {
  return reinterpretDblAsInt(tvCastToDouble(&tv));
}

int64_t convArrToIntHelper(ArrayData* a) {
  return a->empty() ? 0 : 1;
}

ObjectData* convCellToObjHelper(TypedValue tv) {
  // Note: the call sites of this function all assume that
  // no user code will run and no recoverable exceptions will
  // occur while running this code. This seems trivially true
  // in all cases but converting arrays to objects. It also
  // seems true for that case as well, since the source array
  // is essentially metadata for the object. If that is not true,
  // you might end up looking at this code in a debugger and now
  // you know why.
  tvCastToObjectInPlace(&tv); // consumes a ref on counted values
  return tv.m_data.pobj;
}

StringData* convDblToStrHelper(int64_t i) {
  double d = reinterpretIntAsDbl(i);
  auto r = buildStringData(d);
  r->incRefCount();
  return r;
}

StringData* convIntToStrHelper(int64_t i) {
  auto r = buildStringData(i);
  r->incRefCount();
  return r;
}

StringData* convObjToStrHelper(ObjectData* o) {
  auto s = o->invokeToString();
  auto r = s.get();
  if (!r->isStatic()) r->incRefCount();
  return r;
}

StringData* convResToStrHelper(ResourceData* o) {
  auto s = o->o_toString();
  auto r = s.get();
  if (!r->isStatic()) r->incRefCount();
  return r;
}

const StaticString
  s_empty(""),
  s_1("1"),
  s_Array("Array");

StringData* convCellToStrHelper(TypedValue tv) {
  switch (tv.m_type) {
  case KindOfUninit:
  case KindOfNull:     return s_empty.get();
  case KindOfBoolean:  return tv.m_data.num ? s_1.get() : s_empty.get();
  case KindOfInt64:    return convIntToStrHelper(tv.m_data.num);
  case KindOfDouble:   return convDblToStrHelper(tv.m_data.num);
  case KindOfString:   tv.m_data.pstr->incRefCount();
                       /* fallthrough */
  case KindOfStaticString:
                       return tv.m_data.pstr;
  case KindOfArray:    return s_Array.get();
  case KindOfObject:   return convObjToStrHelper(tv.m_data.pobj);
  case KindOfResource: return convResToStrHelper(tv.m_data.pres);
  default:             not_reached();
  }
}

void raisePropertyOnNonObject() {
  raise_warning("Cannot access property on non-object");
}

void raiseUndefProp(ObjectData* base, const StringData* name) {
  base->raiseUndefProp(name);
}

void raise_error_sd(const StringData *msg) {
  raise_error("%s", msg->data());
}

void VerifyParamTypeFail(int paramNum) {
  VMRegAnchor _;
  const ActRec* ar = liveFrame();
  const Func* func = ar->m_func;
  const TypeConstraint& tc = func->params()[paramNum].typeConstraint();
  TypedValue* tv = frame_local(ar, paramNum);
  assert(!tc.check(tv, func));
  tc.verifyFail(func, paramNum, tv);
}

void VerifyParamTypeCallable(TypedValue value, int param) {
  if (UNLIKELY(!f_is_callable(tvAsCVarRef(&value)))) {
    VerifyParamTypeFail(param);
  }
}

HOT_FUNC_VM
void VerifyParamTypeSlow(const Class* cls,
                         const Class* constraint,
                         int param,
                         const TypeConstraint* expected) {
  if (LIKELY(constraint && cls->classof(constraint))) {
    return;
  }

  // Check a typedef for a class.  We interp'd if the param wasn't an
  // object, so if it's a typedef for something non-objecty we're
  // failing anyway.
  if (auto namedEntity = expected->namedEntity()) {
    auto def = namedEntity->getCachedTypedef();
    if (UNLIKELY(!def)) {
      VMRegAnchor _;
      String nameStr(const_cast<StringData*>(expected->typeName()));
      if (AutoloadHandler::s_instance->autoloadType(nameStr)) {
        def = namedEntity->getCachedTypedef();
      }
    }
    if (def) {
      // There's no need to handle nullable typedefs specially here:
      // we already know we're checking a non-null object with the
      // class `cls'.  We do however need to check for typedefs to
      // mixed.
      if (def->kind == KindOfObject) {
        constraint = def->klass;
        if (constraint && cls->classof(constraint)) return;
      } else if (def->kind == KindOfAny) {
        return;
      }
    }
  }

  VerifyParamTypeFail(param);
}

RefData* closureStaticLocInit(StringData* name, ActRec* fp, TypedValue val) {
  auto const func = fp->m_func;
  assert(func->isClosureBody() || func->isGeneratorFromClosure());
  auto const closureLoc =
    LIKELY(func->isClosureBody())
      ? frame_local(fp, func->numParams())
      : frame_local(fp, frame_continuation(fp)->m_origFunc->numParams());

  bool inited;
  auto const refData = lookupStaticFromClosure(
    closureLoc->m_data.pobj, name, inited);
  if (!inited) {
    cellCopy(val, *refData->tv());
  }
  refData->incRefCount();
  return refData;
}

HOT_FUNC_VM
bool instanceOfHelper(const Class* objClass,
                      const Class* testClass) {
  return testClass && objClass->classof(testClass);
}

ALWAYS_INLINE
static int64_t ak_exist_string_impl(ArrayData* arr, StringData* key) {
  int64_t n;
  if (key->isStrictlyInteger(n)) {
    return arr->exists(n);
  }
  return arr->exists(key);
}

HOT_FUNC_VM
int64_t ak_exist_string(ArrayData* arr, StringData* key) {
  return ak_exist_string_impl(arr, key);
}

HOT_FUNC_VM
int64_t ak_exist_int(ArrayData* arr, int64_t key) {
  bool res = arr->exists(key);
  return res;
}

HOT_FUNC_VM
int64_t ak_exist_string_obj(ObjectData* obj, StringData* key) {
  if (obj->isCollection()) {
    return collectionOffsetContains(obj, key);
  }
  CArrRef arr = obj->o_toArray();
  int64_t res = ak_exist_string_impl(arr.get(), key);
  return res;
}

HOT_FUNC_VM
int64_t ak_exist_int_obj(ObjectData* obj, int64_t key) {
  if (obj->isCollection()) {
    return collectionOffsetContains(obj, key);
  }
  CArrRef arr = obj->o_toArray();
  bool res = arr.get()->exists(key);
  return res;
}

ALWAYS_INLINE
TypedValue& getDefaultIfNullCell(TypedValue* tv, TypedValue& def) {
  if (UNLIKELY(nullptr == tv)) {
    // refcount is already correct since def was never decrefed
    return def;
  }
  tvRefcountedDecRef(&def);
  TypedValue* ret = tvToCell(tv);
  tvRefcountedIncRef(ret);
  return *ret;
}

HOT_FUNC_VM
TypedValue arrayIdxS(ArrayData* a, StringData* key, TypedValue def) {
  return getDefaultIfNullCell(a->nvGet(key), def);
}

HOT_FUNC_VM
TypedValue arrayIdxSi(ArrayData* a, StringData* key, TypedValue def) {
  int64_t i;
  return UNLIKELY(key->isStrictlyInteger(i)) ?
         getDefaultIfNullCell(a->nvGet(i), def) :
         getDefaultIfNullCell(a->nvGet(key), def);
}

HOT_FUNC_VM
TypedValue arrayIdxI(ArrayData* a, int64_t key, TypedValue def) {
  return getDefaultIfNullCell(a->nvGet(key), def);
}

HOT_FUNC_VM
TypedValue* ldGblAddrHelper(StringData* name) {
  return g_vmContext->m_globalVarEnv->lookup(name);
}

HOT_FUNC_VM
TypedValue* ldGblAddrDefHelper(StringData* name) {
  TypedValue* r = g_vmContext->m_globalVarEnv->lookupAdd(name);
  decRefStr(name);
  return r;
}

TCA sswitchHelperFast(const StringData* val,
                      const SSwitchMap* table,
                      TCA* def) {
  TCA* dest = table->find(val);
  return dest ? *dest : *def;
}

// TODO(#2031980): clear these out
void tv_release_generic(TypedValue* tv) {
  assert(Transl::tx64->stateIsDirty());
  assert(tv->m_type == KindOfString || tv->m_type == KindOfArray ||
         tv->m_type == KindOfObject || tv->m_type == KindOfResource ||
         tv->m_type == KindOfRef);
  g_destructors[typeToDestrIndex(tv->m_type)](tv->m_data.pref);
}

void tv_release_typed(RefData* pv, DataType dt) {
  assert(Transl::tx64->stateIsDirty());
  assert(dt == KindOfString || dt == KindOfArray ||
         dt == KindOfObject || dt == KindOfResource ||
         dt == KindOfRef);
  g_destructors[typeToDestrIndex(dt)](pv);
}

Cell lookupCnsHelper(const TypedValue* tv,
                     StringData* nm,
                     bool error) {
  assert(tv->m_type == KindOfUninit);

  // Deferred constants such as SID
  if (UNLIKELY(tv->m_data.pref != nullptr)) {
    ClassInfo::ConstantInfo* ci =
      (ClassInfo::ConstantInfo*)(void*)tv->m_data.pref;
    Cell *cns = const_cast<Variant&>(ci->getDeferredValue()).asTypedValue();
    if (LIKELY(cns->m_type != KindOfUninit)) {
      Cell c1;
      cellDup(*cns, c1);
      return c1;
    }
  }

  Cell *cns = nullptr;
  if (UNLIKELY(TargetCache::s_constants().get() != nullptr)) {
    cns = TargetCache::s_constants()->nvGet(nm);
  }
  if (!cns) {
    cns = Unit::loadCns(const_cast<StringData*>(nm));
  }
  if (LIKELY(cns != nullptr)) {
    Cell c1;
    c1.m_type = cns->m_type;
    c1.m_data = cns->m_data;
    return c1;
  }

  // Undefined constants
  if (error) {
    raise_error("Undefined constant '%s'", nm->data());
  } else {
    raise_notice(Strings::UNDEFINED_CONSTANT, nm->data(), nm->data());
    Cell c1;
    c1.m_data.pstr = const_cast<StringData*>(nm);
    c1.m_type = KindOfStaticString;
    return c1;
  }
  not_reached();
}

Cell lookupCnsUHelper(const TypedValue* tv,
                      StringData* nm,
                      StringData* fallback) {
  Cell *cns = nullptr;
  Cell c1;

  // lookup qualified name in thread-local constants
  bool cacheConsts = TargetCache::s_constants().get() != nullptr;
  if (UNLIKELY(cacheConsts)) {
    cns = TargetCache::s_constants()->nvGet(nm);
  }
  if (!cns) {
    cns = Unit::loadCns(const_cast<StringData*>(nm));
  }

  // try cache handle for unqualified name
  if (UNLIKELY(!cns && tv->m_type != KindOfUninit)) {
    cns = const_cast<Cell*>(tv);
  }

  // lookup unqualified name in thread-local constants
  if (UNLIKELY(!cns)) {
    if (UNLIKELY(cacheConsts)) {
      cns = TargetCache::s_constants()->nvGet(fallback);
    }
    if (!cns) {
      cns = Unit::loadCns(const_cast<StringData*>(fallback));
    }
    if (UNLIKELY(!cns)) {
      raise_notice(Strings::UNDEFINED_CONSTANT,
                   fallback->data(), fallback->data());
      c1.m_data.pstr = const_cast<StringData*>(fallback);
      c1.m_type = KindOfStaticString;
    }
  } else {
    c1.m_type = cns->m_type;
    c1.m_data = cns->m_data;
  }
  return c1;
}

void iterFreeHelper(Iter* iter) {
  iter->free();
}

void miterFreeHelper(Iter* iter) {
  iter->mfree();
}

void citerFreeHelper(Iter* iter) {
  iter->cfree();
}

//////////////////////////////////////////////////////////////////////

}}
Esempio n. 28
0
void APCDetailedStats::collectStats(
    std::map<const StringData*, int64_t>& stats) const {
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeUncounted.get(),
                                              m_uncounted->getValue()));
  stats.insert(
      std::pair<const StringData*, int64_t>(s_typeAPCString.get(),
                                            m_apcString->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeUncountedString.get(),
                                              m_uncString->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeSerArray.get(),
                                              m_serArray->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeAPCArray.get(),
                                              m_apcArray->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typUncountedArray.get(),
                                              m_uncArray->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeSerObject.get(),
                                              m_serObject->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_typeAPCObject.get(),
                                              m_apcObject->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_setValueCount.get(),
                                              m_setValues->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_deleteValuesCount.get(),
                                              m_delValues->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_replacedValueCount.get(),
                                              m_replValues->getValue()));
  stats.insert(
        std::pair<const StringData*, int64_t>(s_expiredValueCount.get(),
                                              m_expValues->getValue()));
}
Esempio n. 29
0
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////

using HPHP::JIT::CallerFrame;
using HPHP::JIT::EagerCallerFrame;
using std::string;

const StaticString
  s_internal("internal"),
  s_user("user");

Array f_get_defined_functions() {
  return make_map_array(s_internal, ClassInfo::GetSystemFunctions(),
                     s_user, ClassInfo::GetUserFunctions());
}

bool f_function_exists(const String& function_name,
                       bool autoload /* = true */) {
  return
    function_exists(function_name) ||
    (autoload &&
     AutoloadHandler::s_instance->autoloadFunc(function_name.get()) &&
     function_exists(function_name));
}

const StaticString
  s__invoke("__invoke"),
  s_Closure__invoke("Closure::__invoke"),
  s_colon2("::");

bool f_is_callable(CVarRef 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) {
    CArrRef arr = tv_func->m_data.parr;
    CVarRef clsname = arr.rvalAtRef(int64_t(0));
    CVarRef mthname = arr.rvalAtRef(int64_t(1));
    if (arr.size() != 2 ||
        &clsname == &null_variant ||
        &mthname == &null_variant) {
      name = v.toString();
      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;
}

Variant f_call_user_func(int _argc, CVarRef function,
                         CArrRef _argv /* = null_array */) {
  return vm_call_user_func(function, _argv);
}

Variant f_call_user_func_array(CVarRef function, CVarRef params) {
  return vm_call_user_func(function, params);
}

Variant f_check_user_func_async(CVarRef handles, int timeout /* = -1 */) {
  raise_error("%s is no longer supported", __func__);
  return uninit_null();
}

Variant f_end_user_func_async(CObjRef handle,
                              int default_strategy /*= k_GLOBAL_STATE_IGNORE*/,
                              CVarRef additional_strategies /* = null */) {
  raise_error("%s is no longer supported", __func__);
  return uninit_null();
}

const StaticString
  s_func("func"),
  s_args("args"),
  s_exception("exception"),
  s_ret("ret");

String f_call_user_func_serialized(const String& input) {
  Variant out;
  try {
    Variant in = unserialize_from_string(input);
    out.set(s_ret, vm_call_user_func(in[s_func], in[s_args].toArray()));
  } catch (Object &e) {
    out.set(s_exception, e);
  }
  return f_serialize(out);
}

Variant f_call_user_func_array_rpc(const String& host, int port,
                                   const String& auth,
                                   int timeout, CVarRef function,
                                   CArrRef params) {
  return f_call_user_func_rpc(0, host, port, auth, timeout, function, params);
}

Variant f_call_user_func_rpc(int _argc, const String& host, int port,
                             const String& auth,
                             int timeout, CVarRef function,
                             CArrRef _argv /* = null_array */) {
  std::string shost = host.data();
  if (!RuntimeOption::DebuggerRpcHostDomain.empty()) {
    unsigned int pos = shost.find(RuntimeOption::DebuggerRpcHostDomain);
    if (pos != shost.length() - RuntimeOption::DebuggerRpcHostDomain.size()) {
      shost += RuntimeOption::DebuggerRpcHostDomain;
    }
  }

  std::string url = "http://";
  url += shost;
  url += ":";
  url += boost::lexical_cast<std::string>(port);
  url += "/call_user_func_serialized?auth=";
  url += auth.data();

  Array blob = make_map_array(s_func, function, s_args, _argv);
  String message = f_serialize(blob);

  std::vector<string> headers;
  LibEventHttpClientPtr http = LibEventHttpClient::Get(shost, port);
  if (!http->send(url, headers, timeout < 0 ? 0 : timeout, false,
                  message.data(), message.size())) {
    raise_error("Unable to send RPC request");
    return false;
  }

  int code = http->getCode();
  if (code <= 0) {
    raise_error("Server timed out or unable to find specified URL: %s",
                url.c_str());
    return false;
  }

  int len = 0;
  char *response = http->recv(len);
  String sresponse(response, len, AttachString);
  if (code != 200) {
    raise_error("Internal server error: %d %s", code,
                HttpProtocol::GetReasonString(code));
    return false;
  }

  // This double decoding can be avoided by modifying RPC server to directly
  // take PHP serialization format.
  Variant res = unserialize_from_string(HHVM_FN(json_decode)(sresponse));
  if (!res.isArray()) {
    raise_error("Internal protocol error");
    return false;
  }

  if (res.toArray().exists(s_exception)) {
    throw res[s_exception];
  }
  return res[s_ret];
}

Variant f_forward_static_call_array(CVarRef function, CArrRef params) {
  return f_forward_static_call(0, function, params);
}

Variant f_forward_static_call(int _argc, CVarRef function,
                              CArrRef _argv /* = null_array */) {
  // Setting the bound parameter to true tells vm_call_user_func()
  // propogate the current late bound class
  return vm_call_user_func(function, _argv, true);
}

Variant f_get_called_class() {
  EagerCallerFrame cf;
  ActRec* ar = cf();
  if (ar) {
    if (ar->hasThis()) return Variant(ar->getThis()->o_getClassName());
    if (ar->hasClass()) return Variant(ar->getClass()->preClass()->name());
  }
  return Variant(false);
}

String f_create_function(const String& args, const String& code) {
  return g_vmContext->createFunction(args, code);
}

///////////////////////////////////////////////////////////////////////////////

Variant f_func_get_arg(int arg_num) {
  CallerFrame cf;
  ActRec* ar = cf.actRecForArgs();

  if (ar == NULL) {
    return false;
  }
  if (ar->hasVarEnv() && ar->getVarEnv()->isGlobalScope()) {
    raise_warning(
      "func_get_arg():  Called from the global scope - no function context"
    );
    return false;
  }
  if (arg_num < 0) {
    raise_warning(
      "func_get_arg():  The argument number should be >= 0"
    );
    return false;
  }
  if (arg_num >= ar->numArgs()) {
    raise_warning(
      "func_get_arg():  Argument %d not passed to function", arg_num
    );
    return false;
  }

  const int numParams = ar->m_func->numParams();

  if (arg_num < numParams) {
    // Formal parameter. Value is on the stack.
    TypedValue* loc =
      (TypedValue*)(uintptr_t(ar) - (arg_num + 1) * sizeof(TypedValue));
    return tvAsVariant(loc);
  }

  const int numArgs = ar->numArgs();
  const int extraArgs = numArgs - numParams;

  // Not a formal parameter.  Value is potentially in the
  // ExtraArgs/VarEnv.
  const int extraArgNum = arg_num - numParams;
  if (extraArgNum < extraArgs) {
    return tvAsVariant(ar->getExtraArg(extraArgNum));
  }

  return false;
}

Array hhvm_get_frame_args(const ActRec* ar, int offset) {
  if (ar == NULL) {
    return Array();
  }
  int numParams = ar->m_func->numParams();
  int numArgs = ar->numArgs();

  PackedArrayInit retInit(std::max(numArgs - offset, 0));
  auto local = reinterpret_cast<TypedValue*>(
    uintptr_t(ar) - sizeof(TypedValue)
  );
  local -= offset;
  for (int i = offset; i < numArgs; ++i) {
    if (i < numParams) {
      // This corresponds to one of the function's formal parameters, so it's
      // on the stack.
      retInit.append(tvAsCVarRef(local));
      --local;
    } else {
      // This is not a formal parameter, so it's in the ExtraArgs.
      retInit.append(tvAsCVarRef(ar->getExtraArg(i - numParams)));
    }
  }

  return retInit.toArray();
}

#define FUNC_GET_ARGS_IMPL(offset) do {                                        \
  EagerCallerFrame cf;                                                         \
  ActRec* ar = cf.actRecForArgs();                                             \
  if (ar && ar->hasVarEnv() && ar->getVarEnv()->isGlobalScope()) {             \
    raise_warning(                                                             \
      "func_get_args():  Called from the global scope - no function context"   \
    );                                                                         \
    return false;                                                              \
  }                                                                            \
  return hhvm_get_frame_args(ar, offset);                                      \
} while(0)

Variant f_func_get_args() {
  FUNC_GET_ARGS_IMPL(0);
}

Variant f_hphp_func_slice_args(int offset) {
  if (offset < 0) {
    offset = 0;
  }
  FUNC_GET_ARGS_IMPL(offset);
}

int64_t f_func_num_args() {
  EagerCallerFrame cf;
  ActRec* ar = cf.actRecForArgs();
  if (ar == NULL) {
    return -1;
  }
  if (ar->hasVarEnv() && ar->getVarEnv()->isGlobalScope()) {
    raise_warning(
      "func_num_args():  Called from the global scope - no function context"
    );
    return -1;
  }
  return ar->numArgs();
}

///////////////////////////////////////////////////////////////////////////////

void f_register_postsend_function(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  g_context->registerShutdownFunction(function, _argv,
                                      ExecutionContext::PostSend);
}

void f_register_shutdown_function(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  g_context->registerShutdownFunction(function, _argv,
                                      ExecutionContext::ShutDown);
}

void f_register_cleanup_function(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  g_context->registerShutdownFunction(function, _argv,
                                      ExecutionContext::CleanUp);
}

///////////////////////////////////////////////////////////////////////////////
}
Esempio n. 30
0
  void moduleInit() override {
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_3DES.get(), StaticString("tripledes").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_ARCFOUR.get(), StaticString("arcfour").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_ARCFOUR_IV.get(), StaticString("arcfour-iv").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_BLOWFISH.get(), StaticString("blowfish").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_BLOWFISH_COMPAT.get(), StaticString("blowfish-compat").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_CAST_128.get(), StaticString("cast-128").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_CAST_256.get(), StaticString("cast-256").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_CRYPT.get(), StaticString("crypt").get()
    );
    Native::registerConstant<KindOfInt64>(
      s_MCRYPT_DECRYPT.get(), 1
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_DES.get(), StaticString("des").get()
    );
    Native::registerConstant<KindOfInt64>(
      s_MCRYPT_DEV_RANDOM.get(), RANDOM
    );
    Native::registerConstant<KindOfInt64>(
      s_MCRYPT_DEV_URANDOM.get(), URANDOM
    );
    Native::registerConstant<KindOfInt64>(
      s_MCRYPT_ENCRYPT.get(), 0
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_ENIGNA.get(), StaticString("crypt").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_GOST.get(), StaticString("gost").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_IDEA.get(), StaticString("idea").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_LOKI97.get(), StaticString("loki97").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_MARS.get(), StaticString("mars").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_MODE_CBC.get(), StaticString("cbc").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_MODE_CFB.get(), StaticString("cfb").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_MODE_ECB.get(), StaticString("ecb").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_MODE_NOFB.get(), StaticString("nofb").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_MODE_OFB.get(), StaticString("ofb").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_MODE_STREAM.get(), StaticString("stream").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_PANAMA.get(), StaticString("panama").get()
    );
    Native::registerConstant<KindOfInt64>(
      s_MCRYPT_RAND.get(), RAND
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_RC2.get(), StaticString("rc2").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_RC6.get(), StaticString("rc6").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_RIJNDAEL_128.get(), StaticString("rijndael-128").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_RIJNDAEL_192.get(), StaticString("rijndael-192").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_RIJNDAEL_256.get(), StaticString("rijndael-256").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_SAFER128.get(), StaticString("safer-sk128").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_SAFER64.get(), StaticString("safer-sk64").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_SAFERPLUS.get(), StaticString("saferplus").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_SERPENT.get(), StaticString("serpent").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_SKIPJACK.get(), StaticString("skipjack").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_THREEWAY.get(), StaticString("threeway").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_TRIPLEDES.get(), StaticString("tripledes").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_TWOFISH.get(), StaticString("twofish").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_WAKE.get(), StaticString("wake").get()
    );
    Native::registerConstant<KindOfStaticString>(
      s_MCRYPT_XTEA.get(), StaticString("xtea").get()
    );

    HHVM_FE(mcrypt_module_open);
    HHVM_FE(mcrypt_module_close);
    HHVM_FE(mcrypt_list_algorithms);
    HHVM_FE(mcrypt_list_modes);
    HHVM_FE(mcrypt_module_get_algo_block_size);
    HHVM_FE(mcrypt_module_get_algo_key_size);
    HHVM_FE(mcrypt_module_get_supported_key_sizes);
    HHVM_FE(mcrypt_module_is_block_algorithm_mode);
    HHVM_FE(mcrypt_module_is_block_algorithm);
    HHVM_FE(mcrypt_module_is_block_mode);
    HHVM_FE(mcrypt_module_self_test);
    HHVM_FE(mcrypt_create_iv);
    HHVM_FE(mcrypt_encrypt);
    HHVM_FE(mcrypt_decrypt);
    HHVM_FE(mcrypt_cbc);
    HHVM_FE(mcrypt_cfb);
    HHVM_FE(mcrypt_ecb);
    HHVM_FE(mcrypt_ofb);
    HHVM_FE(mcrypt_get_block_size);
    HHVM_FE(mcrypt_get_cipher_name);
    HHVM_FE(mcrypt_get_iv_size);
    HHVM_FE(mcrypt_get_key_size);
    HHVM_FE(mcrypt_enc_get_algorithms_name);
    HHVM_FE(mcrypt_enc_get_block_size);
    HHVM_FE(mcrypt_enc_get_iv_size);
    HHVM_FE(mcrypt_enc_get_key_size);
    HHVM_FE(mcrypt_enc_get_modes_name);
    HHVM_FE(mcrypt_enc_get_supported_key_sizes);
    HHVM_FE(mcrypt_enc_is_block_algorithm_mode);
    HHVM_FE(mcrypt_enc_is_block_algorithm);
    HHVM_FE(mcrypt_enc_is_block_mode);
    HHVM_FE(mcrypt_enc_self_test);
    HHVM_FE(mcrypt_generic_init);
    HHVM_FE(mcrypt_generic);
    HHVM_FE(mdecrypt_generic);
    HHVM_FE(mcrypt_generic_deinit);
    HHVM_FE(mcrypt_generic_end);

    loadSystemlib();
  }