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

source code of qtdeclarative/src/qml/jsruntime/qv4lookup.cpp