Array f_get_defined_constants(CVarRef categorize /* = null_variant */) { if (categorize.toBoolean()) { throw NotSupportedException(__func__, "constant categorization not " "supported"); } return StringData::GetConstants(); }
bool Array::more(CVarRef v2) const { if (m_px == NULL || v2.isNull()) { return HPHP::more(toBoolean(), v2.toBoolean()); } if (v2.getType() == KindOfArray) { return v2.toArray().get()->compare(m_px) < 0; } return v2.less(*this); }
bool Array::less(CVarRef v2) const { if (m_px == nullptr || v2.isNull()) { return HPHP::less(toBoolean(), v2.toBoolean()); } if (v2.getType() == KindOfArray) { return m_px->compare(v2.toArray().get()) < 0; } return v2.more(*this); }
static bool HHVM_METHOD(IntlCalendar, roll, int64_t field, CVarRef value) { CAL_FETCH(data, this_, false); CAL_CHECK_FIELD(field, "intlcal_roll"); UErrorCode error = U_ZERO_ERROR; if (value.isBoolean()) { data->calendar()->roll((UCalendarDateFields)field, (UBool)value.toBoolean(), error); } else { data->calendar()->roll((UCalendarDateFields)field, (int32_t)value.toInt64(), error); } if (U_FAILURE(error)) { data->setError(error, "intlcal_roll: Error calling ICU Calendar::roll"); return false; } return true; }
int hphp_ffi_exportVariant(CVarRef v, void** result) { switch (v.getType()) { case KindOfNull: return 0; case KindOfBoolean: *result = (void*)v.toBoolean(); return 1; case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { *result = (void*)v.toInt64(); return 2; } case KindOfDouble: { union { double d; void* p; } u; u.d = v.toDouble(); *result = u.p; return 3; } case LiteralString: *result = (void*)v.getLiteralString(); return 4; case KindOfString: { StringData *sd = v.getStringData(); sd->incRefCount(); *result = (void*)sd; return 5; } case KindOfArray: { ArrayData *ad = v.getArrayData(); ad->incRefCount(); *result = (void*)ad; return 6; } case KindOfObject: { ObjectData *od = v.getObjectData(); od->incRefCount(); *result = (void*)od; return 7; } default: ASSERT(false); return 0; } }
Variant f_assert(CVarRef assertion) { if (!s_option_data->assertActive) return true; Transl::CallerFrame cf; Offset callerOffset; auto const fp = cf(&callerOffset); auto const passed = [&]() -> bool { if (assertion.isString()) { if (RuntimeOption::RepoAuthoritative) { // We could support this with compile-time string literals, // but it's not yet implemented. throw NotSupportedException(__func__, "assert with strings argument in RepoAuthoritative mode"); } return eval_for_assert(fp, assertion.toString()).toBoolean(); } return assertion.toBoolean(); }(); if (passed) return true; if (!s_option_data->assertCallback.isNull()) { auto const unit = fp->m_func->unit(); VectorInit ai(3); ai.add(String(unit->filepath())); ai.add(Variant(unit->getLineNumber(callerOffset))); ai.add(assertion.isString() ? assertion.toString() : String("")); f_call_user_func(1, s_option_data->assertCallback, ai.toArray()); } if (s_option_data->assertWarning) { auto const str = !assertion.isString() ? String("Assertion failed") : concat3("Assertion \"", assertion.toString(), "\" failed"); raise_warning("%s", str.data()); } if (s_option_data->assertBail) { throw Assertion(); } return uninit_null(); }
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; }
bool register_intercept(CStrRef 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 = CREATE_VECTOR2(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 (RegisteredFlagsMap::iterator iter = s_registered_flags.begin(); iter != s_registered_flags.end(); ++iter) { flag_maybe_interrupted(iter->second); } } else { RegisteredFlagsMap::iterator iter = s_registered_flags.find(name); if (iter != s_registered_flags.end()) { flag_maybe_interrupted(iter->second); } } return true; }
bool setOption(long option, CVarRef value) { if (m_cp == NULL) { return false; } m_error_no = CURLE_OK; switch (option) { case CURLOPT_INFILESIZE: case CURLOPT_VERBOSE: case CURLOPT_HEADER: case CURLOPT_NOPROGRESS: case CURLOPT_NOBODY: case CURLOPT_FAILONERROR: case CURLOPT_UPLOAD: case CURLOPT_POST: case CURLOPT_FTPLISTONLY: case CURLOPT_FTPAPPEND: case CURLOPT_NETRC: case CURLOPT_PUT: case CURLOPT_TIMEOUT: #if LIBCURL_VERSION_NUM >= 0x071002 case CURLOPT_TIMEOUT_MS: #endif case CURLOPT_FTP_USE_EPSV: case CURLOPT_LOW_SPEED_LIMIT: case CURLOPT_SSLVERSION: case CURLOPT_LOW_SPEED_TIME: case CURLOPT_RESUME_FROM: case CURLOPT_TIMEVALUE: case CURLOPT_TIMECONDITION: case CURLOPT_TRANSFERTEXT: case CURLOPT_HTTPPROXYTUNNEL: case CURLOPT_FILETIME: case CURLOPT_MAXREDIRS: case CURLOPT_MAXCONNECTS: case CURLOPT_CLOSEPOLICY: case CURLOPT_FRESH_CONNECT: case CURLOPT_FORBID_REUSE: case CURLOPT_CONNECTTIMEOUT: #if LIBCURL_VERSION_NUM >= 0x071002 case CURLOPT_CONNECTTIMEOUT_MS: #endif case CURLOPT_SSL_VERIFYHOST: case CURLOPT_SSL_VERIFYPEER: //case CURLOPT_DNS_USE_GLOBAL_CACHE: not thread-safe when set to true case CURLOPT_NOSIGNAL: case CURLOPT_PROXYTYPE: case CURLOPT_BUFFERSIZE: case CURLOPT_HTTPGET: case CURLOPT_HTTP_VERSION: case CURLOPT_CRLF: case CURLOPT_DNS_CACHE_TIMEOUT: case CURLOPT_PROXYPORT: case CURLOPT_FTP_USE_EPRT: case CURLOPT_HTTPAUTH: case CURLOPT_PROXYAUTH: case CURLOPT_FTP_CREATE_MISSING_DIRS: case CURLOPT_FTPSSLAUTH: case CURLOPT_FTP_SSL: case CURLOPT_UNRESTRICTED_AUTH: case CURLOPT_PORT: case CURLOPT_AUTOREFERER: case CURLOPT_COOKIESESSION: case CURLOPT_TCP_NODELAY: case CURLOPT_IPRESOLVE: case CURLOPT_FOLLOWLOCATION: m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, value.toInt64()); break; case CURLOPT_RETURNTRANSFER: m_write.method = value.toBoolean() ? PHP_CURL_RETURN : PHP_CURL_STDOUT; break; case CURLOPT_BINARYTRANSFER: m_write.type = value.toBoolean() ? PHP_CURL_BINARY : PHP_CURL_ASCII; break; case CURLOPT_PRIVATE: case CURLOPT_URL: case CURLOPT_PROXY: case CURLOPT_USERPWD: case CURLOPT_PROXYUSERPWD: case CURLOPT_RANGE: case CURLOPT_CUSTOMREQUEST: case CURLOPT_USERAGENT: case CURLOPT_FTPPORT: case CURLOPT_COOKIE: case CURLOPT_REFERER: case CURLOPT_INTERFACE: case CURLOPT_KRB4LEVEL: case CURLOPT_EGDSOCKET: case CURLOPT_CAINFO: case CURLOPT_CAPATH: case CURLOPT_SSL_CIPHER_LIST: case CURLOPT_SSLKEY: case CURLOPT_SSLKEYTYPE: case CURLOPT_SSLKEYPASSWD: case CURLOPT_SSLENGINE: case CURLOPT_SSLENGINE_DEFAULT: case CURLOPT_SSLCERTTYPE: case CURLOPT_ENCODING: case CURLOPT_COOKIEJAR: case CURLOPT_SSLCERT: case CURLOPT_RANDOM_FILE: case CURLOPT_COOKIEFILE: { String svalue = value.toString(); #if LIBCURL_VERSION_NUM >= 0x071100 /* Strings passed to libcurl as 'char *' arguments, are copied by the library... NOTE: before 7.17.0 strings were not copied. */ m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, svalue.c_str()); #else char *copystr = strndup(svalue.data(), svalue.size()); m_to_free->str.push_back(copystr); m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, copystr); #endif if (option == CURLOPT_URL) m_url = value; } break; case CURLOPT_FILE: case CURLOPT_INFILE: case CURLOPT_WRITEHEADER: case CURLOPT_STDERR: { if (!value.is(KindOfObject)) { return false; } Object obj = value.toObject(); if (obj.isNull() || obj.getTyped<File>(true) == NULL) { return false; } switch (option) { case CURLOPT_FILE: m_write.fp = obj; m_write.method = PHP_CURL_FILE; break; case CURLOPT_WRITEHEADER: m_write_header.fp = obj; m_write_header.method = PHP_CURL_FILE; break; case CURLOPT_INFILE: m_read.fp = obj; m_emptyPost = false; break; default: { if (obj.getTyped<PlainFile>(true) == NULL) { return false; } FILE *fp = obj.getTyped<PlainFile>()->getStream(); if (!fp) { return false; } m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, fp); break; } } } break; case CURLOPT_WRITEFUNCTION: m_write.callback = value; m_write.method = PHP_CURL_USER; break; case CURLOPT_READFUNCTION: m_read.callback = value; m_read.method = PHP_CURL_USER; m_emptyPost = false; break; case CURLOPT_HEADERFUNCTION: m_write_header.callback = value; m_write_header.method = PHP_CURL_USER; break; case CURLOPT_POSTFIELDS: m_emptyPost = false; if (value.is(KindOfArray) || value.is(KindOfObject)) { Array arr = value.toArray(); curl_httppost *first = NULL; curl_httppost *last = NULL; for (ArrayIter iter(arr); iter; ++iter) { String key = iter.first().toString(); String val = iter.second().toString(); const char *postval = val.data(); /* The arguments after _NAMELENGTH and _CONTENTSLENGTH * must be explicitly cast to long in curl_formadd * use since curl needs a long not an int. */ if (*postval == '@') { ++postval; m_error_no = (CURLcode)curl_formadd (&first, &last, CURLFORM_COPYNAME, key.data(), CURLFORM_NAMELENGTH, (long)key.size(), CURLFORM_FILE, postval, CURLFORM_END); } else { m_error_no = (CURLcode)curl_formadd (&first, &last, CURLFORM_COPYNAME, key.data(), CURLFORM_NAMELENGTH, (long)key.size(), CURLFORM_COPYCONTENTS, postval, CURLFORM_CONTENTSLENGTH,(long)val.size(), CURLFORM_END); } } if (m_error_no != CURLE_OK) { return false; } m_to_free->post.push_back(first); m_error_no = curl_easy_setopt(m_cp, CURLOPT_HTTPPOST, first); } else { String svalue = value.toString(); #if LIBCURL_VERSION_NUM >= 0x071100 /* with curl 7.17.0 and later, we can use COPYPOSTFIELDS, but we have to provide size before */ m_error_no = curl_easy_setopt(m_cp, CURLOPT_POSTFIELDSIZE, svalue.size()); m_error_no = curl_easy_setopt(m_cp, CURLOPT_COPYPOSTFIELDS, svalue.c_str()); #else char *post = strndup(svalue.data(), svalue.size()); m_to_free->str.push_back(post); m_error_no = curl_easy_setopt(m_cp, CURLOPT_POSTFIELDS, post); m_error_no = curl_easy_setopt(m_cp, CURLOPT_POSTFIELDSIZE, svalue.size()); #endif } break; case CURLOPT_HTTPHEADER: case CURLOPT_QUOTE: case CURLOPT_HTTP200ALIASES: case CURLOPT_POSTQUOTE: if (value.is(KindOfArray) || value.is(KindOfObject)) { Array arr = value.toArray(); curl_slist *slist = NULL; for (ArrayIter iter(arr); iter; ++iter) { String key = iter.first().toString(); String val = iter.second().toString(); slist = curl_slist_append(slist, val.c_str()); if (!slist) { raise_warning("Could not build curl_slist"); return false; } } m_to_free->slist.push_back(slist); m_error_no = curl_easy_setopt(m_cp, (CURLoption)option, slist); } else { raise_warning("You must pass either an object or an array with " "the CURLOPT_HTTPHEADER, CURLOPT_QUOTE, " "CURLOPT_HTTP200ALIASES and CURLOPT_POSTQUOTE " "arguments"); return false; } break; case CURLINFO_HEADER_OUT: if (value.toInt64() == 1) { curl_easy_setopt(m_cp, CURLOPT_DEBUGFUNCTION, curl_debug); curl_easy_setopt(m_cp, CURLOPT_DEBUGDATA, (void *)this); curl_easy_setopt(m_cp, CURLOPT_VERBOSE, 1); } else { curl_easy_setopt(m_cp, CURLOPT_DEBUGFUNCTION, NULL); curl_easy_setopt(m_cp, CURLOPT_DEBUGDATA, NULL); curl_easy_setopt(m_cp, CURLOPT_VERBOSE, 0); } break; default: m_error_no = CURLE_FAILED_INIT; throw_invalid_argument("option: %d", option); break; } m_opts.set(int64(option), value); return m_error_no == CURLE_OK; }
SharedVariant::SharedVariant(CVarRef source, bool serialized, bool inner /* = false */, bool unserializeObj /* = false */) : m_count (1), m_shouldCache(false), m_flags(0){ ASSERT(!serialized || source.isString()); m_type = source.getType(); switch (m_type) { case KindOfBoolean: { m_data.num = source.toBoolean(); break; } case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_data.dbl = source.toDouble(); break; } case KindOfStaticString: case KindOfString: { String s = source.toString(); if (serialized) { m_type = KindOfObject; // It is priming, and there might not be the right class definitions // for unserialization. s = apc_reserialize(s); } m_data.str = s->copy(true); break; } case KindOfArray: { ArrayData *arr = source.getArrayData(); if (!inner) { // only need to call hasInternalReference() on the toplevel array PointerSet seen; if (arr->hasInternalReference(seen)) { setSerializedArray(); m_shouldCache = true; String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); break; } } size_t size = arr->size(); if (arr->isVectorData()) { setIsVector(); m_data.vec = new VectorData(size); uint i = 0; for (ArrayIter it(arr); !it.end(); it.next(), i++) { SharedVariant* val = Create(it.secondRef(), false, true, unserializeObj); if (val->m_shouldCache) m_shouldCache = true; m_data.vec->vals[i] = val; } } else { m_data.map = new ImmutableMap(size); for (ArrayIter it(arr); !it.end(); it.next()) { SharedVariant* key = Create(it.first(), false, true, unserializeObj); SharedVariant* val = Create(it.secondRef(), false, true, unserializeObj); if (val->m_shouldCache) m_shouldCache = true; m_data.map->add(key, val); } } break; } case KindOfNull: { m_data.num = 0; break; } default: { ASSERT(source.isObject()); m_shouldCache = true; if (unserializeObj) { // This assumes hasInternalReference(seen, true) is false ImmutableObj* obj = new ImmutableObj(source.getObjectData()); m_data.obj = obj; setIsObj(); } else { String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); } break; } } }
ProcessSharedVariant::ProcessSharedVariant(CVarRef source, ProcessSharedVariantLock* lock) : m_lock(putPtr(lock)) { switch (source.getType()) { case KindOfBoolean: { m_type = KindOfBoolean; m_data.num = source.toBoolean(); break; } case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_type = KindOfDouble; m_data.dbl = source.toDouble(); break; } case LiteralString: case KindOfStaticString: case KindOfString: { String s = source.toString(); m_type = KindOfString; if (lock) { m_data.str = putPtr(SharedMemoryManager::GetSegment() ->construct<SharedMemoryString> (boost::interprocess::anonymous_instance) (s.data(), s.size())); } else { // Just need this string to live long enough for the key lookup so // don't store in shared memory. m_data.str = putPtr(new SharedMemoryString(s.data(), s.size())); } break; } case KindOfArray: { ASSERT(lock); m_type = KindOfArray; uint i = 0; ProcessSharedVariantMapData* mapData = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariantMapData> (boost::interprocess::anonymous_instance)(); m_data.map = putPtr(mapData); ProcessSharedVariantToIntMap* map = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariantToIntMap> (boost::interprocess::anonymous_instance)(); mapData->map = putPtr(map); SharedMemoryVector<SharedVariant*>* keys = SharedMemoryManager::GetSegment() ->construct<SharedMemoryVector<SharedVariant*> > (boost::interprocess::anonymous_instance)(); mapData->keys = putPtr(keys); SharedMemoryVector<SharedVariant*>* vals = SharedMemoryManager::GetSegment() ->construct<SharedMemoryVector<SharedVariant*> > (boost::interprocess::anonymous_instance)(); mapData->vals = putPtr(vals); for (ArrayIterPtr it = source.begin(); !it->end(); it->next()) { ProcessSharedVariant* key = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariant> (boost::interprocess::anonymous_instance) (it->first(), getLock()); ProcessSharedVariant* val = SharedMemoryManager::GetSegment() ->construct<ProcessSharedVariant> (boost::interprocess::anonymous_instance) (it->second(), getLock()); (*map)[key] = i++; keys->push_back(putPtr(key)); vals->push_back(putPtr(val)); } break; } default: { m_type = KindOfObject; String s = f_serialize(source); m_data.str = putPtr(SharedMemoryManager::GetSegment() ->construct<SharedMemoryString> (boost::interprocess::anonymous_instance) (s.data(), s.size())); break; } } }
void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, CVarRef value, CArrRef fieldspec) { // At this point the typeID (and field num, if applicable) should've already // been written to the output so all we need to do is write the payload. switch (thrift_typeID) { case T_STOP: case T_VOID: return; case T_STRUCT: { if (!value.is(KindOfObject)) { throw_tprotocolexception("Attempt to send non-object " "type as a T_STRUCT", INVALID_DATA); } binary_serialize_spec(value.toObject(), transport, f_hphp_get_static_property(value.toObject()-> o_getClassName(), s_TSPEC, false).toArray()); } return; case T_BOOL: transport.writeI8(value.toBoolean() ? 1 : 0); return; case T_BYTE: transport.writeI8(value.toByte()); return; case T_I16: transport.writeI16(value.toInt16()); return; case T_I32: transport.writeI32(value.toInt32()); return; case T_I64: case T_U64: transport.writeI64(value.toInt64()); return; case T_DOUBLE: { union { int64_t c; double d; } a; a.d = value.toDouble(); transport.writeI64(a.c); } return; case T_FLOAT: { union { int32_t c; float d; } a; a.d = (float)value.toDouble(); transport.writeI32(a.c); } return; //case T_UTF7: case T_UTF8: case T_UTF16: case T_STRING: { String sv = value.toString(); transport.writeString(sv.data(), sv.size()); } return; case T_MAP: { Array ht = value.toArray(); uint8_t keytype = fieldspec.rvalAt(PHPTransport::s_ktype, AccessFlags::Error_Key).toByte(); transport.writeI8(keytype); uint8_t valtype = fieldspec.rvalAt(PHPTransport::s_vtype, AccessFlags::Error_Key).toByte(); transport.writeI8(valtype); Array valspec = fieldspec.rvalAt(PHPTransport::s_val, AccessFlags::Error_Key).toArray(); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize_hashtable_key(keytype, transport, key_ptr.first()); binary_serialize(valtype, transport, key_ptr.second(), valspec); } } return; case T_LIST: { Array ht = value.toArray(); Variant val; uint8_t valtype = fieldspec.rvalAt(PHPTransport::s_etype, AccessFlags::Error_Key).toInt64(); transport.writeI8(valtype); Array valspec = fieldspec.rvalAt(PHPTransport::s_elem, AccessFlags::Error_Key).toArray(); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize(valtype, transport, key_ptr.second(), valspec); } } return; case T_SET: { Array ht = value.toArray(); uint8_t keytype = fieldspec.rvalAt(PHPTransport::s_etype, AccessFlags::Error_Key).toByte(); transport.writeI8(keytype); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize_hashtable_key(keytype, transport, key_ptr.first()); } } return; }; char errbuf[128]; sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID); throw_tprotocolexception(String(errbuf, CopyString), INVALID_DATA); }
ThreadSharedVariant::ThreadSharedVariant(CVarRef source, bool serialized, bool inner /* = false */) { ASSERT(!serialized || source.isString()); setOwner(); m_ref = 1; switch (source.getType()) { case KindOfBoolean: { m_type = KindOfBoolean; m_data.num = source.toBoolean(); break; } case KindOfByte: case KindOfInt16: case KindOfInt32: case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_type = KindOfDouble; m_data.dbl = source.toDouble(); break; } case KindOfStaticString: case KindOfString: { String s = source.toString(); m_type = serialized ? KindOfObject : KindOfString; if (serialized) { // It is priming, and there might not be the right class definitions // for unserialization. s = apc_reserialize(s); } m_data.str = s->copy(true); break; } case KindOfArray: { m_type = KindOfArray; ArrayData *arr = source.getArrayData(); if (!inner) { // only need to call hasInternalReference() on the toplevel array PointerSet seen; if (arr->hasInternalReference(seen)) { setSerializedArray(); setShouldCache(); String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); break; } } size_t size = arr->size(); if (arr->isVectorData()) { setIsVector(); m_data.vec = new VectorData(size); uint i = 0; for (ArrayIter it(arr); !it.end(); it.next(), i++) { ThreadSharedVariant* val = createAnother(it.second(), false, true); if (val->shouldCache()) setShouldCache(); m_data.vec->vals[i] = val; } } else { m_data.map = new ImmutableMap(size); uint i = 0; for (ArrayIter it(arr); !it.end(); it.next(), i++) { ThreadSharedVariant* key = createAnother(it.first(), false); ThreadSharedVariant* val = createAnother(it.second(), false, true); if (val->shouldCache()) setShouldCache(); m_data.map->add(key, val); } } break; } default: { m_type = KindOfObject; setShouldCache(); String s = apc_serialize(source); m_data.str = new StringData(s.data(), s.size(), CopyString); break; } } }
SharedVariant::SharedVariant(CVarRef source, bool serialized, bool inner /* = false */, bool unserializeObj /* = false */) : m_shouldCache(false), m_flags(0) { assert(!serialized || source.isString()); m_count = 1; m_type = source.getType(); switch (m_type) { case KindOfBoolean: { m_data.num = source.toBoolean(); break; } case KindOfInt64: { m_type = KindOfInt64; m_data.num = source.toInt64(); break; } case KindOfDouble: { m_data.dbl = source.toDouble(); break; } case KindOfStaticString: { if (serialized) goto StringCase; m_data.str = source.getStringData(); break; } StringCase: case KindOfString: { String s = source.toString(); if (serialized) { m_type = KindOfObject; // It is priming, and there might not be the right class definitions // for unserialization. s = apc_reserialize(s); } StringData* st = StringData::LookupStaticString(s.get()); if (st) { m_data.str = st; m_type = KindOfStaticString; break; } m_data.str = s->copy(true); break; } case KindOfArray: { ArrayData *arr = source.getArrayData(); if (!inner) { // only need to call hasInternalReference() on the toplevel array PointerSet seen; if (arr->hasInternalReference(seen)) { setSerializedArray(); m_shouldCache = true; String s = apc_serialize(source); m_data.str = StringData::MakeMalloced(s.data(), s.size()); break; } } if (arr->isVectorData()) { setIsVector(); m_data.vec = new (arr->size()) VectorData(); for (ArrayIter it(arr); !it.end(); it.next()) { SharedVariant* val = Create(it.secondRef(), false, true, unserializeObj); if (val->m_shouldCache) m_shouldCache = true; m_data.vec->vals()[m_data.vec->m_size++] = val; } } else { m_data.map = ImmutableMap::Create(arr, unserializeObj, m_shouldCache); } break; } case KindOfUninit: case KindOfNull: { break; } 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. m_type = KindOfArray; setIsVector(); m_data.vec = new (0) VectorData(); break; } default: { assert(source.isObject()); m_shouldCache = true; if (unserializeObj) { // This assumes hasInternalReference(seen, true) is false ImmutableObj* obj = new ImmutableObj(source.getObjectData()); m_data.obj = obj; setIsObj(); } else { String s = apc_serialize(source); m_data.str = StringData::MakeMalloced(s.data(), s.size()); } break; } } assert(m_type != KindOfResource); }