61d533cf45f6bd032db98eb6d4e24042ab4a52b3
[WebKit-https.git] / Source / JavaScriptCore / runtime / Operations.h
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2002-2018 Apple Inc. All rights reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public License
16  *  along with this library; see the file COPYING.LIB.  If not, write to
17  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  *  Boston, MA 02110-1301, USA.
19  *
20  */
21
22 #pragma once
23
24 #include "CallFrame.h"
25 #include "ExceptionHelpers.h"
26 #include "JSBigInt.h"
27 #include "JSCJSValue.h"
28 #include <wtf/Variant.h>
29
30 namespace JSC {
31
32 #define InvalidPrototypeChain (std::numeric_limits<size_t>::max())
33
34 NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue);
35 JSValue jsTypeStringForValue(CallFrame*, JSValue);
36 JSValue jsTypeStringForValue(VM&, JSGlobalObject*, JSValue);
37 bool jsIsObjectTypeOrNull(CallFrame*, JSValue);
38 size_t normalizePrototypeChain(CallFrame*, JSCell*, bool& sawPolyProto);
39
40 ALWAYS_INLINE JSString* jsString(ExecState* exec, JSString* s1, JSString* s2)
41 {
42     VM& vm = exec->vm();
43     auto scope = DECLARE_THROW_SCOPE(vm);
44
45     unsigned length1 = s1->length();
46     if (!length1)
47         return s2;
48     unsigned length2 = s2->length();
49     if (!length2)
50         return s1;
51     static_assert(JSString::MaxLength == std::numeric_limits<int32_t>::max(), "");
52     if (sumOverflows<int32_t>(length1, length2)) {
53         throwOutOfMemoryError(exec, scope);
54         return nullptr;
55     }
56
57     return JSRopeString::create(vm, s1, s2);
58 }
59
60 ALWAYS_INLINE JSString* jsString(ExecState* exec, JSString* s1, JSString* s2, JSString* s3)
61 {
62     VM& vm = exec->vm();
63     auto scope = DECLARE_THROW_SCOPE(vm);
64
65     unsigned length1 = s1->length();
66     if (!length1)
67         RELEASE_AND_RETURN(scope, jsString(exec, s2, s3));
68
69     unsigned length2 = s2->length();
70     if (!length2)
71         RELEASE_AND_RETURN(scope, jsString(exec, s1, s3));
72
73     unsigned length3 = s3->length();
74     if (!length3)
75         RELEASE_AND_RETURN(scope, jsString(exec, s1, s2));
76
77     static_assert(JSString::MaxLength == std::numeric_limits<int32_t>::max(), "");
78     if (sumOverflows<int32_t>(length1, length2, length3)) {
79         throwOutOfMemoryError(exec, scope);
80         return nullptr;
81     }
82     return JSRopeString::create(vm, s1, s2, s3);
83 }
84
85 ALWAYS_INLINE JSString* jsString(ExecState* exec, const String& u1, const String& u2, const String& u3)
86 {
87     VM* vm = &exec->vm();
88     auto scope = DECLARE_THROW_SCOPE(*vm);
89
90     unsigned length1 = u1.length();
91     unsigned length2 = u2.length();
92     unsigned length3 = u3.length();
93     ASSERT(length1 <= JSString::MaxLength);
94     ASSERT(length2 <= JSString::MaxLength);
95     ASSERT(length3 <= JSString::MaxLength);
96
97     if (!length1)
98         RELEASE_AND_RETURN(scope, jsString(exec, jsString(vm, u2), jsString(vm, u3)));
99
100     if (!length2)
101         RELEASE_AND_RETURN(scope, jsString(exec, jsString(vm, u1), jsString(vm, u3)));
102
103     if (!length3)
104         RELEASE_AND_RETURN(scope, jsString(exec, jsString(vm, u1), jsString(vm, u2)));
105
106     static_assert(JSString::MaxLength == std::numeric_limits<int32_t>::max(), "");
107     if (sumOverflows<int32_t>(length1, length2, length3)) {
108         throwOutOfMemoryError(exec, scope);
109         return nullptr;
110     }
111
112     return JSRopeString::create(*vm, jsString(vm, u1), jsString(vm, u2), jsString(vm, u3));
113 }
114
115 ALWAYS_INLINE JSValue jsStringFromRegisterArray(ExecState* exec, Register* strings, unsigned count)
116 {
117     VM* vm = &exec->vm();
118     auto scope = DECLARE_THROW_SCOPE(*vm);
119     JSRopeString::RopeBuilder<RecordOverflow> ropeBuilder(*vm);
120
121     for (unsigned i = 0; i < count; ++i) {
122         JSValue v = strings[-static_cast<int>(i)].jsValue();
123         JSString* string = v.toString(exec);
124         RETURN_IF_EXCEPTION(scope, { });
125         if (!ropeBuilder.append(string))
126             return throwOutOfMemoryError(exec, scope);
127     }
128
129     return ropeBuilder.release();
130 }
131
132 ALWAYS_INLINE JSValue jsStringFromArguments(ExecState* exec, JSValue thisValue)
133 {
134     VM* vm = &exec->vm();
135     auto scope = DECLARE_THROW_SCOPE(*vm);
136     JSRopeString::RopeBuilder<RecordOverflow> ropeBuilder(*vm);
137     JSString* str = thisValue.toString(exec);
138     RETURN_IF_EXCEPTION(scope, { });
139     ropeBuilder.append(str);
140
141     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
142         JSValue v = exec->argument(i);
143         JSString* str = v.toString(exec);
144         RETURN_IF_EXCEPTION(scope, { });
145         if (UNLIKELY(!ropeBuilder.append(str)))
146             return throwOutOfMemoryError(exec, scope);
147     }
148
149     return ropeBuilder.release();
150 }
151
152 ALWAYS_INLINE bool bigIntCompareResult(JSBigInt::ComparisonResult comparisonResult, JSBigInt::ComparisonMode comparisonMode)
153 {
154     if (comparisonMode == JSBigInt::ComparisonMode::LessThan)
155         return comparisonResult == JSBigInt::ComparisonResult::LessThan;
156
157     ASSERT(comparisonMode == JSBigInt::ComparisonMode::LessThanOrEqual);
158     return comparisonResult == JSBigInt::ComparisonResult::LessThan || comparisonResult == JSBigInt::ComparisonResult::Equal;
159 }
160
161 ALWAYS_INLINE bool bigIntCompare(CallFrame* callFrame, JSValue v1, JSValue v2, JSBigInt::ComparisonMode comparisonMode)
162 {
163     ASSERT(v1.isBigInt() || v2.isBigInt());
164     ASSERT(v1.isPrimitive() && v2.isPrimitive());
165
166     VM& vm = callFrame->vm();
167     auto scope = DECLARE_THROW_SCOPE(vm);
168     
169     if (v1.isBigInt() && v2.isBigInt())
170         return bigIntCompareResult(JSBigInt::compare(asBigInt(v1), asBigInt(v2)), comparisonMode);
171     
172     if (v1.isBigInt()) {
173         JSValue primValue = v2;
174         if (primValue.isString()) {
175             JSBigInt* bigIntValue = JSBigInt::stringToBigInt(callFrame, asString(primValue)->value(callFrame));
176             RETURN_IF_EXCEPTION(scope, false);
177             if (!bigIntValue)
178                 return false;
179
180             return bigIntCompareResult(JSBigInt::compare(asBigInt(v1), bigIntValue), comparisonMode);
181         }
182
183         if (primValue.isBigInt())
184             return bigIntCompareResult(JSBigInt::compare(asBigInt(v1), asBigInt(primValue)), comparisonMode);
185
186         double numberValue = primValue.toNumber(callFrame);
187         RETURN_IF_EXCEPTION(scope, false);
188         return bigIntCompareResult(JSBigInt::compareToDouble(asBigInt(v1), numberValue), comparisonMode);
189     }
190     
191     JSValue primValue = v1;
192     if (primValue.isString()) {
193         JSBigInt* bigIntValue = JSBigInt::stringToBigInt(callFrame, asString(primValue)->value(callFrame));
194         RETURN_IF_EXCEPTION(scope, false);
195         if (!bigIntValue)
196             return false;
197
198         return bigIntCompareResult(JSBigInt::compare(bigIntValue, asBigInt(v2)), comparisonMode);
199     }
200     
201     if (primValue.isBigInt())
202         return bigIntCompareResult(JSBigInt::compare(asBigInt(primValue), asBigInt(v2)), comparisonMode);
203     
204     double numberValue = primValue.toNumber(callFrame);
205     RETURN_IF_EXCEPTION(scope, false);
206
207     // Here we check inverted because BigInt is the v2
208     JSBigInt::ComparisonResult comparisonResult = JSBigInt::compareToDouble(asBigInt(v2), numberValue);
209     if (comparisonMode == JSBigInt::ComparisonMode::LessThan)
210         return comparisonResult == JSBigInt::ComparisonResult::GreaterThan;
211
212     return comparisonResult == JSBigInt::ComparisonResult::GreaterThan || comparisonResult == JSBigInt::ComparisonResult::Equal;
213 }
214
215 ALWAYS_INLINE bool toPrimitiveNumeric(CallFrame* callFrame, JSValue v, JSValue& p, double& n)
216 {
217     VM& vm = callFrame->vm();
218     auto scope = DECLARE_THROW_SCOPE(vm);
219     
220     p = v.toPrimitive(callFrame, PreferNumber);
221     RETURN_IF_EXCEPTION(scope, false);
222     if (p.isBigInt())
223         return true;
224     
225     n = p.toNumber(callFrame);
226     RETURN_IF_EXCEPTION(scope, false);
227     return !p.isString();
228 }
229
230 // See ES5 11.8.1/11.8.2/11.8.5 for definition of leftFirst, this value ensures correct
231 // evaluation ordering for argument conversions for '<' and '>'. For '<' pass the value
232 // true, for leftFirst, for '>' pass the value false (and reverse operand order).
233 template<bool leftFirst>
234 ALWAYS_INLINE bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2)
235 {
236     VM& vm = callFrame->vm();
237     auto scope = DECLARE_THROW_SCOPE(vm);
238
239     if (v1.isInt32() && v2.isInt32())
240         return v1.asInt32() < v2.asInt32();
241
242     if (v1.isNumber() && v2.isNumber())
243         return v1.asNumber() < v2.asNumber();
244
245     if (isJSString(v1) && isJSString(v2))
246         return codePointCompareLessThan(asString(v1)->value(callFrame), asString(v2)->value(callFrame));
247
248     double n1;
249     double n2;
250     JSValue p1;
251     JSValue p2;
252     bool wasNotString1;
253     bool wasNotString2;
254     if (leftFirst) {
255         wasNotString1 = toPrimitiveNumeric(callFrame, v1, p1, n1);
256         RETURN_IF_EXCEPTION(scope, false);
257         wasNotString2 = toPrimitiveNumeric(callFrame, v2, p2, n2);
258     } else {
259         wasNotString2 = toPrimitiveNumeric(callFrame, v2, p2, n2);
260         RETURN_IF_EXCEPTION(scope, false);
261         wasNotString1 = toPrimitiveNumeric(callFrame, v1, p1, n1);
262     }
263     RETURN_IF_EXCEPTION(scope, false);
264
265     if (wasNotString1 | wasNotString2) {
266         if (p1.isBigInt() || p2.isBigInt())
267             RELEASE_AND_RETURN(scope, bigIntCompare(callFrame, p1, p2, JSBigInt::ComparisonMode::LessThan));
268
269         return n1 < n2;
270     }
271
272     return codePointCompareLessThan(asString(p1)->value(callFrame), asString(p2)->value(callFrame));
273 }
274
275 // See ES5 11.8.3/11.8.4/11.8.5 for definition of leftFirst, this value ensures correct
276 // evaluation ordering for argument conversions for '<=' and '=>'. For '<=' pass the
277 // value true, for leftFirst, for '=>' pass the value false (and reverse operand order).
278 template<bool leftFirst>
279 ALWAYS_INLINE bool jsLessEq(CallFrame* callFrame, JSValue v1, JSValue v2)
280 {
281     VM& vm = callFrame->vm();
282     auto scope = DECLARE_THROW_SCOPE(vm);
283
284     if (v1.isInt32() && v2.isInt32())
285         return v1.asInt32() <= v2.asInt32();
286
287     if (v1.isNumber() && v2.isNumber())
288         return v1.asNumber() <= v2.asNumber();
289
290     if (isJSString(v1) && isJSString(v2))
291         return !codePointCompareLessThan(asString(v2)->value(callFrame), asString(v1)->value(callFrame));
292
293     double n1;
294     double n2;
295     JSValue p1;
296     JSValue p2;
297     bool wasNotString1;
298     bool wasNotString2;
299     if (leftFirst) {
300         wasNotString1 = toPrimitiveNumeric(callFrame, v1, p1, n1);
301         RETURN_IF_EXCEPTION(scope, false);
302         wasNotString2 = toPrimitiveNumeric(callFrame, v2, p2, n2);
303     } else {
304         wasNotString2 = toPrimitiveNumeric(callFrame, v2, p2, n2);
305         RETURN_IF_EXCEPTION(scope, false);
306         wasNotString1 = toPrimitiveNumeric(callFrame, v1, p1, n1);
307     }
308     RETURN_IF_EXCEPTION(scope, false);
309
310     if (wasNotString1 | wasNotString2) {
311         if (p1.isBigInt() || p2.isBigInt())
312             RELEASE_AND_RETURN(scope, bigIntCompare(callFrame, p1, p2, JSBigInt::ComparisonMode::LessThanOrEqual));
313
314         return n1 <= n2;
315     }
316     return !codePointCompareLessThan(asString(p2)->value(callFrame), asString(p1)->value(callFrame));
317 }
318
319 // Fast-path choices here are based on frequency data from SunSpider:
320 //    <times> Add case: <t1> <t2>
321 //    ---------------------------
322 //    5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
323 //    247412  Add case: 5 5
324 //    20900   Add case: 5 6
325 //    13962   Add case: 5 3
326 //    4000    Add case: 3 5
327
328 ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2)
329 {
330     if (v1.isNumber() && v2.isNumber())
331         return jsNumber(v1.asNumber() + v2.asNumber());
332         
333     if (v1.isString() && !v2.isObject())
334         return jsString(callFrame, asString(v1), v2.toString(callFrame));
335
336     // All other cases are pretty uncommon
337     return jsAddSlowCase(callFrame, v1, v2);
338 }
339
340 ALWAYS_INLINE JSValue jsSub(ExecState* exec, JSValue v1, JSValue v2)
341 {
342     VM& vm = exec->vm();
343     auto scope = DECLARE_THROW_SCOPE(vm);
344
345     auto leftNumeric = v1.toNumeric(exec);
346     RETURN_IF_EXCEPTION(scope, { });
347     auto rightNumeric = v2.toNumeric(exec);
348     RETURN_IF_EXCEPTION(scope, { });
349
350     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
351         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
352             return JSBigInt::sub(vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
353
354         return throwTypeError(exec, scope, "Invalid mix of BigInt and other type in subtraction."_s);
355     }
356
357     return jsNumber(WTF::get<double>(leftNumeric) - WTF::get<double>(rightNumeric));
358 }
359
360 ALWAYS_INLINE JSValue jsMul(ExecState* state, JSValue v1, JSValue v2)
361 {
362     VM& vm = state->vm();
363     auto scope = DECLARE_THROW_SCOPE(vm);
364
365     Variant<JSBigInt*, double> leftNumeric = v1.toNumeric(state);
366     RETURN_IF_EXCEPTION(scope, { });
367     Variant<JSBigInt*, double> rightNumeric = v2.toNumeric(state);
368     RETURN_IF_EXCEPTION(scope, { });
369
370     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
371         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
372             return JSBigInt::multiply(state, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
373
374         throwTypeError(state, scope, "Invalid mix of BigInt and other type in multiplication."_s);
375         return { };
376     }
377
378     double leftValue =  WTF::get<double>(leftNumeric);
379     double rightValue =  WTF::get<double>(rightNumeric);
380     return jsNumber(leftValue * rightValue);
381 }
382
383 inline bool scribbleFreeCells()
384 {
385     return !ASSERT_DISABLED || Options::scribbleFreeCells();
386 }
387
388 #define SCRIBBLE_WORD static_cast<intptr_t>(0xbadbeef0)
389
390 inline bool isScribbledValue(JSValue value)
391 {
392     return JSValue::encode(value) == JSValue::encode(bitwise_cast<JSCell*>(SCRIBBLE_WORD));
393 }
394
395 inline void scribble(void* base, size_t size)
396 {
397     for (size_t i = size / sizeof(EncodedJSValue); i--;) {
398         // Use a 16-byte aligned value to ensure that it passes the cell check.
399         static_cast<EncodedJSValue*>(base)[i] = JSValue::encode(bitwise_cast<JSCell*>(SCRIBBLE_WORD));
400     }
401 }
402
403 } // namespace JSC