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