Variant MethodStatement::MethInvokerFewArgs(MethodCallPackage &mcp, int count, INVOKE_FEW_ARGS_IMPL_ARGS) { const MethodStatementWrapper *msw = (const MethodStatementWrapper*)mcp.extra; const MethodStatement *ms = msw->m_methodStatement; bool check = !ms->m_name->isame(s___invoke.get()); bool isStatic = ms->getModifiers() & ClassStatement::Static; if (isStatic || !mcp.obj) { String cn; if (UNLIKELY(!isStatic && mcp.isObj && mcp.obj == NULL)) { // this is needed for continuations where // we are passed the dummy object cn = ms->getClass()->name(); } else { cn = mcp.getClassName(); } if (ms->refReturn()) { return strongBind(ms->invokeStaticFewArgs(cn, count, INVOKE_FEW_ARGS_PASS_ARGS, msw, check)); } else { return ms->invokeStaticFewArgs(cn, count, INVOKE_FEW_ARGS_PASS_ARGS, msw, check); } } else { if (ms->refReturn()) { return strongBind(ms->invokeInstanceFewArgs(mcp.rootObj, count, INVOKE_FEW_ARGS_PASS_ARGS, msw, check)); } else { return ms->invokeInstanceFewArgs(mcp.rootObj, count, INVOKE_FEW_ARGS_PASS_ARGS, msw, check); } } }
void IniSetting::ParserCallback::makeArray(Variant &hash, const std::string &offset, const std::string &value) { assert(!offset.empty()); Variant val = strongBind(hash); auto start = offset.c_str(); auto p = start; bool last = false; do { String index(p); last = p + index.size() >= start + offset.size(); Variant newval; if (last) { newval = Variant(value); } else { if (val.toArrRef().exists(index)) { newval = val.toArrRef().rvalAt(index); } else { newval = Variant(Array::Create()); } } val.toArrRef().setRef(index, newval); if (!last) { val = strongBind(newval); p += index.size() + 1; } } while (!last); }
Variant IncOpExpression::refval(VariableEnvironment &env, int strict /* = 2 */) const { if (m_front) { return strongBind(eval(env)); } else { return strongBind(Expression::refval(env, strict)); } }
void c_MutableArrayIterator::t___construct(VRefParam array) { if (m_valid) { MArrayIter& mi = marr(); mi.~MArrayIter(); m_valid = false; } Variant var(strongBind(array)); TypedValue* tv = (TypedValue*)(&var); assert(tv->m_type == KindOfRef); TypedValue* rtv = tv->m_data.pref->tv(); if (rtv->m_type == KindOfArray) { MArrayIter& mi = marr(); (void) new (&mi) MArrayIter(tv->m_data.pref); m_valid = mi.advance(); if (!m_valid) mi.~MArrayIter(); } else if (rtv->m_type == KindOfObject) { CStrRef ctxStr = g_vmContext->getContextClassName(); if (rtv->m_data.pobj->isCollection()) { raise_error("Collection elements cannot be taken by reference"); } bool isIterator; Object obj = rtv->m_data.pobj->iterableObject(isIterator); if (isIterator) { raise_error("An iterator cannot be used with foreach by reference"); } Array iterArray = obj->o_toIterArray(ctxStr, true); ArrayData* ad = iterArray.detach(); MArrayIter& mi = marr(); (void) new (&mi) MArrayIter(ad); m_valid = mi.advance(); if (!m_valid) mi.~MArrayIter(); } else { raise_warning("Invalid argument supplied for foreach()"); } }
Variant f_hphp_current_ref(VRefParam array) { if (!array.isArray()) { throw_bad_array_exception(); return false; } return strongBind(array.array_iter_current_ref()); }
bool TestExtMemcached::test_Memcached_cas() { CREATE_MEMCACHED(); for (ArrayIter iter(memc_version); iter; ++iter) { if (!f_version_compare(iter.second().toString(), "1.3.0", ">=")) { SKIP("Need memcached 1.3.0 for CAS"); return Count(true); } } const char *key = "cas_test"; VERIFY(memc->t_set(key, 10, EXPIRATION)); Variant cas; VS(memc->t_get(key, null, strongBind(cas)), 10); VERIFY(!cas.isNull() && cas.isDouble()); VERIFY(memc->t_cas(cas.toDouble(), key, 11, EXPIRATION)); VS(memc->t_get(key, null, cas), 11); VERIFY(!memc->t_cas(cas.toDouble(), key, 12, EXPIRATION)); VS(memc->t_get(key, null, cas), 11); return Count(true); }
Variant c_MutableArrayIterator::t_currentref() { INSTANCE_METHOD_INJECTION_BUILTIN(MutableArrayIterator, MutableArrayIterator::currentref); if (!m_valid) return null; MArrayIter& mi = marr(); if (mi.end()) return null; return strongBind(mi.val()); }
Variant Object::o_argval(bool byRef, CStrRef propName, bool error /* = true */, CStrRef context /* = null_string */) { if (!byRef) { return o_get(propName, error, context); } else { return strongBind(o_lval(propName, context)); } }
Variant Expression::refval(VariableEnvironment &env, int strict /* = 2 */) const { if (strict == 2) { raise_error("Value cannot be used in reference context"); } else if (strict == 1) { raise_notice("Value cannot be used in reference context"); } return strongBind(eval(env)); }
Variant Array::argvalAt(bool byRef, CStrRef key, bool isString /* = false */) const { if (byRef) { return strongBind( const_cast<Array*>(this)->lvalAt(key, AccessFlags::IsKey(isString))); } else { return rvalAtRef(key); } }
Variant MethodStatement::evalBody(VariableEnvironment &env) const { if (isAbstract()) { raise_error("Cannot call abstract method %s()", m_fullName->data()); } if (m_ref) { return strongBind(FunctionStatement::evalBody(env)); } else { return FunctionStatement::evalBody(env); } }
void IniSetting::ParserCallback::makeArray(Variant &hash, const std::string &offset, const std::string &value) { assert(!offset.empty()); Variant val = strongBind(hash); auto start = offset.c_str(); auto p = start; bool last = false; do { String index(p); last = p + index.size() >= start + offset.size(); auto def = Variant(Array::Create()); Variant newval = last ? Variant(value) : val.lvalRef(index, def); val.setRef(index, newval); if (!last) { val = strongBind(newval); p += index.size() + 1; } } while (!last); }
ArrayData *ArrayData::CreateRef(CVarRef value) { if (enable_vector_array && RuntimeOption::UseVectorArray) { VectorArray *va = NEW(VectorArray)(1); va->m_elems[0] = NEW(Variant)(strongBind(value)); va->m_size = 1; va->m_pos = 0; return va; } ArrayInit init(1); init.setRef(value); return init.create(); }
Variant MethodStatement::invokeStatic(CStrRef cls, CArrRef params, const MethodStatementWrapper *msw, bool check /* = true */) const { ASSERT(msw->m_methodStatement == this); if (check) attemptAccess(FrameInjection::GetClassName(false), msw); DECLARE_THREAD_INFO_NOINIT MethScopeVariableEnvironment env(this); env.setCurrentClass(cls); env.setCurrentAlias(get_current_alias()); EvalFrameInjection fi(msw->m_className, m_fullName->data(), env, loc()->file, NULL, FrameInjection::StaticMethod); if (m_ref) { return strongBind(invokeImpl(env, params)); } return invokeImpl(env, params); }
Variant ListAssignmentExpression::eval(VariableEnvironment &env) const { const VariableExpression *v = m_rhs->cast<VariableExpression>(); if (v) { // Rhs has to be taken as lval if a variable in case there are references // to that variable on the lhs. CVarRef rhs(v->lval(env)); Variant tmp(strongBind(rhs)); m_lhs->set(env, tmp); return rhs; } else { Variant rhs(m_rhs->eval(env)); m_lhs->set(env, !m_abnormal || rhs.is(KindOfArray) ? rhs : null_variant); return rhs; } }
Variant MethodStatement::invokeStaticFewArgs(CStrRef cls, int count, INVOKE_FEW_ARGS_IMPL_ARGS, const MethodStatementWrapper *msw, bool check) const { ASSERT(msw->m_methodStatement == this); if (check) attemptAccess(FrameInjection::GetClassName(false), msw); DECLARE_THREAD_INFO_NOINIT MethScopeVariableEnvironment env(this); env.setCurrentClass(cls); env.setCurrentAlias(get_current_alias()); EvalFrameInjection fi(msw->m_className, m_fullName->data(), env, loc()->file, NULL, FrameInjection::StaticMethod); if (m_ref) { return strongBind(invokeImplFewArgs(env, count, INVOKE_FEW_ARGS_PASS_ARGS)); } return invokeImplFewArgs(env, count, INVOKE_FEW_ARGS_PASS_ARGS); }
void c_MutableArrayIterator::t___construct(VRefParam array) { INSTANCE_METHOD_INJECTION_BUILTIN(MutableArrayIterator, MutableArrayIterator::__construct); if (m_valid) { MIterCtx& mi = marr(); mi.~MIterCtx(); m_valid = false; } Variant var(strongBind(array)); TypedValue* tv = (TypedValue*)(&var); ASSERT(tv->m_type == KindOfRef); if (tv->m_data.ptv->m_type == KindOfArray) { ArrayData* ad = tv->m_data.ptv->m_data.parr; if (ad->getCount() > 1) { ArrayData* copy = ad->copy(); copy->incRefCount(); ad->decRefCount(); // count > 1 to begin with; don't need release ad = tv->m_data.ptv->m_data.parr = copy; } MIterCtx& mi = marr(); (void) new (&mi) MIterCtx(tv->m_data.pref); m_valid = mi.m_mArray->advance(); if (!m_valid) mi.~MIterCtx(); } else if (tv->m_data.ptv->m_type == KindOfObject) { CStrRef ctxStr = hhvm ? g_vmContext->getContextClassName(true) : FrameInjection::GetClassName(true); bool isIterator; Object obj = tv->m_data.ptv->m_data.pobj->iterableObject(isIterator); if (isIterator) { raise_error("An iterator cannot be used with foreach by reference"); } Array iterArray = obj->o_toIterArray(ctxStr, true); ArrayData* ad = iterArray.getArrayData(); if (ad->getCount() > 1) { ArrayData* copy = ad->copy(); copy->incRefCount(); ad->decRefCount(); // count > 1 to begin with; don't need release ad = copy; } MIterCtx& mi = marr(); (void) new (&mi) MIterCtx(ad); m_valid = mi.m_mArray->advance(); if (!m_valid) mi.~MIterCtx(); } else { raise_warning("Invalid argument supplied for foreach()"); } }
Variant MethodStatement::invokeInstance(CObjRef obj, CArrRef params, const MethodStatementWrapper *msw, bool check /* = true */) const { ASSERT(msw->m_methodStatement == this); if (getModifiers() & ClassStatement::Static) { return invokeStatic(obj->o_getClassName(), params, msw, check); } if (check) attemptAccess(FrameInjection::GetClassName(false), msw); // The debug frame should have been pushed at ObjectMethodExpression DECLARE_THREAD_INFO_NOINIT MethScopeVariableEnvironment env(this); env.setCurrentObject(obj); env.setCurrentAlias(get_current_alias()); EvalFrameInjection fi(msw->m_className, m_fullName->data(), env, loc()->file, obj.get(), FrameInjection::ObjectMethod); if (m_ref) { return strongBind(invokeImpl(env, params)); } return invokeImpl(env, params); }
bool ZendArray::nextInsertRef(CVarRef data) { if (m_nNextFreeElement < 0) { raise_warning("Cannot add element to the array as the next element is " "already occupied"); return false; } int64 h = m_nNextFreeElement; Bucket * p = NEW(Bucket)(strongBind(data)); p->h = h; uint nIndex = (h & m_nTableMask); CONNECT_TO_BUCKET_LIST(p, m_arBuckets[nIndex]); SET_ARRAY_BUCKET_HEAD(m_arBuckets, nIndex, p); CONNECT_TO_GLOBAL_DLLIST(p); m_nNextFreeElement = h + 1; if (++m_nNumOfElements > m_nTableSize) { resize(); } return true; }
Variant MethodStatement:: invokeStaticDirect(CStrRef cls, CStrRef alias, VariableEnvironment &env, const FunctionCallExpression *caller, bool sp, const MethodStatementWrapper *msw, bool check /* = true */) const { ASSERT(msw->m_methodStatement == this); if (check) attemptAccess(FrameInjection::GetClassName(false), msw); MethScopeVariableEnvironment fenv(this); directBind(env, caller, fenv); fenv.setCurrentClass(cls); fenv.setCurrentAlias(alias); EvalFrameInjection::EvalStaticClassNameHelper helper(cls, sp); DECLARE_THREAD_INFO_NOINIT EvalFrameInjection fi(msw->m_className, m_fullName->data(), fenv, loc()->file, NULL, FrameInjection::StaticMethod); if (m_ref) { return strongBind(evalBody(fenv)); } return evalBody(fenv); }
bool ZendArray::updateRef(StringData *key, CVarRef data) { int64 h = key->hash(); Bucket *p = findForInsert(key->data(), key->size(), h); if (p) { p->data.assignRefHelper(data); return true; } p = NEW(Bucket)(strongBind(data)); p->setStrKey(key, h); uint nIndex = (h & m_nTableMask); CONNECT_TO_BUCKET_LIST(p, m_arBuckets[nIndex]); SET_ARRAY_BUCKET_HEAD(m_arBuckets, nIndex, p); CONNECT_TO_GLOBAL_DLLIST(p); if (++m_size > tableSize()) { resize(); } return true; }
bool ZendArray::updateRef(int64 h, CVarRef data) { Bucket *p = find(h); if (p) { p->data.assignRefHelper(data); return true; } p = NEW(Bucket)(strongBind(data)); p->h = h; uint nIndex = (h & m_nTableMask); CONNECT_TO_BUCKET_LIST(p, m_arBuckets[nIndex]); SET_ARRAY_BUCKET_HEAD(m_arBuckets, nIndex, p); CONNECT_TO_GLOBAL_DLLIST(p); if (h >= m_nNextFreeElement && m_nNextFreeElement >= 0) { m_nNextFreeElement = h + 1; } if (++m_nNumOfElements > m_nTableSize) { resize(); } return true; }
bool ZendArray::updateRef(StringData *key, CVarRef data) { int64 h = key->hash(); Bucket *p = find(key->data(), key->size(), h); if (p) { p->data.assignRefHelper(data); return true; } p = NEW(Bucket)(strongBind(data)); p->key = key; p->key->incRefCount(); p->h = h; uint nIndex = (h & m_nTableMask); CONNECT_TO_BUCKET_LIST(p, m_arBuckets[nIndex]); SET_ARRAY_BUCKET_HEAD(m_arBuckets, nIndex, p); CONNECT_TO_GLOBAL_DLLIST(p); if (++m_nNumOfElements > m_nTableSize) { resize(); } return true; }
Variant MethodStatement:: invokeInstanceDirect(CObjRef obj, CStrRef alias, VariableEnvironment &env, const FunctionCallExpression *caller, const MethodStatementWrapper *msw, bool check /* = true */) const { ASSERT(msw->m_methodStatement == this); if (getModifiers() & ClassStatement::Static) { return invokeStaticDirect(obj->o_getClassName(), alias, env, caller, false, msw, check); } if (check) attemptAccess(FrameInjection::GetClassName(false), msw); DECLARE_THREAD_INFO_NOINIT MethScopeVariableEnvironment fenv(this); directBind(env, caller, fenv); fenv.setCurrentObject(obj); fenv.setCurrentAlias(alias); EvalFrameInjection::EvalStaticClassNameHelper helper(obj); EvalFrameInjection fi(msw->m_className, m_fullName->data(), fenv, loc()->file, obj.get(), FrameInjection::ObjectMethod); if (m_ref) { return strongBind(evalBody(fenv)); } return evalBody(fenv); }
Variant LvalExpression::refval(VariableEnvironment &env, int strict /* = 2 */) const { return strongBind(lval(env)); }
bool TestCppBase::TestVariant() { // operators { Variant v(15); v += 20; VERIFY(v.isNumeric()); VERIFY(v.is(KindOfInt64)); VERIFY(v == Variant(35)); } // conversions { Variant v("123"); VERIFY(v.toInt32() == 123); } // offset { Variant v = "test"; VS(v.rvalAt(0), "t"); } { Variant v; v.lvalAt(0) = String("v0"); v.lvalAt(1) = String("v1"); VERIFY(v[0] == "v0"); VERIFY(v[1] == "v1"); } { Variant v; v.lvalAt() = String("test"); VS(v, CREATE_VECTOR1("test")); } { Variant v; v.lvalAt(1) = String("test"); VS(v[1], "test"); VS(v[1.5], "test"); VS(v[Variant(1.5)], "test"); VS(v[s_1], "test"); VS(v[Variant("1")], "test"); } { Variant v; v.lvalAt(Variant(1.5)) = String("test"); VS(v[1], "test"); VS(v[1.5], "test"); VS(v[Variant(1.5)], "test"); VS(v[s_1], "test"); VS(v[Variant("1")], "test"); } { Variant v; v.lvalAt(s_1) = String("test"); VS(v[1], "test"); VS(v[1.5], "test"); VS(v[Variant(1.5)], "test"); VS(v[s_1], "test"); VS(v[Variant("1")], "test"); } { Variant v; v.lvalAt(Variant("1")) = String("test"); VS(v[1], "test"); VS(v[1.5], "test"); VS(v[Variant(1.5)], "test"); VS(v[s_1], "test"); VS(v[Variant("1")], "test"); } // membership { Variant v; v.lvalAt(s_n0) = String("v0"); v.lvalAt(s_n1) = String("v1"); v.remove(s_n1); VS(v, CREATE_MAP1(s_n0, "v0")); v.append("v2"); VS(v, CREATE_MAP2(s_n0, "v0", 0, "v2")); } { Variant v; v.lvalAt(s_n0) = String("v0"); v.lvalAt(1) = String("v1"); v.remove(Variant(1.5)); VS(v, CREATE_MAP1("n0", "v0")); } { Variant v; v.lvalAt(s_n0) = String("v0"); v.lvalAt(1) = String("v1"); v.remove(Variant("1")); VS(v, CREATE_MAP1("n0", "v0")); } { Variant v; v.lvalAt(s_n0) = String("v0"); v.lvalAt(1) = String("v1"); v.remove(String("1")); VS(v, CREATE_MAP1("n0", "v0")); } { Variant v; v.lvalAt(s_n0) = String("v0"); v.lvalAt(empty_string) = String("v1"); v.remove(Variant()); VS(v, CREATE_MAP1("n0", "v0")); } // references { Variant v1("original"); Variant v2 = v1; v2 = String("changed"); VERIFY(v1 == "original"); } { Variant v1("original"); Variant v2 = strongBind(v1); v2 = String("changed"); VERIFY(v1 == "changed"); } { Variant v1 = 10; Variant v2 = Array(ArrayInit(1).setRef(v1).create()); v1 = 20; VS(v2[0], 20); } { Variant v1 = 10; Variant v2; v2.lvalAt() = ref(v1); v1 = 20; VS(v2[0], 20); } { Variant v1 = 10; Variant v2 = CREATE_VECTOR1(5); v2.lvalAt() = ref(v1); v1 = 20; VS(v2[1], 20); } { Variant v1 = 10; Variant v2 = strongBind(v1); v2++; VS(v2, 11); VS(v1, 11); } { Variant arr = CREATE_VECTOR2(1, 2); Variant v; for (MutableArrayIter iter = arr.begin(nullptr, v); iter.advance();) { v++; } VS(arr, CREATE_VECTOR2(2, 3)); } // array escalation { Variant arr; lval(arr.lvalAt(0)).lvalAt(0) = 1.2; VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2))); } { Variant arr; lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2; VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2))); } { Variant arr = Array::Create(); lval(arr.lvalAt(0)).lvalAt(0) = 1.2; VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2))); } { Variant arr = Array::Create(); lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2; VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2))); } { Variant arr = Array::Create("test"); arr.lvalAt(0) = CREATE_VECTOR1(1.2); VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2))); } { Variant arr = Array::Create("test"); lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2; VS(arr, CREATE_MAP2(0, "test", s_name, CREATE_VECTOR1(1.2))); } return Count(true); }
Variant ObjectMethodExpression::eval(VariableEnvironment &env) const { String name(m_name->get(env)); Variant obj(m_obj->eval(env)); if (!obj.is(KindOfObject)) { raise_error("Call to a member function %s() on a non-object", name.c_str()); } #ifdef ENABLE_LATE_STATIC_BINDING EvalFrameInjection::EvalStaticClassNameHelper helper(obj.toObject()); #endif Variant cobj(env.currentObject()); const MethodStatement *ms = NULL; if (cobj.is(KindOfObject) && obj.getObjectData() == cobj.getObjectData()) { // Have to try current class first for private method const ClassStatement *cls = env.currentClassStatement(); if (cls) { const MethodStatement *ccms = cls->findMethod(name.c_str()); if (ccms && ccms->getModifiers() & ClassStatement::Private) { ms = ccms; } } } if (!ms) { ms = obj.getObjectData()->getMethodStatement(name.data()); } SET_LINE; if (ms) { return strongBind(ms->invokeInstanceDirect(toObject(obj), env, this)); } // Handle builtins MethodCallPackage mcp1; mcp1.methodCall(obj, name, -1); const CallInfo* ci = mcp1.ci; // If the lookup failed methodCall() must throw an exception, // so if we reach here ci must not be NULL ASSERT(ci); unsigned int count = m_params.size(); if (count <= 6) { CVarRef a0 = (count > 0) ? evalParam(env, ci, 0) : null; CVarRef a1 = (count > 1) ? evalParam(env, ci, 1) : null; CVarRef a2 = (count > 2) ? evalParam(env, ci, 2) : null; CVarRef a3 = (count > 3) ? evalParam(env, ci, 3) : null; CVarRef a4 = (count > 4) ? evalParam(env, ci, 4) : null; CVarRef a5 = (count > 5) ? evalParam(env, ci, 5) : null; return strongBind((ci->getMethFewArgs())(mcp1, count, a0, a1, a2, a3, a4, a5)); } if (RuntimeOption::UseArgArray) { ArgArray *args = prepareArgArray(env, ci, count); return strongBind((ci->getMeth())(mcp1, args)); } ArrayInit ai(count); for (unsigned int i = 0; i < count; ++i) { if (ci->mustBeRef(i)) { ai.setRef(m_params[i]->refval(env)); } else if (ci->isRef(i)) { ai.setRef(m_params[i]->refval(env, 0)); } else { ai.set(m_params[i]->eval(env)); } } return strongBind((ci->getMeth())(mcp1, Array(ai.create()))); }
Variant c_MutableArrayIterator::t_currentref() { if (!m_valid) return uninit_null(); MArrayIter& mi = marr(); if (mi.end()) return uninit_null(); return strongBind(mi.val()); }
Variant Array::refvalAt(CStrRef key, bool isString /* = false */) { return strongBind(lvalAt(key, AccessFlags::IsKey(isString))); }
Variant c_MutableArrayIterator::t_currentref() { INSTANCE_METHOD_INJECTION_BUILTIN(MutableArrayIterator, MutableArrayIterator::currentref); if (!m_valid) return null; MIterCtx& mi = marr(); return strongBind(*(Variant*)(&mi.m_val)); }