DFG should have adaptive structure watchpoints
[WebKit-https.git] / Source / JavaScriptCore / runtime / Operations.h
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009, 2013, 2014 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 #ifndef Operations_h
23 #define Operations_h
24
25 #include "CallFrame.h"
26 #include "ExceptionHelpers.h"
27 #include "JSCJSValue.h"
28
29 namespace JSC {
30
31 NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue);
32 JSValue jsTypeStringForValue(CallFrame*, JSValue);
33 JSValue jsTypeStringForValue(VM&, JSGlobalObject*, JSValue);
34 bool jsIsObjectTypeOrNull(CallFrame*, JSValue);
35 bool jsIsFunctionType(JSValue);
36
37 ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2)
38 {
39     VM& vm = exec->vm();
40
41     int32_t length1 = s1->length();
42     if (!length1)
43         return s2;
44     int32_t length2 = s2->length();
45     if (!length2)
46         return s1;
47     if (sumOverflows<int32_t>(length1, length2))
48         return throwOutOfMemoryError(exec);
49
50     return JSRopeString::create(vm, s1, s2);
51 }
52
53 ALWAYS_INLINE JSValue jsString(ExecState* exec, const String& u1, const String& u2, const String& u3)
54 {
55     VM* vm = &exec->vm();
56
57     int32_t length1 = u1.length();
58     int32_t length2 = u2.length();
59     int32_t length3 = u3.length();
60     
61     if (length1 < 0 || length2 < 0 || length3 < 0)
62         return throwOutOfMemoryError(exec);
63     
64     if (!length1)
65         return jsString(exec, jsString(vm, u2), jsString(vm, u3));
66     if (!length2)
67         return jsString(exec, jsString(vm, u1), jsString(vm, u3));
68     if (!length3)
69         return jsString(exec, jsString(vm, u1), jsString(vm, u2));
70
71     if (sumOverflows<int32_t>(length1, length2, length3))
72         return throwOutOfMemoryError(exec);
73
74     return JSRopeString::create(exec->vm(), jsString(vm, u1), jsString(vm, u2), jsString(vm, u3));
75 }
76
77 ALWAYS_INLINE JSValue jsStringFromRegisterArray(ExecState* exec, Register* strings, unsigned count)
78 {
79     VM* vm = &exec->vm();
80     JSRopeString::RopeBuilder ropeBuilder(*vm);
81
82     for (unsigned i = 0; i < count; ++i) {
83         JSValue v = strings[-static_cast<int>(i)].jsValue();
84         if (!ropeBuilder.append(v.toString(exec)))
85             return throwOutOfMemoryError(exec);
86     }
87
88     return ropeBuilder.release();
89 }
90
91 ALWAYS_INLINE JSValue jsStringFromArguments(ExecState* exec, JSValue thisValue)
92 {
93     VM* vm = &exec->vm();
94     JSRopeString::RopeBuilder ropeBuilder(*vm);
95     ropeBuilder.append(thisValue.toString(exec));
96
97     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
98         JSValue v = exec->argument(i);
99         if (!ropeBuilder.append(v.toString(exec)))
100             return throwOutOfMemoryError(exec);
101     }
102
103     return ropeBuilder.release();
104 }
105
106 // See ES5 11.8.1/11.8.2/11.8.5 for definition of leftFirst, this value ensures correct
107 // evaluation ordering for argument conversions for '<' and '>'. For '<' pass the value
108 // true, for leftFirst, for '>' pass the value false (and reverse operand order).
109 template<bool leftFirst>
110 ALWAYS_INLINE bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2)
111 {
112     if (v1.isInt32() && v2.isInt32())
113         return v1.asInt32() < v2.asInt32();
114
115     if (v1.isNumber() && v2.isNumber())
116         return v1.asNumber() < v2.asNumber();
117
118     if (isJSString(v1) && isJSString(v2))
119         return codePointCompareLessThan(asString(v1)->value(callFrame), asString(v2)->value(callFrame));
120
121     double n1;
122     double n2;
123     JSValue p1;
124     JSValue p2;
125     bool wasNotString1;
126     bool wasNotString2;
127     if (leftFirst) {
128         wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
129         wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
130     } else {
131         wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
132         wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
133     }
134
135     if (wasNotString1 | wasNotString2)
136         return n1 < n2;
137     return codePointCompareLessThan(asString(p1)->value(callFrame), asString(p2)->value(callFrame));
138 }
139
140 // See ES5 11.8.3/11.8.4/11.8.5 for definition of leftFirst, this value ensures correct
141 // evaluation ordering for argument conversions for '<=' and '=>'. For '<=' pass the
142 // value true, for leftFirst, for '=>' pass the value false (and reverse operand order).
143 template<bool leftFirst>
144 ALWAYS_INLINE bool jsLessEq(CallFrame* callFrame, JSValue v1, JSValue v2)
145 {
146     if (v1.isInt32() && v2.isInt32())
147         return v1.asInt32() <= v2.asInt32();
148
149     if (v1.isNumber() && v2.isNumber())
150         return v1.asNumber() <= v2.asNumber();
151
152     if (isJSString(v1) && isJSString(v2))
153         return !codePointCompareLessThan(asString(v2)->value(callFrame), asString(v1)->value(callFrame));
154
155     double n1;
156     double n2;
157     JSValue p1;
158     JSValue p2;
159     bool wasNotString1;
160     bool wasNotString2;
161     if (leftFirst) {
162         wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
163         wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
164     } else {
165         wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
166         wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
167     }
168
169     if (wasNotString1 | wasNotString2)
170         return n1 <= n2;
171     return !codePointCompareLessThan(asString(p2)->value(callFrame), asString(p1)->value(callFrame));
172 }
173
174 // Fast-path choices here are based on frequency data from SunSpider:
175 //    <times> Add case: <t1> <t2>
176 //    ---------------------------
177 //    5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
178 //    247412  Add case: 5 5
179 //    20900   Add case: 5 6
180 //    13962   Add case: 5 3
181 //    4000    Add case: 3 5
182
183 ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2)
184 {
185     if (v1.isNumber() && v2.isNumber())
186         return jsNumber(v1.asNumber() + v2.asNumber());
187         
188     if (v1.isString() && !v2.isObject())
189         return jsString(callFrame, asString(v1), v2.toString(callFrame));
190
191     // All other cases are pretty uncommon
192     return jsAddSlowCase(callFrame, v1, v2);
193 }
194
195 #define InvalidPrototypeChain (std::numeric_limits<size_t>::max())
196
197 inline size_t normalizePrototypeChain(CallFrame* callFrame, Structure* structure)
198 {
199     VM& vm = callFrame->vm();
200     size_t count = 0;
201     while (1) {
202         if (structure->isProxy())
203             return InvalidPrototypeChain;
204         JSValue v = structure->prototypeForLookup(callFrame);
205         if (v.isNull())
206             return count;
207
208         JSCell* base = v.asCell();
209         structure = base->structure(vm);
210         // Since we're accessing a prototype in a loop, it's a good bet that it
211         // should not be treated as a dictionary.
212         if (structure->isDictionary())
213             structure->flattenDictionaryStructure(vm, asObject(base));
214
215         ++count;
216     }
217 }
218
219 } // namespace JSC
220
221 #endif // Operations_h