]>
git.saurik.com Git - apple/javascriptcore.git/blob - runtime/Operations.h
b2081f3dd9bf89c83bb4d85cd431ac9c95034b9e
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
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.
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.
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.
25 #include "ExceptionHelpers.h"
26 #include "Interpreter.h"
28 #include "JSValueInlineMethods.h"
32 NEVER_INLINE JSValue
jsAddSlowCase(CallFrame
*, JSValue
, JSValue
);
33 JSValue
jsTypeStringForValue(CallFrame
*, JSValue
);
34 bool jsIsObjectType(JSValue
);
35 bool jsIsFunctionType(JSValue
);
37 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, JSString
* s1
, JSString
* s2
)
39 JSGlobalData
& globalData
= exec
->globalData();
41 unsigned length1
= s1
->length();
44 unsigned length2
= s2
->length();
47 if ((length1
+ length2
) < length1
)
48 return throwOutOfMemoryError(exec
);
50 return JSRopeString::create(globalData
, s1
, s2
);
53 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, const UString
& u1
, const UString
& u2
, const UString
& u3
)
55 JSGlobalData
* globalData
= &exec
->globalData();
57 unsigned length1
= u1
.length();
58 unsigned length2
= u2
.length();
59 unsigned length3
= u3
.length();
61 return jsString(exec
, jsString(globalData
, u2
), jsString(globalData
, u3
));
63 return jsString(exec
, jsString(globalData
, u1
), jsString(globalData
, u3
));
65 return jsString(exec
, jsString(globalData
, u1
), jsString(globalData
, u2
));
67 if ((length1
+ length2
) < length1
)
68 return throwOutOfMemoryError(exec
);
69 if ((length1
+ length2
+ length3
) < length3
)
70 return throwOutOfMemoryError(exec
);
72 return JSRopeString::create(exec
->globalData(), jsString(globalData
, u1
), jsString(globalData
, u2
), jsString(globalData
, u3
));
75 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, Register
* strings
, unsigned count
)
77 JSGlobalData
* globalData
= &exec
->globalData();
78 JSRopeString::RopeBuilder
ropeBuilder(*globalData
);
80 unsigned oldLength
= 0;
82 for (unsigned i
= 0; i
< count
; ++i
) {
83 JSValue v
= strings
[i
].jsValue();
84 ropeBuilder
.append(v
.toString(exec
));
86 if (ropeBuilder
.length() < oldLength
) // True for overflow
87 return throwOutOfMemoryError(exec
);
90 return ropeBuilder
.release();
93 ALWAYS_INLINE JSValue
jsStringFromArguments(ExecState
* exec
, JSValue thisValue
)
95 JSGlobalData
* globalData
= &exec
->globalData();
96 JSRopeString::RopeBuilder
ropeBuilder(*globalData
);
97 ropeBuilder
.append(thisValue
.toString(exec
));
99 unsigned oldLength
= 0;
101 for (unsigned i
= 0; i
< exec
->argumentCount(); ++i
) {
102 JSValue v
= exec
->argument(i
);
103 ropeBuilder
.append(v
.toString(exec
));
105 if (ropeBuilder
.length() < oldLength
) // True for overflow
106 return throwOutOfMemoryError(exec
);
109 return ropeBuilder
.release();
113 inline bool JSValue::equal(ExecState
* exec
, JSValue v1
, JSValue v2
)
115 if (v1
.isInt32() && v2
.isInt32())
118 return equalSlowCase(exec
, v1
, v2
);
121 ALWAYS_INLINE
bool JSValue::equalSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
)
124 if (v1
.isNumber() && v2
.isNumber())
125 return v1
.asNumber() == v2
.asNumber();
127 bool s1
= v1
.isString();
128 bool s2
= v2
.isString();
130 return asString(v1
)->value(exec
) == asString(v2
)->value(exec
);
132 if (v1
.isUndefinedOrNull()) {
133 if (v2
.isUndefinedOrNull())
137 return v2
.asCell()->structure()->typeInfo().masqueradesAsUndefined();
140 if (v2
.isUndefinedOrNull()) {
143 return v1
.asCell()->structure()->typeInfo().masqueradesAsUndefined();
149 JSValue p1
= v1
.toPrimitive(exec
);
150 if (exec
->hadException())
153 if (v1
.isInt32() && v2
.isInt32())
159 JSValue p2
= v2
.toPrimitive(exec
);
160 if (exec
->hadException())
163 if (v1
.isInt32() && v2
.isInt32())
169 double d1
= v1
.toNumber(exec
);
170 double d2
= v2
.toNumber(exec
);
174 if (v1
.isBoolean()) {
176 return static_cast<double>(v1
.asBoolean()) == v2
.asNumber();
177 } else if (v2
.isBoolean()) {
179 return v1
.asNumber() == static_cast<double>(v2
.asBoolean());
187 ALWAYS_INLINE
bool JSValue::strictEqualSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
)
189 ASSERT(v1
.isCell() && v2
.isCell());
191 if (v1
.asCell()->isString() && v2
.asCell()->isString())
192 return asString(v1
)->value(exec
) == asString(v2
)->value(exec
);
197 inline bool JSValue::strictEqual(ExecState
* exec
, JSValue v1
, JSValue v2
)
199 if (v1
.isInt32() && v2
.isInt32())
202 if (v1
.isNumber() && v2
.isNumber())
203 return v1
.asNumber() == v2
.asNumber();
205 if (!v1
.isCell() || !v2
.isCell())
208 return strictEqualSlowCaseInline(exec
, v1
, v2
);
211 // See ES5 11.8.1/11.8.2/11.8.5 for definition of leftFirst, this value ensures correct
212 // evaluation ordering for argument conversions for '<' and '>'. For '<' pass the value
213 // true, for leftFirst, for '>' pass the value false (and reverse operand order).
214 template<bool leftFirst
>
215 ALWAYS_INLINE
bool jsLess(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
217 if (v1
.isInt32() && v2
.isInt32())
218 return v1
.asInt32() < v2
.asInt32();
220 if (v1
.isNumber() && v2
.isNumber())
221 return v1
.asNumber() < v2
.asNumber();
223 if (isJSString(v1
) && isJSString(v2
))
224 return asString(v1
)->value(callFrame
) < asString(v2
)->value(callFrame
);
233 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
234 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
236 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
237 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
240 if (wasNotString1
| wasNotString2
)
242 return asString(p1
)->value(callFrame
) < asString(p2
)->value(callFrame
);
245 // See ES5 11.8.3/11.8.4/11.8.5 for definition of leftFirst, this value ensures correct
246 // evaluation ordering for argument conversions for '<=' and '=>'. For '<=' pass the
247 // value true, for leftFirst, for '=>' pass the value false (and reverse operand order).
248 template<bool leftFirst
>
249 ALWAYS_INLINE
bool jsLessEq(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
251 if (v1
.isInt32() && v2
.isInt32())
252 return v1
.asInt32() <= v2
.asInt32();
254 if (v1
.isNumber() && v2
.isNumber())
255 return v1
.asNumber() <= v2
.asNumber();
257 if (isJSString(v1
) && isJSString(v2
))
258 return !(asString(v2
)->value(callFrame
) < asString(v1
)->value(callFrame
));
267 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
268 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
270 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
271 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
274 if (wasNotString1
| wasNotString2
)
276 return !(asString(p2
)->value(callFrame
) < asString(p1
)->value(callFrame
));
279 // Fast-path choices here are based on frequency data from SunSpider:
280 // <times> Add case: <t1> <t2>
281 // ---------------------------
282 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
283 // 247412 Add case: 5 5
284 // 20900 Add case: 5 6
285 // 13962 Add case: 5 3
286 // 4000 Add case: 3 5
288 ALWAYS_INLINE JSValue
jsAdd(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
290 if (v1
.isNumber() && v2
.isNumber())
291 return jsNumber(v1
.asNumber() + v2
.asNumber());
293 if (v1
.isString() && !v2
.isObject())
294 return jsString(callFrame
, asString(v1
), v2
.toString(callFrame
));
296 // All other cases are pretty uncommon
297 return jsAddSlowCase(callFrame
, v1
, v2
);
300 inline size_t normalizePrototypeChain(CallFrame
* callFrame
, JSValue base
, JSValue slotBase
, const Identifier
& propertyName
, size_t& slotOffset
)
302 JSCell
* cell
= base
.asCell();
305 while (slotBase
!= cell
) {
306 JSValue v
= cell
->structure()->prototypeForLookup(callFrame
);
308 // If we didn't find slotBase in base's prototype chain, then base
309 // must be a proxy for another object.
316 // Since we're accessing a prototype in a loop, it's a good bet that it
317 // should not be treated as a dictionary.
318 if (cell
->structure()->isDictionary()) {
319 asObject(cell
)->flattenDictionaryObject(callFrame
->globalData());
320 if (slotBase
== cell
)
321 slotOffset
= cell
->structure()->get(callFrame
->globalData(), propertyName
);
331 inline size_t normalizePrototypeChain(CallFrame
* callFrame
, JSCell
* base
)
335 JSValue v
= base
->structure()->prototypeForLookup(callFrame
);
341 // Since we're accessing a prototype in a loop, it's a good bet that it
342 // should not be treated as a dictionary.
343 if (base
->structure()->isDictionary())
344 asObject(base
)->flattenDictionaryObject(callFrame
->globalData());
350 ALWAYS_INLINE JSValue
resolveBase(CallFrame
* callFrame
, Identifier
& property
, ScopeChainNode
* scopeChain
, bool isStrictPut
)
352 ScopeChainIterator iter
= scopeChain
->begin();
353 ScopeChainIterator next
= iter
;
355 ScopeChainIterator end
= scopeChain
->end();
363 if (isStrictPut
&& !base
->getPropertySlot(callFrame
, property
, slot
))
367 if (base
->getPropertySlot(callFrame
, property
, slot
))
374 ASSERT_NOT_REACHED();
379 #endif // Operations_h