]>
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 "ExceptionHelpers.h"
26 #include "Interpreter.h"
27 #include "JSCJSValueInlines.h"
30 #include "StructureInlines.h"
34 NEVER_INLINE JSValue
jsAddSlowCase(CallFrame
*, JSValue
, JSValue
);
35 JSValue
jsTypeStringForValue(CallFrame
*, JSValue
);
36 JSValue
jsTypeStringForValue(VM
&, JSGlobalObject
*, JSValue
);
37 bool jsIsObjectType(CallFrame
*, JSValue
);
38 bool jsIsFunctionType(JSValue
);
40 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, JSString
* s1
, JSString
* s2
)
44 unsigned length1
= s1
->length();
47 unsigned length2
= s2
->length();
50 if ((length1
+ length2
) < length1
)
51 return throwOutOfMemoryError(exec
);
53 return JSRopeString::create(vm
, s1
, s2
);
56 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, const String
& u1
, const String
& u2
, const String
& u3
)
60 unsigned length1
= u1
.length();
61 unsigned length2
= u2
.length();
62 unsigned length3
= u3
.length();
64 return jsString(exec
, jsString(vm
, u2
), jsString(vm
, u3
));
66 return jsString(exec
, jsString(vm
, u1
), jsString(vm
, u3
));
68 return jsString(exec
, jsString(vm
, u1
), jsString(vm
, u2
));
70 if ((length1
+ length2
) < length1
)
71 return throwOutOfMemoryError(exec
);
72 if ((length1
+ length2
+ length3
) < length3
)
73 return throwOutOfMemoryError(exec
);
75 return JSRopeString::create(exec
->vm(), jsString(vm
, u1
), jsString(vm
, u2
), jsString(vm
, u3
));
78 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, Register
* strings
, unsigned count
)
81 JSRopeString::RopeBuilder
ropeBuilder(*vm
);
83 unsigned oldLength
= 0;
85 for (unsigned i
= 0; i
< count
; ++i
) {
86 JSValue v
= strings
[i
].jsValue();
87 ropeBuilder
.append(v
.toString(exec
));
89 if (ropeBuilder
.length() < oldLength
) // True for overflow
90 return throwOutOfMemoryError(exec
);
91 oldLength
= ropeBuilder
.length();
94 return ropeBuilder
.release();
97 ALWAYS_INLINE JSValue
jsStringFromArguments(ExecState
* exec
, JSValue thisValue
)
100 JSRopeString::RopeBuilder
ropeBuilder(*vm
);
101 ropeBuilder
.append(thisValue
.toString(exec
));
103 unsigned oldLength
= 0;
105 for (unsigned i
= 0; i
< exec
->argumentCount(); ++i
) {
106 JSValue v
= exec
->argument(i
);
107 ropeBuilder
.append(v
.toString(exec
));
109 if (ropeBuilder
.length() < oldLength
) // True for overflow
110 return throwOutOfMemoryError(exec
);
111 oldLength
= ropeBuilder
.length();
114 return ropeBuilder
.release();
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).
120 template<bool leftFirst
>
121 ALWAYS_INLINE
bool jsLess(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
123 if (v1
.isInt32() && v2
.isInt32())
124 return v1
.asInt32() < v2
.asInt32();
126 if (v1
.isNumber() && v2
.isNumber())
127 return v1
.asNumber() < v2
.asNumber();
129 if (isJSString(v1
) && isJSString(v2
))
130 return codePointCompareLessThan(asString(v1
)->value(callFrame
), asString(v2
)->value(callFrame
));
139 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
140 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
142 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
143 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
146 if (wasNotString1
| wasNotString2
)
148 return codePointCompareLessThan(asString(p1
)->value(callFrame
), asString(p2
)->value(callFrame
));
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).
154 template<bool leftFirst
>
155 ALWAYS_INLINE
bool jsLessEq(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
157 if (v1
.isInt32() && v2
.isInt32())
158 return v1
.asInt32() <= v2
.asInt32();
160 if (v1
.isNumber() && v2
.isNumber())
161 return v1
.asNumber() <= v2
.asNumber();
163 if (isJSString(v1
) && isJSString(v2
))
164 return !codePointCompareLessThan(asString(v2
)->value(callFrame
), asString(v1
)->value(callFrame
));
173 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
174 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
176 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
177 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
180 if (wasNotString1
| wasNotString2
)
182 return !codePointCompareLessThan(asString(p2
)->value(callFrame
), asString(p1
)->value(callFrame
));
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
194 ALWAYS_INLINE JSValue
jsAdd(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
196 if (v1
.isNumber() && v2
.isNumber())
197 return jsNumber(v1
.asNumber() + v2
.asNumber());
199 if (v1
.isString() && !v2
.isObject())
200 return jsString(callFrame
, asString(v1
), v2
.toString(callFrame
));
202 // All other cases are pretty uncommon
203 return jsAddSlowCase(callFrame
, v1
, v2
);
206 #define InvalidPrototypeChain (std::numeric_limits<size_t>::max())
208 inline size_t normalizePrototypeChainForChainAccess(CallFrame
* callFrame
, JSValue base
, JSValue slotBase
, const Identifier
& propertyName
, PropertyOffset
& slotOffset
)
210 JSCell
* cell
= base
.asCell();
213 while (slotBase
!= cell
) {
215 return InvalidPrototypeChain
;
217 if (cell
->structure()->typeInfo().hasImpureGetOwnPropertySlot())
218 return InvalidPrototypeChain
;
220 JSValue v
= cell
->structure()->prototypeForLookup(callFrame
);
222 // If we didn't find slotBase in base's prototype chain, then base
223 // must be a proxy for another object.
226 return InvalidPrototypeChain
;
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
);
245 inline size_t normalizePrototypeChain(CallFrame
* callFrame
, JSCell
* base
)
250 return InvalidPrototypeChain
;
252 JSValue v
= base
->structure()->prototypeForLookup(callFrame
);
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());
267 inline bool isPrototypeChainNormalized(JSGlobalObject
* globalObject
, Structure
* structure
)
270 if (structure
->typeInfo().type() == ProxyType
)
273 JSValue v
= structure
->prototypeForLookup(globalObject
);
277 structure
= v
.asCell()->structure();
279 if (structure
->isDictionary())
286 #endif // Operations_h