source: webkit/trunk/JavaScriptCore/runtime/Operations.h@ 45609

Last change on this file since 45609 was 44224, checked in by [email protected], 16 years ago

Revert 44221.

  • Property svn:eol-style set to native
File size: 11.5 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 *
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.
9 *
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.
14 *
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.
19 *
20 */
21
22#ifndef Operations_h
23#define Operations_h
24
25#include "Interpreter.h"
26#include "JSImmediate.h"
27#include "JSNumberCell.h"
28#include "JSString.h"
29
30namespace JSC {
31
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);
37
38 // ECMA 11.9.3
39 inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
40 {
41 if (JSImmediate::areBothImmediateIntegerNumbers(v1, v2))
42 return v1 == v2;
43
44 return equalSlowCase(exec, v1, v2);
45 }
46
47 ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
48 {
49 ASSERT(!JSImmediate::areBothImmediateIntegerNumbers(v1, v2));
50
51 do {
52 if (v1.isNumber() && v2.isNumber())
53 return v1.uncheckedGetNumber() == v2.uncheckedGetNumber();
54
55 bool s1 = v1.isString();
56 bool s2 = v2.isString();
57 if (s1 && s2)
58 return asString(v1)->value() == asString(v2)->value();
59
60 if (v1.isUndefinedOrNull()) {
61 if (v2.isUndefinedOrNull())
62 return true;
63 if (JSImmediate::isImmediate(v2))
64 return false;
65 return v2.asCell()->structure()->typeInfo().masqueradesAsUndefined();
66 }
67
68 if (v2.isUndefinedOrNull()) {
69 if (JSImmediate::isImmediate(v1))
70 return false;
71 return v1.asCell()->structure()->typeInfo().masqueradesAsUndefined();
72 }
73
74 if (v1.isObject()) {
75 if (v2.isObject())
76 return v1 == v2;
77 JSValue p1 = v1.toPrimitive(exec);
78 if (exec->hadException())
79 return false;
80 v1 = p1;
81 if (JSImmediate::areBothImmediateIntegerNumbers(v1, v2))
82 return v1 == v2;
83 continue;
84 }
85
86 if (v2.isObject()) {
87 JSValue p2 = v2.toPrimitive(exec);
88 if (exec->hadException())
89 return false;
90 v2 = p2;
91 if (JSImmediate::areBothImmediateIntegerNumbers(v1, v2))
92 return v1 == v2;
93 continue;
94 }
95
96 if (s1 || s2) {
97 double d1 = v1.toNumber(exec);
98 double d2 = v2.toNumber(exec);
99 return d1 == d2;
100 }
101
102 if (v1.isBoolean()) {
103 if (v2.isNumber())
104 return static_cast<double>(v1.getBoolean()) == v2.uncheckedGetNumber();
105 } else if (v2.isBoolean()) {
106 if (v1.isNumber())
107 return v1.uncheckedGetNumber() == static_cast<double>(v2.getBoolean());
108 }
109
110 return v1 == v2;
111 } while (true);
112 }
113
114 // ECMA 11.9.3
115 ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(JSValue v1, JSValue v2)
116 {
117 ASSERT(!JSImmediate::isEitherImmediate(v1, v2));
118
119 if (v1.asCell()->isString() && v2.asCell()->isString())
120 return asString(v1)->value() == asString(v2)->value();
121
122 return v1 == v2;
123 }
124
125 inline bool JSValue::strictEqual(JSValue v1, JSValue v2)
126 {
127 if (JSImmediate::areBothImmediateIntegerNumbers(v1, v2))
128 return v1 == v2;
129
130 if (v1.isNumber() && v2.isNumber())
131 return v1.uncheckedGetNumber() == v2.uncheckedGetNumber();
132
133 if (JSImmediate::isEitherImmediate(v1, v2))
134 return v1 == v2;
135
136 return strictEqualSlowCaseInline(v1, v2);
137 }
138
139 inline bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2)
140 {
141 if (JSValue::areBothInt32Fast(v1, v2))
142 return v1.getInt32Fast() < v2.getInt32Fast();
143
144 double n1;
145 double n2;
146 if (v1.getNumber(n1) && v2.getNumber(n2))
147 return n1 < n2;
148
149 JSGlobalData* globalData = &callFrame->globalData();
150 if (isJSString(globalData, v1) && isJSString(globalData, v2))
151 return asString(v1)->value() < asString(v2)->value();
152
153 JSValue p1;
154 JSValue p2;
155 bool wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
156 bool wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
157
158 if (wasNotString1 | wasNotString2)
159 return n1 < n2;
160
161 return asString(p1)->value() < asString(p2)->value();
162 }
163
164 inline bool jsLessEq(CallFrame* callFrame, JSValue v1, JSValue v2)
165 {
166 if (JSValue::areBothInt32Fast(v1, v2))
167 return v1.getInt32Fast() <= v2.getInt32Fast();
168
169 double n1;
170 double n2;
171 if (v1.getNumber(n1) && v2.getNumber(n2))
172 return n1 <= n2;
173
174 JSGlobalData* globalData = &callFrame->globalData();
175 if (isJSString(globalData, v1) && isJSString(globalData, v2))
176 return !(asString(v2)->value() < asString(v1)->value());
177
178 JSValue p1;
179 JSValue p2;
180 bool wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
181 bool wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
182
183 if (wasNotString1 | wasNotString2)
184 return n1 <= n2;
185
186 return !(asString(p2)->value() < asString(p1)->value());
187 }
188
189 // Fast-path choices here are based on frequency data from SunSpider:
190 // <times> Add case: <t1> <t2>
191 // ---------------------------
192 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
193 // 247412 Add case: 5 5
194 // 20900 Add case: 5 6
195 // 13962 Add case: 5 3
196 // 4000 Add case: 3 5
197
198 ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2)
199 {
200 double left;
201 double right = 0.0;
202
203 bool rightIsNumber = v2.getNumber(right);
204 if (rightIsNumber && v1.getNumber(left))
205 return jsNumber(callFrame, left + right);
206
207 bool leftIsString = v1.isString();
208 if (leftIsString && v2.isString()) {
209 RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep());
210 if (!value)
211 return throwOutOfMemoryError(callFrame);
212 return jsString(callFrame, value.release());
213 }
214
215 if (rightIsNumber & leftIsString) {
216 RefPtr<UString::Rep> value = v2.isInt32Fast() ?
217 concatenate(asString(v1)->value().rep(), v2.getInt32Fast()) :
218 concatenate(asString(v1)->value().rep(), right);
219
220 if (!value)
221 return throwOutOfMemoryError(callFrame);
222 return jsString(callFrame, value.release());
223 }
224
225 // All other cases are pretty uncommon
226 return jsAddSlowCase(callFrame, v1, v2);
227 }
228
229 inline size_t countPrototypeChainEntriesAndCheckForProxies(CallFrame* callFrame, JSValue baseValue, const PropertySlot& slot)
230 {
231 JSCell* cell = asCell(baseValue);
232 size_t count = 0;
233
234 while (slot.slotBase() != cell) {
235 JSValue v = cell->structure()->prototypeForLookup(callFrame);
236
237 // If we didn't find slotBase in baseValue's prototype chain, then baseValue
238 // must be a proxy for another object.
239
240 if (v.isNull())
241 return 0;
242
243 cell = asCell(v);
244
245 // Since we're accessing a prototype in a loop, it's a good bet that it
246 // should not be treated as a dictionary.
247 if (cell->structure()->isDictionary())
248 asObject(cell)->setStructure(Structure::fromDictionaryTransition(cell->structure()));
249
250 ++count;
251 }
252
253 ASSERT(count);
254 return count;
255 }
256
257 ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain)
258 {
259 ScopeChainIterator iter = scopeChain->begin();
260 ScopeChainIterator next = iter;
261 ++next;
262 ScopeChainIterator end = scopeChain->end();
263 ASSERT(iter != end);
264
265 PropertySlot slot;
266 JSObject* base;
267 while (true) {
268 base = *iter;
269 if (next == end || base->getPropertySlot(callFrame, property, slot))
270 return base;
271
272 iter = next;
273 ++next;
274 }
275
276 ASSERT_NOT_REACHED();
277 return JSValue();
278 }
279
280 ALWAYS_INLINE JSValue concatenateStrings(CallFrame* callFrame, Register* strings, unsigned count)
281 {
282 ASSERT(count >= 3);
283
284 // Estimate the amount of space required to hold the entire string. If all
285 // arguments are strings, we can easily calculate the exact amount of space
286 // required. For any other arguments, for now let's assume they may require
287 // 11 UChars of storage. This is enouch to hold any int, and likely is also
288 // reasonable for the other immediates. We may want to come back and tune
289 // this value at some point.
290 unsigned bufferSize = 0;
291 for (unsigned i = 0; i < count; ++i) {
292 JSValue v = strings[i].jsValue();
293 if (LIKELY(v.isString()))
294 bufferSize += asString(v)->value().size();
295 else
296 bufferSize += 11;
297 }
298
299 // Allocate an output string to store the result.
300 // If the first argument is a String, and if it has the capacity (or can grow
301 // its capacity) to hold the entire result then use this as a base to concatenate
302 // onto. Otherwise, allocate a new empty output buffer.
303 JSValue firstValue = strings[0].jsValue();
304 RefPtr<UString::Rep> resultRep;
305 if (firstValue.isString() && (resultRep = asString(firstValue)->value().rep())->reserveCapacity(bufferSize)) {
306 // We're going to concatenate onto the first string - remove it from the list of items to be appended.
307 ++strings;
308 --count;
309 } else
310 resultRep = UString::Rep::createEmptyBuffer(bufferSize);
311 UString result(resultRep);
312
313 // Loop over the openards, writing them into the output buffer.
314 for (unsigned i = 0; i < count; ++i) {
315 JSValue v = strings[i].jsValue();
316 if (LIKELY(v.isString()))
317 result.append(asString(v)->value());
318 else if (v.isInt32Fast())
319 result.appendNumeric(v.getInt32Fast());
320 else {
321 double d;
322 if (v.getNumber(d))
323 result.appendNumeric(d);
324 else
325 result.append(v.toString(callFrame));
326 }
327 }
328
329 return jsString(callFrame, result);
330 }
331
332} // namespace JSC
333
334#endif // Operations_h
Note: See TracBrowser for help on using the repository browser.