Use makePseudoMainExit in more places
[hiphop-php.git] / hphp / runtime / vm / member-operations.cpp
bloba3c308d35741e12c2a94e30d70b95f5e336df830
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/member-operations.h"
18 #include "hphp/runtime/ext/ext_collections.h"
20 namespace HPHP {
22 StringData* prepareAnyKey(TypedValue* tv) {
23 if (IS_STRING_TYPE(tv->m_type)) {
24 StringData* str = tv->m_data.pstr;
25 str->incRefCount();
26 return str;
27 } else {
28 return tvAsCVarRef(tv).toString().detach();
32 void objArrayAccess(ObjectData* base) {
33 assert(!base->isCollection());
34 if (!base->getVMClass()->classof(SystemLib::s_ArrayAccessClass)) {
35 raise_error("Object does not implement ArrayAccess");
39 TypedValue* objOffsetGet(TypedValue& tvRef, ObjectData* base,
40 const Variant& offset, bool validate /* = true */) {
41 if (validate) {
42 objArrayAccess(base);
44 TypedValue* result;
45 assert(!base->isCollection());
46 static StringData* sd__offsetGet = makeStaticString("offsetGet");
47 const Func* method = base->methodNamed(sd__offsetGet);
48 assert(method != nullptr);
49 g_context->invokeFuncFew(&tvRef, method, base, nullptr, 1, offset.asCell());
50 result = &tvRef;
51 return result;
54 static bool objOffsetExists(ObjectData* base, const Variant& offset) {
55 objArrayAccess(base);
56 TypedValue tvResult;
57 tvWriteUninit(&tvResult);
58 static StringData* sd__offsetExists
59 = makeStaticString("offsetExists");
60 assert(!base->isCollection());
61 const Func* method = base->methodNamed(sd__offsetExists);
62 assert(method != nullptr);
63 g_context->invokeFuncFew(&tvResult, method, base, nullptr, 1,
64 offset.asCell());
65 tvCastToBooleanInPlace(&tvResult);
66 return bool(tvResult.m_data.num);
69 bool objOffsetIsset(TypedValue& tvRef, ObjectData* base, const Variant& offset,
70 bool validate /* = true */) {
71 auto exists = objOffsetExists(base, offset);
73 if (!exists) {
74 return false;
77 if (!base->getVMClass()->classof(SystemLib::s_ArrayObjectClass)) {
78 return exists;
81 TypedValue tvResult;
82 tvWriteUninit(&tvResult);
83 return is_not_null(tvAsVariant(objOffsetGet(tvResult, base, offset)));
86 bool objOffsetEmpty(TypedValue& tvRef, ObjectData* base, const Variant& offset,
87 bool validate /* = true */) {
88 if (!objOffsetExists(base, offset)) {
89 return true;
91 TypedValue* result = objOffsetGet(tvRef, base, offset, false);
92 assert(result);
93 return !cellToBool(*tvToCell(result));
96 void objOffsetAppend(ObjectData* base, TypedValue* val,
97 bool validate /* = true */) {
98 assert(!base->isCollection());
99 if (validate) {
100 objArrayAccess(base);
102 objOffsetSet(base, init_null_variant, val, false);
105 void objOffsetSet(ObjectData* base, const Variant& offset, TypedValue* val,
106 bool validate /* = true */) {
107 if (validate) {
108 objArrayAccess(base);
110 static StringData* sd__offsetSet = makeStaticString("offsetSet");
111 assert(!base->isCollection());
112 const Func* method = base->methodNamed(sd__offsetSet);
113 assert(method != nullptr);
114 TypedValue tvResult;
115 tvWriteUninit(&tvResult);
116 TypedValue args[2] = { *offset.asCell(), *tvToCell(val) };
117 g_context->invokeFuncFew(&tvResult, method, base, nullptr, 2, args);
118 tvRefcountedDecRef(&tvResult);
121 void objOffsetUnset(ObjectData* base, const Variant& offset) {
122 objArrayAccess(base);
123 static StringData* sd__offsetUnset
124 = makeStaticString("offsetUnset");
125 assert(!base->isCollection());
126 const Func* method = base->methodNamed(sd__offsetUnset);
127 assert(method != nullptr);
128 TypedValue tv;
129 tvWriteUninit(&tv);
130 g_context->invokeFuncFew(&tv, method, base, nullptr, 1, offset.asCell());
131 tvRefcountedDecRef(&tv);
134 // Mutable collections support appending new elements using [] without a key
135 // like so: "$vector[] = 123;". However, collections do not support using []
136 // without a key to implicitly create a new element without supplying assigning
137 // an initial value (ex "$vector[]['a'] = 73;").
138 void throw_cannot_use_newelem_for_lval_read() {
139 Object e(SystemLib::AllocInvalidOperationExceptionObject(
140 "Cannot use [] with collections for reading in an lvalue context"));
141 throw e;
144 ///////////////////////////////////////////////////////////////////////////////