]>
git.saurik.com Git - apple/javascriptcore.git/blob - runtime/Operations.h
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 "Interpreter.h"
26 #include "JSImmediate.h"
27 #include "JSNumberCell.h"
32 NEVER_INLINE JSValue
throwOutOfMemoryError(ExecState
*);
33 NEVER_INLINE JSValue
jsAddSlowCase(CallFrame
*, JSValue
, JSValue
);
34 JSValue
jsTypeStringForValue(CallFrame
*, JSValue
);
35 bool jsIsObjectType(JSValue
);
36 bool jsIsFunctionType(JSValue
);
39 inline bool JSValue::equal(ExecState
* exec
, JSValue v1
, JSValue v2
)
41 if (v1
.isInt32() && v2
.isInt32())
44 return equalSlowCase(exec
, v1
, v2
);
47 ALWAYS_INLINE
bool JSValue::equalSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
)
50 if (v1
.isNumber() && v2
.isNumber())
51 return v1
.uncheckedGetNumber() == v2
.uncheckedGetNumber();
53 bool s1
= v1
.isString();
54 bool s2
= v2
.isString();
56 return asString(v1
)->value() == asString(v2
)->value();
58 if (v1
.isUndefinedOrNull()) {
59 if (v2
.isUndefinedOrNull())
63 return v2
.asCell()->structure()->typeInfo().masqueradesAsUndefined();
66 if (v2
.isUndefinedOrNull()) {
69 return v1
.asCell()->structure()->typeInfo().masqueradesAsUndefined();
75 JSValue p1
= v1
.toPrimitive(exec
);
76 if (exec
->hadException())
79 if (v1
.isInt32() && v2
.isInt32())
85 JSValue p2
= v2
.toPrimitive(exec
);
86 if (exec
->hadException())
89 if (v1
.isInt32() && v2
.isInt32())
95 double d1
= v1
.toNumber(exec
);
96 double d2
= v2
.toNumber(exec
);
100 if (v1
.isBoolean()) {
102 return static_cast<double>(v1
.getBoolean()) == v2
.uncheckedGetNumber();
103 } else if (v2
.isBoolean()) {
105 return v1
.uncheckedGetNumber() == static_cast<double>(v2
.getBoolean());
113 ALWAYS_INLINE
bool JSValue::strictEqualSlowCaseInline(JSValue v1
, JSValue v2
)
115 ASSERT(v1
.isCell() && v2
.isCell());
117 if (v1
.asCell()->isString() && v2
.asCell()->isString())
118 return asString(v1
)->value() == asString(v2
)->value();
123 inline bool JSValue::strictEqual(JSValue v1
, JSValue v2
)
125 if (v1
.isInt32() && v2
.isInt32())
128 if (v1
.isNumber() && v2
.isNumber())
129 return v1
.uncheckedGetNumber() == v2
.uncheckedGetNumber();
131 if (!v1
.isCell() || !v2
.isCell())
134 return strictEqualSlowCaseInline(v1
, v2
);
137 inline bool jsLess(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
139 if (v1
.isInt32() && v2
.isInt32())
140 return v1
.asInt32() < v2
.asInt32();
144 if (v1
.getNumber(n1
) && v2
.getNumber(n2
))
147 JSGlobalData
* globalData
= &callFrame
->globalData();
148 if (isJSString(globalData
, v1
) && isJSString(globalData
, v2
))
149 return asString(v1
)->value() < asString(v2
)->value();
153 bool wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
154 bool wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
156 if (wasNotString1
| wasNotString2
)
159 return asString(p1
)->value() < asString(p2
)->value();
162 inline bool jsLessEq(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
164 if (v1
.isInt32() && v2
.isInt32())
165 return v1
.asInt32() <= v2
.asInt32();
169 if (v1
.getNumber(n1
) && v2
.getNumber(n2
))
172 JSGlobalData
* globalData
= &callFrame
->globalData();
173 if (isJSString(globalData
, v1
) && isJSString(globalData
, v2
))
174 return !(asString(v2
)->value() < asString(v1
)->value());
178 bool wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
179 bool wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
181 if (wasNotString1
| wasNotString2
)
184 return !(asString(p2
)->value() < asString(p1
)->value());
187 // Fast-path choices here are based on frequency data from SunSpider:
188 // <times> Add case: <t1> <t2>
189 // ---------------------------
190 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
191 // 247412 Add case: 5 5
192 // 20900 Add case: 5 6
193 // 13962 Add case: 5 3
194 // 4000 Add case: 3 5
196 ALWAYS_INLINE JSValue
jsAdd(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
201 bool rightIsNumber
= v2
.getNumber(right
);
202 if (rightIsNumber
&& v1
.getNumber(left
))
203 return jsNumber(callFrame
, left
+ right
);
205 bool leftIsString
= v1
.isString();
206 if (leftIsString
&& v2
.isString()) {
207 RefPtr
<UString::Rep
> value
= concatenate(asString(v1
)->value().rep(), asString(v2
)->value().rep());
209 return throwOutOfMemoryError(callFrame
);
210 return jsString(callFrame
, value
.release());
213 if (rightIsNumber
& leftIsString
) {
214 RefPtr
<UString::Rep
> value
= v2
.isInt32() ?
215 concatenate(asString(v1
)->value().rep(), v2
.asInt32()) :
216 concatenate(asString(v1
)->value().rep(), right
);
219 return throwOutOfMemoryError(callFrame
);
220 return jsString(callFrame
, value
.release());
223 // All other cases are pretty uncommon
224 return jsAddSlowCase(callFrame
, v1
, v2
);
227 inline size_t normalizePrototypeChain(CallFrame
* callFrame
, JSValue base
, JSValue slotBase
, const Identifier
& propertyName
, size_t& slotOffset
)
229 JSCell
* cell
= asCell(base
);
232 while (slotBase
!= cell
) {
233 JSValue v
= cell
->structure()->prototypeForLookup(callFrame
);
235 // If we didn't find slotBase in base's prototype chain, then base
236 // must be a proxy for another object.
243 // Since we're accessing a prototype in a loop, it's a good bet that it
244 // should not be treated as a dictionary.
245 if (cell
->structure()->isDictionary()) {
246 asObject(cell
)->flattenDictionaryObject();
247 if (slotBase
== cell
)
248 slotOffset
= cell
->structure()->get(propertyName
);
258 ALWAYS_INLINE JSValue
resolveBase(CallFrame
* callFrame
, Identifier
& property
, ScopeChainNode
* scopeChain
)
260 ScopeChainIterator iter
= scopeChain
->begin();
261 ScopeChainIterator next
= iter
;
263 ScopeChainIterator end
= scopeChain
->end();
270 if (next
== end
|| base
->getPropertySlot(callFrame
, property
, slot
))
277 ASSERT_NOT_REACHED();
281 ALWAYS_INLINE JSValue
concatenateStrings(CallFrame
* callFrame
, Register
* strings
, unsigned count
)
285 // Estimate the amount of space required to hold the entire string. If all
286 // arguments are strings, we can easily calculate the exact amount of space
287 // required. For any other arguments, for now let's assume they may require
288 // 11 UChars of storage. This is enouch to hold any int, and likely is also
289 // reasonable for the other immediates. We may want to come back and tune
290 // this value at some point.
291 unsigned bufferSize
= 0;
292 for (unsigned i
= 0; i
< count
; ++i
) {
293 JSValue v
= strings
[i
].jsValue();
294 if (LIKELY(v
.isString()))
295 bufferSize
+= asString(v
)->value().size();
300 // Allocate an output string to store the result.
301 // If the first argument is a String, and if it has the capacity (or can grow
302 // its capacity) to hold the entire result then use this as a base to concatenate
303 // onto. Otherwise, allocate a new empty output buffer.
304 JSValue firstValue
= strings
[0].jsValue();
305 RefPtr
<UString::Rep
> resultRep
;
306 if (firstValue
.isString() && (resultRep
= asString(firstValue
)->value().rep())->reserveCapacity(bufferSize
)) {
307 // We're going to concatenate onto the first string - remove it from the list of items to be appended.
311 resultRep
= UString::Rep::createEmptyBuffer(bufferSize
);
312 UString
result(resultRep
);
314 // Loop over the openards, writing them into the output buffer.
315 for (unsigned i
= 0; i
< count
; ++i
) {
316 JSValue v
= strings
[i
].jsValue();
317 if (LIKELY(v
.isString()))
318 result
.append(asString(v
)->value());
319 else if (v
.isInt32())
320 result
.appendNumeric(v
.asInt32());
324 result
.appendNumeric(d
);
326 result
.append(v
.toString(callFrame
));
330 return jsString(callFrame
, result
);
335 #endif // Operations_h