Exemple #1
0
void Variant::setEvalScalar() {
  switch (m_type) {
  case KindOfString: {
    StringData *pstr = m_data.pstr;
    if (!pstr->isStatic()) {
      StringData *sd = makeStaticString(pstr);
      decRefStr(pstr);
      m_data.pstr = sd;
      assert(m_data.pstr->isStatic());
      m_type = KindOfStaticString;
    }
    break;
  }
  case KindOfArray: {
    ArrayData *parr = m_data.parr;
    if (!parr->isStatic()) {
      ArrayData *ad = ArrayData::GetScalarArray(parr);
      decRefArr(parr);
      m_data.parr = ad;
      assert(m_data.parr->isStatic());
    }
    break;
  }
  case KindOfRef:
    not_reached();
    break;
  case KindOfObject:
  case KindOfResource:
    not_reached(); // object shouldn't be in a scalar array
    break;
  default:
    break;
  }
}
void ZendArray::onSetEvalScalar() {
  for (Bucket *p = m_pListHead; p; p = p->pListNext) {
    StringData *key = p->skey;
    if (p->hasStrKey() && !key->isStatic()) {
      StringData *skey= StringData::GetStaticString(key);
      if (key && key->decRefCount() == 0) {
        DELETE(StringData)(key);
      }
      p->skey = skey;
    }
    p->data.setEvalScalar();
  }
}
Exemple #3
0
Variant::Variant(const String& v) {
  m_type = KindOfString;
  StringData *s = v.get();
  if (s) {
    m_data.pstr = s;
    if (s->isStatic()) {
      m_type = KindOfStaticString;
    } else {
      s->incRefCount();
    }
  } else {
    m_type = KindOfNull;
  }
}
Exemple #4
0
bool register_intercept(const String& name, const Variant& callback,
                        const Variant& data) {
  StringIMap<Variant> &handlers = s_intercept_data->m_intercept_handlers;
  if (!callback.toBoolean()) {
    if (name.empty()) {
      s_intercept_data->m_global_handler.unset();
      StringIMap<Variant> empty;
      handlers.swap(empty);
    } else {
      auto tmp = handlers[name];
      auto it = handlers.find(name);
      if (it != handlers.end()) {
        auto tmp = it->second;
        handlers.erase(it);
      }
    }
    return true;
  }

  EventHook::EnableIntercept();

  Array handler = make_packed_array(callback, data);

  if (name.empty()) {
    s_intercept_data->m_global_handler = handler;
    StringIMap<Variant> empty;
    handlers.swap(empty);
  } else {
    handlers[name] = handler;
  }

  Lock lock(s_mutex);
  if (name.empty()) {
    for (auto& entry : s_registered_flags) {
      flag_maybe_intercepted(entry.second.second);
    }
  } else {
    StringData* sd = name.get();
    if (!sd->isStatic()) {
      sd = makeStaticString(sd);
    }
    auto &entry = s_registered_flags[StrNR(sd)];
    entry.first = true;
    flag_maybe_intercepted(entry.second);
  }

  return true;
}
int32_t ImmutableObj::getSpaceUsage() {
  int32_t size = sizeof(ImmutableObj) + sizeof(Prop) * m_propCount;
  if (!m_cls->isStatic()) {
    size += sizeof(StringData) + m_cls->size();
  }

  for (int i = 0; i < m_propCount; i++) {
    StringData *sd = m_props[i].name;
    if (!sd->isStatic()) {
      size += sizeof(StringData) + sd->size();
    }
    if (m_props[i].val) {
      size += m_props[i].val->getSpaceUsage();
    }
  }
  return size;
}
Exemple #6
0
void Variant::setEvalScalar() {
    switch (m_type) {
    case KindOfUninit:
    case KindOfNull:
    case KindOfBoolean:
    case KindOfInt64:
    case KindOfDouble:
    case KindOfStaticString:
        return;

    case KindOfString: {
        StringData *pstr = m_data.pstr;
        if (!pstr->isStatic()) {
            StringData *sd = makeStaticString(pstr);
            decRefStr(pstr);
            m_data.pstr = sd;
            assert(m_data.pstr->isStatic());
            m_type = KindOfStaticString;
        }
        return;
    }

    case KindOfPersistentArray:
    case KindOfArray: {
        auto parr = m_data.parr;
        if (!parr->isStatic()) {
            auto ad = ArrayData::GetScalarArray(parr);
            assert(ad->isStatic());
            m_data.parr = ad;
            m_type = KindOfPersistentArray;
            decRefArr(parr);
        }
        return;
    }

    case KindOfObject:
    case KindOfResource:
    case KindOfRef:
    case KindOfClass:
        break;
    }
    not_reached();
}
Exemple #7
0
bool register_intercept(const String& name, CVarRef callback, CVarRef data) {
  StringIMap<Variant> &handlers = s_intercept_data->m_intercept_handlers;
  if (!callback.toBoolean()) {
    if (name.empty()) {
      s_intercept_data->m_global_handler.reset();
      handlers.clear();
    } else {
      handlers.erase(name);
    }
    return true;
  }

  EventHook::EnableIntercept();

  Array handler = make_packed_array(callback, data);

  if (name.empty()) {
    s_intercept_data->m_global_handler = handler;
    handlers.clear();
  } else {
    handlers[name] = handler;
  }

  Lock lock(s_mutex);
  if (name.empty()) {
    for (auto& entry : s_registered_flags) {
      flag_maybe_intercepted(entry.second.second);
    }
  } else {
    StringData* sd = name.get();
    if (!sd->isStatic()) {
      sd = makeStaticString(sd);
    }
    auto &entry = s_registered_flags[StrNR(sd)];
    entry.first = true;
    flag_maybe_intercepted(entry.second);
  }

  return true;
}
Exemple #8
0
Variant *get_intercept_handler(CStrRef name, char* flag) {
  TRACE(1, "get_intercept_handler %s flag is %d\n",
        name.get()->data(), (int)*flag);
  if (*flag == -1) {
    Lock lock(s_mutex);
    if (*flag == -1) {
      StringData *sd = name.get();
      if (!sd->isStatic()) {
        sd = StringData::GetStaticString(sd);
      }
      s_registered_flags[StrNR(sd)].push_back(flag);
      *flag = 0;
    }
  }

  Variant *handler = get_enabled_intercept_handler(name);
  if (handler == nullptr) {
    return nullptr;
  }
  *flag = 1;
  return handler;
}
void ImmutableObj::getSizeStats(SharedVariantStats *stats) {
  stats->initStats();
  if (m_cls->isStatic()) {
    stats->dataTotalSize += sizeof(ImmutableObj) + sizeof(Prop) * m_propCount;
  } else {
    stats->dataSize += m_cls->size();
    stats->dataTotalSize += sizeof(ImmutableObj) + sizeof(Prop) * m_propCount +
                            sizeof(StringData) + m_cls->size();
  }

  for (int i = 0; i < m_propCount; i++) {
    StringData *sd = m_props[i].name;
    if (!sd->isStatic()) {
      stats->dataSize += sd->size();
      stats->dataTotalSize += sizeof(StringData) + sd->size();
    }
    if (m_props[i].val) {
      SharedVariantStats childStats;
      m_props[i].val->getStats(&childStats);
      stats->addChildStats(&childStats);
    }
  }
}
Exemple #10
0
Variant *get_intercept_handler(const String& name, char* flag) {
  TRACE(1, "get_intercept_handler %s flag is %d\n",
        name.get()->data(), (int)*flag);
  if (*flag == -1) {
    Lock lock(s_mutex);
    if (*flag == -1) {
      StringData *sd = name.get();
      if (!sd->isStatic()) {
        sd = makeStaticString(sd);
      }
      auto &entry = s_registered_flags[StrNR(sd)];
      entry.second.push_back(flag);
      *flag = entry.first;
    }
    if (!*flag) return nullptr;
  }

  Variant *handler = get_enabled_intercept_handler(name);
  if (handler == nullptr) {
    return nullptr;
  }
  assert(*flag);
  return handler;
}
void Variant::setEvalScalar() {
  switch (m_type) {
    DT_UNCOUNTED_CASE:
      return;

    case KindOfString: {
      StringData *pstr = m_data.pstr;
      if (!pstr->isStatic()) {
        StringData *sd = makeStaticString(pstr);
        decRefStr(pstr);
        m_data.pstr = sd;
        assert(m_data.pstr->isStatic());
        m_type = KindOfStaticString;
      }
      return;
    }

    case KindOfArray: {
      ArrayData *parr = m_data.parr;
      if (!parr->isStatic()) {
        ArrayData *ad = ArrayData::GetScalarArray(parr);
        decRefArr(parr);
        m_data.parr = ad;
        assert(m_data.parr->isStatic());
      }
      return;
    }

    case KindOfObject:
    case KindOfResource:
    case KindOfRef:
    case KindOfClass:
      break;
  }
  not_reached();
}
Exemple #12
0
APCHandle::Pair APCHandle::Create(const Variant& source,
                                  bool serialized,
                                  APCHandleLevel level,
                                  bool unserializeObj) {

  auto type = source.getType(); // this gets rid of the ref, if it was one
  switch (type) {
    case KindOfUninit: {
      auto value = APCTypedValue::tvUninit();
      return {value->getHandle(), sizeof(APCTypedValue)};
    }
    case KindOfNull: {
      auto value = APCTypedValue::tvNull();
      return {value->getHandle(), sizeof(APCTypedValue)};
    }
    case KindOfBoolean: {
      auto value = source.getBoolean() ? APCTypedValue::tvTrue()
                                       : APCTypedValue::tvFalse();
      return {value->getHandle(), sizeof(APCTypedValue)};
    }
    case KindOfInt64: {
      auto value = new APCTypedValue(source.getInt64());
      return {value->getHandle(), sizeof(APCTypedValue)};
    }
    case KindOfDouble: {
      auto value = new APCTypedValue(source.getDouble());
      return {value->getHandle(), sizeof(APCTypedValue)};
    }
    case KindOfPersistentString:
    case KindOfString: {
      StringData* s = source.getStringData();
      if (serialized) {
        // It is priming, and there might not be the right class definitions
        // for unserialization.
        return APCString::MakeSerializedObject(apc_reserialize(String{s}));
      }
      if (s->isStatic()) {
        auto value = new APCTypedValue(APCTypedValue::StaticStr{}, s);
        return APCHandle::Pair{value->getHandle(), sizeof(APCTypedValue)};
      }
      auto const st = lookupStaticString(s);
      if (st) {
        auto value = new APCTypedValue(APCTypedValue::StaticStr{}, st);
        return {value->getHandle(), sizeof(APCTypedValue)};
      }
      if (apcExtension::UseUncounted) {
        auto st = StringData::MakeUncounted(s->slice());
        auto value = new APCTypedValue(APCTypedValue::UncountedStr{}, st);
        return {value->getHandle(), st->size() + sizeof(APCTypedValue)};
      }
      return APCString::MakeSharedString(s);
    }

    case KindOfPersistentVec:
    case KindOfVec: {
      auto ad = source.getArrayData();
      assert(ad->isVecArray());
      if (ad->isStatic()) {
        auto value = new APCTypedValue(APCTypedValue::StaticVec{}, ad);
        return {value->getHandle(), sizeof(APCTypedValue)};
      }

      return APCArray::MakeSharedVec(ad, level, unserializeObj);
    }

    case KindOfPersistentDict:
    case KindOfDict: {
      auto ad = source.getArrayData();
      assert(ad->isDict());
      if (ad->isStatic()) {
        auto value = new APCTypedValue(APCTypedValue::StaticDict{}, ad);
        return {value->getHandle(), sizeof(APCTypedValue)};
      }

      return APCArray::MakeSharedDict(ad, level, unserializeObj);
    }

    case KindOfPersistentKeyset:
    case KindOfKeyset: {
      auto ad = source.getArrayData();
      assert(ad->isKeyset());
      if (ad->isStatic()) {
        auto value = new APCTypedValue(APCTypedValue::StaticKeyset{}, ad);
        return {value->getHandle(), sizeof(APCTypedValue)};
      }

      return APCArray::MakeSharedKeyset(ad, level, unserializeObj);
    }

    case KindOfPersistentArray:
    case KindOfArray: {
      auto ad = source.getArrayData();
      assert(ad->isPHPArray());
      if (ad->isStatic()) {
        auto value = new APCTypedValue(APCTypedValue::StaticArr{}, ad);
        return {value->getHandle(), sizeof(APCTypedValue)};
      }

      return APCArray::MakeSharedArray(ad, level, unserializeObj);
    }

    case KindOfObject:
      if (source.getObjectData()->isCollection()) {
        return APCCollection::Make(source.getObjectData(),
                                   level,
                                   unserializeObj);
      }
      return unserializeObj ? APCObject::Construct(source.getObjectData()) :
             APCString::MakeSerializedObject(apc_serialize(source));

    case KindOfResource:
      // TODO Task #2661075: Here and elsewhere in the runtime, we convert
      // Resources to the empty array during various serialization operations,
      // which does not match Zend behavior. We should fix this.
      return APCArray::MakeSharedEmptyArray();

    case KindOfRef:
    case KindOfClass:
      return {nullptr, 0};
  }
  not_reached();
}
Exemple #13
0
APCHandle* APCHandle::Create(const Variant& source,
                             size_t& size,
                             bool serialized,
                             bool inner /* = false */,
                             bool unserializeObj /* = false */) {
  auto type = source.getType(); // this gets rid of the ref, if it was one
  switch (type) {
    case KindOfBoolean: {
      auto value = new APCTypedValue(type,
          static_cast<int64_t>(source.getBoolean()));
      size = sizeof(APCTypedValue);
      return value->getHandle();
    }
    case KindOfInt64: {
      auto value = new APCTypedValue(type, source.getInt64());
      size = sizeof(APCTypedValue);
      return value->getHandle();
    }
    case KindOfDouble: {
      auto value = new APCTypedValue(type, source.getDouble());
      size = sizeof(APCTypedValue);
      return value->getHandle();
    }
    case KindOfUninit:
    case KindOfNull: {
      auto value = new APCTypedValue(type);
      size = sizeof(APCTypedValue);
      return value->getHandle();
    }

    case KindOfStaticString: {
      if (serialized) goto StringCase;

      auto value = new APCTypedValue(type, source.getStringData());
      size = sizeof(APCTypedValue);
      return value->getHandle();
    }
StringCase:
    case KindOfString: {
      StringData* s = source.getStringData();
      if (serialized) {
        // It is priming, and there might not be the right class definitions
        // for unserialization.
        return APCObject::MakeShared(apc_reserialize(s), size);
      }

      auto const st = lookupStaticString(s);
      if (st) {
        APCTypedValue* value = new APCTypedValue(KindOfStaticString, st);
        size = sizeof(APCTypedValue);
        return value->getHandle();
      }

      assert(!s->isStatic()); // would've been handled above
      if (!inner && apcExtension::UseUncounted) {
        StringData* st = StringData::MakeUncounted(s->slice());
        APCTypedValue* value = new APCTypedValue(st);
        size = sizeof(APCTypedValue) + st->size();
        return value->getHandle();
      }
      return APCString::MakeShared(type, s, size);
    }

    case KindOfArray:
      return APCArray::MakeShared(source.getArrayData(),
                                  size,
                                  inner,
                                  unserializeObj);

    case KindOfResource:
      // TODO Task #2661075: Here and elsewhere in the runtime, we convert
      // Resources to the empty array during various serialization operations,
      // which does not match Zend behavior. We should fix this.
      size = sizeof(APCArray);
      return APCArray::MakeShared();

    case KindOfObject:
      return unserializeObj ?
          APCObject::Construct(source.getObjectData(), size) :
          APCObject::MakeShared(apc_serialize(source), size);

    default:
      return nullptr;
  }
}