a088ad1cbc2078d6205aff0abad3da73a96f5b26
[WebKit-https.git] / Source / JavaScriptCore / runtime / Operations.cpp
1 /*
2  * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  * Copyright (C) 2008, 2016 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 #include "config.h"
23 #include "Operations.h"
24
25 #include "Error.h"
26 #include "JSBigInt.h"
27 #include "JSCInlines.h"
28 #include "JSObject.h"
29 #include "JSString.h"
30 #include <wtf/MathExtras.h>
31
32 namespace JSC {
33
34 bool JSValue::equalSlowCase(ExecState* exec, JSValue v1, JSValue v2)
35 {
36     return equalSlowCaseInline(exec, v1, v2);
37 }
38
39 bool JSValue::strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2)
40 {
41     return strictEqualSlowCaseInline(exec, v1, v2);
42 }
43
44 NEVER_INLINE JSValue jsAddSlowCase(CallFrame* callFrame, JSValue v1, JSValue v2)
45 {
46     // exception for the Date exception in defaultValue()
47     VM& vm = callFrame->vm();
48     auto scope = DECLARE_THROW_SCOPE(vm);
49     JSValue p1 = v1.toPrimitive(callFrame);
50     RETURN_IF_EXCEPTION(scope, { });
51     JSValue p2 = v2.toPrimitive(callFrame);
52     RETURN_IF_EXCEPTION(scope, { });
53
54     if (p1.isString()) {
55         JSString* p2String = p2.toString(callFrame);
56         RETURN_IF_EXCEPTION(scope, { });
57         RELEASE_AND_RETURN(scope, jsString(callFrame, asString(p1), p2String));
58     }
59
60     if (p2.isString()) {
61         JSString* p1String = p1.toString(callFrame);
62         RETURN_IF_EXCEPTION(scope, { });
63         RELEASE_AND_RETURN(scope, jsString(callFrame, p1String, asString(p2)));
64     }
65
66     auto leftNumeric = p1.toNumeric(callFrame);
67     RETURN_IF_EXCEPTION(scope, { });
68     auto rightNumeric = p2.toNumeric(callFrame);
69     RETURN_IF_EXCEPTION(scope, { });
70
71     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
72         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
73             return JSBigInt::add(vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
74
75         return throwTypeError(callFrame, scope, "Invalid mix of BigInt and other type in addition."_s);
76     }
77
78     return jsNumber(WTF::get<double>(leftNumeric) + WTF::get<double>(rightNumeric));
79 }
80
81 JSValue jsTypeStringForValue(VM& vm, JSGlobalObject* globalObject, JSValue v)
82 {
83     if (v.isUndefined())
84         return vm.smallStrings.undefinedString();
85     if (v.isBoolean())
86         return vm.smallStrings.booleanString();
87     if (v.isNumber())
88         return vm.smallStrings.numberString();
89     if (v.isString())
90         return vm.smallStrings.stringString();
91     if (v.isSymbol())
92         return vm.smallStrings.symbolString();
93     if (v.isBigInt())
94         return vm.smallStrings.bigintString();
95     if (v.isObject()) {
96         JSObject* object = asObject(v);
97         // Return "undefined" for objects that should be treated
98         // as null when doing comparisons.
99         if (object->structure(vm)->masqueradesAsUndefined(globalObject))
100             return vm.smallStrings.undefinedString();
101         if (object->isFunction(vm))
102             return vm.smallStrings.functionString();
103     }
104     return vm.smallStrings.objectString();
105 }
106
107 JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v)
108 {
109     return jsTypeStringForValue(callFrame->vm(), callFrame->lexicalGlobalObject(), v);
110 }
111
112 bool jsIsObjectTypeOrNull(CallFrame* callFrame, JSValue v)
113 {
114     VM& vm = callFrame->vm();
115     if (!v.isCell())
116         return v.isNull();
117
118     JSType type = v.asCell()->type();
119     if (type == StringType || type == SymbolType || type == BigIntType)
120         return false;
121     if (type >= ObjectType) {
122         if (asObject(v)->structure(vm)->masqueradesAsUndefined(callFrame->lexicalGlobalObject()))
123             return false;
124         JSObject* object = asObject(v);
125         if (object->isFunction(vm))
126             return false;
127     }
128     return true;
129 }
130
131 size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base, bool& sawPolyProto)
132 {
133     VM& vm = callFrame->vm();
134     size_t count = 0;
135     sawPolyProto = false;
136     JSCell* current = base;
137     JSGlobalObject* globalObject = callFrame->lexicalGlobalObject();
138     while (1) {
139         Structure* structure = current->structure(vm);
140         if (structure->isProxy())
141             return InvalidPrototypeChain;
142
143         sawPolyProto |= structure->hasPolyProto();
144
145         JSValue prototype = structure->prototypeForLookup(globalObject, current);
146         if (prototype.isNull())
147             return count;
148
149         current = prototype.asCell();
150         structure = current->structure(vm);
151         if (structure->isDictionary()) {
152             if (structure->hasBeenFlattenedBefore())
153                 return InvalidPrototypeChain;
154             structure->flattenDictionaryStructure(vm, asObject(current));
155         }
156
157         ++count;
158     }
159 }
160
161 } // namespace JSC