1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qv4object_p.h"
41 #include "qv4objectproto_p.h"
42 #include "qv4stringobject_p.h"
43 #include "qv4argumentsobject_p.h"
44 #include <private/qv4mm_p.h>
45 #include "qv4lookup_p.h"
46 #include "qv4scopedvalue_p.h"
47 #include "qv4memberdata_p.h"
48 #include "qv4objectiterator_p.h"
49 #include "qv4identifier_p.h"
50 #include "qv4string_p.h"
51 #include "qv4identifiertable_p.h"
52 #include "qv4jscall_p.h"
53 #include "qv4symbol_p.h"
54 #include "qv4proxy_p.h"
55 
56 #include <stdint.h>
57 
58 using namespace QV4;
59 
60 DEFINE_OBJECT_VTABLE(Object);
61 
setInternalClass(Heap::InternalClass * ic)62 void Object::setInternalClass(Heap::InternalClass *ic)
63 {
64     d()->internalClass.set(engine(), ic);
65     if (ic->isUsedAsProto)
66         ic->updateProtoUsage(d());
67     Q_ASSERT(ic && ic->vtable);
68     uint nInline = d()->vtable()->nInlineProperties;
69     if (ic->size <= nInline)
70         return;
71     bool hasMD = d()->memberData != nullptr;
72     uint requiredSize = ic->size - nInline;
73     if (!(hasMD && requiredSize) || (hasMD && d()->memberData->values.size < requiredSize))
74         d()->memberData.set(ic->engine, MemberData::allocate(ic->engine, requiredSize, d()->memberData));
75 }
76 
getProperty(const InternalClassEntry & entry,Property * p) const77 void Object::getProperty(const InternalClassEntry &entry, Property *p) const
78 {
79     p->value = *propertyData(entry.index);
80     if (entry.attributes.isAccessor())
81         p->set = *propertyData(entry.setterIndex);
82 }
83 
setProperty(const InternalClassEntry & entry,const Property * p)84 void Object::setProperty(const InternalClassEntry &entry, const Property *p)
85 {
86     setProperty(entry.index, p->value);
87     if (entry.attributes.isAccessor())
88         setProperty(entry.setterIndex, p->set);
89 }
90 
setUsedAsProto()91 void Heap::Object::setUsedAsProto()
92 {
93     internalClass.set(internalClass->engine, internalClass->asProtoClass());
94 }
95 
getValueAccessor(const Value * thisObject,const Value & v,PropertyAttributes attrs)96 ReturnedValue Object::getValueAccessor(const Value *thisObject, const Value &v, PropertyAttributes attrs)
97 {
98     if (!attrs.isAccessor())
99         return v.asReturnedValue();
100     const QV4::FunctionObject *f = v.as<FunctionObject>();
101     if (!f)
102         return Encode::undefined();
103 
104     Scope scope(f->engine());
105     JSCallData jsCallData(scope);
106     if (thisObject)
107         *jsCallData->thisObject = *thisObject;
108     return checkedResult(scope.engine, f->call(jsCallData));
109 }
110 
putValue(uint memberIndex,PropertyAttributes attrs,const Value & value)111 bool Object::putValue(uint memberIndex, PropertyAttributes attrs, const Value &value)
112 {
113     Heap::InternalClass *ic = internalClass();
114     if (ic->engine->hasException)
115         return false;
116 
117     if (attrs.isAccessor()) {
118         const FunctionObject *set = propertyData(memberIndex)->as<FunctionObject>();
119         if (set) {
120             Scope scope(ic->engine);
121             ScopedFunctionObject setter(scope, set);
122             JSCallData jsCallData(scope, 1);
123             jsCallData->args[0] = value;
124             *jsCallData->thisObject = this;
125             setter->call(jsCallData);
126             return !ic->engine->hasException;
127         }
128         return false;
129     }
130 
131     if (!attrs.isWritable())
132         return false;
133 
134     setProperty(memberIndex, value);
135     return true;
136 }
137 
defineDefaultProperty(const QString & name,const Value & value,PropertyAttributes attributes)138 void Object::defineDefaultProperty(const QString &name, const Value &value, PropertyAttributes attributes)
139 {
140     ExecutionEngine *e = engine();
141     Scope scope(e);
142     ScopedString s(scope, e->newIdentifier(name));
143     defineDefaultProperty(s, value, attributes);
144 }
145 
defineDefaultProperty(const QString & name,VTable::Call code,int argumentCount,PropertyAttributes attributes)146 void Object::defineDefaultProperty(const QString &name, VTable::Call code,
147                                    int argumentCount, PropertyAttributes attributes)
148 {
149     ExecutionEngine *e = engine();
150     Scope scope(e);
151     ScopedString s(scope, e->newIdentifier(name));
152     ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(e, s, code, argumentCount));
153     defineDefaultProperty(s, function, attributes);
154 }
155 
defineDefaultProperty(StringOrSymbol * nameOrSymbol,VTable::Call code,int argumentCount,PropertyAttributes attributes)156 void Object::defineDefaultProperty(StringOrSymbol *nameOrSymbol, VTable::Call code,
157                                    int argumentCount, PropertyAttributes attributes)
158 {
159     ExecutionEngine *e = engine();
160     Scope scope(e);
161     ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(e, nameOrSymbol, code, argumentCount));
162     defineDefaultProperty(nameOrSymbol, function, attributes);
163 }
164 
defineAccessorProperty(const QString & name,VTable::Call getter,VTable::Call setter)165 void Object::defineAccessorProperty(const QString &name, VTable::Call getter, VTable::Call setter)
166 {
167     ExecutionEngine *e = engine();
168     Scope scope(e);
169     ScopedString s(scope, e->newIdentifier(name));
170     defineAccessorProperty(s, getter, setter);
171 }
172 
defineAccessorProperty(StringOrSymbol * name,VTable::Call getter,VTable::Call setter)173 void Object::defineAccessorProperty(StringOrSymbol *name, VTable::Call getter, VTable::Call setter)
174 {
175     ExecutionEngine *v4 = engine();
176     QV4::Scope scope(v4);
177     ScopedProperty p(scope);
178     QString n = name->toQString();
179     if (n.at(0) == QLatin1Char('@'))
180         n = QChar::fromLatin1('[') + n.midRef(1) + QChar::fromLatin1(']');
181     if (getter) {
182         ScopedString getName(scope, v4->newString(QString::fromLatin1("get ") + n));
183         p->setGetter(ScopedFunctionObject(scope, FunctionObject::createBuiltinFunction(v4, getName, getter, 0)));
184     } else {
185         p->setGetter(nullptr);
186     }
187     if (setter) {
188         ScopedString setName(scope, v4->newString(QString::fromLatin1("set ") + n));
189         p->setSetter(ScopedFunctionObject(scope, FunctionObject::createBuiltinFunction(v4, setName, setter, 0)));
190     } else {
191         p->setSetter(nullptr);
192     }
193     insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable);
194 }
195 
196 
197 
defineReadonlyProperty(const QString & name,const Value & value)198 void Object::defineReadonlyProperty(const QString &name, const Value &value)
199 {
200     QV4::ExecutionEngine *e = engine();
201     Scope scope(e);
202     ScopedString s(scope, e->newIdentifier(name));
203     defineReadonlyProperty(s, value);
204 }
205 
defineReadonlyProperty(String * name,const Value & value)206 void Object::defineReadonlyProperty(String *name, const Value &value)
207 {
208     insertMember(name, value, Attr_ReadOnly);
209 }
210 
defineReadonlyConfigurableProperty(const QString & name,const Value & value)211 void Object::defineReadonlyConfigurableProperty(const QString &name, const Value &value)
212 {
213     QV4::ExecutionEngine *e = engine();
214     Scope scope(e);
215     ScopedString s(scope, e->newIdentifier(name));
216     defineReadonlyConfigurableProperty(s, value);
217 }
218 
defineReadonlyConfigurableProperty(StringOrSymbol * name,const Value & value)219 void Object::defineReadonlyConfigurableProperty(StringOrSymbol *name, const Value &value)
220 {
221     insertMember(name, value, Attr_ReadOnly_ButConfigurable);
222 }
223 
addSymbolSpecies()224 void Object::addSymbolSpecies()
225 {
226     Scope scope(engine());
227     ScopedProperty p(scope);
228     p->setGetter(scope.engine->getSymbolSpecies());
229     p->setSetter(nullptr);
230     insertMember(scope.engine->symbol_species(), p, QV4::Attr_Accessor|QV4::Attr_NotWritable|QV4::Attr_NotEnumerable);
231 }
232 
markObjects(Heap::Base * b,MarkStack * stack)233 void Heap::Object::markObjects(Heap::Base *b, MarkStack *stack)
234 {
235     Base::markObjects(b, stack);
236     Object *o = static_cast<Object *>(b);
237     if (o->memberData)
238         o->memberData->mark(stack);
239     if (o->arrayData)
240         o->arrayData->mark(stack);
241     uint nInline = o->vtable()->nInlineProperties;
242     Value *v = reinterpret_cast<Value *>(o) + o->vtable()->inlinePropertyOffset;
243     const Value *end = v + nInline;
244     while (v < end) {
245         v->mark(stack);
246         ++v;
247     }
248 }
249 
insertMember(StringOrSymbol * s,const Property * p,PropertyAttributes attributes)250 void Object::insertMember(StringOrSymbol *s, const Property *p, PropertyAttributes attributes)
251 {
252     InternalClassEntry idx;
253     PropertyKey key = s->toPropertyKey();
254     Heap::InternalClass::addMember(this, key, attributes, &idx);
255 
256     setProperty(idx.index, p->value);
257     if (attributes.isAccessor())
258         setProperty(idx.setterIndex, p->set);
259 }
260 
setPrototypeUnchecked(const Object * p)261 void Object::setPrototypeUnchecked(const Object *p)
262 {
263     setInternalClass(internalClass()->changePrototype(p ? p->d() : nullptr));
264 }
265 
266 // Section 8.12.2
getValueOrSetter(PropertyKey id,PropertyAttributes * attrs)267 PropertyIndex Object::getValueOrSetter(PropertyKey id, PropertyAttributes *attrs)
268 {
269     if (id.isArrayIndex()) {
270         uint index = id.asArrayIndex();
271         Heap::Object *o = d();
272         while (o) {
273             if (o->arrayData) {
274                 uint idx = o->arrayData->mappedIndex(index);
275                 if (idx != UINT_MAX) {
276                     *attrs = o->arrayData->attributes(index);
277                     return { o->arrayData , o->arrayData->values.values + (attrs->isAccessor() ? idx + SetterOffset : idx) };
278                 }
279             }
280             if (o->vtable()->type == Type_StringObject) {
281                 if (index < static_cast<const Heap::StringObject *>(o)->length()) {
282                     // this is an evil hack, but it works, as the method is only ever called from put,
283                     // where we don't use the returned pointer there for non writable attributes
284                     *attrs = (Attr_NotWritable|Attr_NotConfigurable);
285                     return { reinterpret_cast<Heap::ArrayData *>(0x1), nullptr };
286                 }
287             }
288             o = o->prototype();
289         }
290     } else {
291         Heap::Object *o = d();
292         while (o) {
293             auto idx = o->internalClass->findValueOrSetter(id);
294             if (idx.isValid()) {
295                 *attrs = idx.attrs;
296                 return o->writablePropertyData(idx.index);
297             }
298 
299             o = o->prototype();
300         }
301     }
302     *attrs = Attr_Invalid;
303     return { nullptr, nullptr };
304 }
305 
virtualGet(const Managed * m,PropertyKey id,const Value * receiver,bool * hasProperty)306 ReturnedValue Object::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
307 {
308     return static_cast<const Object *>(m)->internalGet(id, receiver, hasProperty);
309 }
310 
virtualPut(Managed * m,PropertyKey id,const Value & value,Value * receiver)311 bool Object::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
312 {
313     return static_cast<Object *>(m)->internalPut(id, value, receiver);
314 }
315 
virtualDeleteProperty(Managed * m,PropertyKey id)316 bool Object::virtualDeleteProperty(Managed *m, PropertyKey id)
317 {
318     return static_cast<Object *>(m)->internalDeleteProperty(id);
319 }
320 
next(const Object * o,Property * pd,PropertyAttributes * attrs)321 PropertyKey ObjectOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs)
322 {
323     if (arrayIndex != UINT_MAX && o->arrayData()) {
324         SparseArrayNode *arrayNode = nullptr;
325         if (o->arrayType() == Heap::ArrayData::Sparse) {
326             SparseArray *sparse = o->arrayData()->sparse;
327             arrayNode = arrayIndex ? sparse->lowerBound(arrayIndex) : sparse->begin();
328         }
329 
330         // sparse arrays
331         if (arrayNode) {
332             while (arrayNode != o->sparseEnd()) {
333                 uint k = arrayNode->key();
334                 uint pidx = arrayNode->value;
335                 Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>();
336                 const Property *p = reinterpret_cast<const Property *>(sa->values.data() + pidx);
337                 arrayNode = arrayNode->nextNode();
338                 PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data;
339                 arrayIndex = k + 1;
340                 if (pd)
341                     pd->copy(p, a);
342                 if (attrs)
343                     *attrs = a;
344                 return PropertyKey::fromArrayIndex(k);
345             }
346             arrayIndex = UINT_MAX;
347         }
348         // dense arrays
349         while (arrayIndex < o->d()->arrayData->values.size) {
350             Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>();
351             const Value &val = sa->data(arrayIndex);
352             PropertyAttributes a = o->arrayData()->attributes(arrayIndex);
353             int index = arrayIndex;
354             ++arrayIndex;
355             if (!val.isEmpty()) {
356                 if (pd)
357                     pd->value = val;
358                 if (attrs)
359                     *attrs = a;
360                 return PropertyKey::fromArrayIndex(index);
361             }
362         }
363         arrayIndex = UINT_MAX;
364     }
365 
366     while (true) {
367         while (memberIndex < o->internalClass()->size) {
368             PropertyKey n = o->internalClass()->nameMap.at(memberIndex);
369             ++memberIndex;
370             if (!n.isStringOrSymbol())
371                 // accessor properties have a dummy entry with n == 0
372                 continue;
373             if (!iterateOverSymbols && n.isSymbol())
374                 continue;
375             if (iterateOverSymbols && !n.isSymbol())
376                 continue;
377 
378             InternalClassEntry e = o->internalClass()->find(n);
379             if (!e.isValid())
380                 continue;
381             if (pd) {
382                 pd->value = *o->propertyData(e.index);
383                 if (e.attributes.isAccessor())
384                     pd->set = *o->propertyData(e.setterIndex);
385             }
386             if (attrs)
387                 *attrs = e.attributes;
388             return n;
389         }
390         if (iterateOverSymbols)
391             break;
392         iterateOverSymbols = true;
393         memberIndex = 0;
394     }
395 
396     return PropertyKey::invalid();
397 }
398 
virtualOwnPropertyKeys(const Object * o,Value * target)399 OwnPropertyKeyIterator *Object::virtualOwnPropertyKeys(const Object *o, Value *target)
400 {
401     *target = *o;
402     return new ObjectOwnPropertyKeyIterator;
403 }
404 
405 // Section 8.12.3
internalGet(PropertyKey id,const Value * receiver,bool * hasProperty) const406 ReturnedValue Object::internalGet(PropertyKey id, const Value *receiver, bool *hasProperty) const
407 {
408     Heap::Object *o = d();
409 
410     if (id.isArrayIndex()) {
411         const uint index = id.asArrayIndex();
412         Scope scope(this);
413         PropertyAttributes attrs;
414         ScopedProperty pd(scope);
415         while (1) {
416             if (o->arrayData && o->arrayData->getProperty(index, pd, &attrs)) {
417                 if (hasProperty)
418                     *hasProperty = true;
419                 return Object::getValue(receiver, pd->value, attrs);
420             }
421             if (o->internalClass->vtable->type == Type_StringObject) {
422                 ScopedString str(scope, static_cast<Heap::StringObject *>(o)->getIndex(index));
423                 if (str) {
424                     attrs = (Attr_NotWritable|Attr_NotConfigurable);
425                     if (hasProperty)
426                         *hasProperty = true;
427                     return str.asReturnedValue();
428                 }
429             }
430             o = o->prototype();
431             if (!o || o->internalClass->vtable->get != Object::virtualGet)
432                 break;
433         }
434     } else {
435         while (1) {
436             auto idx = o->internalClass->findValueOrGetter(id);
437             if (idx.isValid()) {
438                 if (hasProperty)
439                     *hasProperty = true;
440                 return Object::getValue(receiver, *o->propertyData(idx.index), idx.attrs);
441             }
442             o = o->prototype();
443             if (!o || o->internalClass->vtable->get != Object::virtualGet)
444                 break;
445         }
446     }
447 
448     if (o) {
449         const Value v = Value::fromHeapObject(o);
450         const Object &obj = static_cast<const Object &>(v);
451         return obj.get(id, receiver, hasProperty);
452     }
453 
454     if (hasProperty)
455         *hasProperty = false;
456     return Encode::undefined();
457 }
458 
459 // Section 8.12.5
internalPut(PropertyKey id,const Value & value,Value * receiver)460 bool Object::internalPut(PropertyKey id, const Value &value, Value *receiver)
461 {
462     Scope scope(this);
463     if (scope.engine->hasException)
464         return false;
465 
466     Object *r = receiver->objectValue();
467     if (r && r->d() == d()) {
468         // receiver and this object are the same
469         if (d()->internalClass->vtable->getOwnProperty == Object::virtualGetOwnProperty) {
470             // This object standard methods in the vtable, so we can take a shortcut
471             // and avoid the calls to getOwnProperty and defineOwnProperty
472 
473             PropertyAttributes attrs;
474             PropertyIndex propertyIndex{nullptr, nullptr};
475 
476             if (id.isArrayIndex()) {
477                 if (arrayData())
478                     propertyIndex = arrayData()->getValueOrSetter(id.asArrayIndex(), &attrs);
479             } else {
480                 auto member = internalClass()->findValueOrSetter(id);
481                 if (member.isValid()) {
482                     attrs = member.attrs;
483                     propertyIndex = d()->writablePropertyData(member.index);
484                 }
485             }
486 
487             if (!propertyIndex.isNull() && !attrs.isAccessor()) {
488                 if (!attrs.isWritable())
489                     return false;
490                 else if (isArrayObject() && id == scope.engine->id_length()->propertyKey()) {
491                     bool ok;
492                     uint l = value.asArrayLength(&ok);
493                     if (!ok) {
494                         scope.engine->throwRangeError(value);
495                         return false;
496                     }
497                     ok = setArrayLength(l);
498                     if (!ok)
499                         return false;
500                 } else {
501                     propertyIndex.set(scope.engine, value);
502                 }
503                 return true;
504             }
505         }
506     }
507 
508     ScopedProperty p(scope);
509     PropertyAttributes attrs;
510     attrs = getOwnProperty(id, p);
511     if (attrs == Attr_Invalid) {
512         ScopedObject p(scope, getPrototypeOf());
513         if (p)
514             return p->put(id, value, receiver);
515         attrs = Attr_Data;
516     }
517 
518     if (attrs.isAccessor()) {
519         ScopedFunctionObject setter(scope, p->setter());
520         if (!setter)
521             return false;
522         JSCallData jsCallData(scope, 1);
523         jsCallData->args[0] = value;
524         *jsCallData->thisObject = *receiver;
525         setter->call(jsCallData);
526         return !scope.engine->hasException;
527     }
528 
529     // Data property
530     if (!attrs.isWritable())
531         return false;
532     if (!r)
533         return false;
534     attrs = r->getOwnProperty(id, p);
535 
536     if (attrs != Attr_Invalid) {
537         if (attrs.isAccessor() || !attrs.isWritable())
538             return false;
539     } else {
540         if (!r->isExtensible())
541             return false;
542         attrs = Attr_Data;
543     }
544 
545     if (r->internalClass()->vtable->defineOwnProperty == virtualDefineOwnProperty) {
546         // standard object, we can avoid some more checks
547         if (id.isArrayIndex()) {
548             r->arraySet(id.asArrayIndex(), value);
549         } else {
550             ScopedStringOrSymbol s(scope, id.asStringOrSymbol());
551             r->insertMember(s, value);
552         }
553         return true;
554     }
555 
556     p->value = value;
557     return r->defineOwnProperty(id, p, attrs);
558 }
559 
560 // Section 8.12.7
internalDeleteProperty(PropertyKey id)561 bool Object::internalDeleteProperty(PropertyKey id)
562 {
563     if (internalClass()->engine->hasException)
564         return false;
565 
566     if (id.isArrayIndex()) {
567         uint index = id.asArrayIndex();
568         Scope scope(engine());
569         if (scope.engine->hasException)
570             return false;
571 
572         Scoped<ArrayData> ad(scope, arrayData());
573         if (!ad || ad->vtable()->del(this, index))
574             return true;
575 
576         return false;
577     }
578 
579     auto memberIdx = internalClass()->findValueOrGetter(id);
580     if (memberIdx.isValid()) {
581         if (memberIdx.attrs.isConfigurable()) {
582             Heap::InternalClass::removeMember(this, id);
583             return true;
584         }
585         return false;
586     }
587 
588     return true;
589 }
590 
internalDefineOwnProperty(ExecutionEngine * engine,uint index,const InternalClassEntry * memberEntry,const Property * p,PropertyAttributes attrs)591 bool Object::internalDefineOwnProperty(ExecutionEngine *engine, uint index, const InternalClassEntry *memberEntry, const Property *p, PropertyAttributes attrs)
592 {
593     // clause 5
594     if (attrs.isEmpty())
595         return true;
596 
597     Scope scope(engine);
598     ScopedProperty current(scope);
599     PropertyAttributes cattrs;
600     if (memberEntry) {
601         getProperty(*memberEntry, current);
602         cattrs = memberEntry->attributes;
603     } else if (arrayData()) {
604         arrayData()->getProperty(index, current, &cattrs);
605         cattrs = arrayData()->attributes(index);
606     }
607 
608     // clause 6
609     if (p->isSubset(attrs, current, cattrs))
610         return true;
611 
612     // clause 7
613     if (!cattrs.isConfigurable()) {
614         if (attrs.isConfigurable())
615             return false;
616         if (attrs.hasEnumerable() && attrs.isEnumerable() != cattrs.isEnumerable())
617             return false;
618     }
619 
620     // clause 8
621     if (attrs.isGeneric() || current->value.isEmpty())
622         goto accept;
623 
624     // clause 9
625     if (cattrs.isData() != attrs.isData()) {
626         // 9a
627         if (!cattrs.isConfigurable())
628             return false;
629         if (cattrs.isData()) {
630             // 9b
631             cattrs.setType(PropertyAttributes::Accessor);
632             cattrs.clearWritable();
633             if (!memberEntry) {
634                 // need to convert the array and the slot
635                 initSparseArray();
636                 Q_ASSERT(arrayData());
637                 setArrayAttributes(index, cattrs);
638             }
639             current->setGetter(nullptr);
640             current->setSetter(nullptr);
641         } else {
642             // 9c
643             cattrs.setType(PropertyAttributes::Data);
644             cattrs.setWritable(false);
645             if (!memberEntry) {
646                 // need to convert the array and the slot
647                 setArrayAttributes(index, cattrs);
648             }
649             current->value = Value::undefinedValue();
650         }
651     } else if (cattrs.isData() && attrs.isData()) { // clause 10
652         if (!cattrs.isConfigurable() && !cattrs.isWritable()) {
653             if (attrs.isWritable() || !current->value.sameValue(p->value))
654                 return false;
655         }
656     } else { // clause 10
657         Q_ASSERT(cattrs.isAccessor() && attrs.isAccessor());
658         if (!cattrs.isConfigurable()) {
659             if (!p->value.isEmpty() && current->value.rawValue() != p->value.rawValue())
660                 return false;
661             if (!p->set.isEmpty() && current->set.rawValue() != p->set.rawValue())
662                 return false;
663         }
664     }
665 
666   accept:
667 
668     current->merge(cattrs, p, attrs);
669     if (memberEntry) {
670         PropertyKey key = internalClass()->nameMap.at(memberEntry->index);
671         InternalClassEntry e;
672         Heap::InternalClass::changeMember(this, key, cattrs, &e);
673         setProperty(e, current);
674     } else {
675         setArrayAttributes(index, cattrs);
676         arrayData()->setProperty(scope.engine, index, current);
677     }
678     return true;
679 }
680 
copyArrayData(Object * other)681 void Object::copyArrayData(Object *other)
682 {
683     Q_ASSERT(isArrayObject());
684     Scope scope(engine());
685 
686     if (other->protoHasArray() || ArgumentsObject::isNonStrictArgumentsObject(other) ||
687         (other->arrayType() == Heap::ArrayData::Sparse && other->arrayData()->attrs)) {
688         uint len = other->getLength();
689         Q_ASSERT(len);
690 
691         ScopedValue v(scope);
692         for (uint i = 0; i < len; ++i) {
693             arraySet(i, (v = other->get(i)));
694         }
695     } else if (!other->arrayData()) {
696         ;
697     } else {
698         Q_ASSERT(!arrayData() && other->arrayData());
699         ArrayData::realloc(this, static_cast<ArrayData::Type>(other->d()->arrayData->type),
700                            other->d()->arrayData->values.alloc, false);
701         if (other->arrayType() == Heap::ArrayData::Sparse) {
702             Heap::ArrayData *od = other->d()->arrayData;
703             Heap::ArrayData *dd = d()->arrayData;
704             dd->sparse = new SparseArray(*od->sparse);
705         } else {
706             Heap::ArrayData *dd = d()->arrayData;
707             dd->values.size = other->d()->arrayData->values.size;
708             dd->offset = other->d()->arrayData->offset;
709         }
710         // ### need a write barrier
711         memcpy(d()->arrayData->values.values, other->d()->arrayData->values.values, other->d()->arrayData->values.alloc*sizeof(Value));
712     }
713     setArrayLengthUnchecked(other->getLength());
714 }
715 
virtualGetLength(const Managed * m)716 qint64 Object::virtualGetLength(const Managed *m)
717 {
718     Scope scope(static_cast<const Object *>(m)->engine());
719     ScopedValue v(scope, static_cast<Object *>(const_cast<Managed *>(m))->get(scope.engine->id_length()));
720     return v->toLength();
721 }
722 
723 // 'var' is 'V' in 15.3.5.3.
virtualInstanceOf(const Object * typeObject,const Value & var)724 ReturnedValue Object::virtualInstanceOf(const Object *typeObject, const Value &var)
725 {
726     QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
727 
728     // 15.3.5.3, Assume F is a Function object.
729     const FunctionObject *function = typeObject->as<FunctionObject>();
730     if (!function)
731         return engine->throwTypeError();
732 
733     return checkedInstanceOf(engine, function, var);
734 }
735 
virtualResolveLookupGetter(const Object * object,ExecutionEngine * engine,Lookup * lookup)736 ReturnedValue Object::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
737 {
738     Heap::Object *obj = object->d();
739     PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
740     if (name.isArrayIndex()) {
741         lookup->indexedLookup.index = name.asArrayIndex();
742         lookup->getter = Lookup::getterIndexed;
743         return lookup->getter(lookup, engine, *object);
744     }
745 
746     auto index = obj->internalClass->findValueOrGetter(name);
747     if (index.isValid()) {
748         PropertyAttributes attrs = index.attrs;
749         uint nInline = obj->vtable()->nInlineProperties;
750         if (attrs.isData()) {
751             if (index.index < obj->vtable()->nInlineProperties) {
752                 index.index += obj->vtable()->inlinePropertyOffset;
753                 lookup->getter = Lookup::getter0Inline;
754             } else {
755                 index.index -= nInline;
756                 lookup->getter = Lookup::getter0MemberData;
757             }
758         } else {
759             lookup->getter = Lookup::getterAccessor;
760         }
761         lookup->objectLookup.ic = obj->internalClass;
762         lookup->objectLookup.offset = index.index;
763         return lookup->getter(lookup, engine, *object);
764     }
765 
766     lookup->protoLookup.protoId = obj->internalClass->protoId;
767     lookup->resolveProtoGetter(name, obj->prototype());
768     return lookup->getter(lookup, engine, *object);
769 }
770 
virtualResolveLookupSetter(Object * object,ExecutionEngine * engine,Lookup * lookup,const Value & value)771 bool Object::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value)
772 {
773     Scope scope(engine);
774     ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
775 
776     Heap::InternalClass *c = object->internalClass();
777     PropertyKey key = name->toPropertyKey();
778     auto idx = c->findValueOrSetter(key);
779     if (idx.isValid()) {
780         if (object->isArrayObject() && idx.index == Heap::ArrayObject::LengthPropertyIndex) {
781             Q_ASSERT(!idx.attrs.isAccessor());
782             lookup->setter = Lookup::arrayLengthSetter;
783             return lookup->setter(lookup, engine, *object, value);
784         } else if (idx.attrs.isData() && idx.attrs.isWritable()) {
785             lookup->objectLookup.ic = object->internalClass();
786             lookup->objectLookup.index = idx.index;
787             const auto nInline = object->d()->vtable()->nInlineProperties;
788             if (idx.index < nInline) {
789                 lookup->setter = Lookup::setter0Inline;
790                 lookup->objectLookup.offset = idx.index + object->d()->vtable()->inlinePropertyOffset;
791             } else {
792                 lookup->setter = Lookup::setter0MemberData;
793                 lookup->objectLookup.offset = idx.index - nInline;
794             }
795             return lookup->setter(lookup, engine, *object, value);
796         } else {
797             // ### handle setter
798             lookup->setter = Lookup::setterFallback;
799         }
800         return lookup->setter(lookup, engine, *object, value);
801     }
802 
803     lookup->insertionLookup.protoId = c->protoId;
804     if (!object->put(key, value)) {
805         lookup->setter = Lookup::setterFallback;
806         return false;
807     }
808 
809     if (object->internalClass() == c) {
810         // ### setter in the prototype, should handle this
811         lookup->setter = Lookup::setterFallback;
812         return true;
813     }
814     idx = object->internalClass()->findValueOrSetter(key);
815     if (!idx.isValid() || idx.attrs.isAccessor()) { // ### can this even happen?
816         lookup->setter = Lookup::setterFallback;
817         return false;
818     }
819     lookup->insertionLookup.newClass = object->internalClass();
820     lookup->insertionLookup.offset = idx.index;
821     lookup->setter = Lookup::setterInsert;
822     return true;
823 }
824 
checkedInstanceOf(ExecutionEngine * engine,const FunctionObject * f,const Value & var)825 ReturnedValue Object::checkedInstanceOf(ExecutionEngine *engine, const FunctionObject *f, const Value &var)
826 {
827     Scope scope(engine);
828     if (f->isBoundFunction()) {
829         ScopedValue v(scope, static_cast<const BoundFunction *>(f)->target());
830         f = v->as<FunctionObject>();
831     }
832 
833     // 15.3.5.3, 1: HasInstance can only be used on an object
834     const Object *lhs = var.as<Object>();
835     if (!lhs)
836         return Encode(false);
837 
838     // 15.3.5.3, 2
839     Value p = Value::fromReturnedValue(f->protoProperty());
840     const Object *o = p.objectValue();
841     if (!o) // 15.3.5.3, 3
842         return f->engine()->throwTypeError();
843 
844     Heap::Object *v = lhs->d();
845 
846     // 15.3.5.3, 4
847     while (v) {
848         // 15.3.5.3, 4, a
849         v = v->prototype();
850 
851         // 15.3.5.3, 4, b
852         if (!v)
853             break; // will return false
854 
855         // 15.3.5.3, 4, c
856         else if (o->d() == v)
857             return Encode(true);
858     }
859 
860     return Encode(false);
861 }
862 
virtualHasProperty(const Managed * m,PropertyKey id)863 bool Object::virtualHasProperty(const Managed *m, PropertyKey id)
864 {
865     Scope scope(m->engine());
866     ScopedObject o(scope, m);
867     ScopedProperty p(scope);
868 
869     if (o->getOwnProperty(id, p) != Attr_Invalid)
870         return true;
871 
872     o = o->getPrototypeOf();
873     if (o)
874         return o->hasProperty(id);
875 
876     return false;
877 }
878 
virtualGetOwnProperty(const Managed * m,PropertyKey id,Property * p)879 PropertyAttributes Object::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
880 {
881     PropertyAttributes attrs;
882     const Object *o = static_cast<const Object *>(m);
883     if (id.isArrayIndex()) {
884         uint index = id.asArrayIndex();
885         if (o->arrayData()) {
886             if (o->arrayData()->getProperty(index, p, &attrs))
887                 return attrs;
888         }
889     } else {
890         Q_ASSERT(id.asStringOrSymbol());
891 
892         auto member = o->internalClass()->find(id);
893         if (member.isValid()) {
894             attrs = member.attributes;
895             if (p) {
896                 p->value = *o->propertyData(member.index);
897                 if (attrs.isAccessor())
898                     p->set = *o->propertyData(member.setterIndex);
899             }
900             return attrs;
901         }
902     }
903 
904     return Attr_Invalid;
905 }
906 
virtualDefineOwnProperty(Managed * m,PropertyKey id,const Property * p,PropertyAttributes attrs)907 bool Object::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs)
908 {
909     Object *o = static_cast<Object *>(m);
910     Scope scope(o);
911 
912     if (id.isArrayIndex()) {
913         uint index = id.asArrayIndex();
914 
915         bool hasProperty = false;
916 
917         if (o->arrayData()) {
918             hasProperty = o->arrayData()->mappedIndex(index) != UINT_MAX;
919             if (!hasProperty && o->isStringObject())
920                 hasProperty = (index < static_cast<StringObject *>(o)->length());
921         }
922 
923         if (!hasProperty) {
924             if (!o->isExtensible())
925                 return false;
926 
927             ScopedProperty pp(scope);
928             pp->copy(p, attrs);
929             pp->fullyPopulated(&attrs);
930             if (attrs == Attr_Data) {
931                 ScopedValue v(scope, pp->value);
932                 o->arraySet(index, v);
933             } else {
934                 o->arraySet(index, pp, attrs);
935             }
936             return true;
937         }
938 
939         return o->internalDefineOwnProperty(scope.engine, index, nullptr, p, attrs);
940     }
941 
942     auto memberIndex = o->internalClass()->find(id);
943 
944     if (!memberIndex.isValid()) {
945         if (!o->isExtensible())
946             return false;
947 
948         Scoped<StringOrSymbol> name(scope, id.asStringOrSymbol());
949         ScopedProperty pd(scope);
950         pd->copy(p, attrs);
951         pd->fullyPopulated(&attrs);
952         o->insertMember(name, pd, attrs);
953         return true;
954     }
955 
956     return o->internalDefineOwnProperty(scope.engine, UINT_MAX, &memberIndex, p, attrs);
957 }
958 
virtualIsExtensible(const Managed * m)959 bool Object::virtualIsExtensible(const Managed *m)
960 {
961     return m->d()->internalClass->extensible;
962 }
963 
virtualPreventExtensions(Managed * m)964 bool Object::virtualPreventExtensions(Managed *m)
965 {
966     Q_ASSERT(m->isObject());
967     Object *o = static_cast<Object *>(m);
968     o->setInternalClass(o->internalClass()->nonExtensible());
969     return true;
970 }
971 
virtualGetPrototypeOf(const Managed * m)972 Heap::Object *Object::virtualGetPrototypeOf(const Managed *m)
973 {
974     return m->internalClass()->prototype;
975 }
976 
virtualSetPrototypeOf(Managed * m,const Object * proto)977 bool Object::virtualSetPrototypeOf(Managed *m, const Object *proto)
978 {
979     Q_ASSERT(m->isObject());
980     Object *o = static_cast<Object *>(m);
981     Heap::Object *current = o->internalClass()->prototype;
982     Heap::Object *protod = proto ? proto->d() : nullptr;
983     if (current == protod)
984         return true;
985     if (!o->internalClass()->extensible)
986         return false;
987     Heap::Object *p = protod;
988     while (p) {
989         if (p == o->d())
990             return false;
991         if (p->vtable()->getPrototypeOf != Object::staticVTable()->getPrototypeOf)
992             break;
993         p = p->prototype();
994     }
995     o->setInternalClass(o->internalClass()->changePrototype(protod));
996     return true;
997 }
998 
setArrayLength(uint newLen)999 bool Object::setArrayLength(uint newLen)
1000 {
1001     Q_ASSERT(isArrayObject());
1002     if (!internalClass()->propertyData[Heap::ArrayObject::LengthPropertyIndex].isWritable())
1003         return false;
1004     uint oldLen = getLength();
1005     bool ok = true;
1006     if (newLen < oldLen) {
1007         if (arrayData()) {
1008             uint l = arrayData()->vtable()->truncate(this, newLen);
1009             if (l != newLen)
1010                 ok = false;
1011             newLen = l;
1012         }
1013     } else {
1014         if (newLen >= 0x100000)
1015             initSparseArray();
1016     }
1017     setArrayLengthUnchecked(newLen);
1018     return ok;
1019 }
1020 
initSparseArray()1021 void Object::initSparseArray()
1022 {
1023     if (arrayType() == Heap::ArrayData::Sparse)
1024         return;
1025 
1026     ArrayData::realloc(this, Heap::ArrayData::Sparse, 0, false);
1027 }
1028 
isConcatSpreadable() const1029 bool Object::isConcatSpreadable() const
1030 {
1031     Scope scope(this);
1032     ScopedValue spreadable(scope, get(scope.engine->symbol_isConcatSpreadable()));
1033     if (!spreadable->isUndefined())
1034         return spreadable->toBoolean();
1035     return isArray();
1036 }
1037 
isArray() const1038 bool Object::isArray() const
1039 {
1040     if (isArrayObject())
1041         return true;
1042     if (vtable() == ProxyObject::staticVTable()) {
1043         const ProxyObject *p = static_cast<const ProxyObject *>(this);
1044         Scope scope(this);
1045         if (!p->d()->handler) {
1046             scope.engine->throwTypeError();
1047             return false;
1048         }
1049         ScopedObject o(scope, p->d()->target);
1050         return o->isArray();
1051     }
1052     return false;
1053 }
1054 
speciesConstructor(Scope & scope,const FunctionObject * defaultConstructor) const1055 const FunctionObject *Object::speciesConstructor(Scope &scope, const FunctionObject *defaultConstructor) const
1056 {
1057     ScopedValue C(scope, get(scope.engine->id_constructor()));
1058     if (C->isUndefined())
1059         return defaultConstructor;
1060     const Object *c = C->objectValue();
1061     if (!c) {
1062         scope.engine->throwTypeError();
1063         return nullptr;
1064     }
1065     ScopedValue S(scope, c->get(scope.engine->symbol_species()));
1066     if (S->isNullOrUndefined())
1067         return defaultConstructor;
1068     const FunctionObject *f = S->as<FunctionObject>();
1069     if (!f || !f->isConstructor()) {
1070         scope.engine->throwTypeError();
1071         return nullptr;
1072     }
1073     Q_ASSERT(f->isFunctionObject());
1074     return static_cast<const FunctionObject *>(f);
1075 }
1076 
setProtoFromNewTarget(const Value * newTarget)1077 bool Object::setProtoFromNewTarget(const Value *newTarget)
1078 {
1079     if (!newTarget || newTarget->isUndefined())
1080         return false;
1081 
1082     Q_ASSERT(newTarget->isFunctionObject());
1083     Scope scope(this);
1084     ScopedObject proto(scope, static_cast<const FunctionObject *>(newTarget)->protoProperty());
1085     if (proto) {
1086         setPrototypeOf(proto);
1087         return true;
1088     }
1089     return false;
1090 }
1091 
1092 
1093 DEFINE_OBJECT_VTABLE(ArrayObject);
1094 
init(const QStringList & list)1095 void Heap::ArrayObject::init(const QStringList &list)
1096 {
1097     Object::init();
1098     commonInit();
1099     Scope scope(internalClass->engine);
1100     ScopedObject a(scope, this);
1101 
1102     // Converts a QStringList to JS.
1103     // The result is a new Array object with length equal to the length
1104     // of the QStringList, and the elements being the QStringList's
1105     // elements converted to JS Strings.
1106     int len = list.count();
1107     a->arrayReserve(len);
1108     ScopedValue v(scope);
1109     for (int ii = 0; ii < len; ++ii)
1110         a->arrayPut(ii, (v = scope.engine->newString(list.at(ii))));
1111     a->setArrayLengthUnchecked(len);
1112 }
1113 
virtualGetLength(const Managed * m)1114 qint64 ArrayObject::virtualGetLength(const Managed *m)
1115 {
1116     const ArrayObject *a = static_cast<const ArrayObject *>(m);
1117     return a->propertyData(Heap::ArrayObject::LengthPropertyIndex)->toLength();
1118 }
1119 
toQStringList() const1120 QStringList ArrayObject::toQStringList() const
1121 {
1122     QStringList result;
1123 
1124     QV4::ExecutionEngine *engine = internalClass()->engine;
1125     Scope scope(engine);
1126     ScopedValue v(scope);
1127 
1128     uint length = getLength();
1129     for (uint i = 0; i < length; ++i) {
1130         v = const_cast<ArrayObject *>(this)->get(i);
1131         result.append(v->toQStringNoThrow());
1132     }
1133     return result;
1134 }
1135 
virtualDefineOwnProperty(Managed * m,PropertyKey id,const Property * p,PropertyAttributes attrs)1136 bool ArrayObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs)
1137 {
1138     Q_ASSERT(m->isArrayObject());
1139     ArrayObject *a = static_cast<ArrayObject *>(m);
1140 
1141     if (id.isArrayIndex()) {
1142         uint index = id.asArrayIndex();
1143         uint len = a->getLength();
1144         if (index >= len && !a->internalClass()->propertyData[Heap::ArrayObject::LengthPropertyIndex].isWritable())
1145             return false;
1146 
1147         bool succeeded = Object::virtualDefineOwnProperty(m, id, p, attrs);
1148         if (!succeeded)
1149             return false;
1150 
1151         if (index >= len)
1152             a->setArrayLengthUnchecked(index + 1);
1153 
1154         return true;
1155     }
1156 
1157     ExecutionEngine *engine = m->engine();
1158     if (id == engine->id_length()->propertyKey()) {
1159         Scope scope(engine);
1160         Q_ASSERT(a->internalClass()->verifyIndex(engine->id_length()->propertyKey(), Heap::ArrayObject::LengthPropertyIndex));
1161         ScopedProperty lp(scope);
1162         InternalClassEntry e = a->internalClass()->find(scope.engine->id_length()->propertyKey());
1163         a->getProperty(e, lp);
1164         if (attrs.isEmpty() || p->isSubset(attrs, lp, e.attributes))
1165             return true;
1166         if (!e.attributes.isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable())
1167             return false;
1168         bool succeeded = true;
1169         if (attrs.type() == PropertyAttributes::Data) {
1170             bool ok;
1171             uint l = p->value.asArrayLength(&ok);
1172             if (!ok) {
1173                 ScopedValue v(scope, p->value);
1174                 engine->throwRangeError(v);
1175                 return false;
1176             }
1177             succeeded = a->setArrayLength(l);
1178         }
1179         if (attrs.hasWritable() && !attrs.isWritable()) {
1180             e.attributes.setWritable(false);
1181             Heap::InternalClass::changeMember(a, engine->id_length()->propertyKey(), e.attributes);
1182         }
1183         if (!succeeded)
1184             return false;
1185         return true;
1186     }
1187     return Object::virtualDefineOwnProperty(m, id, p, attrs);
1188 }
1189