Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qv4runtime.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 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
// Qt-Security score:significant
4
5
#
include
"qv4runtime_p.h"
6
7
#
include
<
private
/
qqmlengine_p
.
h
>
8
#
include
<
private
/
qqmljavascriptexpression_p
.
h
>
9
#
include
<
private
/
qqmljsast_p
.
h
>
10
#
include
<
private
/
qqmltypewrapper_p
.
h
>
11
#
include
<
private
/
qqmlvaluetypewrapper_p
.
h
>
12
#
include
<
private
/
qv4argumentsobject_p
.
h
>
13
#
include
<
private
/
qv4engine_p
.
h
>
14
#
include
<
private
/
qv4function_p
.
h
>
15
#
include
<
private
/
qv4generatorobject_p
.
h
>
16
#
include
<
private
/
qv4global_p
.
h
>
17
#
include
<
private
/
qv4globalobject_p
.
h
>
18
#
include
<
private
/
qv4jscall_p
.
h
>
19
#
include
<
private
/
qv4lookup_p
.
h
>
20
#
include
<
private
/
qv4math_p
.
h
>
21
#
include
<
private
/
qv4object_p
.
h
>
22
#
include
<
private
/
qv4qmlcontext_p
.
h
>
23
#
include
<
private
/
qv4qobjectwrapper_p
.
h
>
24
#
include
<
private
/
qv4regexp_p
.
h
>
25
#
include
<
private
/
qv4regexpobject_p
.
h
>
26
#
include
<
private
/
qv4scopedvalue_p
.
h
>
27
#
include
<
private
/
qv4stackframe_p
.
h
>
28
#
include
<
private
/
qv4symbol_p
.
h
>
29
30
#
include
<
wtf
/
MathExtras
.
h
>
31
32
#
include
<
QtCore
/
private
/
qlocale_tools_p
.
h
>
33
#
include
<
QtCore
/
qdebug
.
h
>
34
35
#
ifdef
QV4_COUNT_RUNTIME_FUNCTIONS
36
#
include
<
QtCore
/
qbuffer
.
h
>
37
#
endif
// QV4_COUNT_RUNTIME_FUNCTIONS
38
39
#
include
<
cassert
>
40
#
include
<
cstdio
>
41
#
include
<
stdlib
.
h
>
42
43
QT_BEGIN_NAMESPACE
44
45
Q_STATIC_LOGGING_CATEGORY
(lcCoercingTypeAssertion,
"qt.qml.coercingTypeAssertion"
);
46
47
namespace
QV4
{
48
49
#
ifdef
QV4_COUNT_RUNTIME_FUNCTIONS
50
struct
RuntimeCounters
::
Data
{
51
enum
Type
{
52
None
= 0,
53
Undefined
= 1,
54
Null
= 2,
55
Boolean
= 3,
56
Integer
= 4,
57
Managed
= 5,
58
Double
= 7
59
};
60
61
static
const
char
*
pretty
(
Type
t
) {
62
switch
(
t
) {
63
case
None
:
return
""
;
64
case
Undefined
:
return
"Undefined"
;
65
case
Null
:
return
"Null"
;
66
case
Boolean
:
return
"Boolean"
;
67
case
Integer
:
return
"Integer"
;
68
case
Managed
:
return
"Managed"
;
69
case
Double
:
return
"Double"
;
70
default
:
return
"Unknown"
;
71
}
72
}
73
74
static
unsigned
mangle
(
unsigned
tag
) {
75
switch
(
tag
) {
76
case
Value
::
Undefined_Type
:
return
Undefined
;
77
case
Value
::
Null_Type
:
return
Null
;
78
case
Value
::
Boolean_Type
:
return
Boolean
;
79
case
Value
::
Integer_Type
:
return
Integer
;
80
case
Value
::
Managed_Type
:
return
Managed
;
81
default
:
return
Double
;
82
}
83
}
84
85
static
unsigned
mangle
(
unsigned
tag1
,
unsigned
tag2
) {
86
return
(
mangle
(
tag1
) << 3) |
mangle
(
tag2
);
87
}
88
89
static
void
unmangle
(
unsigned
signature
,
Type
&
tag1
,
Type
&
tag2
) {
90
tag1
=
Type
((
signature
>> 3) & 7);
91
tag2
=
Type
(
signature
& 7);
92
}
93
94
typedef
QList
<
quint64
>
Counters
;
95
QHash
<
const
char
*,
Counters
>
counters
;
96
97
inline
void
count
(
const
char
*
func
) {
98
QList
<
quint64
> &
cnt
=
counters
[
func
];
99
if
(
cnt
.
isEmpty
())
100
cnt
.
resize
(64);
101
cnt
[0] += 1;
102
}
103
104
inline
void
count
(
const
char
*
func
,
unsigned
tag
) {
105
QList
<
quint64
> &
cnt
=
counters
[
func
];
106
if
(
cnt
.
isEmpty
())
107
cnt
.
resize
(64);
108
cnt
[
mangle
(
tag
)] += 1;
109
}
110
111
inline
void
count
(
const
char
*
func
,
unsigned
tag1
,
unsigned
tag2
) {
112
QList
<
quint64
> &
cnt
=
counters
[
func
];
113
if
(
cnt
.
isEmpty
())
114
cnt
.
resize
(64);
115
cnt
[
mangle
(
tag1
,
tag2
)] += 1;
116
}
117
118
struct
Line
{
119
const
char
*
func
;
120
Type
tag1
,
tag2
;
121
quint64
count
;
122
123
static
bool
less
(
const
Line
&
line1
,
const
Line
&
line2
) {
124
return
line1
.
count
>
line2
.
count
;
125
}
126
};
127
128
void
dump
()
const
{
129
QBuffer
buf
;
130
buf
.
open
(
QIODevice
::
WriteOnly
);
131
QTextStream
outs
(&
buf
);
132
QList
<
Line
>
lines
;
133
for
(
auto
it
=
counters
.
cbegin
(),
end
=
counters
.
cend
();
it
!=
end
; ++
it
) {
134
const
Counters
&
fCount
=
it
.
value
();
135
for
(
int
i
= 0,
ei
=
fCount
.
size
();
i
!=
ei
; ++
i
) {
136
quint64
count
=
fCount
[
i
];
137
if
(!
count
)
138
continue
;
139
Line
line
;
140
line
.
func
=
it
.
key
();
141
unmangle
(
i
,
line
.
tag1
,
line
.
tag2
);
142
line
.
count
=
count
;
143
lines
.
append
(
line
);
144
}
145
}
146
std
::
sort
(
lines
.
begin
(),
lines
.
end
(),
Line
::
less
);
147
outs
<<
lines
.
size
() <<
" counters:"
<<
endl
;
148
for
(
const
Line
&
line
:
std
::
as_const
(
lines
))
149
outs
<<
qSetFieldWidth
(10) <<
line
.
count
<<
qSetFieldWidth
(0)
150
<<
" | "
<<
line
.
func
151
<<
" | "
<<
pretty
(
line
.
tag1
)
152
<<
" | "
<<
pretty
(
line
.
tag2
)
153
<<
endl
;
154
qDebug
(
"%s"
,
buf
.
data
().
constData
());
155
}
156
};
157
158
RuntimeCounters
*
RuntimeCounters
::
instance
= 0;
159
static
RuntimeCounters
runtimeCountersInstance
;
160
RuntimeCounters
::
RuntimeCounters
()
161
:
d
(
new
Data
)
162
{
163
if
(!
instance
)
164
instance
=
this
;
165
}
166
167
RuntimeCounters
::~
RuntimeCounters
()
168
{
169
d
->
dump
();
170
delete
d
;
171
}
172
173
void
RuntimeCounters
::
count
(
const
char
*
func
)
174
{
175
d
->
count
(
func
);
176
}
177
178
void
RuntimeCounters
::
count
(
const
char
*
func
,
uint
tag
)
179
{
180
d
->
count
(
func
,
tag
);
181
}
182
183
void
RuntimeCounters
::
count
(
const
char
*
func
,
uint
tag1
,
uint
tag2
)
184
{
185
d
->
count
(
func
,
tag1
,
tag2
);
186
}
187
188
#
endif
// QV4_COUNT_RUNTIME_FUNCTIONS
189
190
static
QV4
::Lookup *
runtimeLookup
(Function *f, uint i)
191
{
192
return
f->executableCompilationUnit()->runtimeLookups + i;
193
}
194
195
void
RuntimeHelpers
::
numberToString
(
QString
*
result
,
double
num
,
int
radix
)
196
{
197
Q_ASSERT
(
result
);
198
199
if
(
std
::
isnan
(
num
)) {
200
*
result
=
QStringLiteral
(
"NaN"
);
201
return
;
202
}
else
if
(
qt_is_inf
(
num
)) {
203
*
result
=
num
< 0 ?
QStringLiteral
(
"-Infinity"
) :
QStringLiteral
(
"Infinity"
);
204
return
;
205
}
206
207
if
(
radix
== 10) {
208
// We cannot use our usual locale->toString(...) here, because EcmaScript has special rules
209
// about the longest permissible number, depending on if it's <0 or >0.
210
const
int
ecma_shortest_low
= -6;
211
const
int
ecma_shortest_high
= 21;
212
213
const
QLatin1Char
zero
(
'0'
);
214
const
QLatin1Char
dot
(
'.'
);
215
216
int
decpt
= 0;
217
int
sign
= 0;
218
*
result
=
qdtoa
(
num
, &
decpt
, &
sign
);
219
220
if
(
decpt
<=
ecma_shortest_low
||
decpt
>
ecma_shortest_high
) {
221
if
(
result
->
size
() > 1)
222
result
->
insert
(1,
dot
);
223
result
->
append
(
QLatin1Char
(
'e'
));
224
if
(
decpt
> 0)
225
result
->
append
(
QLatin1Char
(
'+'
));
226
result
->
append
(
QString
::
number
(
decpt
- 1));
227
}
else
if
(
decpt
<= 0) {
228
result
->
prepend
(
QLatin1String
(
"0."
) +
QString
(-
decpt
,
zero
));
229
}
else
if
(
decpt
<
result
->
size
()) {
230
result
->
insert
(
decpt
,
dot
);
231
}
else
{
232
result
->
append
(
QString
(
decpt
-
result
->
size
(),
zero
));
233
}
234
235
if
(
sign
&&
num
)
236
result
->
prepend
(
QLatin1Char
(
'-'
));
237
238
return
;
239
}
240
241
result
->
clear
();
242
bool
negative
=
false
;
243
244
if
(
num
< 0) {
245
negative
=
true
;
246
num
= -
num
;
247
}
248
249
double
frac
=
num
- ::
floor
(
num
);
250
num
=
Value
::
toInteger
(
num
);
251
252
do
{
253
char
c
= (
char
)::
fmod
(
num
,
radix
);
254
c
= (
c
< 10) ? (
c
+
'0'
) : (
c
- 10 +
'a'
);
255
result
->
prepend
(
QLatin1Char
(
c
));
256
num
= ::
floor
(
num
/
radix
);
257
}
while
(
num
!= 0);
258
259
if
(
frac
!= 0) {
260
result
->
append
(
QLatin1Char
(
'.'
));
261
double
magnitude
= 1;
262
double
next
=
frac
;
263
do
{
264
next
*=
radix
;
265
const
int
floored
= ::
floor
(
next
);
266
char
c
=
char
(
floored
);
267
c
= (
c
< 10) ? (
c
+
'0'
) : (
c
- 10 +
'a'
);
268
result
->
append
(
QLatin1Char
(
c
));
269
magnitude
/=
radix
;
270
frac
-=
double
(
floored
) *
magnitude
;
271
next
-=
double
(
floored
);
272
273
// The next digit still makes a difference
274
// if a value of "radix" for it would change frac.
275
// Otherwise we've reached the limit of numerical precision.
276
}
while
(
frac
> 0 &&
frac
-
magnitude
!=
frac
);
277
}
278
279
if
(
negative
)
280
result
->
prepend
(
QLatin1Char
(
'-'
));
281
}
282
283
ReturnedValue
Runtime
::
Closure
::
call
(
ExecutionEngine
*
engine
,
int
functionId
)
284
{
285
QV4
::
Function
*
clos
=
engine
->
currentStackFrame
->
v4Function
->
executableCompilationUnit
()
286
->
runtimeFunctions
[
functionId
];
287
Q_ASSERT
(
clos
);
288
ExecutionContext
*
current
=
engine
->
currentContext
();
289
Scope
s
(
engine
);
290
QV4
::
ScopedObject
closure
(
s
);
291
292
if
(
clos
->
isGenerator
())
293
closure
=
GeneratorFunction
::
create
(
current
,
clos
)->
asReturnedValue
();
294
else
295
closure
=
FunctionObject
::
createScriptFunction
(
current
,
clos
)->
asReturnedValue
();
296
// ### TODO: only keep reference to scripts if actually needed; see QTBUG-130795
297
Scoped
<
QV4
::
QmlContext
>
callingQmlContext
(
s
,
s
.
engine
->
qmlContext
());
298
if
(
callingQmlContext
) {
299
// ### TODO: It would be more efficient to use custom Function prototypes instead of setting a property
300
// ==> QTBUG-130798
301
Scoped
<
QV4
::
QQmlContextWrapper
>
qmlContextWrapper
(
s
,
callingQmlContext
->
d
()->
qml
());
302
const
QV4
::
QQmlContextWrapper
*
resource
=
qmlContextWrapper
;
303
QQmlRefPointer
<
QQmlContextData
>
context
=
resource
->
getContext
();
304
/* we can use fromReturnedValue here, as isNullOrUndefined doesn't allocate.
305
fetching importedScripts twvice is less overhead than unconditionally creating a scope,
306
as script imports are rather rare*/
307
if
(!
QV4
::
Value
::
fromReturnedValue
(
context
->
importedScripts
()).
isNullOrUndefined
()) {
308
QV4
::
ScopedString
name
(
s
,
engine
->
newString
(
QLatin1StringView
(
"$importedScripts"
)));
309
QV4
::
ScopedObject
scripts
(
s
,
context
->
importedScripts
());
310
closure
->
insertMember
(
name
,
scripts
,
Attr_Invalid
);
311
}
312
}
313
return
closure
.
asReturnedValue
();
314
}
315
316
Bool
Runtime
::
DeleteProperty_NoThrow
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
base
,
const
Value
&
index
)
317
{
318
Scope
scope
(
engine
);
319
ScopedObject
o
(
scope
,
base
.
toObject
(
engine
));
320
if
(
scope
.
hasException
())
321
return
Encode
::
undefined
();
322
Q_ASSERT
(
o
);
323
324
ScopedPropertyKey
key
(
scope
,
index
.
toPropertyKey
(
engine
));
325
if
(
engine
->
hasException
)
326
return
false
;
327
return
o
->
deleteProperty
(
key
);
328
}
329
330
ReturnedValue
Runtime
::
DeleteProperty
::
call
(
ExecutionEngine
*
engine
,
QV4
::
Function
*
function
,
const
QV4
::
Value
&
base
,
const
QV4
::
Value
&
index
)
331
{
332
if
(!
Runtime
::
DeleteProperty_NoThrow
::
call
(
engine
,
base
,
index
)) {
333
if
(
function
->
isStrict
())
334
engine
->
throwTypeError
();
335
return
Encode
(
false
);
336
}
else
{
337
return
Encode
(
true
);
338
}
339
}
340
341
Bool
Runtime
::
DeleteName_NoThrow
::
call
(
ExecutionEngine
*
engine
,
int
nameIndex
)
342
{
343
Scope
scope
(
engine
);
344
ScopedString
name
(
scope
,
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
nameIndex
]);
345
return
engine
->
currentContext
()->
deleteProperty
(
name
);
346
}
347
348
ReturnedValue
Runtime
::
DeleteName
::
call
(
ExecutionEngine
*
engine
,
Function
*
function
,
int
name
)
349
{
350
if
(!
Runtime
::
DeleteName_NoThrow
::
call
(
engine
,
name
)) {
351
if
(
function
->
isStrict
())
352
engine
->
throwTypeError
();
353
return
Encode
(
false
);
354
}
else
{
355
return
Encode
(
true
);
356
}
357
}
358
359
static
QV4
::
ReturnedValue
doInstanceof
(ExecutionEngine *engine,
const
Value &lval,
const
Value &rval)
360
{
361
// 11.8.6, 5: rval must be an Object
362
const
Object *rhs = rval.as<Object>();
363
if
(!rhs)
364
return
engine->throwTypeError();
365
366
const
FunctionObject *f = rhs->as<FunctionObject>();
367
// shortcut hasInstance evaluation. In this case we know that we are calling the regular hasInstance()
368
// method of the FunctionPrototype
369
if
(f && f->d()->prototype() == engine->functionPrototype()->d() && !f->hasHasInstanceProperty())
370
return
Object::checkedInstanceOf(engine, f, lval);
371
372
Scope
scope(engine);
373
ScopedValue
hasInstance(scope, rhs->get(engine->symbol_hasInstance()));
374
if
(hasInstance->isUndefined())
375
return
Encode(rhs->instanceOf(lval));
376
377
FunctionObject *fHasInstance = hasInstance->as<FunctionObject>();
378
if
(!fHasInstance)
379
return
engine->throwTypeError();
380
381
return
Encode(fHasInstance->call(&rval, &lval, 1));
382
}
383
384
QV4
::
ReturnedValue
Runtime
::
Instanceof
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
lval
,
const
Value
&
rval
)
385
{
386
Scope
scope
(
engine
);
387
ScopedValue
result
(
scope
,
doInstanceof
(
engine
,
lval
,
rval
));
388
return
scope
.
hasException
() ?
Encode
::
undefined
() :
Encode
(
result
->
toBoolean
());
389
}
390
391
QV4
::
ReturnedValue
Runtime
::
As
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
lval
,
const
Value
&
rval
)
392
{
393
Scope
scope
(
engine
);
394
ScopedValue
result
(
scope
,
doInstanceof
(
engine
,
lval
,
rval
));
395
396
if
(
scope
.
hasException
()) {
397
// "foo instanceof valueType" must not throw an exception.
398
// So this can only be an object type.
399
engine
->
catchException
();
400
return
Encode
::
null
();
401
}
402
403
if
(
result
->
toBoolean
())
404
return
lval
.
asReturnedValue
();
405
else
if
(
result
->
isBoolean
())
406
return
Encode
::
null
();
407
408
if
(
engine
->
callingQmlContext
()->
valueTypesAreAssertable
())
409
return
Encode
::
undefined
();
410
411
// Try to convert the value type
412
Scoped
<
QQmlTypeWrapper
>
typeWrapper
(
scope
,
rval
);
413
if
(!
typeWrapper
)
414
return
Encode
::
undefined
();
415
416
const
auto
*
stackFrame
=
engine
->
currentStackFrame
;
417
if
(
lval
.
as
<
QQmlValueTypeWrapper
>()) {
418
qCWarning
(
lcCoercingTypeAssertion
).
nospace
().
noquote
()
419
<<
stackFrame
->
source
() <<
':'
<<
stackFrame
->
lineNumber
() <<
':'
420
<<
" Coercing between incompatible value types mistakenly yields null rather than"
421
<<
" undefined. Add 'pragma ValueTypeBehavior: Assertable' to prevent this."
;
422
return
Encode
::
null
();
423
}
424
425
if
(
lval
.
as
<
QV4
::
QObjectWrapper
>()) {
426
qCWarning
(
lcCoercingTypeAssertion
).
nospace
().
noquote
()
427
<<
stackFrame
->
source
() <<
':'
<<
stackFrame
->
lineNumber
() <<
':'
428
<<
" Coercing from instances of object types to value types mistakenly yields null"
429
<<
" rather than undefined. Add 'pragma ValueTypeBehavior: Assertable' to prevent"
430
<<
" this."
;
431
return
Encode
::
null
();
432
}
433
434
result
=
coerce
(
engine
,
lval
,
typeWrapper
->
d
()->
type
(),
false
);
435
if
(
result
->
isUndefined
())
436
return
Encode
::
undefined
();
437
438
qCWarning
(
lcCoercingTypeAssertion
).
nospace
().
noquote
()
439
<<
stackFrame
->
source
() <<
':'
<<
stackFrame
->
lineNumber
() <<
':'
440
<<
" Coercing a value to "
<<
typeWrapper
->
toQStringNoThrow
()
441
<<
" using a type assertion. This behavior is deprecated."
442
<<
" Add 'pragma ValueTypeBehavior: Assertable' to prevent it."
;
443
return
result
->
asReturnedValue
();
444
}
445
446
QV4
::
ReturnedValue
Runtime
::
In
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
left
,
const
Value
&
right
)
447
{
448
Object
*
ro
=
right
.
objectValue
();
449
if
(!
ro
)
450
return
engine
->
throwTypeError
();
451
Scope
scope
(
engine
);
452
ScopedPropertyKey
s
(
scope
,
left
.
toPropertyKey
(
engine
));
453
if
(
scope
.
hasException
())
454
return
Encode
::
undefined
();
455
bool
r
=
ro
->
hasProperty
(
s
);
456
return
Encode
(
r
);
457
}
458
459
double
RuntimeHelpers
::
stringToNumber
(
const
QString
&
string
)
460
{
461
// The actual maximum valid length is certainly shorter, but due to the sheer number of
462
// different number formatting variants, we rather err on the side of caution here.
463
// For example, you can have up to 772 valid decimal digits left of the dot, as stated in the
464
// libdoubleconversion sources. The same maximum value would be represented by roughly 3.5 times
465
// as many binary digits.
466
const
int
excessiveLength
= 16 * 1024;
467
if
(
string
.
size
() >
excessiveLength
)
468
return
qQNaN
();
469
470
const
QStringView
s
=
QStringView
(
string
).
trimmed
();
471
if
(
s
.
startsWith
(
QLatin1Char
(
'0'
))) {
472
int
base
= -1;
473
if
(
s
.
startsWith
(
QLatin1String
(
"0x"
)) ||
s
.
startsWith
(
QLatin1String
(
"0X"
)))
474
base
= 16;
475
else
if
(
s
.
startsWith
(
QLatin1String
(
"0o"
)) ||
s
.
startsWith
(
QLatin1String
(
"0O"
)))
476
base
= 8;
477
else
if
(
s
.
startsWith
(
QLatin1String
(
"0b"
)) ||
s
.
startsWith
(
QLatin1String
(
"0B"
)))
478
base
= 2;
479
if
(
base
> 0) {
480
bool
ok
=
true
;
481
qlonglong
num
;
482
num
=
s
.
mid
(2).
toLongLong
(&
ok
,
base
);
483
if
(!
ok
)
484
return
qQNaN
();
485
return
num
;
486
}
487
}
488
bool
ok
=
false
;
489
QByteArray
ba
=
s
.
toLatin1
();
490
const
char
*
begin
=
ba
.
constData
();
491
const
char
*
end
=
nullptr
;
492
double
d
=
qstrtod
(
begin
, &
end
, &
ok
);
493
if
(
end
-
begin
!=
ba
.
size
()) {
494
if
(
ba
==
"Infinity"
||
ba
==
"+Infinity"
)
495
d
=
Q_INFINITY
;
496
else
if
(
ba
==
"-Infinity"
)
497
d
= -
Q_INFINITY
;
498
else
499
d
=
std
::
numeric_limits
<
double
>::
quiet_NaN
();
500
}
501
return
d
;
502
}
503
504
Heap
::
String
*
RuntimeHelpers
::
stringFromNumber
(
ExecutionEngine
*
engine
,
double
number
)
505
{
506
QString
qstr
;
507
RuntimeHelpers
::
numberToString
(&
qstr
,
number
, 10);
508
return
engine
->
newString
(
qstr
);
509
}
510
511
ReturnedValue
RuntimeHelpers
::
objectDefaultValue
(
const
Object
*
object
,
int
typeHint
)
512
{
513
ExecutionEngine
*
engine
=
object
->
internalClass
()->
engine
;
514
if
(
engine
->
hasException
)
515
return
Encode
::
undefined
();
516
517
String
*
hint
;
518
switch
(
typeHint
) {
519
case
STRING_HINT
:
520
hint
=
engine
->
id_string
();
521
break
;
522
case
NUMBER_HINT
:
523
hint
=
engine
->
id_number
();
524
break
;
525
default
:
526
hint
=
engine
->
id_default
();
527
break
;
528
}
529
530
Scope
scope
(
engine
);
531
Value
v
=
Value
::
fromReturnedValue
(
object
->
get
(
engine
->
symbol_toPrimitive
()));
532
if
(
engine
->
hasException
|| (!
v
.
isNullOrUndefined
() && !
v
.
isFunctionObject
())) {
533
engine
->
throwTypeError
(
QStringLiteral
(
"Value for symbol toPrimitive is not a function"
));
534
return
Encode
::
undefined
();
535
}
536
537
ScopedFunctionObject
toPrimitive
(
scope
,
v
);
538
if
(
toPrimitive
) {
539
ScopedValue
result
(
scope
,
toPrimitive
->
call
(
object
,
hint
, 1));
540
if
(
engine
->
hasException
)
541
return
Encode
::
undefined
();
542
if
(!
result
->
isPrimitive
())
543
return
engine
->
throwTypeError
();
544
return
result
->
asReturnedValue
();
545
}
546
547
if
(
hint
==
engine
->
id_default
())
548
hint
=
engine
->
id_number
();
549
return
ordinaryToPrimitive
(
engine
,
object
,
hint
);
550
}
551
552
553
ReturnedValue
RuntimeHelpers
::
ordinaryToPrimitive
(
ExecutionEngine
*
engine
,
const
Object
*
object
,
String
*
typeHint
)
554
{
555
Q_ASSERT
(!
engine
->
hasException
);
556
557
String
*
meth1
=
engine
->
id_toString
();
558
String
*
meth2
=
engine
->
id_valueOf
();
559
560
if
(
typeHint
->
propertyKey
() ==
engine
->
id_number
()->
propertyKey
()) {
561
qSwap
(
meth1
,
meth2
);
562
}
else
{
563
Q_ASSERT
(
typeHint
->
propertyKey
() ==
engine
->
id_string
()->
propertyKey
());
564
}
565
566
Scope
scope
(
engine
);
567
ScopedValue
result
(
scope
);
568
569
ScopedValue
conv
(
scope
,
object
->
get
(
meth1
));
570
if
(
FunctionObject
*
o
=
conv
->
as
<
FunctionObject
>()) {
571
result
=
o
->
call
(
object
,
nullptr
, 0);
572
if
(
engine
->
hasException
)
573
return
Encode
::
undefined
();
574
if
(
result
->
isPrimitive
())
575
return
result
->
asReturnedValue
();
576
}
577
578
if
(
engine
->
hasException
)
579
return
Encode
::
undefined
();
580
581
conv
=
object
->
get
(
meth2
);
582
if
(
FunctionObject
*
o
=
conv
->
as
<
FunctionObject
>()) {
583
result
=
o
->
call
(
object
,
nullptr
, 0);
584
if
(
engine
->
hasException
)
585
return
Encode
::
undefined
();
586
if
(
result
->
isPrimitive
())
587
return
result
->
asReturnedValue
();
588
}
589
590
return
engine
->
throwTypeError
();
591
}
592
593
594
Heap
::
Object
*
RuntimeHelpers
::
convertToObject
(
ExecutionEngine
*
engine
,
const
Value
&
value
)
595
{
596
Q_ASSERT
(!
value
.
isObject
());
597
switch
(
value
.
type
()) {
598
case
Value
::
Undefined_Type
:
599
engine
->
throwTypeError
(
QLatin1String
(
"Value is undefined and could not be converted to an object"
));
600
return
nullptr
;
601
case
Value
::
Null_Type
:
602
engine
->
throwTypeError
(
QLatin1String
(
"Value is null and could not be converted to an object"
));
603
return
nullptr
;
604
case
Value
::
Boolean_Type
:
605
return
engine
->
newBooleanObject
(
value
.
booleanValue
());
606
case
Value
::
Managed_Type
:
607
Q_ASSERT
(
value
.
isStringOrSymbol
());
608
if
(!
value
.
isString
())
609
return
engine
->
newSymbolObject
(
value
.
symbolValue
());
610
return
engine
->
newStringObject
(
value
.
stringValue
());
611
case
Value
::
Integer_Type
:
612
default
:
// double
613
return
engine
->
newNumberObject
(
value
.
asDouble
());
614
}
615
}
616
617
Heap
::
String
*
RuntimeHelpers
::
convertToString
(
ExecutionEngine
*
engine
,
Value
value
,
TypeHint
hint
)
618
{
619
redo
:
620
switch
(
value
.
type
()) {
621
case
Value
::
Empty_Type
:
622
Q_ASSERT
(!
"empty Value encountered"
);
623
Q_UNREACHABLE
();
624
case
Value
::
Undefined_Type
:
625
return
engine
->
id_undefined
()->
d
();
626
case
Value
::
Null_Type
:
627
return
engine
->
id_null
()->
d
();
628
case
Value
::
Boolean_Type
:
629
if
(
value
.
booleanValue
())
630
return
engine
->
id_true
()->
d
();
631
else
632
return
engine
->
id_false
()->
d
();
633
case
Value
::
Managed_Type
: {
634
if
(
value
.
isString
())
635
return
static_cast
<
const
String
&>(
value
).
d
();
636
if
(
value
.
isSymbol
()) {
637
engine
->
throwTypeError
(
QLatin1String
(
"Cannot convert a symbol to a string."
));
638
return
nullptr
;
639
}
640
value
=
Value
::
fromReturnedValue
(
RuntimeHelpers
::
toPrimitive
(
value
,
hint
));
641
Q_ASSERT
(
value
.
isPrimitive
());
642
if
(
value
.
isString
())
643
return
static_cast
<
const
String
&>(
value
).
d
();
644
goto
redo
;
645
}
646
case
Value
::
Integer_Type
:
647
return
engine
->
newString
(
QString
::
number
(
value
.
int_32
()));
648
default
:
// double
649
return
RuntimeHelpers
::
stringFromNumber
(
engine
,
value
.
doubleValue
());
650
}
// switch
651
}
652
653
// This is slightly different from the method above, as
654
// the + operator requires a slightly different conversion
655
static
Heap
::String *
convert_to_string_add
(ExecutionEngine *engine, Value value)
656
{
657
return
RuntimeHelpers::convertToString(engine, value, PREFERREDTYPE_HINT);
658
}
659
660
QV4
::
ReturnedValue
RuntimeHelpers
::
addHelper
(
ExecutionEngine
*
engine
,
const
Value
&
left
,
const
Value
&
right
)
661
{
662
Scope
scope
(
engine
);
663
664
ScopedValue
pleft
(
scope
,
RuntimeHelpers
::
toPrimitive
(
left
,
PREFERREDTYPE_HINT
));
665
ScopedValue
pright
(
scope
,
RuntimeHelpers
::
toPrimitive
(
right
,
PREFERREDTYPE_HINT
));
666
String
*
sleft
=
pleft
->
stringValue
();
667
String
*
sright
=
pright
->
stringValue
();
668
if
(
sleft
||
sright
) {
669
if
(!
sleft
) {
670
pleft
=
convert_to_string_add
(
engine
,
pleft
);
671
sleft
=
static_cast
<
String
*>(
pleft
.
ptr
);
672
}
673
if
(!
sright
) {
674
pright
=
convert_to_string_add
(
engine
,
pright
);
675
sright
=
static_cast
<
String
*>(
pright
.
ptr
);
676
}
677
if
(
engine
->
hasException
)
678
return
Encode
::
undefined
();
679
if
(!
sleft
->
d
()->
length
())
680
return
sright
->
asReturnedValue
();
681
if
(!
sright
->
d
()->
length
())
682
return
sleft
->
asReturnedValue
();
683
MemoryManager
*
mm
=
engine
->
memoryManager
;
684
return
(
mm
->
alloc
<
ComplexString
>(
sleft
->
d
(),
sright
->
d
()))->
asReturnedValue
();
685
}
686
double
x
=
RuntimeHelpers
::
toNumber
(
pleft
);
687
double
y
=
RuntimeHelpers
::
toNumber
(
pright
);
688
return
Encode
(
x
+
y
);
689
}
690
691
ReturnedValue
Runtime
::
GetTemplateObject
::
call
(
Function
*
function
,
int
index
)
692
{
693
return
function
->
executableCompilationUnit
()->
templateObjectAt
(
index
)->
asReturnedValue
();
694
}
695
696
void
Runtime
::
StoreProperty
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
object
,
int
nameIndex
,
const
Value
&
value
)
697
{
698
Scope
scope
(
engine
);
699
QV4
::
Function
*
v4Function
=
engine
->
currentStackFrame
->
v4Function
;
700
ScopedString
name
(
scope
,
v4Function
->
compilationUnit
->
runtimeStrings
[
nameIndex
]);
701
ScopedObject
o
(
scope
,
object
);
702
if
(!
o
) {
703
if
(
v4Function
->
isStrict
()) {
704
engine
->
throwTypeError
();
705
return
;
706
}
707
o
=
object
.
toObject
(
engine
);
708
}
709
if
((!
o
|| !
o
->
put
(
name
,
value
)) &&
v4Function
->
isStrict
())
710
engine
->
throwTypeError
();
711
}
712
713
static
Q_NEVER_INLINE ReturnedValue
getElementIntFallback
(
ExecutionEngine
*
engine
,
const
Value
&
object
,
uint
idx
)
714
{
715
Q_ASSERT
(
idx
<
UINT_MAX
);
716
Scope
scope
(
engine
);
717
718
ScopedObject
o
(
scope
,
object
);
719
if
(!
o
) {
720
if
(
const
String
*
str
=
object
.
as
<
String
>()) {
721
if
(
idx
>= (
uint
)
str
->
toQString
().
size
()) {
722
return
Encode
::
undefined
();
723
}
724
const
QString
s
=
str
->
toQString
().
mid
(
idx
, 1);
725
return
scope
.
engine
->
newString
(
s
)->
asReturnedValue
();
726
}
727
728
if
(
object
.
isNullOrUndefined
()) {
729
QString
message
=
QStringLiteral
(
"Cannot read property '%1' of %2"
).
arg
(
idx
).
arg
(
object
.
toQStringNoThrow
());
730
return
engine
->
throwTypeError
(
message
);
731
}
732
733
o
=
RuntimeHelpers
::
convertToObject
(
scope
.
engine
,
object
);
734
Q_ASSERT
(!!
o
);
// can't fail as null/undefined is covered above
735
}
736
737
if
(
o
->
arrayData
() && !
o
->
arrayData
()->
attrs
) {
738
ScopedValue
v
(
scope
,
o
->
arrayData
()->
get
(
idx
));
739
if
(!
v
->
isEmpty
())
740
return
v
->
asReturnedValue
();
741
}
742
743
return
o
->
get
(
idx
);
744
}
745
746
static
Q_NEVER_INLINE ReturnedValue
getElementFallback
(
ExecutionEngine
*
engine
,
const
Value
&
object
,
const
Value
&
index
)
747
{
748
Q_ASSERT
(!
index
.
isPositiveInt
());
749
750
Scope
scope
(
engine
);
751
752
ScopedObject
o
(
scope
,
object
);
753
if
(!
o
) {
754
if
(
object
.
isNullOrUndefined
()) {
755
const
QString
message
=
756
QStringLiteral
(
"Cannot read property '%1' of %2"
)
757
.
arg
(
index
.
toQStringNoThrow
(),
object
.
toQStringNoThrow
());
758
return
engine
->
throwTypeError
(
message
);
759
}
760
761
o
=
RuntimeHelpers
::
convertToObject
(
scope
.
engine
,
object
);
762
Q_ASSERT
(!!
o
);
// can't fail as null/undefined is covered above
763
}
764
765
ScopedPropertyKey
name
(
scope
,
index
.
toPropertyKey
(
engine
));
766
if
(
scope
.
hasException
())
767
return
Encode
::
undefined
();
768
return
o
->
get
(
name
);
769
}
770
771
ReturnedValue
Runtime
::
LoadElement
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
object
,
const
Value
&
index
)
772
{
773
if
(
index
.
isPositiveInt
()) {
774
uint
idx
=
static_cast
<
uint
>(
index
.
int_32
());
775
if
(
Heap
::
Base
*
b
=
object
.
heapObject
()) {
776
if
(
b
->
internalClass
->
vtable
->
isObject
) {
777
Heap
::
Object
*
o
=
static_cast
<
Heap
::
Object
*>(
b
);
778
if
(
o
->
arrayData
&&
o
->
arrayData
->
type
==
Heap
::
ArrayData
::
Simple
) {
779
Heap
::
SimpleArrayData
*
s
=
o
->
arrayData
.
cast
<
Heap
::
SimpleArrayData
>();
780
if
(
idx
<
s
->
values
.
size
)
781
if
(!
s
->
data
(
idx
).
isEmpty
())
782
return
s
->
data
(
idx
).
asReturnedValue
();
783
}
784
}
785
}
786
return
getElementIntFallback
(
engine
,
object
,
idx
);
787
}
788
789
return
getElementFallback
(
engine
,
object
,
index
);
790
}
791
792
static
Q_NEVER_INLINE
bool
setElementFallback
(ExecutionEngine *engine,
const
Value &object,
const
Value &index,
const
Value &value)
793
{
794
Scope
scope(engine);
795
ScopedObject
o(scope, object);
796
if
(!o) {
797
if
(engine->currentStackFrame->v4Function->isStrict()) {
798
engine->throwTypeError();
799
return
false
;
800
}
801
802
o = object.toObject(engine);
803
}
804
if
(engine->hasException)
805
return
false
;
806
807
if
(index.isPositiveInt()) {
808
uint idx =
static_cast
<uint>(index.int_32());
809
if
(o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) {
810
Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
811
if
(idx < s->values.size) {
812
s->setData(engine, idx, value);
813
return
true
;
814
}
815
}
816
return
o->put(idx, value);
817
}
818
819
ScopedPropertyKey name(scope, index.toPropertyKey(engine));
820
if
(engine->hasException)
821
return
false
;
822
return
o->put(name, value);
823
}
824
825
void
Runtime
::
StoreElement
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
object
,
const
Value
&
index
,
const
Value
&
value
)
826
{
827
if
(
index
.
isPositiveInt
()) {
828
uint
idx
=
static_cast
<
uint
>(
index
.
int_32
());
829
if
(
Heap
::
Base
*
b
=
object
.
heapObject
()) {
830
if
(
b
->
internalClass
->
vtable
->
isObject
) {
831
Heap
::
Object
*
o
=
static_cast
<
Heap
::
Object
*>(
b
);
832
if
(
o
->
arrayData
&&
o
->
arrayData
->
type
==
Heap
::
ArrayData
::
Simple
) {
833
Heap
::
SimpleArrayData
*
s
=
o
->
arrayData
.
cast
<
Heap
::
SimpleArrayData
>();
834
if
(
idx
<
s
->
values
.
size
) {
835
s
->
setData
(
engine
,
idx
,
value
);
836
return
;
837
}
838
}
839
}
840
}
841
}
842
843
if
(!
setElementFallback
(
engine
,
object
,
index
,
value
) &&
engine
->
currentStackFrame
->
v4Function
->
isStrict
())
844
engine
->
throwTypeError
();
845
}
846
847
ReturnedValue
Runtime
::
GetIterator
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
in
,
int
iterator
)
848
{
849
Scope
scope
(
engine
);
850
ScopedObject
o
(
scope
, (
Object
*)
nullptr
);
851
if
(!
in
.
isNullOrUndefined
())
852
o
=
in
.
toObject
(
engine
);
853
if
(
engine
->
hasException
)
854
return
Encode
::
undefined
();
855
if
(
iterator
==
static_cast
<
int
>(
QQmlJS
::
AST
::
ForEachType
::
Of
)) {
856
if
(!
o
)
857
return
engine
->
throwTypeError
();
858
ScopedFunctionObject
f
(
scope
,
o
->
get
(
engine
->
symbol_iterator
()));
859
if
(!
f
)
860
return
engine
->
throwTypeError
();
861
JSCallData
cData
(
o
,
nullptr
, 0);
862
ScopedObject
it
(
scope
,
f
->
call
(
cData
));
863
if
(
engine
->
hasException
)
864
return
Encode
::
undefined
();
865
if
(!
it
)
866
return
engine
->
throwTypeError
();
867
return
it
->
asReturnedValue
();
868
}
869
return
engine
->
newForInIteratorObject
(
o
)->
asReturnedValue
();
870
}
871
872
ReturnedValue
Runtime
::
IteratorNext
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
iterator
,
Value
*
value
)
873
{
874
// if we throw an exception from here, return true, not undefined. This is to ensure iteratorDone is set to true
875
// and the stack unwinding won't close the iterator
876
Q_ASSERT
(
iterator
.
isObject
());
877
878
Scope
scope
(
engine
);
879
ScopedFunctionObject
f
(
scope
,
static_cast
<
const
Object
&>(
iterator
).
get
(
engine
->
id_next
()));
880
if
(!
f
) {
881
engine
->
throwTypeError
();
882
return
Encode
(
true
);
883
}
884
JSCallData
cData
(&
iterator
,
nullptr
, 0);
885
ScopedObject
o
(
scope
,
f
->
call
(
cData
));
886
if
(
scope
.
hasException
())
887
return
Encode
(
true
);
888
if
(!
o
) {
889
engine
->
throwTypeError
();
890
return
Encode
(
true
);
891
}
892
893
ScopedValue
d
(
scope
,
o
->
get
(
engine
->
id_done
()));
894
if
(
scope
.
hasException
())
895
return
Encode
(
true
);
896
bool
done
=
d
->
toBoolean
();
897
if
(
done
) {
898
*
value
=
Encode
::
undefined
();
899
return
Encode
(
true
);
900
}
901
902
*
value
=
o
->
get
(
engine
->
id_value
());
903
if
(
scope
.
hasException
())
904
return
Encode
(
true
);
905
return
Encode
(
false
);
906
}
907
908
ReturnedValue
Runtime
::
IteratorNextForYieldStar
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
received
,
const
Value
&
iterator
,
Value
*
object
)
909
{
910
// the return value encodes how to continue the yield* iteration.
911
// true implies iteration is done, false for iteration to continue
912
// a return value of undefines is a special marker, that the iterator has been invoked with return()
913
914
Scope
scope
(
engine
);
915
Q_ASSERT
(
iterator
.
isObject
());
916
917
const
Value
*
arg
= &
received
;
918
bool
returnCalled
=
false
;
919
FunctionObject
*
f
=
nullptr
;
920
if
(
engine
->
hasException
) {
921
if
(
engine
->
exceptionValue
->
isEmpty
()) {
922
// generator called with return()
923
*
engine
->
exceptionValue
=
Encode
::
undefined
();
924
engine
->
hasException
=
false
;
925
926
ScopedValue
ret
(
scope
,
static_cast
<
const
Object
&>(
iterator
).
get
(
engine
->
id_return
()));
927
if
(
engine
->
hasException
)
928
return
Encode
(
true
);
929
if
(
ret
->
isUndefined
()) {
930
// propagate return()
931
return
Encode
::
undefined
();
932
}
933
returnCalled
=
true
;
934
f
=
ret
->
as
<
FunctionObject
>();
935
}
else
{
936
// generator called with throw
937
ScopedValue
exceptionValue
(
scope
, *
engine
->
exceptionValue
);
938
*
engine
->
exceptionValue
=
Encode
::
undefined
();
939
engine
->
hasException
=
false
;
940
941
ScopedValue
t
(
scope
,
static_cast
<
const
Object
&>(
iterator
).
get
(
engine
->
id_throw
()));
942
if
(
engine
->
hasException
)
943
return
Encode
(
true
);
944
if
(
t
->
isUndefined
()) {
945
// no throw method on the iterator
946
IteratorClose
::
call
(
engine
,
iterator
);
947
if
(!
engine
->
hasException
)
948
engine
->
throwTypeError
();
949
return
Encode
(
true
);
950
}
951
f
=
t
->
as
<
FunctionObject
>();
952
arg
=
exceptionValue
;
953
}
954
}
else
{
955
// generator called with next()
956
ScopedFunctionObject
next
(
scope
,
static_cast
<
const
Object
&>(
iterator
).
get
(
engine
->
id_next
()));
957
f
=
next
->
as
<
FunctionObject
>();
958
}
959
960
if
(!
f
) {
961
engine
->
throwTypeError
();
962
return
Encode
(
true
);
963
}
964
965
ScopedObject
o
(
scope
,
f
->
call
(&
iterator
,
arg
, 1));
966
if
(
scope
.
hasException
())
967
return
Encode
(
true
);
968
if
(!
o
) {
969
engine
->
throwTypeError
();
970
return
Encode
(
true
);
971
}
972
973
ScopedValue
d
(
scope
,
o
->
get
(
engine
->
id_done
()));
974
if
(
scope
.
hasException
())
975
return
Encode
(
true
);
976
bool
done
=
d
->
toBoolean
();
977
if
(
done
) {
978
*
object
=
o
->
get
(
engine
->
id_value
());
979
return
(
returnCalled
&& !
engine
->
hasException
) ?
Encode
::
undefined
() :
Encode
(
true
);
980
}
981
*
object
=
o
;
982
return
Encode
(
false
);
983
}
984
985
ReturnedValue
Runtime
::
IteratorClose
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
iterator
)
986
{
987
Q_ASSERT
(
iterator
.
isObject
());
988
989
Scope
scope
(
engine
);
990
ScopedValue
e
(
scope
);
991
bool
hadException
=
engine
->
hasException
;
992
if
(
hadException
) {
993
e
= *
engine
->
exceptionValue
;
994
engine
->
hasException
=
false
;
995
}
996
997
auto
originalCompletion
= [=]() {
998
if
(
hadException
) {
999
*
engine
->
exceptionValue
=
e
;
1000
engine
->
hasException
=
hadException
;
1001
}
1002
return
Encode
::
undefined
();
1003
};
1004
1005
ScopedValue
ret
(
scope
,
static_cast
<
const
Object
&>(
iterator
).
get
(
engine
->
id_return
()));
1006
ScopedObject
o
(
scope
);
1007
if
(!
ret
->
isUndefined
()) {
1008
FunctionObject
*
f
=
ret
->
as
<
FunctionObject
>();
1009
o
=
f
->
call
(&
iterator
,
nullptr
, 0);
1010
if
(
engine
->
hasException
&& !
hadException
)
1011
return
Encode
::
undefined
();
1012
}
1013
if
(
hadException
||
ret
->
isUndefined
())
1014
return
originalCompletion
();
1015
1016
if
(!
o
)
1017
return
engine
->
throwTypeError
();
1018
1019
return
originalCompletion
();
1020
}
1021
1022
ReturnedValue
Runtime
::
DestructureRestElement
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
iterator
)
1023
{
1024
Q_ASSERT
(
iterator
.
isObject
());
1025
1026
Scope
scope
(
engine
);
1027
ScopedArrayObject
array
(
scope
,
engine
->
newArrayObject
());
1028
array
->
arrayCreate
();
1029
uint
index
= 0;
1030
while
(1) {
1031
ScopedValue
n
(
scope
);
1032
ScopedValue
done
(
scope
,
IteratorNext
::
call
(
engine
,
iterator
,
n
));
1033
if
(
engine
->
hasException
)
1034
return
Encode
::
undefined
();
1035
Q_ASSERT
(
done
->
isBoolean
());
1036
if
(
done
->
booleanValue
())
1037
break
;
1038
array
->
arraySet
(
index
,
n
);
1039
++
index
;
1040
}
1041
return
array
->
asReturnedValue
();
1042
}
1043
1044
void
Runtime
::
StoreNameSloppy
::
call
(
ExecutionEngine
*
engine
,
int
nameIndex
,
const
Value
&
value
)
1045
{
1046
Scope
scope
(
engine
);
1047
ScopedString
name
(
scope
,
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
nameIndex
]);
1048
ExecutionContext
::
Error
e
=
engine
->
currentContext
()->
setProperty
(
name
,
value
);
1049
1050
if
(
e
==
ExecutionContext
::
RangeError
)
1051
engine
->
globalObject
->
put
(
name
,
value
);
1052
}
1053
1054
void
Runtime
::
StoreNameStrict
::
call
(
ExecutionEngine
*
engine
,
int
nameIndex
,
const
Value
&
value
)
1055
{
1056
Scope
scope
(
engine
);
1057
ScopedString
name
(
scope
,
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
nameIndex
]);
1058
ExecutionContext
::
Error
e
=
engine
->
currentContext
()->
setProperty
(
name
,
value
);
1059
if
(
e
==
ExecutionContext
::
TypeError
)
1060
engine
->
throwTypeError
();
1061
else
if
(
e
==
ExecutionContext
::
RangeError
)
1062
engine
->
throwReferenceError
(
name
);
1063
}
1064
1065
ReturnedValue
Runtime
::
LoadProperty
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
object
,
int
nameIndex
)
1066
{
1067
Scope
scope
(
engine
);
1068
ScopedString
name
(
scope
,
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
nameIndex
]);
1069
1070
ScopedObject
o
(
scope
,
object
);
1071
if
(
o
)
1072
return
o
->
get
(
name
);
1073
1074
if
(
object
.
isNullOrUndefined
()) {
1075
const
QString
message
=
QStringLiteral
(
"Cannot read property '%1' of %2"
)
1076
.
arg
(
name
->
toQString
(),
object
.
toQStringNoThrow
());
1077
return
engine
->
throwTypeError
(
message
);
1078
}
1079
1080
o
=
RuntimeHelpers
::
convertToObject
(
scope
.
engine
,
object
);
1081
if
(!
o
)
// type error
1082
return
Encode
::
undefined
();
1083
return
o
->
get
(
name
);
1084
}
1085
1086
ReturnedValue
Runtime
::
LoadName
::
call
(
ExecutionEngine
*
engine
,
int
nameIndex
)
1087
{
1088
Scope
scope
(
engine
);
1089
ScopedString
name
(
scope
,
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
nameIndex
]);
1090
return
engine
->
currentContext
()->
getProperty
(
name
);
1091
}
1092
1093
static
Object *
getSuperBase
(
Scope
&scope)
1094
{
1095
Scoped<JavaScriptFunctionObject> f(scope);
1096
ScopedObject
homeObject(scope);
1097
if
(scope.engine->currentStackFrame->isJSTypesFrame()) {
1098
JSTypesStackFrame *frame =
static_cast
<JSTypesStackFrame *>(
1099
scope.engine->currentStackFrame);
1100
1101
if
(frame->jsFrame->thisObject.isEmpty()) {
1102
scope.engine->throwReferenceError(
1103
QStringLiteral(
"Missing call to super()."
), QString(), 0, 0);
1104
return
nullptr
;
1105
}
1106
1107
f = Value::fromStaticValue(frame->jsFrame->function);
1108
homeObject = f->getHomeObject();
1109
}
else
{
1110
Q_ASSERT(scope.engine->currentStackFrame->isMetaTypesFrame());
1111
MetaTypesStackFrame *frame =
static_cast
<MetaTypesStackFrame *>(
1112
scope.engine->currentStackFrame);
1113
if
(frame->thisObject() ==
nullptr
) {
1114
scope.engine->throwReferenceError(
1115
QStringLiteral(
"Missing call to super()."
), QString(), 0, 0);
1116
return
nullptr
;
1117
}
1118
}
1119
1120
if
(!homeObject) {
1121
ScopedContext
ctx(scope, scope.engine->currentContext());
1122
Q_ASSERT(ctx);
1123
while
(ctx) {
1124
if
(CallContext *c = ctx->asCallContext()) {
1125
f = c->d()->function;
1126
QV4
::Function *fn = f->function();
1127
if
(fn && !fn->isArrowFunction() && fn->kind != Function::Eval)
1128
break
;
1129
}
1130
ctx = ctx->d()->outer;
1131
}
1132
if
(f)
1133
homeObject = f->getHomeObject();
1134
}
1135
if
(!homeObject) {
1136
scope.engine->throwTypeError();
1137
return
nullptr
;
1138
}
1139
Q_ASSERT(homeObject);
1140
ScopedObject
proto(scope, homeObject->getPrototypeOf());
1141
if
(!proto) {
1142
scope.engine->throwTypeError();
1143
return
nullptr
;
1144
}
1145
return
proto;
1146
}
1147
1148
ReturnedValue
Runtime
::
LoadSuperProperty
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
property
)
1149
{
1150
Scope
scope
(
engine
);
1151
Object
*
base
=
getSuperBase
(
scope
);
1152
if
(!
base
)
1153
return
Encode
::
undefined
();
1154
ScopedPropertyKey
key
(
scope
,
property
.
toPropertyKey
(
engine
));
1155
if
(
engine
->
hasException
)
1156
return
Encode
::
undefined
();
1157
1158
if
(
scope
.
engine
->
currentStackFrame
->
isJSTypesFrame
()) {
1159
JSTypesStackFrame
*
frame
=
static_cast
<
JSTypesStackFrame
*>(
1160
scope
.
engine
->
currentStackFrame
);
1161
return
base
->
get
(
key
, &(
frame
->
jsFrame
->
thisObject
.
asValue
<
Value
>()));
1162
}
else
{
1163
Q_ASSERT
(
scope
.
engine
->
currentStackFrame
->
isMetaTypesFrame
());
1164
MetaTypesStackFrame
*
frame
=
static_cast
<
MetaTypesStackFrame
*>(
1165
scope
.
engine
->
currentStackFrame
);
1166
Scoped
<
QObjectWrapper
>
wrapper
(
scope
,
QObjectWrapper
::
wrap
(
engine
,
frame
->
thisObject
()));
1167
return
base
->
get
(
key
,
wrapper
);
1168
}
1169
}
1170
1171
void
Runtime
::
StoreSuperProperty
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
property
,
const
Value
&
value
)
1172
{
1173
Scope
scope
(
engine
);
1174
Object
*
base
=
getSuperBase
(
scope
);
1175
if
(!
base
)
1176
return
;
1177
ScopedPropertyKey
key
(
scope
,
property
.
toPropertyKey
(
engine
));
1178
if
(
engine
->
hasException
)
1179
return
;
1180
1181
bool
result
;
1182
if
(
scope
.
engine
->
currentStackFrame
->
isJSTypesFrame
()) {
1183
JSTypesStackFrame
*
frame
=
static_cast
<
JSTypesStackFrame
*>(
1184
scope
.
engine
->
currentStackFrame
);
1185
result
=
base
->
put
(
key
,
value
, &(
frame
->
jsFrame
->
thisObject
.
asValue
<
Value
>()));
1186
}
else
{
1187
Q_ASSERT
(
scope
.
engine
->
currentStackFrame
->
isMetaTypesFrame
());
1188
MetaTypesStackFrame
*
frame
=
static_cast
<
MetaTypesStackFrame
*>(
1189
scope
.
engine
->
currentStackFrame
);
1190
Scoped
<
QObjectWrapper
>
wrapper
(
scope
,
QObjectWrapper
::
wrap
(
engine
,
frame
->
thisObject
()));
1191
result
=
base
->
put
(
key
,
value
,
wrapper
);
1192
}
1193
1194
if
(!
result
&&
engine
->
currentStackFrame
->
v4Function
->
isStrict
())
1195
engine
->
throwTypeError
();
1196
}
1197
1198
ReturnedValue
Runtime
::
LoadGlobalLookup
::
call
(
ExecutionEngine
*
engine
,
Function
*
f
,
int
index
)
1199
{
1200
Lookup
*
l
=
runtimeLookup
(
f
,
index
);
1201
return
l
->
globalGetter
(
engine
);
1202
}
1203
1204
ReturnedValue
Runtime
::
LoadQmlContextPropertyLookup
::
call
(
ExecutionEngine
*
engine
,
uint
index
)
1205
{
1206
Lookup
*
l
=
runtimeLookup
(
engine
->
currentStackFrame
->
v4Function
,
index
);
1207
return
l
->
contextGetter
(
engine
,
nullptr
);
1208
}
1209
1210
ReturnedValue
Runtime
::
GetLookup
::
call
(
ExecutionEngine
*
engine
,
Function
*
f
,
const
Value
&
base
,
int
index
)
1211
{
1212
Lookup
*
l
=
runtimeLookup
(
f
,
index
);
1213
1214
if
(
base
.
isNullOrUndefined
()) {
1215
const
QString
message
=
QStringLiteral
(
"Cannot read property '%1' of %2"
)
1216
.
arg
(
f
->
compilationUnit
->
runtimeStrings
[
l
->
nameIndex
]->
toQString
(),
1217
base
.
toQStringNoThrow
());
1218
return
engine
->
throwTypeError
(
message
);
1219
}
1220
1221
return
l
->
getter
(
engine
,
base
);
1222
}
1223
1224
void
Runtime
::
SetLookupSloppy
::
call
(
Function
*
f
,
const
Value
&
base
,
int
index
,
const
Value
&
value
)
1225
{
1226
ExecutionEngine
*
engine
=
f
->
internalClass
->
engine
;
1227
QV4
::
Lookup
*
l
=
runtimeLookup
(
f
,
index
);
1228
l
->
setter
(
engine
,
const_cast
<
Value
&>(
base
),
value
);
1229
}
1230
1231
void
Runtime
::
SetLookupStrict
::
call
(
Function
*
f
,
const
Value
&
base
,
int
index
,
const
Value
&
value
)
1232
{
1233
ExecutionEngine
*
engine
=
f
->
internalClass
->
engine
;
1234
QV4
::
Lookup
*
l
=
runtimeLookup
(
f
,
index
);
1235
if
(!
l
->
setter
(
engine
,
const_cast
<
Value
&>(
base
),
value
))
1236
engine
->
throwTypeError
();
1237
}
1238
1239
ReturnedValue
Runtime
::
LoadSuperConstructor
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
t
)
1240
{
1241
if
(
engine
->
currentStackFrame
->
isJSTypesFrame
()) {
1242
JSTypesStackFrame
*
frame
=
static_cast
<
JSTypesStackFrame
*>(
engine
->
currentStackFrame
);
1243
if
(
frame
->
thisObject
() !=
Value
::
emptyValue
().
asReturnedValue
()) {
1244
// ### TODO: fix line number
1245
return
engine
->
throwReferenceError
(
1246
QStringLiteral
(
"super() already called."
),
QString
(), 0, 0);
1247
}
1248
}
else
{
1249
Q_ASSERT
(
engine
->
currentStackFrame
->
isMetaTypesFrame
());
1250
MetaTypesStackFrame
*
frame
=
static_cast
<
MetaTypesStackFrame
*>(
engine
->
currentStackFrame
);
1251
if
(
frame
->
thisObject
() !=
nullptr
) {
1252
// ### TODO: fix line number
1253
return
engine
->
throwReferenceError
(
1254
QStringLiteral
(
"super() already called."
),
QString
(), 0, 0);
1255
}
1256
}
1257
1258
const
FunctionObject
*
f
=
t
.
as
<
FunctionObject
>();
1259
if
(!
f
)
1260
return
engine
->
throwTypeError
();
1261
Heap
::
Object
*
c
=
static_cast
<
const
Object
&>(
t
).
getPrototypeOf
();
1262
if
(!
c
->
vtable
()->
callAsConstructor
)
1263
return
engine
->
throwTypeError
();
1264
return
c
->
asReturnedValue
();
1265
}
1266
1267
uint
RuntimeHelpers
::
equalHelper
(
const
Value
&
x
,
const
Value
&
y
)
1268
{
1269
Q_ASSERT
(
x
.
type
() !=
y
.
type
() || (
x
.
isManaged
() && (
x
.
isString
() !=
y
.
isString
())));
1270
1271
if
(
x
.
isNumber
() &&
y
.
isNumber
())
1272
return
x
.
asDouble
() ==
y
.
asDouble
();
1273
if
(
x
.
isNull
() &&
y
.
isUndefined
()) {
1274
return
true
;
1275
}
else
if
(
x
.
isUndefined
() &&
y
.
isNull
()) {
1276
return
true
;
1277
}
else
if
(
x
.
isNumber
() &&
y
.
isString
()) {
1278
double
dy
=
RuntimeHelpers
::
toNumber
(
y
);
1279
return
x
.
asDouble
() ==
dy
;
1280
}
else
if
(
x
.
isString
() &&
y
.
isNumber
()) {
1281
double
dx
=
RuntimeHelpers
::
toNumber
(
x
);
1282
return
dx
==
y
.
asDouble
();
1283
}
else
if
(
x
.
isBoolean
()) {
1284
return
Runtime
::
CompareEqual
::
call
(
Value
::
fromDouble
((
double
)
x
.
booleanValue
()),
y
);
1285
}
else
if
(
y
.
isBoolean
()) {
1286
return
Runtime
::
CompareEqual
::
call
(
x
,
Value
::
fromDouble
((
double
)
y
.
booleanValue
()));
1287
}
else
{
1288
Object
*
xo
=
x
.
objectValue
();
1289
Object
*
yo
=
y
.
objectValue
();
1290
if
(
yo
&& (
x
.
isNumber
() ||
x
.
isString
())) {
1291
Scope
scope
(
yo
->
engine
());
1292
ScopedValue
py
(
scope
,
RuntimeHelpers
::
objectDefaultValue
(
yo
,
PREFERREDTYPE_HINT
));
1293
return
Runtime
::
CompareEqual
::
call
(
x
,
py
);
1294
}
else
if
(
xo
&& (
y
.
isNumber
() ||
y
.
isString
())) {
1295
Scope
scope
(
xo
->
engine
());
1296
ScopedValue
px
(
scope
,
RuntimeHelpers
::
objectDefaultValue
(
xo
,
PREFERREDTYPE_HINT
));
1297
return
Runtime
::
CompareEqual
::
call
(
px
,
y
);
1298
}
1299
}
1300
1301
return
false
;
1302
}
1303
1304
Bool
RuntimeHelpers
::
strictEqual
(
const
Value
&
x
,
const
Value
&
y
)
1305
{
1306
TRACE2
(x, y);
1307
1308
if
(
x
.
rawValue
() ==
y
.
rawValue
())
1309
// NaN != NaN
1310
return
!
x
.
isNaN
();
1311
1312
if
(
x
.
isNumber
())
1313
return
y
.
isNumber
() &&
x
.
asDouble
() ==
y
.
asDouble
();
1314
if
(
x
.
isManaged
()) {
1315
return
y
.
isManaged
() &&
x
.
cast
<
Managed
>()->
isEqualTo
(
y
.
cast
<
Managed
>());
1316
}
1317
return
false
;
1318
}
1319
1320
QV4
::
Bool
Runtime
::
CompareGreaterThan
::
call
(
const
Value
&
l
,
const
Value
&
r
)
1321
{
1322
TRACE2
(l, r);
1323
if
(
l
.
isInteger
() &&
r
.
isInteger
())
1324
return
l
.
integerValue
() >
r
.
integerValue
();
1325
if
(
l
.
isNumber
() &&
r
.
isNumber
())
1326
return
l
.
asDouble
() >
r
.
asDouble
();
1327
String
*
sl
=
l
.
stringValue
();
1328
String
*
sr
=
r
.
stringValue
();
1329
if
(
sl
&&
sr
) {
1330
return
sr
->
lessThan
(
sl
);
1331
}
1332
1333
Object
*
ro
=
r
.
objectValue
();
1334
Object
*
lo
=
l
.
objectValue
();
1335
if
(
ro
||
lo
) {
1336
QV4
::
ExecutionEngine
*
e
= (
lo
?
lo
:
ro
)->
engine
();
1337
QV4
::
Scope
scope
(
e
);
1338
QV4
::
ScopedValue
pl
(
scope
,
lo
?
RuntimeHelpers
::
objectDefaultValue
(
lo
,
QV4
::
NUMBER_HINT
) :
l
.
asReturnedValue
());
1339
QV4
::
ScopedValue
pr
(
scope
,
ro
?
RuntimeHelpers
::
objectDefaultValue
(
ro
,
QV4
::
NUMBER_HINT
) :
r
.
asReturnedValue
());
1340
return
Runtime
::
CompareGreaterThan
::
call
(
pl
,
pr
);
1341
}
1342
1343
double
dl
=
RuntimeHelpers
::
toNumber
(
l
);
1344
double
dr
=
RuntimeHelpers
::
toNumber
(
r
);
1345
return
dl
>
dr
;
1346
}
1347
1348
QV4
::
Bool
Runtime
::
CompareLessThan
::
call
(
const
Value
&
l
,
const
Value
&
r
)
1349
{
1350
TRACE2
(l, r);
1351
if
(
l
.
isInteger
() &&
r
.
isInteger
())
1352
return
l
.
integerValue
() <
r
.
integerValue
();
1353
if
(
l
.
isNumber
() &&
r
.
isNumber
())
1354
return
l
.
asDouble
() <
r
.
asDouble
();
1355
String
*
sl
=
l
.
stringValue
();
1356
String
*
sr
=
r
.
stringValue
();
1357
if
(
sl
&&
sr
) {
1358
return
sl
->
lessThan
(
sr
);
1359
}
1360
1361
Object
*
ro
=
r
.
objectValue
();
1362
Object
*
lo
=
l
.
objectValue
();
1363
if
(
ro
||
lo
) {
1364
QV4
::
ExecutionEngine
*
e
= (
lo
?
lo
:
ro
)->
engine
();
1365
QV4
::
Scope
scope
(
e
);
1366
QV4
::
ScopedValue
pl
(
scope
,
lo
?
RuntimeHelpers
::
objectDefaultValue
(
lo
,
QV4
::
NUMBER_HINT
) :
l
.
asReturnedValue
());
1367
QV4
::
ScopedValue
pr
(
scope
,
ro
?
RuntimeHelpers
::
objectDefaultValue
(
ro
,
QV4
::
NUMBER_HINT
) :
r
.
asReturnedValue
());
1368
return
Runtime
::
CompareLessThan
::
call
(
pl
,
pr
);
1369
}
1370
1371
double
dl
=
RuntimeHelpers
::
toNumber
(
l
);
1372
double
dr
=
RuntimeHelpers
::
toNumber
(
r
);
1373
return
dl
<
dr
;
1374
}
1375
1376
QV4
::
Bool
Runtime
::
CompareGreaterEqual
::
call
(
const
Value
&
l
,
const
Value
&
r
)
1377
{
1378
TRACE2
(l, r);
1379
if
(
l
.
isInteger
() &&
r
.
isInteger
())
1380
return
l
.
integerValue
() >=
r
.
integerValue
();
1381
if
(
l
.
isNumber
() &&
r
.
isNumber
())
1382
return
l
.
asDouble
() >=
r
.
asDouble
();
1383
String
*
sl
=
l
.
stringValue
();
1384
String
*
sr
=
r
.
stringValue
();
1385
if
(
sl
&&
sr
) {
1386
return
!
sl
->
lessThan
(
sr
);
1387
}
1388
1389
Object
*
ro
=
r
.
objectValue
();
1390
Object
*
lo
=
l
.
objectValue
();
1391
if
(
ro
||
lo
) {
1392
QV4
::
ExecutionEngine
*
e
= (
lo
?
lo
:
ro
)->
engine
();
1393
QV4
::
Scope
scope
(
e
);
1394
QV4
::
ScopedValue
pl
(
scope
,
lo
?
RuntimeHelpers
::
objectDefaultValue
(
lo
,
QV4
::
NUMBER_HINT
) :
l
.
asReturnedValue
());
1395
QV4
::
ScopedValue
pr
(
scope
,
ro
?
RuntimeHelpers
::
objectDefaultValue
(
ro
,
QV4
::
NUMBER_HINT
) :
r
.
asReturnedValue
());
1396
return
Runtime
::
CompareGreaterEqual
::
call
(
pl
,
pr
);
1397
}
1398
1399
double
dl
=
RuntimeHelpers
::
toNumber
(
l
);
1400
double
dr
=
RuntimeHelpers
::
toNumber
(
r
);
1401
return
dl
>=
dr
;
1402
}
1403
1404
QV4
::
Bool
Runtime
::
CompareLessEqual
::
call
(
const
Value
&
l
,
const
Value
&
r
)
1405
{
1406
TRACE2
(l, r);
1407
if
(
l
.
isInteger
() &&
r
.
isInteger
())
1408
return
l
.
integerValue
() <=
r
.
integerValue
();
1409
if
(
l
.
isNumber
() &&
r
.
isNumber
())
1410
return
l
.
asDouble
() <=
r
.
asDouble
();
1411
String
*
sl
=
l
.
stringValue
();
1412
String
*
sr
=
r
.
stringValue
();
1413
if
(
sl
&&
sr
) {
1414
return
!
sr
->
lessThan
(
sl
);
1415
}
1416
1417
Object
*
ro
=
r
.
objectValue
();
1418
Object
*
lo
=
l
.
objectValue
();
1419
if
(
ro
||
lo
) {
1420
QV4
::
ExecutionEngine
*
e
= (
lo
?
lo
:
ro
)->
engine
();
1421
QV4
::
Scope
scope
(
e
);
1422
QV4
::
ScopedValue
pl
(
scope
,
lo
?
RuntimeHelpers
::
objectDefaultValue
(
lo
,
QV4
::
NUMBER_HINT
) :
l
.
asReturnedValue
());
1423
QV4
::
ScopedValue
pr
(
scope
,
ro
?
RuntimeHelpers
::
objectDefaultValue
(
ro
,
QV4
::
NUMBER_HINT
) :
r
.
asReturnedValue
());
1424
return
Runtime
::
CompareLessEqual
::
call
(
pl
,
pr
);
1425
}
1426
1427
double
dl
=
RuntimeHelpers
::
toNumber
(
l
);
1428
double
dr
=
RuntimeHelpers
::
toNumber
(
r
);
1429
return
dl
<=
dr
;
1430
}
1431
1432
Bool
Runtime
::
CompareInstanceof
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
left
,
const
Value
&
right
)
1433
{
1434
TRACE2
(left, right);
1435
1436
Scope
scope
(
engine
);
1437
ScopedValue
v
(
scope
,
Instanceof
::
call
(
engine
,
left
,
right
));
1438
return
v
->
booleanValue
();
1439
}
1440
1441
uint
Runtime
::
CompareIn
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
left
,
const
Value
&
right
)
1442
{
1443
TRACE2
(left, right);
1444
1445
Scope
scope
(
engine
);
1446
ScopedValue
v
(
scope
,
In
::
call
(
engine
,
left
,
right
));
1447
return
v
->
booleanValue
();
1448
}
1449
1450
static
ReturnedValue
throwPropertyIsNotAFunctionTypeError
(ExecutionEngine *engine, Value *thisObject,
const
QString &propertyName)
1451
{
1452
QString objectAsString = QStringLiteral(
"[null]"
);
1453
if
(!thisObject->isUndefined())
1454
objectAsString = thisObject->toQStringNoThrow();
1455
QString msg = QStringLiteral(
"Property '%1' of object %2 is not a function"
)
1456
.arg(propertyName, objectAsString);
1457
return
engine->throwTypeError(msg);
1458
}
1459
1460
ReturnedValue
Runtime
::
CallGlobalLookup
::
call
(
ExecutionEngine
*
engine
,
uint
index
,
Value
argv
[],
int
argc
)
1461
{
1462
Scope
scope
(
engine
);
1463
Lookup
*
l
=
runtimeLookup
(
engine
->
currentStackFrame
->
v4Function
,
index
);
1464
Value
function
=
Value
::
fromReturnedValue
(
l
->
globalGetter
(
engine
));
1465
Value
thisObject
=
Value
::
undefinedValue
();
1466
if
(!
function
.
isFunctionObject
()) {
1467
return
throwPropertyIsNotAFunctionTypeError
(
engine
, &
thisObject
,
1468
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
l
->
nameIndex
]->
toQString
());
1469
}
1470
1471
return
checkedResult
(
engine
,
static_cast
<
FunctionObject
&>(
function
).
call
(
1472
&
thisObject
,
argv
,
argc
));
1473
}
1474
1475
ReturnedValue
Runtime
::
CallQmlContextPropertyLookup
::
call
(
ExecutionEngine
*
engine
,
uint
index
,
1476
Value
*
argv
,
int
argc
)
1477
{
1478
Scope
scope
(
engine
);
1479
ScopedValue
thisObject
(
scope
);
1480
Lookup
*
l
=
runtimeLookup
(
engine
->
currentStackFrame
->
v4Function
,
index
);
1481
Value
function
=
Value
::
fromReturnedValue
(
l
->
contextGetter
(
engine
,
thisObject
));
1482
if
(!
function
.
isFunctionObject
()) {
1483
return
throwPropertyIsNotAFunctionTypeError
(
engine
,
thisObject
,
1484
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
l
->
nameIndex
]->
toQString
());
1485
}
1486
1487
return
checkedResult
(
engine
,
static_cast
<
FunctionObject
&>(
function
).
call
(
1488
thisObject
,
argv
,
argc
));
1489
}
1490
1491
ReturnedValue
Runtime
::
CallPossiblyDirectEval
::
call
(
ExecutionEngine
*
engine
,
Value
*
argv
,
int
argc
)
1492
{
1493
Scope
scope
(
engine
);
1494
ScopedValue
thisObject
(
scope
);
1495
1496
ScopedFunctionObject
function
(
1497
scope
,
engine
->
currentContext
()->
getPropertyAndBase
(
engine
->
id_eval
(),
thisObject
));
1498
if
(
engine
->
hasException
)
1499
return
Encode
::
undefined
();
1500
1501
if
(!
function
)
1502
return
throwPropertyIsNotAFunctionTypeError
(
engine
,
thisObject
,
QLatin1String
(
"eval"
));
1503
1504
if
(
function
->
d
() ==
engine
->
evalFunction
()->
d
())
1505
return
static_cast
<
EvalFunction
*>(
function
.
getPointer
())->
evalCall
(
thisObject
,
argv
,
argc
,
true
);
1506
1507
return
checkedResult
(
engine
,
function
->
call
(
thisObject
,
argv
,
argc
));
1508
}
1509
1510
ReturnedValue
Runtime
::
CallName
::
call
(
ExecutionEngine
*
engine
,
int
nameIndex
,
Value
*
argv
,
int
argc
)
1511
{
1512
Scope
scope
(
engine
);
1513
ScopedValue
thisObject
(
scope
);
1514
ScopedString
name
(
scope
,
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
nameIndex
]);
1515
1516
ScopedFunctionObject
f
(
scope
,
engine
->
currentContext
()->
getPropertyAndBase
(
name
,
thisObject
));
1517
if
(
engine
->
hasException
)
1518
return
Encode
::
undefined
();
1519
1520
if
(!
f
) {
1521
return
throwPropertyIsNotAFunctionTypeError
(
1522
engine
,
thisObject
,
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
1523
->
runtimeStrings
[
nameIndex
]->
toQString
());
1524
}
1525
1526
return
checkedResult
(
engine
,
f
->
call
(
thisObject
,
argv
,
argc
));
1527
}
1528
1529
ReturnedValue
Runtime
::
CallProperty
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
baseRef
,
int
nameIndex
,
Value
*
argv
,
int
argc
)
1530
{
1531
const
Value
*
base
= &
baseRef
;
1532
Scope
scope
(
engine
);
1533
ScopedString
name
(
1534
scope
,
1535
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
nameIndex
]);
1536
ScopedObject
lookupObject
(
scope
,
base
);
1537
1538
if
(!
lookupObject
) {
1539
Q_ASSERT
(!
base
->
isEmpty
());
1540
if
(
base
->
isNullOrUndefined
()) {
1541
QString
message
=
QStringLiteral
(
"Cannot call method '%1' of %2"
)
1542
.
arg
(
name
->
toQString
(),
base
->
toQStringNoThrow
());
1543
return
engine
->
throwTypeError
(
message
);
1544
}
1545
1546
if
(
base
->
isManaged
()) {
1547
const
Managed
*
m
=
static_cast
<
const
Managed
*>(
base
);
1548
lookupObject
=
m
->
internalClass
()->
prototype
;
1549
Q_ASSERT
(
m
->
internalClass
()->
prototype
);
1550
}
else
{
1551
lookupObject
=
RuntimeHelpers
::
convertToObject
(
engine
, *
base
);
1552
if
(
engine
->
hasException
)
// type error
1553
return
Encode
::
undefined
();
1554
if
(!
engine
->
currentStackFrame
->
v4Function
->
isStrict
())
1555
base
=
lookupObject
;
1556
}
1557
}
1558
1559
ScopedFunctionObject
f
(
scope
,
static_cast
<
Object
*>(
lookupObject
)->
get
(
name
));
1560
1561
if
(!
f
) {
1562
QString
error
=
QStringLiteral
(
"Property '%1' of object %2 is not a function"
)
1563
.
arg
(
name
->
toQString
(),
1564
base
->
toQStringNoThrow
());
1565
return
engine
->
throwTypeError
(
error
);
1566
}
1567
1568
return
checkedResult
(
engine
,
f
->
call
(
base
,
argv
,
argc
));
1569
}
1570
1571
ReturnedValue
Runtime
::
CallPropertyLookup
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
base
,
uint
index
,
Value
*
argv
,
int
argc
)
1572
{
1573
Lookup
*
l
=
runtimeLookup
(
engine
->
currentStackFrame
->
v4Function
,
index
);
1574
1575
if
(
base
.
isNullOrUndefined
()) {
1576
const
QString
message
=
QStringLiteral
(
"Cannot call method '%1' of %2"
)
1577
.
arg
(
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
1578
->
runtimeStrings
[
l
->
nameIndex
]->
toQString
(),
1579
base
.
toQStringNoThrow
());
1580
return
engine
->
throwTypeError
(
message
);
1581
}
1582
1583
// ok to have the value on the stack here
1584
Value
f
=
Value
::
fromReturnedValue
(
l
->
getter
(
engine
,
base
));
1585
1586
if
(
Q_LIKELY
(
f
.
isFunctionObject
()))
1587
return
checkedResult
(
engine
,
static_cast
<
FunctionObject
&>(
f
).
call
(&
base
,
argv
,
argc
));
1588
1589
if
(
QmlSignalHandler
*
handler
=
f
.
as
<
QmlSignalHandler
>())
1590
return
checkedResult
(
engine
,
handler
->
call
(&
base
,
argv
,
argc
));
1591
1592
const
QString
message
=
QStringLiteral
(
"Property '%1' of object %2 is not a function"
)
1593
.
arg
(
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
1594
->
runtimeStrings
[
l
->
nameIndex
]
1595
->
toQString
(),
1596
base
.
toQStringNoThrow
());
1597
return
engine
->
throwTypeError
(
message
);
1598
}
1599
1600
ReturnedValue
Runtime
::
CallValue
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
func
,
Value
*
argv
,
int
argc
)
1601
{
1602
if
(!
func
.
isFunctionObject
())
1603
return
engine
->
throwTypeError
(
QStringLiteral
(
"%1 is not a function"
).
arg
(
func
.
toQStringNoThrow
()));
1604
Value
undef
=
Value
::
undefinedValue
();
1605
return
checkedResult
(
engine
,
static_cast
<
const
FunctionObject
&>(
func
).
call
(
1606
&
undef
,
argv
,
argc
));
1607
}
1608
1609
ReturnedValue
Runtime
::
CallWithReceiver
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
func
,
1610
const
Value
&
thisObject
,
Value
argv
[],
int
argc
)
1611
{
1612
if
(!
func
.
isFunctionObject
())
1613
return
engine
->
throwTypeError
(
QStringLiteral
(
"%1 is not a function"
).
arg
(
func
.
toQStringNoThrow
()));
1614
return
checkedResult
(
engine
,
static_cast
<
const
FunctionObject
&>(
func
).
call
(
1615
&
thisObject
,
argv
,
argc
));
1616
}
1617
1618
struct
CallArgs
{
1619
Value *
argv
;
1620
int
argc
;
1621
};
1622
1623
static
CallArgs
createSpreadArguments
(
Scope
&scope, Value *argv,
int
argc)
1624
{
1625
ScopedValue
it(scope);
1626
ScopedValue
done(scope);
1627
1628
int
argCount = 0;
1629
1630
Value *v = scope.constructUndefined(1);
1631
Value *arguments = v;
1632
for
(
int
i = 0; i < argc; ++i) {
1633
if
(!argv[i].isEmpty()) {
1634
*v = argv[i];
1635
++argCount;
1636
v = scope.constructUndefined(1);
1637
continue
;
1638
}
1639
// spread element
1640
++i;
1641
it = Runtime::GetIterator::call(scope.engine, argv[i],
/* ForInIterator */
1);
1642
if
(scope.hasException())
1643
return
{
nullptr
, 0 };
1644
while
(1) {
1645
done = Runtime::IteratorNext::call(scope.engine, it, v);
1646
if
(scope.hasException())
1647
return
{
nullptr
, 0 };
1648
Q_ASSERT(done->isBoolean());
1649
if
(done->booleanValue())
1650
break
;
1651
++argCount;
1652
constexpr
auto
safetyMargin = 100;
// leave some space on the stack for actual work with the elements
1653
if
(qint64(scope.engine->jsStackLimit - scope.engine->jsStackTop) < safetyMargin) {
1654
scope.engine->throwRangeError(QLatin1String(
"Too many elements in array to use it with the spread operator"
));
1655
return
{
nullptr
, 0 };
1656
}
1657
v = scope.constructUndefined(1);
1658
}
1659
}
1660
return
{ arguments, argCount };
1661
}
1662
1663
ReturnedValue
Runtime
::
CallWithSpread
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
function
,
const
Value
&
thisObject
,
Value
*
argv
,
int
argc
)
1664
{
1665
Q_ASSERT
(
argc
>= 1);
1666
if
(!
function
.
isFunctionObject
())
1667
return
engine
->
throwTypeError
();
1668
1669
Scope
scope
(
engine
);
1670
CallArgs
arguments
=
createSpreadArguments
(
scope
,
argv
,
argc
);
1671
if
(
engine
->
hasException
)
1672
return
Encode
::
undefined
();
1673
1674
return
checkedResult
(
engine
,
static_cast
<
const
FunctionObject
&>(
function
).
call
(
1675
&
thisObject
,
arguments
.
argv
,
arguments
.
argc
));
1676
}
1677
1678
ReturnedValue
Runtime
::
Construct
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
function
,
const
Value
&
newTarget
,
Value
*
argv
,
int
argc
)
1679
{
1680
if
(!
function
.
isFunctionObject
())
1681
return
engine
->
throwTypeError
();
1682
1683
return
static_cast
<
const
FunctionObject
&>(
function
).
callAsConstructor
(
argv
,
argc
, &
newTarget
);
1684
}
1685
1686
ReturnedValue
Runtime
::
ConstructWithSpread
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
function
,
const
Value
&
newTarget
,
Value
*
argv
,
int
argc
)
1687
{
1688
if
(!
function
.
isFunctionObject
())
1689
return
engine
->
throwTypeError
();
1690
1691
Scope
scope
(
engine
);
1692
CallArgs
arguments
=
createSpreadArguments
(
scope
,
argv
,
argc
);
1693
if
(
engine
->
hasException
)
1694
return
Encode
::
undefined
();
1695
1696
return
static_cast
<
const
FunctionObject
&>(
function
).
callAsConstructor
(
arguments
.
argv
,
arguments
.
argc
, &
newTarget
);
1697
}
1698
1699
ReturnedValue
Runtime
::
TailCall
::
call
(
JSTypesStackFrame
*
frame
,
ExecutionEngine
*
engine
)
1700
{
1701
// IMPORTANT! The JIT assumes that this method has the same amount (or less) arguments than
1702
// the jitted function, so it can safely do a tail call.
1703
1704
Value
*
tos
=
engine
->
jsStackTop
;
1705
const
Value
&
function
=
tos
[
StackOffsets
::
tailCall_function
];
1706
const
Value
&
thisObject
=
tos
[
StackOffsets
::
tailCall_thisObject
];
1707
Value
*
argv
=
reinterpret_cast
<
Value
*>(
frame
->
jsFrame
) +
tos
[
StackOffsets
::
tailCall_argv
].
int_32
();
1708
int
argc
=
tos
[
StackOffsets
::
tailCall_argc
].
int_32
();
1709
Q_ASSERT
(
argc
>= 0);
1710
1711
const
JavaScriptFunctionObject
*
jsfo
=
function
.
as
<
JavaScriptFunctionObject
>();
1712
if
(!
jsfo
) {
1713
if
(
const
FunctionObject
*
fo
=
function
.
as
<
FunctionObject
>())
1714
return
checkedResult
(
engine
,
fo
->
call
(&
thisObject
,
argv
,
argc
));
1715
return
engine
->
throwTypeError
();
1716
}
1717
1718
if
(!
frame
->
callerCanHandleTailCall
() || !
jsfo
->
canBeTailCalled
() ||
engine
->
debugger
()
1719
||
unsigned
(
argc
) >
jsfo
->
formalParameterCount
()) {
1720
// Cannot tailcall, do a normal call:
1721
return
checkedResult
(
engine
,
jsfo
->
call
(&
thisObject
,
argv
,
argc
));
1722
}
1723
1724
memmove
(
frame
->
jsFrame
->
args
,
argv
,
argc
*
sizeof
(
Value
));
1725
frame
->
init
(
jsfo
->
function
(),
frame
->
jsFrame
->
argValues
<
Value
>(),
argc
,
1726
frame
->
callerCanHandleTailCall
());
1727
frame
->
setupJSFrame
(
frame
->
framePointer
(), *
jsfo
,
jsfo
->
scope
(),
thisObject
,
1728
Primitive
::
undefinedValue
());
1729
engine
->
jsStackTop
=
frame
->
framePointer
() +
frame
->
requiredJSStackFrameSize
();
1730
frame
->
setPendingTailCall
(
true
);
1731
return
Encode
::
undefined
();
1732
}
1733
1734
void
Runtime
::
ThrowException
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
value
)
1735
{
1736
if
(!
value
.
isEmpty
())
1737
engine
->
throwError
(
value
);
1738
}
1739
1740
ReturnedValue
Runtime
::
TypeofValue
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
value
)
1741
{
1742
Scope
scope
(
engine
);
1743
ScopedString
res
(
scope
);
1744
switch
(
value
.
type
()) {
1745
case
Value
::
Undefined_Type
:
1746
res
=
engine
->
id_undefined
();
1747
break
;
1748
case
Value
::
Null_Type
:
1749
res
=
engine
->
id_object
();
1750
break
;
1751
case
Value
::
Boolean_Type
:
1752
res
=
engine
->
id_boolean
();
1753
break
;
1754
case
Value
::
Managed_Type
:
1755
if
(
value
.
isString
())
1756
res
=
engine
->
id_string
();
1757
else
if
(
value
.
isSymbol
())
1758
res
=
engine
->
id_symbol
();
1759
else
if
(
value
.
objectValue
()->
as
<
FunctionObject
>())
1760
res
=
engine
->
id_function
();
1761
else
1762
res
=
engine
->
id_object
();
// ### implementation-defined
1763
break
;
1764
default
:
1765
res
=
engine
->
id_number
();
1766
break
;
1767
}
1768
return
res
.
asReturnedValue
();
1769
}
1770
1771
QV4
::
ReturnedValue
Runtime
::
TypeofName
::
call
(
ExecutionEngine
*
engine
,
int
nameIndex
)
1772
{
1773
Scope
scope
(
engine
);
1774
ScopedString
name
(
scope
,
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
nameIndex
]);
1775
ScopedValue
prop
(
scope
,
engine
->
currentContext
()->
getProperty
(
name
));
1776
// typeof doesn't throw. clear any possible exception
1777
scope
.
engine
->
hasException
=
false
;
1778
return
TypeofValue
::
call
(
engine
,
prop
);
1779
}
1780
1781
void
Runtime
::
PushCallContext
::
call
(
JSTypesStackFrame
*
frame
)
1782
{
1783
frame
->
jsFrame
->
context
=
ExecutionContext
::
newCallContext
(
frame
)->
asReturnedValue
();
1784
}
1785
1786
ReturnedValue
Runtime
::
PushWithContext
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
acc
)
1787
{
1788
Q_ASSERT
(
engine
->
currentStackFrame
->
isJSTypesFrame
());
1789
CallData
*
jsFrame
=
static_cast
<
JSTypesStackFrame
*>(
engine
->
currentStackFrame
)->
jsFrame
;
1790
Value
&
newAcc
=
jsFrame
->
accumulator
.
asValue
<
Value
>();
1791
newAcc
=
Value
::
fromHeapObject
(
acc
.
toObject
(
engine
));
1792
if
(!
engine
->
hasException
) {
1793
Q_ASSERT
(
newAcc
.
isObject
());
1794
const
Object
&
obj
=
static_cast
<
const
Object
&>(
newAcc
);
1795
Value
&
context
=
jsFrame
->
context
.
asValue
<
Value
>();
1796
auto
ec
=
static_cast
<
const
ExecutionContext
*>(&
context
);
1797
context
=
ec
->
newWithContext
(
obj
.
d
())->
asReturnedValue
();
1798
}
1799
return
newAcc
.
asReturnedValue
();
1800
}
1801
1802
void
Runtime
::
PushCatchContext
::
call
(
ExecutionEngine
*
engine
,
int
blockIndex
,
int
exceptionVarNameIndex
)
1803
{
1804
Q_ASSERT
(
engine
->
currentStackFrame
->
isJSTypesFrame
());
1805
auto
name
=
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
exceptionVarNameIndex
];
1806
static_cast
<
JSTypesStackFrame
*>(
engine
->
currentStackFrame
)->
jsFrame
->
context
1807
=
ExecutionContext
::
newCatchContext
(
engine
->
currentStackFrame
,
blockIndex
,
name
)->
asReturnedValue
();
1808
}
1809
1810
void
Runtime
::
PushBlockContext
::
call
(
ExecutionEngine
*
engine
,
int
index
)
1811
{
1812
Q_ASSERT
(
engine
->
currentStackFrame
->
isJSTypesFrame
());
1813
static_cast
<
JSTypesStackFrame
*>(
engine
->
currentStackFrame
)->
jsFrame
->
context
1814
=
ExecutionContext
::
newBlockContext
(
engine
->
currentStackFrame
,
index
)->
asReturnedValue
();
1815
}
1816
1817
void
Runtime
::
CloneBlockContext
::
call
(
ExecutionEngine
*
engine
)
1818
{
1819
Q_ASSERT
(
engine
->
currentStackFrame
->
isJSTypesFrame
());
1820
auto
frame
=
static_cast
<
JSTypesStackFrame
*>(
engine
->
currentStackFrame
);
1821
auto
context
=
static_cast
<
Heap
::
CallContext
*>(
1822
Value
::
fromStaticValue
(
frame
->
jsFrame
->
context
).
m
());
1823
frame
->
jsFrame
->
context
=
1824
ExecutionContext
::
cloneBlockContext
(
engine
,
context
)->
asReturnedValue
();
1825
}
1826
1827
void
Runtime
::
PushScriptContext
::
call
(
ExecutionEngine
*
engine
,
int
index
)
1828
{
1829
Q_ASSERT
(
engine
->
currentStackFrame
->
isJSTypesFrame
());
1830
Q_ASSERT
(
engine
->
currentContext
()->
d
()->
type
==
Heap
::
ExecutionContext
::
Type_GlobalContext
||
1831
engine
->
currentContext
()->
d
()->
type
==
Heap
::
ExecutionContext
::
Type_QmlContext
);
1832
ReturnedValue
c
=
ExecutionContext
::
newBlockContext
(
engine
->
currentStackFrame
,
index
)->
asReturnedValue
();
1833
engine
->
setScriptContext
(
c
);
1834
static_cast
<
JSTypesStackFrame
*>(
engine
->
currentStackFrame
)->
jsFrame
->
context
=
c
;
1835
}
1836
1837
void
Runtime
::
PopScriptContext
::
call
(
ExecutionEngine
*
engine
)
1838
{
1839
Q_ASSERT
(
engine
->
currentStackFrame
->
isJSTypesFrame
());
1840
ReturnedValue
root
=
engine
->
rootContext
()->
asReturnedValue
();
1841
engine
->
setScriptContext
(
root
);
1842
static_cast
<
JSTypesStackFrame
*>(
engine
->
currentStackFrame
)->
jsFrame
->
context
=
root
;
1843
}
1844
1845
void
Runtime
::
ThrowReferenceError
::
call
(
ExecutionEngine
*
engine
,
int
nameIndex
)
1846
{
1847
Scope
scope
(
engine
);
1848
ScopedString
name
(
scope
,
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
nameIndex
]);
1849
engine
->
throwReferenceError
(
name
);
1850
}
1851
1852
void
Runtime
::
ThrowOnNullOrUndefined
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
v
)
1853
{
1854
if
(
v
.
isNullOrUndefined
())
1855
engine
->
throwTypeError
();
1856
}
1857
1858
void
Runtime
::
MarkCustom
::
call
(
const
Value
&
toBeMarked
)
1859
{
1860
auto
*
h
=
toBeMarked
.
heapObject
();
1861
if
(!
h
)
1862
return
;
1863
Q_ASSERT
(
h
->
internalClass
);
1864
auto
engine
=
h
->
internalClass
->
engine
;
1865
Q_ASSERT
(
engine
);
1866
// runtime function is only meant to be called while gc is ongoing
1867
Q_ASSERT
(
engine
->
isGCOngoing
);
1868
QV4
::
WriteBarrier
::
markCustom
(
engine
, [&](
QV4
::
MarkStack
*
ms
) {
1869
h
->
mark
(
ms
);
1870
});
1871
}
1872
1873
ReturnedValue
Runtime
::
ConvertThisToObject
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
t
)
1874
{
1875
if
(!
t
.
isObject
()) {
1876
if
(
t
.
isNullOrUndefined
()) {
1877
return
engine
->
globalObject
->
asReturnedValue
();
1878
}
else
{
1879
return
t
.
toObject
(
engine
)->
asReturnedValue
();
1880
}
1881
}
1882
return
t
.
asReturnedValue
();
1883
}
1884
1885
void
Runtime
::
DeclareVar
::
call
(
ExecutionEngine
*
engine
,
Bool
deletable
,
int
nameIndex
)
1886
{
1887
Scope
scope
(
engine
);
1888
ScopedString
name
(
scope
,
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeStrings
[
nameIndex
]);
1889
engine
->
currentContext
()->
createMutableBinding
(
name
,
deletable
);
1890
}
1891
1892
ReturnedValue
Runtime
::
ArrayLiteral
::
call
(
ExecutionEngine
*
engine
,
Value
*
values
,
uint
length
)
1893
{
1894
return
engine
->
newArrayObject
(
values
,
length
)->
asReturnedValue
();
1895
}
1896
1897
ReturnedValue
Runtime
::
ObjectLiteral
::
call
(
ExecutionEngine
*
engine
,
int
classId
,
QV4
::
Value
args
[],
int
argc
)
1898
{
1899
Scope
scope
(
engine
);
1900
Scoped
<
InternalClass
>
klass
(
scope
,
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeClasses
[
classId
]);
1901
ScopedObject
o
(
scope
,
engine
->
newObject
(
klass
->
d
()));
1902
1903
Q_ASSERT
(
uint
(
argc
) >=
klass
->
d
()->
size
);
1904
1905
for
(
uint
i
= 0;
i
<
klass
->
d
()->
size
; ++
i
)
1906
o
->
setProperty
(
i
, *
args
++);
1907
1908
Q_ASSERT
((
argc
-
klass
->
d
()->
size
) % 3 == 0);
1909
int
additionalArgs
= (
argc
-
int
(
klass
->
d
()->
size
))/3;
1910
1911
if
(!
additionalArgs
)
1912
return
o
->
asReturnedValue
();
1913
1914
ScopedPropertyKey
name
(
scope
);
1915
ScopedProperty
pd
(
scope
);
1916
ScopedFunctionObject
fn
(
scope
);
1917
ScopedString
fnName
(
scope
);
1918
ScopedValue
value
(
scope
);
1919
for
(
int
i
= 0;
i
<
additionalArgs
; ++
i
) {
1920
Q_ASSERT
(
args
->
isInteger
());
1921
ObjectLiteralArgument
arg
=
ObjectLiteralArgument
(
args
->
integerValue
());
1922
name
=
args
[1].
toPropertyKey
(
engine
);
1923
value
=
args
[2];
1924
if
(
engine
->
hasException
)
1925
return
Encode
::
undefined
();
1926
if
(
arg
!=
ObjectLiteralArgument
::
Value
) {
1927
Q_ASSERT
(
args
[2].
isInteger
());
1928
int
functionId
=
args
[2].
integerValue
();
1929
QV4
::
Function
*
clos
=
engine
->
currentStackFrame
->
v4Function
->
executableCompilationUnit
()
1930
->
runtimeFunctions
[
functionId
];
1931
Q_ASSERT
(
clos
);
1932
1933
PropertyKey
::
FunctionNamePrefix
prefix
=
PropertyKey
::
None
;
1934
if
(
arg
==
ObjectLiteralArgument
::
Getter
)
1935
prefix
=
PropertyKey
::
Getter
;
1936
else
if
(
arg
==
ObjectLiteralArgument
::
Setter
)
1937
prefix
=
PropertyKey
::
Setter
;
1938
else
1939
arg
=
ObjectLiteralArgument
::
Value
;
1940
fnName
=
name
->
asFunctionName
(
engine
,
prefix
);
1941
1942
ExecutionContext
*
current
=
engine
->
currentContext
();
1943
if
(
clos
->
isGenerator
())
1944
value
=
MemberGeneratorFunction
::
create
(
current
,
clos
,
o
,
fnName
)->
asReturnedValue
();
1945
else
1946
value
=
FunctionObject
::
createMemberFunction
(
current
,
clos
,
o
,
fnName
)->
asReturnedValue
();
1947
}
else
if
(
args
[2].
isFunctionObject
()) {
1948
fn
=
static_cast
<
const
FunctionObject
&>(
args
[2]);
1949
1950
fnName
=
name
->
asFunctionName
(
engine
,
PropertyKey
::
None
);
1951
fn
->
setName
(
fnName
);
1952
}
1953
Q_ASSERT
(
arg
!=
ObjectLiteralArgument
::
Method
);
1954
Q_ASSERT
(
arg
==
ObjectLiteralArgument
::
Value
||
value
->
isFunctionObject
());
1955
if
(
arg
==
ObjectLiteralArgument
::
Value
||
arg
==
ObjectLiteralArgument
::
Getter
) {
1956
pd
->
value
=
value
;
1957
pd
->
set
=
Value
::
emptyValue
();
1958
}
else
{
1959
pd
->
value
=
Value
::
emptyValue
();
1960
pd
->
set
=
value
;
1961
}
1962
bool
ok
=
o
->
defineOwnProperty
(
name
,
pd
, (
arg
==
ObjectLiteralArgument
::
Value
?
Attr_Data
:
Attr_Accessor
));
1963
if
(!
ok
)
1964
return
engine
->
throwTypeError
();
1965
1966
args
+= 3;
1967
}
1968
return
o
.
asReturnedValue
();
1969
}
1970
1971
ReturnedValue
Runtime
::
CreateClass
::
call
(
ExecutionEngine
*
engine
,
int
classIndex
,
1972
const
Value
&
superClass
,
Value
computedNames
[])
1973
{
1974
const
QV4
::
ExecutableCompilationUnit
*
unit
1975
=
engine
->
currentStackFrame
->
v4Function
->
executableCompilationUnit
();
1976
const
QV4
::
CompiledData
::
Class
*
cls
=
unit
->
unitData
()->
classAt
(
classIndex
);
1977
1978
Scope
scope
(
engine
);
1979
ScopedObject
protoParent
(
scope
,
engine
->
objectPrototype
());
1980
ScopedObject
constructorParent
(
scope
,
engine
->
functionPrototype
());
1981
if
(!
superClass
.
isEmpty
()) {
1982
if
(
superClass
.
isNull
()) {
1983
protoParent
=
Encode
::
null
();
1984
}
else
{
1985
const
FunctionObject
*
superFunction
=
superClass
.
as
<
FunctionObject
>();
1986
// ### check that the heritage object is a constructor
1987
if
(!
superFunction
|| !
superFunction
->
isConstructor
())
1988
return
engine
->
throwTypeError
(
QStringLiteral
(
"The superclass is not a function object."
));
1989
const
FunctionObject
*
s
=
static_cast
<
const
FunctionObject
*>(&
superClass
);
1990
ScopedValue
result
(
scope
,
s
->
get
(
scope
.
engine
->
id_prototype
()));
1991
if
(!
result
->
isObject
() && !
result
->
isNull
())
1992
return
engine
->
throwTypeError
(
QStringLiteral
(
"The value of the superclass's prototype property is not an object."
));
1993
protoParent
= *
result
;
1994
constructorParent
=
superClass
;
1995
}
1996
}
1997
1998
ScopedObject
proto
(
scope
,
engine
->
newObject
());
1999
proto
->
setPrototypeUnchecked
(
protoParent
);
2000
ExecutionContext
*
current
=
engine
->
currentContext
();
2001
2002
ScopedFunctionObject
constructor
(
scope
);
2003
QV4
::
Function
*
f
=
cls
->
constructorFunction
!=
UINT_MAX
?
unit
->
runtimeFunctions
[
cls
->
constructorFunction
] :
nullptr
;
2004
constructor
=
FunctionObject
::
createConstructorFunction
(
current
,
f
,
proto
, !
superClass
.
isEmpty
())->
asReturnedValue
();
2005
constructor
->
setPrototypeUnchecked
(
constructorParent
);
2006
Value
argCount
=
Value
::
fromInt32
(
f
?
f
->
nFormals
: 0);
2007
constructor
->
defineReadonlyConfigurableProperty
(
scope
.
engine
->
id_length
(),
argCount
);
2008
constructor
->
defineReadonlyConfigurableProperty
(
engine
->
id_prototype
(),
proto
);
2009
proto
->
defineDefaultProperty
(
engine
->
id_constructor
(),
constructor
);
2010
2011
ScopedString
name
(
scope
);
2012
if
(
cls
->
nameIndex
!=
UINT_MAX
) {
2013
name
=
unit
->
runtimeStrings
[
cls
->
nameIndex
];
2014
constructor
->
defineReadonlyConfigurableProperty
(
engine
->
id_name
(),
name
);
2015
}
2016
2017
ScopedObject
receiver
(
scope
, *
constructor
);
2018
ScopedPropertyKey
propertyName
(
scope
);
2019
ScopedFunctionObject
function
(
scope
);
2020
ScopedProperty
property
(
scope
);
2021
const
CompiledData
::
Method
*
methods
=
cls
->
methodTable
();
2022
for
(
uint
i
= 0;
i
<
cls
->
nStaticMethods
+
cls
->
nMethods
; ++
i
) {
2023
if
(
i
==
cls
->
nStaticMethods
)
2024
receiver
=
proto
;
2025
if
(
methods
[
i
].
name
==
UINT_MAX
) {
2026
propertyName
=
computedNames
->
toPropertyKey
(
engine
);
2027
if
(
propertyName
==
scope
.
engine
->
id_prototype
()->
propertyKey
() &&
receiver
->
d
() ==
constructor
->
d
())
2028
return
engine
->
throwTypeError
(
QStringLiteral
(
"Cannot declare a static method named 'prototype'."
));
2029
if
(
engine
->
hasException
)
2030
return
Encode
::
undefined
();
2031
++
computedNames
;
2032
}
else
{
2033
name
=
unit
->
runtimeStrings
[
methods
[
i
].
name
];
2034
propertyName
=
name
->
toPropertyKey
();
2035
}
2036
QV4
::
Function
*
f
=
unit
->
runtimeFunctions
[
methods
[
i
].
function
];
2037
Q_ASSERT
(
f
);
2038
PropertyKey
::
FunctionNamePrefix
prefix
=
PropertyKey
::
None
;
2039
if
(
methods
[
i
].
type
==
CompiledData
::
Method
::
Getter
)
2040
prefix
=
PropertyKey
::
Getter
;
2041
else
if
(
methods
[
i
].
type
==
CompiledData
::
Method
::
Setter
)
2042
prefix
=
PropertyKey
::
Setter
;
2043
2044
name
=
propertyName
->
asFunctionName
(
engine
,
prefix
);
2045
2046
if
(
f
->
isGenerator
())
2047
function
=
MemberGeneratorFunction
::
create
(
current
,
f
,
receiver
,
name
);
2048
else
2049
function
=
FunctionObject
::
createMemberFunction
(
current
,
f
,
receiver
,
name
);
2050
Q_ASSERT
(
function
);
2051
PropertyAttributes
attributes
;
2052
switch
(
methods
[
i
].
type
) {
2053
case
CompiledData
::
Method
::
Getter
:
2054
property
->
setGetter
(
function
);
2055
property
->
set
=
Value
::
emptyValue
();
2056
attributes
=
Attr_Accessor
|
Attr_NotEnumerable
;
2057
break
;
2058
case
CompiledData
::
Method
::
Setter
:
2059
property
->
value
=
Value
::
emptyValue
();
2060
property
->
setSetter
(
function
);
2061
attributes
=
Attr_Accessor
|
Attr_NotEnumerable
;
2062
break
;
2063
default
:
// Regular
2064
property
->
value
=
function
;
2065
property
->
set
=
Value
::
emptyValue
();
2066
attributes
=
Attr_Data
|
Attr_NotEnumerable
;
2067
break
;
2068
}
2069
receiver
->
defineOwnProperty
(
propertyName
,
property
,
attributes
);
2070
}
2071
2072
return
constructor
->
asReturnedValue
();
2073
}
2074
2075
QV4
::
ReturnedValue
Runtime
::
CreateMappedArgumentsObject
::
call
(
ExecutionEngine
*
engine
)
2076
{
2077
Q_ASSERT
(
engine
->
currentContext
()->
d
()->
type
==
Heap
::
ExecutionContext
::
Type_CallContext
);
2078
Heap
::
InternalClass
*
ic
=
engine
->
internalClasses
(
EngineBase
::
Class_ArgumentsObject
);
2079
return
engine
->
memoryManager
->
allocObject
<
ArgumentsObject
>(
ic
,
engine
->
currentStackFrame
)->
asReturnedValue
();
2080
}
2081
2082
QV4
::
ReturnedValue
Runtime
::
CreateUnmappedArgumentsObject
::
call
(
ExecutionEngine
*
engine
)
2083
{
2084
Q_ASSERT
(
engine
->
currentStackFrame
->
isJSTypesFrame
());
2085
Heap
::
InternalClass
*
ic
=
engine
->
internalClasses
(
EngineBase
::
Class_StrictArgumentsObject
);
2086
return
engine
->
memoryManager
->
allocObject
<
StrictArgumentsObject
>(
2087
ic
,
static_cast
<
JSTypesStackFrame
*>(
engine
->
currentStackFrame
))->
asReturnedValue
();
2088
}
2089
2090
QV4
::
ReturnedValue
Runtime
::
CreateRestParameter
::
call
(
ExecutionEngine
*
engine
,
int
argIndex
)
2091
{
2092
Q_ASSERT
(
engine
->
currentStackFrame
->
isJSTypesFrame
());
2093
JSTypesStackFrame
*
frame
=
static_cast
<
JSTypesStackFrame
*>(
engine
->
currentStackFrame
);
2094
const
Value
*
values
=
frame
->
argv
() +
argIndex
;
2095
int
nValues
=
frame
->
argc
() -
argIndex
;
2096
if
(
nValues
<= 0)
2097
return
engine
->
newArrayObject
(0)->
asReturnedValue
();
2098
return
engine
->
newArrayObject
(
values
,
nValues
)->
asReturnedValue
();
2099
}
2100
2101
ReturnedValue
Runtime
::
RegexpLiteral
::
call
(
ExecutionEngine
*
engine
,
int
id
)
2102
{
2103
const
auto
val
2104
=
engine
->
currentStackFrame
->
v4Function
->
compilationUnit
->
runtimeRegularExpressions
[
id
];
2105
Heap
::
RegExpObject
*
ro
=
engine
->
newRegExpObject
(
Value
::
fromStaticValue
(
val
).
as
<
RegExp
>());
2106
return
ro
->
asReturnedValue
();
2107
}
2108
2109
ReturnedValue
Runtime
::
ToObject
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
obj
)
2110
{
2111
if
(
obj
.
isObject
())
2112
return
obj
.
asReturnedValue
();
2113
2114
return
obj
.
toObject
(
engine
)->
asReturnedValue
();
2115
}
2116
2117
Bool
Runtime
::
ToBoolean
::
call
(
const
Value
&
obj
)
2118
{
2119
return
obj
.
toBoolean
();
2120
}
2121
2122
ReturnedValue
Runtime
::
ToNumber
::
call
(
ExecutionEngine
*,
const
Value
&
v
)
2123
{
2124
return
Encode
(
v
.
toNumber
());
2125
}
2126
2127
ReturnedValue
Runtime
::
UMinus
::
call
(
const
Value
&
value
)
2128
{
2129
TRACE1
(value);
2130
2131
// +0 != -0, so we need to convert to double when negating 0
2132
if
(
value
.
isInteger
() &&
value
.
integerValue
() &&
2133
value
.
integerValue
() !=
std
::
numeric_limits
<
int
>::
min
())
2134
return
Encode
(-
value
.
integerValue
());
2135
else
{
2136
double
n
=
RuntimeHelpers
::
toNumber
(
value
);
2137
return
Encode
(-
n
);
2138
}
2139
}
2140
2141
// binary operators
2142
2143
ReturnedValue
Runtime
::
Add
::
call
(
ExecutionEngine
*
engine
,
const
Value
&
left
,
const
Value
&
right
)
2144
{
2145
TRACE2
(left, right);
2146
2147
if
(
Q_LIKELY
(
left
.
integerCompatible
() &&
right
.
integerCompatible
()))
2148
return
add_int32
(
left
.
integerValue
(),
right
.
integerValue
());
2149
if
(
left
.
isNumber
() &&
right
.
isNumber
())
2150
return
Value
::
fromDouble
(
left
.
asDouble
() +
right
.
asDouble
()).
asReturnedValue
();
2151
2152
return
RuntimeHelpers
::
addHelper
(
engine
,
left
,
right
);
2153
}
2154
2155
ReturnedValue
Runtime
::
Sub
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2156
{
2157
TRACE2
(left, right);
2158
2159
if
(
Q_LIKELY
(
left
.
integerCompatible
() &&
right
.
integerCompatible
()))
2160
return
sub_int32
(
left
.
integerValue
(),
right
.
integerValue
());
2161
2162
double
lval
=
left
.
isNumber
() ?
left
.
asDouble
() :
left
.
toNumberImpl
();
2163
double
rval
=
right
.
isNumber
() ?
right
.
asDouble
() :
right
.
toNumberImpl
();
2164
2165
return
Value
::
fromDouble
(
lval
-
rval
).
asReturnedValue
();
2166
}
2167
2168
ReturnedValue
Runtime
::
Mul
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2169
{
2170
TRACE2
(left, right);
2171
2172
if
(
Q_LIKELY
(
left
.
integerCompatible
() &&
right
.
integerCompatible
()))
2173
return
mul_int32
(
left
.
integerValue
(),
right
.
integerValue
());
2174
2175
double
lval
=
left
.
isNumber
() ?
left
.
asDouble
() :
left
.
toNumberImpl
();
2176
double
rval
=
right
.
isNumber
() ?
right
.
asDouble
() :
right
.
toNumberImpl
();
2177
2178
return
Value
::
fromDouble
(
lval
*
rval
).
asReturnedValue
();
2179
}
2180
2181
ReturnedValue
Runtime
::
Div
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2182
{
2183
TRACE2
(left, right);
2184
2185
if
(
Value
::
integerCompatible
(
left
,
right
)) {
2186
int
lval
=
left
.
integerValue
();
2187
int
rval
=
right
.
integerValue
();
2188
if
(
rval
!= 0
// division by zero should result in a NaN
2189
&& !(
lval
==
std
::
numeric_limits
<
int
>::
min
() &&
rval
== -1)
// doesn't fit in int
2190
&& (
lval
%
rval
== 0)
// fractions can't be stored in an int
2191
&& !(
lval
== 0 &&
rval
< 0))
// 0 / -something results in -0.0
2192
return
Encode
(
int
(
lval
/
rval
));
2193
else
2194
return
Encode
(
double
(
lval
) /
rval
);
2195
}
2196
2197
double
lval
=
left
.
toNumber
();
2198
double
rval
=
right
.
toNumber
();
2199
return
Value
::
fromDouble
(
lval
/
rval
).
asReturnedValue
();
2200
}
2201
2202
ReturnedValue
Runtime
::
Mod
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2203
{
2204
TRACE2
(left, right);
2205
2206
if
(
Value
::
integerCompatible
(
left
,
right
) &&
left
.
integerValue
() >= 0 &&
right
.
integerValue
() > 0) {
2207
// special cases are handled by fmod, among them:
2208
// - arithmic execeptions for ints in c++, eg: INT_MIN % -1
2209
// - undefined behavior in c++, e.g.: anything % 0
2210
// - uncommon cases which would complicate the condition, e.g.: negative integers
2211
// (this makes sure that -1 % 1 == -0 by passing it to fmod)
2212
return
Encode
(
left
.
integerValue
() %
right
.
integerValue
());
2213
}
2214
2215
double
lval
=
RuntimeHelpers
::
toNumber
(
left
);
2216
double
rval
=
RuntimeHelpers
::
toNumber
(
right
);
2217
#
ifdef
fmod
2218
#
undef
fmod
2219
#
endif
2220
return
Value
::
fromDouble
(
std
::
fmod
(
lval
,
rval
)).
asReturnedValue
();
2221
}
2222
2223
ReturnedValue
Runtime
::
Exp
::
call
(
const
Value
&
base
,
const
Value
&
exp
)
2224
{
2225
double
b
=
base
.
toNumber
();
2226
double
e
=
exp
.
toNumber
();
2227
return
Encode
(
QQmlPrivate
::
jsExponentiate
(
b
,
e
));
2228
}
2229
2230
ReturnedValue
Runtime
::
BitAnd
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2231
{
2232
TRACE2
(left, right);
2233
2234
int
lval
=
left
.
toInt32
();
2235
int
rval
=
right
.
toInt32
();
2236
return
Encode
((
int
)(
lval
&
rval
));
2237
}
2238
2239
ReturnedValue
Runtime
::
BitOr
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2240
{
2241
TRACE2
(left, right);
2242
2243
int
lval
=
left
.
toInt32
();
2244
int
rval
=
right
.
toInt32
();
2245
return
Encode
((
int
)(
lval
|
rval
));
2246
}
2247
2248
ReturnedValue
Runtime
::
BitXor
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2249
{
2250
TRACE2
(left, right);
2251
2252
int
lval
=
left
.
toInt32
();
2253
int
rval
=
right
.
toInt32
();
2254
return
Encode
((
int
)(
lval
^
rval
));
2255
}
2256
2257
ReturnedValue
Runtime
::
Shl
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2258
{
2259
TRACE2
(left, right);
2260
2261
int
lval
=
left
.
toInt32
();
2262
int
rval
=
right
.
toInt32
() & 0x1f;
2263
return
Encode
((
int
)(
lval
<<
rval
));
2264
}
2265
2266
ReturnedValue
Runtime
::
Shr
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2267
{
2268
TRACE2
(left, right);
2269
2270
int
lval
=
left
.
toInt32
();
2271
unsigned
rval
=
right
.
toUInt32
() & 0x1f;
2272
return
Encode
((
int
)(
lval
>>
rval
));
2273
}
2274
2275
ReturnedValue
Runtime
::
UShr
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2276
{
2277
TRACE2
(left, right);
2278
2279
unsigned
lval
=
left
.
toUInt32
();
2280
unsigned
rval
=
right
.
toUInt32
() & 0x1f;
2281
uint
res
=
lval
>>
rval
;
2282
2283
return
Encode
(
res
);
2284
}
2285
2286
ReturnedValue
Runtime
::
GreaterThan
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2287
{
2288
TRACE2
(left, right);
2289
2290
bool
r
=
CompareGreaterThan
::
call
(
left
,
right
);
2291
return
Encode
(
r
);
2292
}
2293
2294
ReturnedValue
Runtime
::
LessThan
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2295
{
2296
TRACE2
(left, right);
2297
2298
bool
r
=
CompareLessThan
::
call
(
left
,
right
);
2299
return
Encode
(
r
);
2300
}
2301
2302
ReturnedValue
Runtime
::
GreaterEqual
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2303
{
2304
TRACE2
(left, right);
2305
2306
bool
r
=
CompareGreaterEqual
::
call
(
left
,
right
);
2307
return
Encode
(
r
);
2308
}
2309
2310
ReturnedValue
Runtime
::
LessEqual
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2311
{
2312
TRACE2
(left, right);
2313
2314
bool
r
=
CompareLessEqual
::
call
(
left
,
right
);
2315
return
Encode
(
r
);
2316
}
2317
2318
struct
LazyScope
2319
{
2320
ExecutionEngine *
engine
=
nullptr
;
2321
Value *
stackMark
=
nullptr
;
2322
~
LazyScope
() {
2323
if
(
engine
)
2324
engine
->jsStackTop =
stackMark
;
2325
}
2326
template
<
typename
T>
2327
void
set
(Value **scopedValue, T value, ExecutionEngine *e) {
2328
if
(!
engine
) {
2329
engine
= e;
2330
stackMark
=
engine
->jsStackTop;
2331
}
2332
if
(!*scopedValue)
2333
*scopedValue = e->jsAlloca(1);
2334
**scopedValue = value;
2335
}
2336
};
2337
2338
Bool
Runtime
::
CompareEqual
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2339
{
2340
TRACE2
(left, right);
2341
2342
Value
lhs
=
left
;
2343
Value
rhs
=
right
;
2344
2345
LazyScope
scope
;
2346
Value
*
lhsGuard
=
nullptr
;
2347
Value
*
rhsGuard
=
nullptr
;
2348
2349
redo
:
2350
if
(
lhs
.
asReturnedValue
() ==
rhs
.
asReturnedValue
())
2351
return
!
lhs
.
isNaN
();
2352
2353
quint32
lt
=
lhs
.
quickType
();
2354
quint32
rt
=
rhs
.
quickType
();
2355
2356
// LHS: Check if managed
2357
if
((
lt
& (
Value
::
ManagedMask
>>
Value
::
Tag_Shift
)) == 0) {
2358
if
(
lhs
.
isUndefined
())
2359
return
rhs
.
isNullOrUndefined
();
2360
2361
// RHS: Check if managed
2362
if
((
rt
& (
Value
::
ManagedMask
>>
Value
::
Tag_Shift
)) == 0) {
2363
if
(
rhs
.
isUndefined
())
2364
return
false
;
2365
2366
Heap
::
Base
*
l
=
lhs
.
m
();
2367
Heap
::
Base
*
r
=
rhs
.
m
();
2368
Q_ASSERT
(
l
);
2369
Q_ASSERT
(
r
);
2370
if
(
l
->
internalClass
->
vtable
->
isStringOrSymbol
==
r
->
internalClass
->
vtable
->
isStringOrSymbol
)
2371
return
static_cast
<
QV4
::
Managed
&>(
lhs
).
isEqualTo
(&
static_cast
<
QV4
::
Managed
&>(
rhs
));
2372
if
(
l
->
internalClass
->
vtable
->
isStringOrSymbol
) {
2373
scope
.
set
(&
rhsGuard
,
RuntimeHelpers
::
objectDefaultValue
(&
static_cast
<
QV4
::
Object
&>(
rhs
),
PREFERREDTYPE_HINT
),
r
->
internalClass
->
engine
);
2374
rhs
=
rhsGuard
->
asReturnedValue
();
2375
goto
redo
;
2376
}
else
{
2377
Q_ASSERT
(
r
->
internalClass
->
vtable
->
isStringOrSymbol
);
2378
scope
.
set
(&
lhsGuard
,
RuntimeHelpers
::
objectDefaultValue
(&
static_cast
<
QV4
::
Object
&>(
lhs
),
PREFERREDTYPE_HINT
),
l
->
internalClass
->
engine
);
2379
lhs
=
lhsGuard
->
asReturnedValue
();
2380
goto
redo
;
2381
}
2382
return
false
;
2383
}
2384
2385
lhs_managed_and_rhs_not
:
2386
switch
(
rt
) {
2387
case
QV4
::
Value
::
QT_Empty
:
2388
Q_UNREACHABLE
();
2389
case
QV4
::
Value
::
QT_Null
:
2390
return
false
;
2391
case
QV4
::
Value
::
QT_Bool
:
2392
case
QV4
::
Value
::
QT_Int
:
2393
rhs
=
Value
::
fromDouble
(
rhs
.
int_32
());
2394
Q_FALLTHROUGH
();
2395
default
:
// double
2396
if
(
lhs
.
m
()->
internalClass
->
vtable
->
isStringOrSymbol
) {
2397
return
lhs
.
m
()->
internalClass
->
vtable
->
isString
? (
RuntimeHelpers
::
toNumber
(
lhs
) ==
rhs
.
doubleValue
()) :
false
;
2398
}
else
{
2399
scope
.
set
(&
lhsGuard
,
RuntimeHelpers
::
objectDefaultValue
(&
static_cast
<
QV4
::
Object
&>(
lhs
),
PREFERREDTYPE_HINT
),
lhs
.
m
()->
internalClass
->
engine
);
2400
lhs
=
lhsGuard
->
asReturnedValue
();
2401
}
2402
}
2403
goto
redo
;
2404
}
else
if
((
rt
& (
Value
::
ManagedMask
>>
Value
::
Tag_Shift
)) == 0) {
2405
if
(
rhs
.
isUndefined
())
2406
return
lhs
.
isNull
();
// Can't be undefined
2407
qSwap
(
lhs
,
rhs
);
2408
qSwap
(
lt
,
rt
);
2409
goto
lhs_managed_and_rhs_not
;
2410
}
2411
2412
switch
(
lt
) {
2413
case
QV4
::
Value
::
QT_Empty
:
2414
Q_UNREACHABLE
();
2415
case
QV4
::
Value
::
QT_Null
:
2416
return
rhs
.
isNull
();
2417
case
QV4
::
Value
::
QT_Bool
:
2418
case
QV4
::
Value
::
QT_Int
:
2419
switch
(
rt
) {
2420
case
QV4
::
Value
::
QT_Empty
:
2421
Q_UNREACHABLE
();
2422
case
QV4
::
Value
::
QT_Null
:
2423
return
false
;
2424
case
QV4
::
Value
::
QT_Bool
:
2425
case
QV4
::
Value
::
QT_Int
:
2426
return
lhs
.
int_32
() ==
rhs
.
int_32
();
2427
default
:
// double
2428
return
lhs
.
int_32
() ==
rhs
.
doubleValue
();
2429
}
2430
default
:
// double
2431
switch
(
rt
) {
2432
case
QV4
::
Value
::
QT_Empty
:
2433
Q_UNREACHABLE
();
2434
case
QV4
::
Value
::
QT_Null
:
2435
return
false
;
2436
case
QV4
::
Value
::
QT_Bool
:
2437
case
QV4
::
Value
::
QT_Int
:
2438
return
lhs
.
doubleValue
() ==
rhs
.
int_32
();
2439
default
:
// double
2440
return
lhs
.
doubleValue
() ==
rhs
.
doubleValue
();
2441
}
2442
}
2443
}
2444
2445
ReturnedValue
Runtime
::
Equal
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2446
{
2447
TRACE2
(left, right);
2448
2449
bool
r
=
CompareEqual
::
call
(
left
,
right
);
2450
return
Encode
(
r
);
2451
}
2452
2453
ReturnedValue
Runtime
::
NotEqual
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2454
{
2455
TRACE2
(left, right);
2456
2457
bool
r
= !
CompareEqual
::
call
(
left
,
right
);
2458
return
Encode
(
r
);
2459
}
2460
2461
ReturnedValue
Runtime
::
StrictEqual
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2462
{
2463
TRACE2
(left, right);
2464
2465
bool
r
=
RuntimeHelpers
::
strictEqual
(
left
,
right
);
2466
return
Encode
(
r
);
2467
}
2468
2469
ReturnedValue
Runtime
::
StrictNotEqual
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2470
{
2471
TRACE2
(left, right);
2472
2473
bool
r
= !
RuntimeHelpers
::
strictEqual
(
left
,
right
);
2474
return
Encode
(
r
);
2475
}
2476
2477
Bool
Runtime
::
CompareNotEqual
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2478
{
2479
TRACE2
(left, right);
2480
2481
return
!
Runtime
::
CompareEqual
::
call
(
left
,
right
);
2482
}
2483
2484
Bool
Runtime
::
CompareStrictEqual
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2485
{
2486
TRACE2
(left, right);
2487
2488
return
RuntimeHelpers
::
strictEqual
(
left
,
right
);
2489
}
2490
2491
Bool
Runtime
::
CompareStrictNotEqual
::
call
(
const
Value
&
left
,
const
Value
&
right
)
2492
{
2493
TRACE2
(left, right);
2494
2495
return
!
RuntimeHelpers
::
strictEqual
(
left
,
right
);
2496
}
2497
2498
template
<
typename
Operation>
2499
static
inline
const
void
*
symbol
()
2500
{
2501
return
reinterpret_cast
<
void
*>(&Operation::call);
2502
}
2503
2504
QHash
<
const
void
*,
const
char
*>
Runtime
::
symbolTable
()
2505
{
2506
static
const
QHash
<
const
void
*,
const
char
*>
symbols
({
2507
#
ifndef
V4_BOOTSTRAP
2508
{
symbol
<
CallGlobalLookup
>(),
"CallGlobalLookup"
},
2509
{
symbol
<
CallQmlContextPropertyLookup
>(),
"CallQmlContextPropertyLookup"
},
2510
{
symbol
<
CallName
>(),
"CallName"
},
2511
{
symbol
<
CallProperty
>(),
"CallProperty"
},
2512
{
symbol
<
CallPropertyLookup
>(),
"CallPropertyLookup"
},
2513
{
symbol
<
CallValue
>(),
"CallValue"
},
2514
{
symbol
<
CallWithReceiver
>(),
"CallWithReceiver"
},
2515
{
symbol
<
CallPossiblyDirectEval
>(),
"CallPossiblyDirectEval"
},
2516
{
symbol
<
CallWithSpread
>(),
"CallWithSpread"
},
2517
{
symbol
<
TailCall
>(),
"TailCall"
},
2518
2519
{
symbol
<
Construct
>(),
"Construct"
},
2520
{
symbol
<
ConstructWithSpread
>(),
"ConstructWithSpread"
},
2521
2522
{
symbol
<
StoreNameStrict
>(),
"StoreNameStrict"
},
2523
{
symbol
<
StoreNameSloppy
>(),
"StoreNameSloppy"
},
2524
{
symbol
<
StoreProperty
>(),
"StoreProperty"
},
2525
{
symbol
<
StoreElement
>(),
"StoreElement"
},
2526
{
symbol
<
LoadProperty
>(),
"LoadProperty"
},
2527
{
symbol
<
LoadName
>(),
"LoadName"
},
2528
{
symbol
<
LoadElement
>(),
"LoadElement"
},
2529
{
symbol
<
LoadSuperProperty
>(),
"LoadSuperProperty"
},
2530
{
symbol
<
StoreSuperProperty
>(),
"StoreSuperProperty"
},
2531
{
symbol
<
LoadSuperConstructor
>(),
"LoadSuperConstructor"
},
2532
{
symbol
<
LoadGlobalLookup
>(),
"LoadGlobalLookup"
},
2533
{
symbol
<
LoadQmlContextPropertyLookup
>(),
"LoadQmlContextPropertyLookup"
},
2534
{
symbol
<
GetLookup
>(),
"GetLookup"
},
2535
{
symbol
<
SetLookupStrict
>(),
"SetLookupStrict"
},
2536
{
symbol
<
SetLookupSloppy
>(),
"SetLookupSloppy"
},
2537
2538
{
symbol
<
TypeofValue
>(),
"TypeofValue"
},
2539
{
symbol
<
TypeofName
>(),
"TypeofName"
},
2540
2541
{
symbol
<
DeleteProperty_NoThrow
>(),
"DeleteProperty_NoThrow"
},
2542
{
symbol
<
DeleteProperty
>(),
"DeleteProperty"
},
2543
{
symbol
<
DeleteName_NoThrow
>(),
"DeleteName_NoThrow"
},
2544
{
symbol
<
DeleteName
>(),
"DeleteName"
},
2545
2546
{
symbol
<
ThrowException
>(),
"ThrowException"
},
2547
{
symbol
<
PushCallContext
>(),
"PushCallContext"
},
2548
{
symbol
<
PushWithContext
>(),
"PushWithContext"
},
2549
{
symbol
<
PushCatchContext
>(),
"PushCatchContext"
},
2550
{
symbol
<
PushBlockContext
>(),
"PushBlockContext"
},
2551
{
symbol
<
CloneBlockContext
>(),
"CloneBlockContext"
},
2552
{
symbol
<
PushScriptContext
>(),
"PushScriptContext"
},
2553
{
symbol
<
PopScriptContext
>(),
"PopScriptContext"
},
2554
{
symbol
<
ThrowReferenceError
>(),
"ThrowReferenceError"
},
2555
{
symbol
<
ThrowOnNullOrUndefined
>(),
"ThrowOnNullOrUndefined"
},
2556
2557
{
symbol
<
Closure
>(),
"Closure"
},
2558
2559
{
symbol
<
MarkCustom
>(),
"MarkCustom"
},
2560
2561
{
symbol
<
ConvertThisToObject
>(),
"ConvertThisToObject"
},
2562
{
symbol
<
DeclareVar
>(),
"DeclareVar"
},
2563
{
symbol
<
CreateMappedArgumentsObject
>(),
"CreateMappedArgumentsObject"
},
2564
{
symbol
<
CreateUnmappedArgumentsObject
>(),
"CreateUnmappedArgumentsObject"
},
2565
{
symbol
<
CreateRestParameter
>(),
"CreateRestParameter"
},
2566
2567
{
symbol
<
ArrayLiteral
>(),
"ArrayLiteral"
},
2568
{
symbol
<
ObjectLiteral
>(),
"ObjectLiteral"
},
2569
{
symbol
<
CreateClass
>(),
"CreateClass"
},
2570
2571
{
symbol
<
GetIterator
>(),
"GetIterator"
},
2572
{
symbol
<
IteratorNext
>(),
"IteratorNext"
},
2573
{
symbol
<
IteratorNextForYieldStar
>(),
"IteratorNextForYieldStar"
},
2574
{
symbol
<
IteratorClose
>(),
"IteratorClose"
},
2575
{
symbol
<
DestructureRestElement
>(),
"DestructureRestElement"
},
2576
2577
{
symbol
<
ToObject
>(),
"ToObject"
},
2578
{
symbol
<
ToBoolean
>(),
"ToBoolean"
},
2579
{
symbol
<
ToNumber
>(),
"ToNumber"
},
2580
2581
{
symbol
<
UMinus
>(),
"UMinus"
},
2582
2583
{
symbol
<
Instanceof
>(),
"Instanceof"
},
2584
{
symbol
<
As
>(),
"As"
},
2585
{
symbol
<
In
>(),
"In"
},
2586
{
symbol
<
Add
>(),
"Add"
},
2587
{
symbol
<
Sub
>(),
"Sub"
},
2588
{
symbol
<
Mul
>(),
"Mul"
},
2589
{
symbol
<
Div
>(),
"Div"
},
2590
{
symbol
<
Mod
>(),
"Mod"
},
2591
{
symbol
<
Exp
>(),
"Exp"
},
2592
{
symbol
<
BitAnd
>(),
"BitAnd"
},
2593
{
symbol
<
BitOr
>(),
"BitOr"
},
2594
{
symbol
<
BitXor
>(),
"BitXor"
},
2595
{
symbol
<
Shl
>(),
"Shl"
},
2596
{
symbol
<
Shr
>(),
"Shr"
},
2597
{
symbol
<
UShr
>(),
"UShr"
},
2598
{
symbol
<
GreaterThan
>(),
"GreaterThan"
},
2599
{
symbol
<
LessThan
>(),
"LessThan"
},
2600
{
symbol
<
GreaterEqual
>(),
"GreaterEqual"
},
2601
{
symbol
<
LessEqual
>(),
"LessEqual"
},
2602
{
symbol
<
Equal
>(),
"Equal"
},
2603
{
symbol
<
NotEqual
>(),
"NotEqual"
},
2604
{
symbol
<
StrictEqual
>(),
"StrictEqual"
},
2605
{
symbol
<
StrictNotEqual
>(),
"StrictNotEqual"
},
2606
2607
{
symbol
<
CompareGreaterThan
>(),
"CompareGreaterThan"
},
2608
{
symbol
<
CompareLessThan
>(),
"CompareLessThan"
},
2609
{
symbol
<
CompareGreaterEqual
>(),
"CompareGreaterEqual"
},
2610
{
symbol
<
CompareLessEqual
>(),
"CompareLessEqual"
},
2611
{
symbol
<
CompareEqual
>(),
"CompareEqual"
},
2612
{
symbol
<
CompareNotEqual
>(),
"CompareNotEqual"
},
2613
{
symbol
<
CompareStrictEqual
>(),
"CompareStrictEqual"
},
2614
{
symbol
<
CompareStrictNotEqual
>(),
"CompareStrictNotEqual"
},
2615
2616
{
symbol
<
CompareInstanceof
>(),
"CompareInstanceOf"
},
2617
{
symbol
<
CompareIn
>(),
"CompareIn"
},
2618
2619
{
symbol
<
RegexpLiteral
>(),
"RegexpLiteral"
},
2620
{
symbol
<
GetTemplateObject
>(),
"GetTemplateObject"
}
2621
#
endif
2622
});
2623
2624
return
symbols
;
2625
}
2626
2627
}
// namespace QV4
2628
2629
QT_END_NAMESPACE
QV4::Heap
Definition
qv4compileddata_p.h:76
QV4
Definition
qjsvalue.h:24
QV4::doInstanceof
static QV4::ReturnedValue doInstanceof(ExecutionEngine *engine, const Value &lval, const Value &rval)
Definition
qv4runtime.cpp:359
QV4::convert_to_string_add
static Heap::String * convert_to_string_add(ExecutionEngine *engine, Value value)
Definition
qv4runtime.cpp:655
QV4::ScopedObject
Scoped< Object > ScopedObject
Definition
qv4global_p.h:166
QV4::throwPropertyIsNotAFunctionTypeError
static ReturnedValue throwPropertyIsNotAFunctionTypeError(ExecutionEngine *engine, Value *thisObject, const QString &propertyName)
Definition
qv4runtime.cpp:1450
QV4::runtimeLookup
static QV4::Lookup * runtimeLookup(Function *f, uint i)
Definition
qv4runtime.cpp:190
QV4::setElementFallback
static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
Definition
qv4runtime.cpp:792
QV4::getSuperBase
static Object * getSuperBase(Scope &scope)
Definition
qv4runtime.cpp:1093
QV4::createSpreadArguments
static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc)
Definition
qv4runtime.cpp:1623
QV4::symbol
static const void * symbol()
Definition
qv4runtime.cpp:2499
QV4::ScopedContext
Scoped< ExecutionContext > ScopedContext
Definition
qv4global_p.h:169
Q_STATIC_LOGGING_CATEGORY
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
TRACE1
#define TRACE1(x)
Definition
qv4runtime_p.h:52
TRACE2
#define TRACE2(x, y)
Definition
qv4runtime_p.h:53
QV4::CallArgs
Definition
qv4runtime.cpp:1618
QV4::CallArgs::argv
Value * argv
Definition
qv4runtime.cpp:1619
QV4::CallArgs::argc
int argc
Definition
qv4runtime.cpp:1620
QV4::LazyScope
Definition
qv4runtime.cpp:2319
QV4::LazyScope::engine
ExecutionEngine * engine
Definition
qv4runtime.cpp:2320
QV4::LazyScope::set
void set(Value **scopedValue, T value, ExecutionEngine *e)
Definition
qv4runtime.cpp:2327
QV4::LazyScope::~LazyScope
~LazyScope()
Definition
qv4runtime.cpp:2322
QV4::LazyScope::stackMark
Value * stackMark
Definition
qv4runtime.cpp:2321
QV4::Scope
Definition
qv4scopedvalue_p.h:61
QV4::ScopedValue
Definition
qv4scopedvalue_p.h:156
qtdeclarative
src
qml
jsruntime
qv4runtime.cpp
Generated on
for Qt by
1.18.0