]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - runtime/Operations.h
JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / runtime / Operations.h
... / ...
CommitLineData
1/*
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009 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 "ExceptionHelpers.h"
26#include "Interpreter.h"
27#include "JSCJSValueInlines.h"
28#include "JSProxy.h"
29#include "JSString.h"
30#include "StructureInlines.h"
31
32namespace JSC {
33
34NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue);
35JSValue jsTypeStringForValue(CallFrame*, JSValue);
36JSValue jsTypeStringForValue(VM&, JSGlobalObject*, JSValue);
37bool jsIsObjectType(CallFrame*, JSValue);
38bool jsIsFunctionType(JSValue);
39
40ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2)
41{
42 VM& vm = exec->vm();
43
44 unsigned length1 = s1->length();
45 if (!length1)
46 return s2;
47 unsigned length2 = s2->length();
48 if (!length2)
49 return s1;
50 if ((length1 + length2) < length1)
51 return throwOutOfMemoryError(exec);
52
53 return JSRopeString::create(vm, s1, s2);
54}
55
56ALWAYS_INLINE JSValue jsString(ExecState* exec, const String& u1, const String& u2, const String& u3)
57{
58 VM* vm = &exec->vm();
59
60 unsigned length1 = u1.length();
61 unsigned length2 = u2.length();
62 unsigned length3 = u3.length();
63 if (!length1)
64 return jsString(exec, jsString(vm, u2), jsString(vm, u3));
65 if (!length2)
66 return jsString(exec, jsString(vm, u1), jsString(vm, u3));
67 if (!length3)
68 return jsString(exec, jsString(vm, u1), jsString(vm, u2));
69
70 if ((length1 + length2) < length1)
71 return throwOutOfMemoryError(exec);
72 if ((length1 + length2 + length3) < length3)
73 return throwOutOfMemoryError(exec);
74
75 return JSRopeString::create(exec->vm(), jsString(vm, u1), jsString(vm, u2), jsString(vm, u3));
76}
77
78ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count)
79{
80 VM* vm = &exec->vm();
81 JSRopeString::RopeBuilder ropeBuilder(*vm);
82
83 unsigned oldLength = 0;
84
85 for (unsigned i = 0; i < count; ++i) {
86 JSValue v = strings[i].jsValue();
87 ropeBuilder.append(v.toString(exec));
88
89 if (ropeBuilder.length() < oldLength) // True for overflow
90 return throwOutOfMemoryError(exec);
91 oldLength = ropeBuilder.length();
92 }
93
94 return ropeBuilder.release();
95}
96
97ALWAYS_INLINE JSValue jsStringFromArguments(ExecState* exec, JSValue thisValue)
98{
99 VM* vm = &exec->vm();
100 JSRopeString::RopeBuilder ropeBuilder(*vm);
101 ropeBuilder.append(thisValue.toString(exec));
102
103 unsigned oldLength = 0;
104
105 for (unsigned i = 0; i < exec->argumentCount(); ++i) {
106 JSValue v = exec->argument(i);
107 ropeBuilder.append(v.toString(exec));
108
109 if (ropeBuilder.length() < oldLength) // True for overflow
110 return throwOutOfMemoryError(exec);
111 oldLength = ropeBuilder.length();
112 }
113
114 return ropeBuilder.release();
115}
116
117// See ES5 11.8.1/11.8.2/11.8.5 for definition of leftFirst, this value ensures correct
118// evaluation ordering for argument conversions for '<' and '>'. For '<' pass the value
119// true, for leftFirst, for '>' pass the value false (and reverse operand order).
120template<bool leftFirst>
121ALWAYS_INLINE bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2)
122{
123 if (v1.isInt32() && v2.isInt32())
124 return v1.asInt32() < v2.asInt32();
125
126 if (v1.isNumber() && v2.isNumber())
127 return v1.asNumber() < v2.asNumber();
128
129 if (isJSString(v1) && isJSString(v2))
130 return codePointCompareLessThan(asString(v1)->value(callFrame), asString(v2)->value(callFrame));
131
132 double n1;
133 double n2;
134 JSValue p1;
135 JSValue p2;
136 bool wasNotString1;
137 bool wasNotString2;
138 if (leftFirst) {
139 wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
140 wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
141 } else {
142 wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
143 wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
144 }
145
146 if (wasNotString1 | wasNotString2)
147 return n1 < n2;
148 return codePointCompareLessThan(asString(p1)->value(callFrame), asString(p2)->value(callFrame));
149}
150
151// See ES5 11.8.3/11.8.4/11.8.5 for definition of leftFirst, this value ensures correct
152// evaluation ordering for argument conversions for '<=' and '=>'. For '<=' pass the
153// value true, for leftFirst, for '=>' pass the value false (and reverse operand order).
154template<bool leftFirst>
155ALWAYS_INLINE bool jsLessEq(CallFrame* callFrame, JSValue v1, JSValue v2)
156{
157 if (v1.isInt32() && v2.isInt32())
158 return v1.asInt32() <= v2.asInt32();
159
160 if (v1.isNumber() && v2.isNumber())
161 return v1.asNumber() <= v2.asNumber();
162
163 if (isJSString(v1) && isJSString(v2))
164 return !codePointCompareLessThan(asString(v2)->value(callFrame), asString(v1)->value(callFrame));
165
166 double n1;
167 double n2;
168 JSValue p1;
169 JSValue p2;
170 bool wasNotString1;
171 bool wasNotString2;
172 if (leftFirst) {
173 wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
174 wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
175 } else {
176 wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
177 wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
178 }
179
180 if (wasNotString1 | wasNotString2)
181 return n1 <= n2;
182 return !codePointCompareLessThan(asString(p2)->value(callFrame), asString(p1)->value(callFrame));
183}
184
185// Fast-path choices here are based on frequency data from SunSpider:
186// <times> Add case: <t1> <t2>
187// ---------------------------
188// 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
189// 247412 Add case: 5 5
190// 20900 Add case: 5 6
191// 13962 Add case: 5 3
192// 4000 Add case: 3 5
193
194ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2)
195{
196 if (v1.isNumber() && v2.isNumber())
197 return jsNumber(v1.asNumber() + v2.asNumber());
198
199 if (v1.isString() && !v2.isObject())
200 return jsString(callFrame, asString(v1), v2.toString(callFrame));
201
202 // All other cases are pretty uncommon
203 return jsAddSlowCase(callFrame, v1, v2);
204}
205
206#define InvalidPrototypeChain (std::numeric_limits<size_t>::max())
207
208inline size_t normalizePrototypeChainForChainAccess(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, PropertyOffset& slotOffset)
209{
210 JSCell* cell = base.asCell();
211 size_t count = 0;
212
213 while (slotBase != cell) {
214 if (cell->isProxy())
215 return InvalidPrototypeChain;
216
217 if (cell->structure()->typeInfo().hasImpureGetOwnPropertySlot())
218 return InvalidPrototypeChain;
219
220 JSValue v = cell->structure()->prototypeForLookup(callFrame);
221
222 // If we didn't find slotBase in base's prototype chain, then base
223 // must be a proxy for another object.
224
225 if (v.isNull())
226 return InvalidPrototypeChain;
227
228 cell = v.asCell();
229
230 // Since we're accessing a prototype in a loop, it's a good bet that it
231 // should not be treated as a dictionary.
232 if (cell->structure()->isDictionary()) {
233 asObject(cell)->flattenDictionaryObject(callFrame->vm());
234 if (slotBase == cell)
235 slotOffset = cell->structure()->get(callFrame->vm(), propertyName);
236 }
237
238 ++count;
239 }
240
241 ASSERT(count);
242 return count;
243}
244
245inline size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base)
246{
247 size_t count = 0;
248 while (1) {
249 if (base->isProxy())
250 return InvalidPrototypeChain;
251
252 JSValue v = base->structure()->prototypeForLookup(callFrame);
253 if (v.isNull())
254 return count;
255
256 base = v.asCell();
257
258 // Since we're accessing a prototype in a loop, it's a good bet that it
259 // should not be treated as a dictionary.
260 if (base->structure()->isDictionary())
261 asObject(base)->flattenDictionaryObject(callFrame->vm());
262
263 ++count;
264 }
265}
266
267inline bool isPrototypeChainNormalized(JSGlobalObject* globalObject, Structure* structure)
268{
269 for (;;) {
270 if (structure->typeInfo().type() == ProxyType)
271 return false;
272
273 JSValue v = structure->prototypeForLookup(globalObject);
274 if (v.isNull())
275 return true;
276
277 structure = v.asCell()->structure();
278
279 if (structure->isDictionary())
280 return false;
281 }
282}
283
284} // namespace JSC
285
286#endif // Operations_h