]>
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, 2013, 2014 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 "CallFrame.h"
26 #include "ExceptionHelpers.h"
27 #include "JSCJSValue.h"
31 NEVER_INLINE JSValue
jsAddSlowCase(CallFrame
*, JSValue
, JSValue
);
32 JSValue
jsTypeStringForValue(CallFrame
*, JSValue
);
33 JSValue
jsTypeStringForValue(VM
&, JSGlobalObject
*, JSValue
);
34 bool jsIsObjectType(CallFrame
*, JSValue
);
35 bool jsIsFunctionType(JSValue
);
37 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, JSString
* s1
, JSString
* s2
)
41 int32_t length1
= s1
->length();
44 int32_t length2
= s2
->length();
47 if (sumOverflows
<int32_t>(length1
, length2
))
48 return throwOutOfMemoryError(exec
);
50 return JSRopeString::create(vm
, s1
, s2
);
53 ALWAYS_INLINE JSValue
jsString(ExecState
* exec
, const String
& u1
, const String
& u2
, const String
& u3
)
57 int32_t length1
= u1
.length();
58 int32_t length2
= u2
.length();
59 int32_t length3
= u3
.length();
61 if (length1
< 0 || length2
< 0 || length3
< 0)
62 return throwOutOfMemoryError(exec
);
65 return jsString(exec
, jsString(vm
, u2
), jsString(vm
, u3
));
67 return jsString(exec
, jsString(vm
, u1
), jsString(vm
, u3
));
69 return jsString(exec
, jsString(vm
, u1
), jsString(vm
, u2
));
71 if (sumOverflows
<int32_t>(length1
, length2
, length3
))
72 return throwOutOfMemoryError(exec
);
74 return JSRopeString::create(exec
->vm(), jsString(vm
, u1
), jsString(vm
, u2
), jsString(vm
, u3
));
77 ALWAYS_INLINE JSValue
jsStringFromRegisterArray(ExecState
* exec
, Register
* strings
, unsigned count
)
80 JSRopeString::RopeBuilder
ropeBuilder(*vm
);
82 for (unsigned i
= 0; i
< count
; ++i
) {
83 JSValue v
= strings
[-static_cast<int>(i
)].jsValue();
84 if (!ropeBuilder
.append(v
.toString(exec
)))
85 return throwOutOfMemoryError(exec
);
88 return ropeBuilder
.release();
91 ALWAYS_INLINE JSValue
jsStringFromArguments(ExecState
* exec
, JSValue thisValue
)
94 JSRopeString::RopeBuilder
ropeBuilder(*vm
);
95 ropeBuilder
.append(thisValue
.toString(exec
));
97 for (unsigned i
= 0; i
< exec
->argumentCount(); ++i
) {
98 JSValue v
= exec
->argument(i
);
99 if (!ropeBuilder
.append(v
.toString(exec
)))
100 return throwOutOfMemoryError(exec
);
103 return ropeBuilder
.release();
106 // See ES5 11.8.1/11.8.2/11.8.5 for definition of leftFirst, this value ensures correct
107 // evaluation ordering for argument conversions for '<' and '>'. For '<' pass the value
108 // true, for leftFirst, for '>' pass the value false (and reverse operand order).
109 template<bool leftFirst
>
110 ALWAYS_INLINE
bool jsLess(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
112 if (v1
.isInt32() && v2
.isInt32())
113 return v1
.asInt32() < v2
.asInt32();
115 if (v1
.isNumber() && v2
.isNumber())
116 return v1
.asNumber() < v2
.asNumber();
118 if (isJSString(v1
) && isJSString(v2
))
119 return codePointCompareLessThan(asString(v1
)->value(callFrame
), asString(v2
)->value(callFrame
));
128 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
129 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
131 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
132 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
135 if (wasNotString1
| wasNotString2
)
137 return codePointCompareLessThan(asString(p1
)->value(callFrame
), asString(p2
)->value(callFrame
));
140 // See ES5 11.8.3/11.8.4/11.8.5 for definition of leftFirst, this value ensures correct
141 // evaluation ordering for argument conversions for '<=' and '=>'. For '<=' pass the
142 // value true, for leftFirst, for '=>' pass the value false (and reverse operand order).
143 template<bool leftFirst
>
144 ALWAYS_INLINE
bool jsLessEq(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
146 if (v1
.isInt32() && v2
.isInt32())
147 return v1
.asInt32() <= v2
.asInt32();
149 if (v1
.isNumber() && v2
.isNumber())
150 return v1
.asNumber() <= v2
.asNumber();
152 if (isJSString(v1
) && isJSString(v2
))
153 return !codePointCompareLessThan(asString(v2
)->value(callFrame
), asString(v1
)->value(callFrame
));
162 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
163 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
165 wasNotString2
= v2
.getPrimitiveNumber(callFrame
, n2
, p2
);
166 wasNotString1
= v1
.getPrimitiveNumber(callFrame
, n1
, p1
);
169 if (wasNotString1
| wasNotString2
)
171 return !codePointCompareLessThan(asString(p2
)->value(callFrame
), asString(p1
)->value(callFrame
));
174 // Fast-path choices here are based on frequency data from SunSpider:
175 // <times> Add case: <t1> <t2>
176 // ---------------------------
177 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
178 // 247412 Add case: 5 5
179 // 20900 Add case: 5 6
180 // 13962 Add case: 5 3
181 // 4000 Add case: 3 5
183 ALWAYS_INLINE JSValue
jsAdd(CallFrame
* callFrame
, JSValue v1
, JSValue v2
)
185 if (v1
.isNumber() && v2
.isNumber())
186 return jsNumber(v1
.asNumber() + v2
.asNumber());
188 if (v1
.isString() && !v2
.isObject())
189 return jsString(callFrame
, asString(v1
), v2
.toString(callFrame
));
191 // All other cases are pretty uncommon
192 return jsAddSlowCase(callFrame
, v1
, v2
);
195 #define InvalidPrototypeChain (std::numeric_limits<size_t>::max())
197 inline size_t normalizePrototypeChainForChainAccess(CallFrame
* callFrame
, JSValue base
, JSValue slotBase
, const Identifier
& propertyName
, PropertyOffset
& slotOffset
)
199 VM
& vm
= callFrame
->vm();
200 JSCell
* cell
= base
.asCell();
203 while (!slotBase
|| slotBase
!= cell
) {
205 return InvalidPrototypeChain
;
207 const TypeInfo
& typeInfo
= cell
->structure()->typeInfo();
208 if (typeInfo
.hasImpureGetOwnPropertySlot() && !typeInfo
.newImpurePropertyFiresWatchpoints())
209 return InvalidPrototypeChain
;
211 JSValue v
= cell
->structure()->prototypeForLookup(callFrame
);
213 // If we didn't find slotBase in base's prototype chain, then base
214 // must be a proxy for another object.
219 return InvalidPrototypeChain
;
224 // Since we're accessing a prototype in a loop, it's a good bet that it
225 // should not be treated as a dictionary.
226 if (cell
->structure(vm
)->isDictionary()) {
227 asObject(cell
)->flattenDictionaryObject(callFrame
->vm());
228 if (slotBase
== cell
)
229 slotOffset
= cell
->structure(vm
)->get(callFrame
->vm(), propertyName
);
238 inline size_t normalizePrototypeChain(CallFrame
* callFrame
, JSCell
* base
)
240 VM
& vm
= callFrame
->vm();
244 return InvalidPrototypeChain
;
246 JSValue v
= base
->structure(vm
)->prototypeForLookup(callFrame
);
252 // Since we're accessing a prototype in a loop, it's a good bet that it
253 // should not be treated as a dictionary.
254 if (base
->structure(vm
)->isDictionary())
255 asObject(base
)->flattenDictionaryObject(callFrame
->vm());
261 inline bool isPrototypeChainNormalized(JSGlobalObject
* globalObject
, Structure
* structure
)
264 if (structure
->isProxy())
267 JSValue v
= structure
->prototypeForLookup(globalObject
);
271 structure
= v
.asCell()->structure();
273 if (structure
->isDictionary())
280 #endif // Operations_h