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 #include "qv4lookup_p.h"
40 #include "qv4functionobject_p.h"
41 #include "qv4jscall_p.h"
42 #include "qv4string_p.h"
43 #include <private/qv4identifiertable_p.h>
44 
45 QT_BEGIN_NAMESPACE
46 
47 using namespace QV4;
48 
49 
resolveProtoGetter(PropertyKey name,const Heap::Object * proto)50 void Lookup::resolveProtoGetter(PropertyKey name, const Heap::Object *proto)
51 {
52     while (proto) {
53         auto index = proto->internalClass->findValueOrGetter(name);
54         if (index.isValid()) {
55             PropertyAttributes attrs = index.attrs;
56             protoLookup.data = proto->propertyData(index.index);
57             if (attrs.isData()) {
58                 getter = getterProto;
59             } else {
60                 getter = getterProtoAccessor;
61             }
62             return;
63         }
64         proto = proto->prototype();
65     }
66     // ### put in a getterNotFound!
67     getter = getterFallback;
68 }
69 
resolveGetter(ExecutionEngine * engine,const Object * object)70 ReturnedValue Lookup::resolveGetter(ExecutionEngine *engine, const Object *object)
71 {
72     return object->resolveLookupGetter(engine, this);
73 }
74 
resolvePrimitiveGetter(ExecutionEngine * engine,const Value & object)75 ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Value &object)
76 {
77     primitiveLookup.type = object.type();
78     switch (primitiveLookup.type) {
79     case Value::Undefined_Type:
80     case Value::Null_Type: {
81         Scope scope(engine);
82         ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
83         const QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString())
84             .arg(QLatin1String(primitiveLookup.type == Value::Undefined_Type ? "undefined" : "null"));
85         return engine->throwTypeError(message);
86     }
87     case Value::Boolean_Type:
88         primitiveLookup.proto = engine->booleanPrototype()->d();
89         break;
90     case Value::Managed_Type: {
91         // ### Should move this over to the Object path, as strings also have an internalClass
92         Q_ASSERT(object.isStringOrSymbol());
93         primitiveLookup.proto = static_cast<const Managed &>(object).internalClass()->prototype;
94         Q_ASSERT(primitiveLookup.proto);
95         Scope scope(engine);
96         ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
97         if (object.isString() && name->equals(engine->id_length())) {
98             // special case, as the property is on the object itself
99             getter = stringLengthGetter;
100             return stringLengthGetter(this, engine, object);
101         }
102         break;
103     }
104     case Value::Integer_Type:
105     default: // Number
106         primitiveLookup.proto = engine->numberPrototype()->d();
107     }
108 
109     PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
110     protoLookup.protoId = primitiveLookup.proto->internalClass->protoId;
111     resolveProtoGetter(name, primitiveLookup.proto);
112 
113     if (getter == getterProto)
114         getter = primitiveGetterProto;
115     else if (getter == getterProtoAccessor)
116         getter = primitiveGetterAccessor;
117     return getter(this, engine, object);
118 }
119 
resolveGlobalGetter(ExecutionEngine * engine)120 ReturnedValue Lookup::resolveGlobalGetter(ExecutionEngine *engine)
121 {
122     Object *o = engine->globalObject;
123     PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
124     protoLookup.protoId = o->internalClass()->protoId;
125     resolveProtoGetter(name, o->d());
126 
127     if (getter == getterProto)
128         globalGetter = globalGetterProto;
129     else if (getter == getterProtoAccessor)
130         globalGetter = globalGetterProtoAccessor;
131     else {
132         globalGetter = globalGetterGeneric;
133         Scope scope(engine);
134         ScopedString n(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
135         return engine->throwReferenceError(n);
136     }
137     return globalGetter(this, engine);
138 }
139 
getterGeneric(Lookup * l,ExecutionEngine * engine,const Value & object)140 ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object)
141 {
142     if (const Object *o = object.as<Object>())
143         return l->resolveGetter(engine, o);
144     return l->resolvePrimitiveGetter(engine, object);
145 }
146 
getterTwoClasses(Lookup * l,ExecutionEngine * engine,const Value & object)147 ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object)
148 {
149     if (const Object *o = object.as<Object>()) {
150         Lookup first = *l;
151         Lookup second = *l;
152 
153         ReturnedValue result = second.resolveGetter(engine, o);
154 
155         if (first.getter == getter0Inline && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
156             l->objectLookupTwoClasses.ic = first.objectLookup.ic;
157             l->objectLookupTwoClasses.ic2 = second.objectLookup.ic;
158             l->objectLookupTwoClasses.offset = first.objectLookup.offset;
159             l->objectLookupTwoClasses.offset2 = second.objectLookup.offset;
160             l->getter = second.getter == getter0Inline ? getter0Inlinegetter0Inline : getter0Inlinegetter0MemberData;
161             return result;
162         }
163         if (first.getter == getter0MemberData && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
164             l->objectLookupTwoClasses.ic = second.objectLookup.ic;
165             l->objectLookupTwoClasses.ic2 = first.objectLookup.ic;
166             l->objectLookupTwoClasses.offset = second.objectLookup.offset;
167             l->objectLookupTwoClasses.offset2 = first.objectLookup.offset;
168             l->getter = second.getter == getter0Inline ? getter0Inlinegetter0MemberData : getter0MemberDatagetter0MemberData;
169             return result;
170         }
171         if (first.getter == getterProto && second.getter == getterProto) {
172             l->protoLookupTwoClasses.protoId = first.protoLookup.protoId;
173             l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId;
174             l->protoLookupTwoClasses.data = first.protoLookup.data;
175             l->protoLookupTwoClasses.data2 = second.protoLookup.data;
176             l->getter = getterProtoTwoClasses;
177             return result;
178         }
179         if (first.getter == getterProtoAccessor && second.getter == getterProtoAccessor) {
180             l->protoLookupTwoClasses.protoId = first.protoLookup.protoId;
181             l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId;
182             l->protoLookupTwoClasses.data = first.protoLookup.data;
183             l->protoLookupTwoClasses.data2 = second.protoLookup.data;
184             l->getter = getterProtoAccessorTwoClasses;
185             return result;
186         }
187 
188     }
189 
190     l->getter = getterFallback;
191     return getterFallback(l, engine, object);
192 }
193 
getterFallback(Lookup * l,ExecutionEngine * engine,const Value & object)194 ReturnedValue Lookup::getterFallback(Lookup *l, ExecutionEngine *engine, const Value &object)
195 {
196     QV4::Scope scope(engine);
197     QV4::ScopedObject o(scope, object.toObject(scope.engine));
198     if (!o)
199         return Encode::undefined();
200     ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
201     return o->get(name);
202 }
203 
getter0MemberData(Lookup * l,ExecutionEngine * engine,const Value & object)204 ReturnedValue Lookup::getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
205 {
206     // we can safely cast to a QV4::Object here. If object is actually a string,
207     // the internal class won't match
208     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
209     if (o) {
210         if (l->objectLookup.ic == o->internalClass)
211             return o->memberData->values.data()[l->objectLookup.offset].asReturnedValue();
212     }
213     return getterTwoClasses(l, engine, object);
214 }
215 
getter0Inline(Lookup * l,ExecutionEngine * engine,const Value & object)216 ReturnedValue Lookup::getter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object)
217 {
218     // we can safely cast to a QV4::Object here. If object is actually a string,
219     // the internal class won't match
220     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
221     if (o) {
222         if (l->objectLookup.ic == o->internalClass)
223             return o->inlinePropertyDataWithOffset(l->objectLookup.offset)->asReturnedValue();
224     }
225     return getterTwoClasses(l, engine, object);
226 }
227 
getterProto(Lookup * l,ExecutionEngine * engine,const Value & object)228 ReturnedValue Lookup::getterProto(Lookup *l, ExecutionEngine *engine, const Value &object)
229 {
230     // we can safely cast to a QV4::Object here. If object is actually a string,
231     // the internal class won't match
232     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
233     if (o) {
234         if (l->protoLookup.protoId == o->internalClass->protoId)
235             return l->protoLookup.data->asReturnedValue();
236     }
237     return getterTwoClasses(l, engine, object);
238 }
239 
getter0Inlinegetter0Inline(Lookup * l,ExecutionEngine * engine,const Value & object)240 ReturnedValue Lookup::getter0Inlinegetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object)
241 {
242     // we can safely cast to a QV4::Object here. If object is actually a string,
243     // the internal class won't match
244     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
245     if (o) {
246         if (l->objectLookupTwoClasses.ic == o->internalClass)
247             return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset)->asReturnedValue();
248         if (l->objectLookupTwoClasses.ic2 == o->internalClass)
249             return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset2)->asReturnedValue();
250     }
251     l->getter = getterFallback;
252     return getterFallback(l, engine, object);
253 }
254 
getter0Inlinegetter0MemberData(Lookup * l,ExecutionEngine * engine,const Value & object)255 ReturnedValue Lookup::getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
256 {
257     // we can safely cast to a QV4::Object here. If object is actually a string,
258     // the internal class won't match
259     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
260     if (o) {
261         if (l->objectLookupTwoClasses.ic == o->internalClass)
262             return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset)->asReturnedValue();
263         if (l->objectLookupTwoClasses.ic2 == o->internalClass)
264             return o->memberData->values.data()[l->objectLookupTwoClasses.offset2].asReturnedValue();
265     }
266     l->getter = getterFallback;
267     return getterFallback(l, engine, object);
268 }
269 
getter0MemberDatagetter0MemberData(Lookup * l,ExecutionEngine * engine,const Value & object)270 ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
271 {
272     // we can safely cast to a QV4::Object here. If object is actually a string,
273     // the internal class won't match
274     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
275     if (o) {
276         if (l->objectLookupTwoClasses.ic == o->internalClass)
277             return o->memberData->values.data()[l->objectLookupTwoClasses.offset].asReturnedValue();
278         if (l->objectLookupTwoClasses.ic2 == o->internalClass)
279             return o->memberData->values.data()[l->objectLookupTwoClasses.offset2].asReturnedValue();
280     }
281     l->getter = getterFallback;
282     return getterFallback(l, engine, object);
283 }
284 
getterProtoTwoClasses(Lookup * l,ExecutionEngine * engine,const Value & object)285 ReturnedValue Lookup::getterProtoTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object)
286 {
287     // we can safely cast to a QV4::Object here. If object is actually a string,
288     // the internal class won't match
289     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
290     if (o) {
291         if (l->protoLookupTwoClasses.protoId == o->internalClass->protoId)
292             return l->protoLookupTwoClasses.data->asReturnedValue();
293         if (l->protoLookupTwoClasses.protoId2 == o->internalClass->protoId)
294             return l->protoLookupTwoClasses.data2->asReturnedValue();
295         return getterFallback(l, engine, object);
296     }
297     l->getter = getterFallback;
298     return getterFallback(l, engine, object);
299 }
300 
getterAccessor(Lookup * l,ExecutionEngine * engine,const Value & object)301 ReturnedValue Lookup::getterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object)
302 {
303     // we can safely cast to a QV4::Object here. If object is actually a string,
304     // the internal class won't match
305     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
306     if (o) {
307         if (l->objectLookup.ic == o->internalClass) {
308             const Value *getter = o->propertyData(l->objectLookup.offset);
309             if (!getter->isFunctionObject()) // ### catch at resolve time
310                 return Encode::undefined();
311 
312             return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
313                                      &object, nullptr, 0));
314         }
315     }
316     l->getter = getterFallback;
317     return getterFallback(l, engine, object);
318 }
319 
getterProtoAccessor(Lookup * l,ExecutionEngine * engine,const Value & object)320 ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object)
321 {
322     // we can safely cast to a QV4::Object here. If object is actually a string,
323     // the internal class won't match
324     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
325     if (o && l->protoLookup.protoId == o->internalClass->protoId) {
326         const Value *getter = l->protoLookup.data;
327         if (!getter->isFunctionObject()) // ### catch at resolve time
328             return Encode::undefined();
329 
330         return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
331                                  &object, nullptr, 0));
332     }
333     return getterTwoClasses(l, engine, object);
334 }
335 
getterProtoAccessorTwoClasses(Lookup * l,ExecutionEngine * engine,const Value & object)336 ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object)
337 {
338     // we can safely cast to a QV4::Object here. If object is actually a string,
339     // the internal class won't match
340     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
341     if (o) {
342         const Value *getter = nullptr;
343         if (l->protoLookupTwoClasses.protoId == o->internalClass->protoId)
344             getter = l->protoLookupTwoClasses.data;
345         else if (l->protoLookupTwoClasses.protoId2 == o->internalClass->protoId)
346             getter = l->protoLookupTwoClasses.data2;
347         if (getter) {
348             if (!getter->isFunctionObject()) // ### catch at resolve time
349                 return Encode::undefined();
350 
351             return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
352                                      &object, nullptr, 0));
353         }
354     }
355     l->getter = getterFallback;
356     return getterFallback(l, engine, object);
357 }
358 
getterIndexed(Lookup * l,ExecutionEngine * engine,const Value & object)359 ReturnedValue Lookup::getterIndexed(Lookup *l, ExecutionEngine *engine, const Value &object)
360 {
361     Object *o = object.objectValue();
362     if (o) {
363         Heap::Object *ho = o->d();
364         if (ho->arrayData && ho->arrayData->type == Heap::ArrayData::Simple) {
365             Heap::SimpleArrayData *s = ho->arrayData.cast<Heap::SimpleArrayData>();
366             if (l->indexedLookup.index < s->values.size)
367                 if (!s->data(l->indexedLookup.index).isEmpty())
368                     return s->data(l->indexedLookup.index).asReturnedValue();
369         }
370         return o->get(l->indexedLookup.index);
371     }
372     l->getter = getterFallback;
373     return getterFallback(l, engine, object);
374 
375 }
376 
primitiveGetterProto(Lookup * l,ExecutionEngine * engine,const Value & object)377 ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object)
378 {
379     if (object.type() == l->primitiveLookup.type && !object.isObject()) {
380         Heap::Object *o = l->primitiveLookup.proto;
381         if (l->primitiveLookup.protoId == o->internalClass->protoId)
382             return l->primitiveLookup.data->asReturnedValue();
383     }
384     l->getter = getterGeneric;
385     return getterGeneric(l, engine, object);
386 }
387 
primitiveGetterAccessor(Lookup * l,ExecutionEngine * engine,const Value & object)388 ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object)
389 {
390     if (object.type() == l->primitiveLookup.type && !object.isObject()) {
391         Heap::Object *o = l->primitiveLookup.proto;
392         if (l->primitiveLookup.protoId == o->internalClass->protoId) {
393             const Value *getter = l->primitiveLookup.data;
394             if (!getter->isFunctionObject()) // ### catch at resolve time
395                 return Encode::undefined();
396 
397             return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
398                                      &object, nullptr, 0));
399         }
400     }
401     l->getter = getterGeneric;
402     return getterGeneric(l, engine, object);
403 }
404 
stringLengthGetter(Lookup * l,ExecutionEngine * engine,const Value & object)405 ReturnedValue Lookup::stringLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object)
406 {
407     if (const String *s = object.as<String>())
408         return Encode(s->d()->length());
409 
410     l->getter = getterGeneric;
411     return getterGeneric(l, engine, object);
412 }
413 
globalGetterGeneric(Lookup * l,ExecutionEngine * engine)414 ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine)
415 {
416     return l->resolveGlobalGetter(engine);
417 }
418 
globalGetterProto(Lookup * l,ExecutionEngine * engine)419 ReturnedValue Lookup::globalGetterProto(Lookup *l, ExecutionEngine *engine)
420 {
421     Heap::Object *o = engine->globalObject->d();
422     if (l->protoLookup.protoId == o->internalClass->protoId)
423         return l->protoLookup.data->asReturnedValue();
424     l->globalGetter = globalGetterGeneric;
425     return globalGetterGeneric(l, engine);
426 }
427 
globalGetterProtoAccessor(Lookup * l,ExecutionEngine * engine)428 ReturnedValue Lookup::globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engine)
429 {
430     Heap::Object *o = engine->globalObject->d();
431     if (l->protoLookup.protoId == o->internalClass->protoId) {
432         const Value *getter = l->protoLookup.data;
433         if (!getter->isFunctionObject()) // ### catch at resolve time
434             return Encode::undefined();
435 
436         return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
437                                   engine->globalObject, nullptr, 0));
438     }
439     l->globalGetter = globalGetterGeneric;
440     return globalGetterGeneric(l, engine);
441 }
442 
resolveSetter(ExecutionEngine * engine,Object * object,const Value & value)443 bool Lookup::resolveSetter(ExecutionEngine *engine, Object *object, const Value &value)
444 {
445     return object->resolveLookupSetter(engine, this, value);
446 }
447 
setterGeneric(Lookup * l,ExecutionEngine * engine,Value & object,const Value & value)448 bool Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
449 {
450     if (object.isObject())
451         return l->resolveSetter(engine, static_cast<Object *>(&object), value);
452 
453     if (engine->currentStackFrame->v4Function->isStrict())
454         return false;
455 
456     Scope scope(engine);
457     ScopedObject o(scope, RuntimeHelpers::convertToObject(scope.engine, object));
458     if (!o) // type error
459         return false;
460     ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
461     return o->put(name, value);
462 }
463 
setterTwoClasses(Lookup * l,ExecutionEngine * engine,Value & object,const Value & value)464 bool Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
465 {
466     Lookup first = *l;
467     Lookup second = *l;
468 
469     if (object.isObject()) {
470         if (!l->resolveSetter(engine, static_cast<Object *>(&object), value)) {
471             l->setter = setterFallback;
472             return false;
473         }
474 
475         if (l->setter == Lookup::setter0MemberData || l->setter == Lookup::setter0Inline) {
476             l->objectLookupTwoClasses.ic = first.objectLookup.ic;
477             l->objectLookupTwoClasses.ic2 = second.objectLookup.ic;
478             l->objectLookupTwoClasses.offset = first.objectLookup.index;
479             l->objectLookupTwoClasses.offset2 = second.objectLookup.index;
480             l->setter = setter0setter0;
481             return true;
482         }
483     }
484 
485     l->setter = setterFallback;
486     return setterFallback(l, engine, object, value);
487 }
488 
setterFallback(Lookup * l,ExecutionEngine * engine,Value & object,const Value & value)489 bool Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
490 {
491     QV4::Scope scope(engine);
492     QV4::ScopedObject o(scope, object.toObject(scope.engine));
493     if (!o)
494         return false;
495 
496     ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
497     return o->put(name, value);
498 }
499 
setter0MemberData(Lookup * l,ExecutionEngine * engine,Value & object,const Value & value)500 bool Lookup::setter0MemberData(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
501 {
502     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
503     if (o && o->internalClass == l->objectLookup.ic) {
504         o->memberData->values.set(engine, l->objectLookup.offset, value);
505         return true;
506     }
507 
508     return setterTwoClasses(l, engine, object, value);
509 }
510 
setter0Inline(Lookup * l,ExecutionEngine * engine,Value & object,const Value & value)511 bool Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
512 {
513     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
514     if (o && o->internalClass == l->objectLookup.ic) {
515         o->setInlinePropertyWithOffset(engine, l->objectLookup.offset, value);
516         return true;
517     }
518 
519     return setterTwoClasses(l, engine, object, value);
520 }
521 
setter0setter0(Lookup * l,ExecutionEngine * engine,Value & object,const Value & value)522 bool Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
523 {
524     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
525     if (o) {
526         if (o->internalClass == l->objectLookupTwoClasses.ic) {
527             o->setProperty(engine, l->objectLookupTwoClasses.offset, value);
528             return true;
529         }
530         if (o->internalClass == l->objectLookupTwoClasses.ic2) {
531             o->setProperty(engine, l->objectLookupTwoClasses.offset2, value);
532             return true;
533         }
534     }
535 
536     l->setter = setterFallback;
537     return setterFallback(l, engine, object, value);
538 }
539 
setterInsert(Lookup * l,ExecutionEngine * engine,Value & object,const Value & value)540 bool Lookup::setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
541 {
542     Object *o = static_cast<Object *>(object.managed());
543     if (o && o->internalClass()->protoId == l->insertionLookup.protoId) {
544         o->setInternalClass(l->insertionLookup.newClass);
545         o->d()->setProperty(engine, l->insertionLookup.offset, value);
546         return true;
547     }
548 
549     l->setter = setterFallback;
550     return setterFallback(l, engine, object, value);
551 }
552 
arrayLengthSetter(Lookup *,ExecutionEngine * engine,Value & object,const Value & value)553 bool Lookup::arrayLengthSetter(Lookup *, ExecutionEngine *engine, Value &object, const Value &value)
554 {
555     Q_ASSERT(object.isObject() && static_cast<Object &>(object).isArrayObject());
556     bool ok;
557     uint len = value.asArrayLength(&ok);
558     if (!ok) {
559         engine->throwRangeError(value);
560         return false;
561     }
562     ok = static_cast<Object &>(object).setArrayLength(len);
563     if (!ok)
564         return false;
565     return true;
566 }
567 
568 QT_END_NAMESPACE
569