]>
git.saurik.com Git - apple/javascriptcore.git/blob - runtime/Operations.h
c3aa0fa4f65a07302c7577dde378fce739699d94
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
);
38 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, JSString
* s1
, JSString
* s2
)
45 unsigned ropeLength
= s1
->ropeLength() + s2
->ropeLength();
46 JSGlobalData
* globalData
= &exec
->globalData();
48 if (ropeLength
<= JSString::s_maxInternalRopeLength
)
49 return new (globalData
) JSString(globalData
, ropeLength
, s1
, s2
);
52 RefPtr
<JSString::Rope
> rope
= JSString::Rope::createOrNull(ropeLength
);
54 return throwOutOfMemoryError(exec
);
55 rope
->append(index
, s1
);
56 rope
->append(index
, s2
);
57 ASSERT(index
== ropeLength
);
58 return new (globalData
) JSString(globalData
, rope
.release());
61 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, const UString
& u1
, JSString
* s2
)
63 unsigned ropeLength
= 1 + s2
->ropeLength();
64 JSGlobalData
* globalData
= &exec
->globalData();
66 if (ropeLength
<= JSString::s_maxInternalRopeLength
)
67 return new (globalData
) JSString(globalData
, ropeLength
, u1
, s2
);
70 RefPtr
<JSString::Rope
> rope
= JSString::Rope::createOrNull(ropeLength
);
72 return throwOutOfMemoryError(exec
);
73 rope
->append(index
, u1
);
74 rope
->append(index
, s2
);
75 ASSERT(index
== ropeLength
);
76 return new (globalData
) JSString(globalData
, rope
.release());
79 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, JSString
* s1
, const UString
& u2
)
81 unsigned ropeLength
= s1
->ropeLength() + 1;
82 JSGlobalData
* globalData
= &exec
->globalData();
84 if (ropeLength
<= JSString::s_maxInternalRopeLength
)
85 return new (globalData
) JSString(globalData
, ropeLength
, s1
, u2
);
88 RefPtr
<JSString::Rope
> rope
= JSString::Rope::createOrNull(ropeLength
);
90 return throwOutOfMemoryError(exec
);
91 rope
->append(index
, s1
);
92 rope
->append(index
, u2
);
93 ASSERT(index
== ropeLength
);
94 return new (globalData
) JSString(globalData
, rope
.release());
97 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, Register
* strings
, unsigned count
)
101 unsigned ropeLength
= 0;
102 for (unsigned i
= 0; i
< count
; ++i
) {
103 JSValue v
= strings
[i
].jsValue();
104 if (LIKELY(v
.isString()))
105 ropeLength
+= asString(v
)->ropeLength();
110 JSGlobalData
* globalData
= &exec
->globalData();
112 return new (globalData
) JSString(exec
, strings
[0].jsValue(), strings
[1].jsValue(), strings
[2].jsValue());
114 RefPtr
<JSString::Rope
> rope
= JSString::Rope::createOrNull(ropeLength
);
116 return throwOutOfMemoryError(exec
);
119 for (unsigned i
= 0; i
< count
; ++i
) {
120 JSValue v
= strings
[i
].jsValue();
121 if (LIKELY(v
.isString()))
122 rope
->append(index
, asString(v
));
124 rope
->append(index
, v
.toString(exec
));
127 ASSERT(index
== ropeLength
);
128 return new (globalData
) JSString(globalData
, rope
.release());
131 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, JSValue thisValue
, const ArgList
& args
)
133 unsigned ropeLength
= 0;
134 if (LIKELY(thisValue
.isString()))
135 ropeLength
+= asString(thisValue
)->ropeLength();
138 for (unsigned i
= 0; i
< args
.size(); ++i
) {
139 JSValue v
= args
.at(i
);
140 if (LIKELY(v
.isString()))
141 ropeLength
+= asString(v
)->ropeLength();
146 RefPtr
<JSString::Rope
> rope
= JSString::Rope::createOrNull(ropeLength
);
148 return throwOutOfMemoryError(exec
);
151 if (LIKELY(thisValue
.isString()))
152 rope
->append(index
, asString(thisValue
));
154 rope
->append(index
, thisValue
.toString(exec
));
155 for (unsigned i
= 0; i
< args
.size(); ++i
) {
156 JSValue v
= args
.at(i
);
157 if (LIKELY(v
.isString()))
158 rope
->append(index
, asString(v
));
160 rope
->append(index
, v
.toString(exec
));
162 ASSERT(index
== ropeLength
);
164 JSGlobalData
* globalData
= &exec
->globalData();
165 return new (globalData
) JSString(globalData
, rope
.release());
169 inline bool JSValue::equal(ExecState
* exec
, JSValue v1
, JSValue v2
)
171 if (v1
.isInt32() && v2
.isInt32())
174 return equalSlowCase(exec
, v1
, v2
);
177 ALWAYS_INLINE
bool JSValue::equalSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
)
180 if (v1
.isNumber() && v2
.isNumber())
181 return v1
.uncheckedGetNumber() == v2
.uncheckedGetNumber();
183 bool s1
= v1
.isString();
184 bool s2
= v2
.isString();
186 return asString(v1
)->value(exec
) == asString(v2
)->value(exec
);
188 if (v1
.isUndefinedOrNull()) {
189 if (v2
.isUndefinedOrNull())
193 return v2
.asCell()->structure()->typeInfo().masqueradesAsUndefined();
196 if (v2
.isUndefinedOrNull()) {
199 return v1
.asCell()->structure()->typeInfo().masqueradesAsUndefined();
205 JSValue p1
= v1
.toPrimitive(exec
);
206 if (exec
->hadException())
209 if (v1
.isInt32() && v2
.isInt32())
215 JSValue p2
= v2
.toPrimitive(exec
);
216 if (exec
->hadException())
219 if (v1
.isInt32() && v2
.isInt32())
225 double d1
= v1
.toNumber(exec
);
226 double d2
= v2
.toNumber(exec
);
230 if (v1
.isBoolean()) {
232 return static_cast<double>(v1
.getBoolean()) == v2
.uncheckedGetNumber();
233 } else if (v2
.isBoolean()) {
235 return v1
.uncheckedGetNumber() == static_cast<double>(v2
.getBoolean());
243 ALWAYS_INLINE
bool JSValue::strictEqualSlowCaseInline(ExecState
* exec
, JSValue v1
, JSValue v2
)
245 ASSERT(v1
.isCell() && v2
.isCell());
247 if (v1
.asCell()->isString() && v2
.asCell()->isString())
248 return asString(v1
)->value(exec
) == asString(v2
)->value(exec
);
253 inline bool JSValue::strictEqual(ExecState
* exec
, JSValue v1
, JSValue v2
)
255 if (v1
.isInt32() && v2
.isInt32())
258 if (v1
.isNumber() && v2
.isNumber())
259 return v1
.uncheckedGetNumber() == v2
.uncheckedGetNumber();
261 if (!v1
.isCell() || !v2
.isCell())
264 return strictEqualSlowCaseInline(exec
, v1
, v2
);
267 ALWAYS_INLINE
bool jsLess(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
269 if (v1
.isInt32() && v2
.isInt32())
270 return v1
.asInt32() < v2
.asInt32();
274 if (v1
.getNumber(n1
) && v2
.getNumber(n2
))
277 JSGlobalData
* globalData
= &callFrame
->globalData();
278 if (isJSString(globalData
, v1
) && isJSString(globalData
, v2
))
279 return asString(v1
)->value(callFrame
) < asString(v2
)->value(callFrame
);
283 bool wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
284 bool wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
286 if (wasNotString1
| wasNotString2
)
289 return asString(p1
)->value(callFrame
) < asString(p2
)->value(callFrame
);
292 inline bool jsLessEq(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
294 if (v1
.isInt32() && v2
.isInt32())
295 return v1
.asInt32() <= v2
.asInt32();
299 if (v1
.getNumber(n1
) && v2
.getNumber(n2
))
302 JSGlobalData
* globalData
= &callFrame
->globalData();
303 if (isJSString(globalData
, v1
) && isJSString(globalData
, v2
))
304 return !(asString(v2
)->value(callFrame
) < asString(v1
)->value(callFrame
));
308 bool wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
309 bool wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
311 if (wasNotString1
| wasNotString2
)
314 return !(asString(p2
)->value(callFrame
) < asString(p1
)->value(callFrame
));
317 // Fast-path choices here are based on frequency data from SunSpider:
318 // <times> Add case: <t1> <t2>
319 // ---------------------------
320 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
321 // 247412 Add case: 5 5
322 // 20900 Add case: 5 6
323 // 13962 Add case: 5 3
324 // 4000 Add case: 3 5
326 ALWAYS_INLINE JSValue
jsAdd(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
328 double left
= 0.0, right
;
329 if (v1
.getNumber(left
) && v2
.getNumber(right
))
330 return jsNumber(callFrame
, left
+ right
);
334 ? jsString(callFrame
, asString(v1
), asString(v2
))
335 : jsString(callFrame
, asString(v1
), v2
.toPrimitiveString(callFrame
));
338 // All other cases are pretty uncommon
339 return jsAddSlowCase(callFrame
, v1
, v2
);
342 inline size_t normalizePrototypeChain(CallFrame
* callFrame
, JSValue base
, JSValue slotBase
, const Identifier
& propertyName
, size_t& slotOffset
)
344 JSCell
* cell
= asCell(base
);
347 while (slotBase
!= cell
) {
348 JSValue v
= cell
->structure()->prototypeForLookup(callFrame
);
350 // If we didn't find slotBase in base's prototype chain, then base
351 // must be a proxy for another object.
358 // Since we're accessing a prototype in a loop, it's a good bet that it
359 // should not be treated as a dictionary.
360 if (cell
->structure()->isDictionary()) {
361 asObject(cell
)->flattenDictionaryObject();
362 if (slotBase
== cell
)
363 slotOffset
= cell
->structure()->get(propertyName
);
373 inline size_t normalizePrototypeChain(CallFrame
* callFrame
, JSCell
* base
)
377 JSValue v
= base
->structure()->prototypeForLookup(callFrame
);
383 // Since we're accessing a prototype in a loop, it's a good bet that it
384 // should not be treated as a dictionary.
385 if (base
->structure()->isDictionary())
386 asObject(base
)->flattenDictionaryObject();
392 ALWAYS_INLINE JSValue
resolveBase(CallFrame
* callFrame
, Identifier
& property
, ScopeChainNode
* scopeChain
)
394 ScopeChainIterator iter
= scopeChain
->begin();
395 ScopeChainIterator next
= iter
;
397 ScopeChainIterator end
= scopeChain
->end();
404 if (next
== end
|| base
->getPropertySlot(callFrame
, property
, slot
))
411 ASSERT_NOT_REACHED();
416 #endif // Operations_h