Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qv4proxy.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
5#include "qv4proxy_p.h"
6#include "qv4symbol_p.h"
7#include "qv4jscall_p.h"
8#include "qv4objectproto_p.h"
9#include "qv4persistent_p.h"
10#include "qv4objectiterator_p.h"
11
12using namespace QV4;
13
16
17void Heap::ProxyObject::init(const QV4::Object *target, const QV4::Object *handler)
18{
19 Object::init();
20 ExecutionEngine *e = internalClass->engine;
21 this->target.set(e, target->d());
22 this->handler.set(e, handler->d());
23}
24
26{
28 FunctionObject::init(e->rootContext());
29 this->target.set(e, target->d());
30 this->handler.set(e, handler->d());
31
32 if (!target->isConstructor())
33 jsConstruct = nullptr;
34}
35
36
37ReturnedValue ProxyObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
38{
39 Scope scope(m);
40 const ProxyObject *o = static_cast<const ProxyObject *>(m);
41 if (!o->d()->handler)
42 return scope.engine->throwTypeError();
43
44 ScopedObject target(scope, o->d()->target);
46 ScopedObject handler(scope, o->d()->handler);
47 ScopedValue trap(scope, handler->get(scope.engine->id_get()));
48 if (scope.hasException())
49 return Encode::undefined();
50 if (trap->isNullOrUndefined())
51 return target->get(id, receiver, hasProperty);
52 if (!trap->isFunctionObject())
53 return scope.engine->throwTypeError();
54 if (hasProperty)
55 *hasProperty = true;
56
57 Value *args = scope.alloc(3);
58 args[0] = target;
59 args[1] = id.toStringOrSymbol(scope.engine);
60 args[2] = *receiver;
61 JSCallData cdata(handler, args, 3);
62
63 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
64 if (scope.hasException())
65 return Encode::undefined();
66 ScopedProperty targetDesc(scope);
67 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
68 if (attributes != Attr_Invalid && !attributes.isConfigurable()) {
69 if (attributes.isData() && !attributes.isWritable()) {
70 if (!trapResult->sameValue(targetDesc->value))
71 return scope.engine->throwTypeError();
72 }
73 if (attributes.isAccessor() && targetDesc->value.isUndefined()) {
74 if (!trapResult->isUndefined())
75 return scope.engine->throwTypeError();
76 }
77 }
78 return trapResult->asReturnedValue();
79}
80
82{
83 Scope scope(m);
84 const ProxyObject *o = static_cast<const ProxyObject *>(m);
85 if (!o->d()->handler)
86 return scope.engine->throwTypeError();
87
88 ScopedObject target(scope, o->d()->target);
90 ScopedObject handler(scope, o->d()->handler);
91 ScopedValue trap(scope, handler->get(scope.engine->id_set()));
92 if (scope.hasException())
93 return Encode::undefined();
94 if (trap->isNullOrUndefined())
95 return target->put(id, value, receiver);
96 if (!trap->isFunctionObject())
97 return scope.engine->throwTypeError();
98
99 Value *args = scope.alloc(4);
100 args[0] = target;
101 args[1] = id.toStringOrSymbol(scope.engine);
102 args[2] = value;
103 args[3] = *receiver;
104 JSCallData cdata(handler, args, 4);
105
106 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
107 if (scope.hasException() || !trapResult->toBoolean())
108 return false;
109 ScopedProperty targetDesc(scope);
110 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
111 if (attributes != Attr_Invalid && !attributes.isConfigurable()) {
112 if (attributes.isData() && !attributes.isWritable()) {
113 if (!value.sameValue(targetDesc->value))
114 return scope.engine->throwTypeError();
115 }
116 if (attributes.isAccessor() && targetDesc->set.isUndefined())
117 return scope.engine->throwTypeError();
118 }
119 return true;
120}
121
123{
124 Scope scope(m);
125 const ProxyObject *o = static_cast<const ProxyObject *>(m);
126 if (!o->d()->handler)
127 return scope.engine->throwTypeError();
128
129 ScopedObject target(scope, o->d()->target);
131 ScopedObject handler(scope, o->d()->handler);
132 ScopedString deleteProp(scope, scope.engine->newString(QStringLiteral("deleteProperty")));
133 ScopedValue trap(scope, handler->get(deleteProp));
134 if (scope.hasException())
135 return Encode::undefined();
136 if (trap->isNullOrUndefined())
137 return target->deleteProperty(id);
138 if (!trap->isFunctionObject())
139 return scope.engine->throwTypeError();
140
141 Value *args = scope.alloc(3);
142 args[0] = target;
143 args[1] = id.toStringOrSymbol(scope.engine);
144 args[2] = o->d(); // ### fix receiver handling
145 JSCallData cdata(handler, args, 3);
146
147 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
148 if (scope.hasException() || !trapResult->toBoolean())
149 return false;
150 ScopedProperty targetDesc(scope);
151 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
152 if (attributes == Attr_Invalid)
153 return true;
154 if (!attributes.isConfigurable())
155 return scope.engine->throwTypeError();
156 return true;
157}
158
160{
161 Scope scope(m);
162 const ProxyObject *o = static_cast<const ProxyObject *>(m);
163 if (!o->d()->handler)
164 return scope.engine->throwTypeError();
165
166 ScopedObject target(scope, o->d()->target);
168 ScopedObject handler(scope, o->d()->handler);
169 ScopedString hasProp(scope, scope.engine->newString(QStringLiteral("has")));
170 ScopedValue trap(scope, handler->get(hasProp));
171 if (scope.hasException())
172 return Encode::undefined();
173 if (trap->isNullOrUndefined())
174 return target->hasProperty(id);
175 if (!trap->isFunctionObject())
176 return scope.engine->throwTypeError();
177
178 Value *args = scope.alloc(2);
179 args[0] = target;
180 args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
181 JSCallData cdata(handler, args, 2);
182
183 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
184 if (scope.hasException())
185 return false;
186 bool result = trapResult->toBoolean();
187 if (!result) {
188 ScopedProperty targetDesc(scope);
189 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
190 if (attributes != Attr_Invalid) {
191 if (!attributes.isConfigurable() || !target->isExtensible())
192 return scope.engine->throwTypeError();
193 }
194 }
195 return result;
196}
197
199{
200 Scope scope(m);
201 const ProxyObject *o = static_cast<const ProxyObject *>(m);
202 if (!o->d()->handler) {
203 scope.engine->throwTypeError();
204 return Attr_Invalid;
205 }
206
207 ScopedObject target(scope, o->d()->target);
209 ScopedObject handler(scope, o->d()->handler);
210 ScopedString deleteProp(scope, scope.engine->newString(QStringLiteral("getOwnPropertyDescriptor")));
211 ScopedValue trap(scope, handler->get(deleteProp));
212 if (scope.hasException())
213 return Attr_Invalid;
214 if (trap->isNullOrUndefined())
215 return target->getOwnProperty(id, p);
216 if (!trap->isFunctionObject()) {
217 scope.engine->throwTypeError();
218 return Attr_Invalid;
219 }
220
221 Value *args = scope.alloc(2);
222 args[0] = target;
223 args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
224 JSCallData cdata(handler, args, 2);
225
226 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
227 if (scope.hasException())
228 return Attr_Invalid;
229 if (!trapResult->isObject() && !trapResult->isUndefined()) {
230 scope.engine->throwTypeError();
231 return Attr_Invalid;
232 }
233
234 ScopedProperty targetDesc(scope);
235 PropertyAttributes targetAttributes = target->getOwnProperty(id, targetDesc);
236 if (trapResult->isUndefined()) {
237 if (p)
238 p->value = Encode::undefined();
239 if (targetAttributes == Attr_Invalid) {
240 return Attr_Invalid;
241 }
242 if (!targetAttributes.isConfigurable() || !target->isExtensible()) {
243 scope.engine->throwTypeError();
244 return Attr_Invalid;
245 }
246 return Attr_Invalid;
247 }
248
249 //bool extensibleTarget = target->isExtensible();
250 ScopedProperty resultDesc(scope);
251 PropertyAttributes resultAttributes;
252 ObjectPrototype::toPropertyDescriptor(scope.engine, trapResult, resultDesc, &resultAttributes);
253 resultDesc->completed(&resultAttributes);
254
255 if (!targetDesc->isCompatible(targetAttributes, resultDesc, resultAttributes)) {
256 scope.engine->throwTypeError();
257 return Attr_Invalid;
258 }
259
260 if (!resultAttributes.isConfigurable()) {
261 if (targetAttributes == Attr_Invalid || targetAttributes.isConfigurable()) {
262 scope.engine->throwTypeError();
263 return Attr_Invalid;
264 }
265 }
266
267 if (p) {
268 p->value = resultDesc->value;
269 p->set = resultDesc->set;
270 }
271 return resultAttributes;
272}
273
275{
276 Scope scope(m);
277 const ProxyObject *o = static_cast<const ProxyObject *>(m);
278 if (!o->d()->handler) {
279 scope.engine->throwTypeError();
280 return false;
281 }
282
283 ScopedObject target(scope, o->d()->target);
285 ScopedObject handler(scope, o->d()->handler);
286 ScopedString prop(scope, scope.engine->newString(QStringLiteral("defineProperty")));
287 ScopedValue trap(scope, handler->get(prop));
288 if (scope.hasException())
289 return false;
290 if (trap->isNullOrUndefined())
291 return target->defineOwnProperty(id, p, attrs);
292 if (!trap->isFunctionObject()) {
293 scope.engine->throwTypeError();
294 return false;
295 }
296
297 Value *args = scope.alloc(3);
298 args[0] = target;
299 args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
301 JSCallData cdata(handler, args, 3);
302
303 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
304 bool result = !scope.hasException() && trapResult->toBoolean();
305 if (!result)
306 return false;
307
308 ScopedProperty targetDesc(scope);
309 PropertyAttributes targetAttributes = target->getOwnProperty(id, targetDesc);
310 bool extensibleTarget = target->isExtensible();
311 bool settingConfigFalse = attrs.hasConfigurable() && !attrs.isConfigurable();
312 if (targetAttributes == Attr_Invalid) {
313 if (!extensibleTarget || settingConfigFalse) {
314 scope.engine->throwTypeError();
315 return false;
316 }
317 } else {
318 if (!targetDesc->isCompatible(targetAttributes, p, attrs)) {
319 scope.engine->throwTypeError();
320 return false;
321 }
322 if (settingConfigFalse && targetAttributes.isConfigurable()) {
323 scope.engine->throwTypeError();
324 return false;
325 }
326 }
327
328 return true;
329}
330
332{
333 Scope scope(m);
334 const ProxyObject *o = static_cast<const ProxyObject *>(m);
335 if (!o->d()->handler)
336 return scope.engine->throwTypeError();
337
338 ScopedObject target(scope, o->d()->target);
340 ScopedObject handler(scope, o->d()->handler);
341 ScopedString hasProp(scope, scope.engine->newString(QStringLiteral("isExtensible")));
342 ScopedValue trap(scope, handler->get(hasProp));
343 if (scope.hasException())
344 return Encode::undefined();
345 if (trap->isNullOrUndefined())
346 return target->isExtensible();
347 if (!trap->isFunctionObject())
348 return scope.engine->throwTypeError();
349
350 Value *args = scope.alloc(1);
351 args[0] = target;
352 JSCallData cdata(handler, args, 1);
353
354 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
355 if (scope.hasException())
356 return false;
357 bool result = trapResult->toBoolean();
358 if (result != target->isExtensible()) {
359 scope.engine->throwTypeError();
360 return false;
361 }
362 return result;
363}
364
366{
367 Scope scope(m);
368 const ProxyObject *o = static_cast<const ProxyObject *>(m);
369 if (!o->d()->handler)
370 return scope.engine->throwTypeError();
371
372 ScopedObject target(scope, o->d()->target);
374 ScopedObject handler(scope, o->d()->handler);
375 ScopedString hasProp(scope, scope.engine->newString(QStringLiteral("preventExtensions")));
376 ScopedValue trap(scope, handler->get(hasProp));
377 if (scope.hasException())
378 return Encode::undefined();
379 if (trap->isNullOrUndefined())
380 return target->preventExtensions();
381 if (!trap->isFunctionObject())
382 return scope.engine->throwTypeError();
383
384 Value *args = scope.alloc(1);
385 args[0] = target;
386 JSCallData cdata(handler, args, 1);
387
388 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
389 if (scope.hasException())
390 return false;
391 bool result = trapResult->toBoolean();
392 if (result && target->isExtensible()) {
393 scope.engine->throwTypeError();
394 return false;
395 }
396 return result;
397}
398
400{
401 Scope scope(m);
402 const ProxyObject *o = static_cast<const ProxyObject *>(m);
403 if (!o->d()->handler) {
404 scope.engine->throwTypeError();
405 return nullptr;
406 }
407
408 ScopedObject target(scope, o->d()->target);
410 ScopedObject handler(scope, o->d()->handler);
411 ScopedString name(scope, scope.engine->newString(QStringLiteral("getPrototypeOf")));
412 ScopedValue trap(scope, handler->get(name));
413 if (scope.hasException())
414 return nullptr;
415 if (trap->isNullOrUndefined())
416 return target->getPrototypeOf();
417 if (!trap->isFunctionObject()) {
418 scope.engine->throwTypeError();
419 return nullptr;
420 }
421
422 Value *args = scope.alloc(1);
423 args[0] = target;
424 JSCallData cdata(handler, args, 1);
425
426 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
427 if (scope.hasException())
428 return nullptr;
429 if (!trapResult->isNull() && !trapResult->isObject()) {
430 scope.engine->throwTypeError();
431 return nullptr;
432 }
433 Heap::Object *proto = trapResult->isNull() ? nullptr : static_cast<Heap::Object *>(trapResult->heapObject());
434 if (!target->isExtensible()) {
435 Heap::Object *targetProto = target->getPrototypeOf();
436 if (proto != targetProto) {
437 scope.engine->throwTypeError();
438 return nullptr;
439 }
440 }
441 return proto;
442}
443
445{
446 Scope scope(m);
447 const ProxyObject *o = static_cast<const ProxyObject *>(m);
448 if (!o->d()->handler) {
449 scope.engine->throwTypeError();
450 return false;
451 }
452
453 ScopedObject target(scope, o->d()->target);
455 ScopedObject handler(scope, o->d()->handler);
456 ScopedString name(scope, scope.engine->newString(QStringLiteral("setPrototypeOf")));
457 ScopedValue trap(scope, handler->get(name));
458 if (scope.hasException())
459 return false;
460 if (trap->isNullOrUndefined())
461 return target->setPrototypeOf(p);
462 if (!trap->isFunctionObject()) {
463 scope.engine->throwTypeError();
464 return false;
465 }
466
467 Value *args = scope.alloc(2);
468 args[0] = target;
469 args[1] = p ? p->asReturnedValue() : Encode::null();
470 JSCallData cdata(handler, args, 2);
471
472 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
473 bool result = !scope.hasException() && trapResult->toBoolean();
474 if (!result)
475 return false;
476 if (!target->isExtensible()) {
477 Heap::Object *targetProto = target->getPrototypeOf();
478 if (p->d() != targetProto) {
479 scope.engine->throwTypeError();
480 return false;
481 }
482 }
483 return true;
484}
485
487{
491
494 PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
495
496};
497
499{
500 ownKeys = keys;
501 len = keys->getLength();
502}
503
505{
506 if (index >= len || m == nullptr)
507 return PropertyKey::invalid();
508
509 Scope scope(m);
510 ScopedObject keys(scope, ownKeys.asManaged());
512 ++index;
513
514 if (pd || attrs) {
515 ScopedProperty p(scope);
516 PropertyAttributes a = const_cast<Object *>(m)->getOwnProperty(key, pd ? pd : p);
517 if (attrs)
518 *attrs = a;
519 }
520
521 return key;
522}
523
525 uint len = target->getLength();
526 bool found = false;
527 for (uint i = 0; i < len; ++i) {
528 ReturnedValue v = target->get(i);
529 if (v == val) {
530 found = true;
532 }
533 }
534 return found;
535}
536
538{
539 Scope scope(m);
540 const ProxyObject *o = static_cast<const ProxyObject *>(m);
541 if (!o->d()->handler) {
542 scope.engine->throwTypeError();
543 return nullptr;
544 }
545
546 ScopedObject target(scope, o->d()->target);
548 ScopedObject handler(scope, o->d()->handler);
549 ScopedString name(scope, scope.engine->newString(QStringLiteral("ownKeys")));
550 ScopedValue trap(scope, handler->get(name));
551
552 if (scope.hasException())
553 return nullptr;
554 if (trap->isUndefined())
555 return target->ownPropertyKeys(iteratorTarget);
556 if (!trap->isFunctionObject()) {
557 scope.engine->throwTypeError();
558 return nullptr;
559 }
560
561 Value *args = scope.alloc(1);
562 args[0] = target;
563 JSCallData cdata(handler, args, 1);
564 ScopedObject trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
565 if (scope.hasException())
566 return nullptr;
567 if (!trapResult) {
568 scope.engine->throwTypeError();
569 return nullptr;
570 }
571
572 uint len = trapResult->getLength();
573 ScopedArrayObject trapKeys(scope, scope.engine->newArrayObject());
575 for (uint i = 0; i < len; ++i) {
576 key = trapResult->get(i);
577 if (scope.hasException())
578 return nullptr;
579 if (!key) {
580 scope.engine->throwTypeError();
581 return nullptr;
582 }
583 Value keyAsValue = Value::fromReturnedValue(key->toPropertyKey().id());
584 trapKeys->push_back(keyAsValue);
585 }
586
587 ScopedArrayObject targetConfigurableKeys(scope, scope.engine->newArrayObject());
588 ScopedArrayObject targetNonConfigurableKeys(scope, scope.engine->newArrayObject());
590 ScopedPropertyKey k(scope);
591 while (1) {
593 k = it.next(nullptr, &attrs);
594 if (!k->isValid())
595 break;
596 Value keyAsValue = Value::fromReturnedValue(k->id());
597 if (attrs.isConfigurable())
598 targetConfigurableKeys->push_back(keyAsValue);
599 else
600 targetNonConfigurableKeys->push_back(keyAsValue);
601 }
602 if (target->isExtensible() && targetNonConfigurableKeys->getLength() == 0) {
603 *iteratorTarget = *m;
604 return new ProxyObjectOwnPropertyKeyIterator(trapKeys);
605 }
606
607 ScopedArrayObject uncheckedResultKeys(scope, scope.engine->newArrayObject());
608 uncheckedResultKeys->copyArrayData(trapKeys);
609
610 len = targetNonConfigurableKeys->getLength();
611 for (uint i = 0; i < len; ++i) {
612 k = PropertyKey::fromId(targetNonConfigurableKeys->get(i));
613 if (!removeAllOccurrences(uncheckedResultKeys, k->id())) {
614 scope.engine->throwTypeError();
615 return nullptr;
616 }
617 }
618
619 if (target->isExtensible()) {
620 *iteratorTarget = *m;
621 return new ProxyObjectOwnPropertyKeyIterator(trapKeys);
622 }
623
624 len = targetConfigurableKeys->getLength();
625 for (uint i = 0; i < len; ++i) {
626 k = PropertyKey::fromId(targetConfigurableKeys->get(i));
627 if (!removeAllOccurrences(uncheckedResultKeys, k->id())) {
628 scope.engine->throwTypeError();
629 return nullptr;
630 }
631 }
632
633 len = uncheckedResultKeys->getLength();
634 for (uint i = 0; i < len; ++i) {
635 if (uncheckedResultKeys->get(i) != Encode::undefined()) {
636 scope.engine->throwTypeError();
637 return nullptr;
638 }
639 }
640
641 *iteratorTarget = *m;
642 return new ProxyObjectOwnPropertyKeyIterator(trapKeys);
643}
644
645
647{
648 Scope scope(f);
649 const ProxyObject *o = static_cast<const ProxyObject *>(f);
650 if (!o->d()->handler)
651 return scope.engine->throwTypeError();
652
653 ScopedFunctionObject target(scope, o->d()->target);
655 ScopedObject handler(scope, o->d()->handler);
656 ScopedString name(scope, scope.engine->newString(QStringLiteral("construct")));
657 ScopedValue trap(scope, handler->get(name));
658
659 if (scope.hasException())
660 return Encode::undefined();
661 if (trap->isNullOrUndefined()) {
662 Q_ASSERT(target->isConstructor());
663 return target->callAsConstructor(argv, argc, newTarget);
664 }
665 if (!trap->isFunctionObject())
666 return scope.engine->throwTypeError();
667
668 ScopedFunctionObject trapFunction(scope, trap);
669 Value *arguments = scope.alloc(3);
670 arguments[0] = target;
671 arguments[1] = scope.engine->newArrayObject(argv, argc);
672 arguments[2] = newTarget ? *newTarget : Value::undefinedValue();
673 ScopedObject result(scope, trapFunction->call(handler, arguments, 3));
674
675 if (!result)
676 return scope.engine->throwTypeError();
677 return result->asReturnedValue();
678}
679
680ReturnedValue ProxyFunctionObject::virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
681{
682 Scope scope(f);
683
684 const ProxyObject *o = static_cast<const ProxyObject *>(f);
685 if (!o->d()->handler)
686 return scope.engine->throwTypeError();
687
688 ScopedFunctionObject target(scope, o->d()->target);
690 ScopedObject handler(scope, o->d()->handler);
691 ScopedString name(scope, scope.engine->newString(QStringLiteral("apply")));
692 ScopedValue trap(scope, handler->get(name));
693
694 if (scope.hasException())
695 return Encode::undefined();
696 if (trap->isNullOrUndefined())
697 return checkedResult(scope.engine, target->call(thisObject, argv, argc));
698 if (!trap->isFunctionObject())
699 return scope.engine->throwTypeError();
700
701 ScopedFunctionObject trapFunction(scope, trap);
702 Value *arguments = scope.alloc(3);
703 arguments[0] = target;
704 arguments[1] = thisObject ? *thisObject : Value::undefinedValue();
705 arguments[2] = scope.engine->newArrayObject(argv, argc);
706 return trapFunction->call(handler, arguments, 3);
707}
708
710
711void Heap::Proxy::init(QV4::ExecutionContext *ctx)
712{
713 Heap::FunctionObject::init(ctx, QStringLiteral("Proxy"));
714
715 Scope scope(ctx);
716 Scoped<QV4::Proxy> ctor(scope, this);
717 ctor->defineDefaultProperty(QStringLiteral("revocable"), QV4::Proxy::method_revocable, 2);
718 ctor->defineReadonlyConfigurableProperty(scope.engine->id_length(), Value::fromInt32(2));
719}
720
722{
723 Scope scope(f);
724 if (argc < 2 || !argv[0].isObject() || !argv[1].isObject())
725 return scope.engine->throwTypeError();
726
727 const Object *target = static_cast<const Object *>(argv);
728 const Object *handler = static_cast<const Object *>(argv + 1);
729 if (const ProxyObject *ptarget = target->as<ProxyObject>())
730 if (!ptarget->d()->handler)
731 return scope.engine->throwTypeError();
732 if (const ProxyObject *phandler = handler->as<ProxyObject>())
733 if (!phandler->d()->handler)
734 return scope.engine->throwTypeError();
735
736 const FunctionObject *targetFunction = target->as<FunctionObject>();
737 if (targetFunction)
738 return scope.engine->memoryManager->allocate<ProxyFunctionObject>(targetFunction, handler)->asReturnedValue();
739 return scope.engine->memoryManager->allocate<ProxyObject>(target, handler)->asReturnedValue();
740}
741
743{
744 return f->engine()->throwTypeError();
745}
746
747ReturnedValue Proxy::method_revocable(const FunctionObject *f, const Value *, const Value *argv, int argc)
748{
749 Scope scope(f);
751 if (scope.hasException())
752 return Encode::undefined();
754
755 ScopedString revoke(scope, scope.engine->newString(QStringLiteral("revoke")));
756 ScopedFunctionObject revoker(scope, scope.engine->memoryManager->allocate<FunctionObject>(scope.engine->rootContext(), nullptr, method_revoke));
757 revoker->defineReadonlyConfigurableProperty(scope.engine->id_length(), Value::fromInt32(0));
758 revoker->defineDefaultProperty(scope.engine->symbol_revokableProxy(), proxy);
759
760 ScopedObject o(scope, scope.engine->newObject());
761 ScopedString p(scope, scope.engine->newString(QStringLiteral("proxy")));
762 o->defineDefaultProperty(p, proxy);
763 o->defineDefaultProperty(revoke, revoker);
764 return o->asReturnedValue();
765}
766
768{
769 Scope scope(f);
770 ScopedObject o(scope, f->get(scope.engine->symbol_revokableProxy()));
771 Q_ASSERT(o);
772 ProxyObject *proxy = o->cast<ProxyObject>();
773
774 proxy->d()->target.set(scope.engine, nullptr);
775 proxy->d()->handler.set(scope.engine, nullptr);
776 return Encode::undefined();
777}
ObjectType::Data * allocate(Args &&... args)
Definition qv4mm_p.h:199
EGLContext ctx
double e
QSet< QString >::iterator it
QList< QVariant > arguments
short next
Definition keywords.cpp:445
\qmltype Particle \inqmlmodule QtQuick.Particles
quint64 ReturnedValue
ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result)
@ Attr_Invalid
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLfloat GLfloat f
GLenum target
GLuint name
GLuint GLfloat * val
GLenum GLsizei len
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
unsigned int uint
Definition qtypes.h:29
static bool removeAllOccurrences(ArrayObject *target, ReturnedValue val)
Definition qv4proxy.cpp:524
#define DEFINE_OBJECT_VTABLE(classname)
QStringList keys
QObject::connect nullptr
QNetworkProxy proxy
[0]
QJSValueList args
PropertyKey next(const Object *o, Property *pd=nullptr, PropertyAttributes *attrs=nullptr) override
Definition qv4proxy.cpp:504
ProxyObjectOwnPropertyKeyIterator(ArrayObject *keys)
Definition qv4proxy.cpp:498
~ProxyObjectOwnPropertyKeyIterator() override=default
static constexpr ReturnedValue undefined()
static constexpr ReturnedValue null()
MemoryManager * memoryManager
ExecutionContext * rootContext() const
Heap::String * newString(const QString &s=QString())
String * id_length() const
String * id_get() const
Heap::Object * newObject()
Symbol * symbol_revokableProxy() const
String * id_set() const
Heap::ArrayObject * newArrayObject(int count=0)
ReturnedValue throwTypeError()
ReturnedValue name() const
ReturnedValue call(const JSCallData &data) const
Heap::ExecutionContext * scope() const
void init(const QV4::FunctionObject *target, const QV4::Object *handler)
Definition qv4proxy.cpp:25
Heap::InternalClass * internalClass() const
static void toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs)
static ReturnedValue fromPropertyDescriptor(ExecutionEngine *engine, const Property *desc, PropertyAttributes attrs)
bool set(StringOrSymbol *name, const Value &v, ThrowOnFailure shouldThrow)
bool isConfigurable() const
bool isValid() const
static PropertyKey fromId(quint64 id)
static PropertyKey invalid()
static PropertyKey fromArrayIndex(uint idx)
quint64 id() const
bool isCompatible(PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const
void completed(PropertyAttributes *attrs)
static ReturnedValue method_revocable(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
Definition qv4proxy.cpp:747
static ReturnedValue method_revoke(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
Definition qv4proxy.cpp:767
Value * alloc(qint64 nValues) const =delete
bool hasException() const
ExecutionEngine * engine
constexpr ReturnedValue asReturnedValue() const
bool isNullOrUndefined() const
bool isUndefined() const
static constexpr VTable::SetPrototypeOf virtualSetPrototypeOf
static constexpr VTable::DefineOwnProperty virtualDefineOwnProperty
static constexpr VTable::OwnPropertyKeys virtualOwnPropertyKeys
static constexpr VTable::GetOwnProperty virtualGetOwnProperty
static constexpr VTable::CallAsConstructor virtualCallAsConstructor
static constexpr VTable::Call virtualCall
static constexpr VTable::PreventExtensions virtualPreventExtensions
static constexpr VTable::GetPrototypeOf virtualGetPrototypeOf
static constexpr VTable::DeleteProperty virtualDeleteProperty
static constexpr VTable::Get virtualGet
static constexpr VTable::HasProperty virtualHasProperty
static constexpr VTable::Put virtualPut
static constexpr VTable::IsExtensible virtualIsExtensible
static constexpr Value fromInt32(int i)
Definition qv4value_p.h:187
bool isFunctionObject() const
Definition qv4value_p.h:309
Heap::String * toString(ExecutionEngine *e) const
Definition qv4value_p.h:114
bool toBoolean() const
Definition qv4value_p.h:97
static constexpr Value undefinedValue()
Definition qv4value_p.h:191
static constexpr Value fromReturnedValue(ReturnedValue val)
Definition qv4value_p.h:165
const T * as() const
Definition qv4value_p.h:132
bool sameValue(Value other) const
Definition qv4value.cpp:226
QML_NEARLY_ALWAYS_INLINE Value::HeapBasePtr heapObject() const
Definition qv4value_p.h:80
static Value fromUInt32(uint i)
Definition qv4value_p.h:203
bool isObject() const
Definition qv4value_p.h:302