source: webkit/trunk/JavaScriptCore/kjs/JSValue.cpp@ 34861

Last change on this file since 34861 was 34821, checked in by Darin Adler, 17 years ago

2008-06-26 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • optimize UString append and the replace function a bit

SunSpider says 1.8% faster.

  • VM/JSPropertyNameIterator.cpp: Added include of JSString.h, now needed because jsString returns a JSString*.
  • VM/Machine.cpp: (KJS::Machine::privateExecute): Removed the toObject call from native function calls. Also removed code to put the this value into a register.
  • kjs/BooleanObject.cpp: (KJS::booleanProtoFuncToString): Rewrite to handle false and true separately.
  • kjs/FunctionPrototype.cpp: (KJS::constructFunction): Use single-character append rather than building a string for each character.
  • kjs/JSFunction.cpp: (KJS::globalFuncUnescape): Ditto.
  • kjs/JSImmediate.cpp: (KJS::JSImmediate::prototype): Added. Gets the appropriate prototype for use with an immediate value. To be used instead of toObject when doing a get on an immediate value.
  • kjs/JSImmediate.h: Added prototype.
  • kjs/JSObject.cpp: (KJS::JSObject::toString): Tweaked formatting.
  • kjs/JSObject.h: (KJS::JSValue::get): Use prototype instead of toObject to avoid creating an object wrapper just to search for properties. This also saves an unnecessary hash table lookup since the object wrappers themselves don't have any properties.
  • kjs/JSString.h: Added toThisString and toThisJSString.
  • kjs/JSValue.cpp: (KJS::JSCell::toThisString): Added. (KJS::JSCell::toThisJSString): Added. (KJS::JSCell::getJSNumber): Added. (KJS::jsString): Changed return type to JSString*. (KJS::jsOwnedString): Ditto.
  • kjs/JSValue.h: (KJS::JSValue::toThisString): Added. (KJS::JSValue::toThisJSString): Added. (KJS::JSValue::getJSNumber): Added.
  • kjs/NumberObject.cpp: (KJS::NumberObject::getJSNumber): Added. (KJS::integer_part_noexp): Append C string directly rather than first turning it into a UString. (KJS::numberProtoFuncToString): Use getJSNumber to check if the value is a number rather than isObject(&NumberObject::info). This works for immediate numbers, number cells, and NumberObject instances. (KJS::numberProtoFuncToLocaleString): Ditto. (KJS::numberProtoFuncValueOf): Ditto. (KJS::numberProtoFuncToFixed): Ditto. (KJS::numberProtoFuncToExponential): Ditto. (KJS::numberProtoFuncToPrecision): Ditto.
  • kjs/NumberObject.h: Added getJSNumber.
  • kjs/PropertySlot.cpp: Tweaked comment.
  • kjs/internal.cpp: (KJS::JSString::toThisString): Added. (KJS::JSString::toThisJSString): Added. (KJS::JSString::getOwnPropertySlot): Changed code that searches the prototype chain to start with the string prototype and not create a string object. (KJS::JSNumberCell::toThisString): Added. (KJS::JSNumberCell::getJSNumber): Added.
  • kjs/lookup.cpp: (KJS::staticFunctionGetter): Moved here, because there's no point in having a function that's only used for a function pointer be inline. (KJS::setUpStaticFunctionSlot): New function for getStaticFunctionSlot.
  • kjs/lookup.h: (KJS::staticValueGetter): Don't mark this inline. It doesn't make sense to have a function that's only used for a function pointer be inline. (KJS::getStaticFunctionSlot): Changed to get properties from the parent first before doing any handling of functions. This is the fastest way to return the function once the initial setup is done.
  • kjs/string_object.cpp: (KJS::StringObject::getPropertyNames): Call value() instead of getString(), avoiding an unnecessary virtual function call (the call to the type() function in the implementation of the isString() function). (KJS::StringObject::toString): Added. (KJS::StringObject::toThisString): Added. (KJS::StringObject::toThisJSString): Added. (KJS::substituteBackreferences): Rewrote to use a appending algorithm instead of a the old one that tried to replace in place. (KJS::stringProtoFuncReplace): Merged this function and the replace function. Replaced the hand-rolled dynamic arrays for source ranges and replacements with Vector. (KJS::stringProtoFuncToString): Handle JSString as well as StringObject. Removed the separate valueOf implementation, since it can just share this. (KJS::stringProtoFuncCharAt): Use toThisString, which handles JSString as well as StringObject, and is slightly more efficient than the old code too. (KJS::stringProtoFuncCharCodeAt): Ditto. (KJS::stringProtoFuncConcat): Ditto. (KJS::stringProtoFuncIndexOf): Ditto. (KJS::stringProtoFuncLastIndexOf): Ditto. (KJS::stringProtoFuncMatch): Ditto. (KJS::stringProtoFuncSearch): Ditto. (KJS::stringProtoFuncSlice): Ditto. (KJS::stringProtoFuncSplit): Ditto. (KJS::stringProtoFuncSubstr): Ditto. (KJS::stringProtoFuncSubstring): Ditto. (KJS::stringProtoFuncToLowerCase): Use toThisJSString. (KJS::stringProtoFuncToUpperCase): Ditto. (KJS::stringProtoFuncToLocaleLowerCase): Ditto. (KJS::stringProtoFuncToLocaleUpperCase): Ditto. (KJS::stringProtoFuncLocaleCompare): Ditto. (KJS::stringProtoFuncBig): Use toThisString. (KJS::stringProtoFuncSmall): Ditto. (KJS::stringProtoFuncBlink): Ditto. (KJS::stringProtoFuncBold): Ditto. (KJS::stringProtoFuncFixed): Ditto. (KJS::stringProtoFuncItalics): Ditto. (KJS::stringProtoFuncStrike): Ditto. (KJS::stringProtoFuncSub): Ditto. (KJS::stringProtoFuncSup): Ditto. (KJS::stringProtoFuncFontcolor): Ditto. (KJS::stringProtoFuncFontsize): Ditto. (KJS::stringProtoFuncAnchor): Ditto. (KJS::stringProtoFuncLink): Ditto.
  • kjs/string_object.h: Added toString, toThisString, and toThisJSString.
  • kjs/ustring.cpp: (KJS::UString::append): Added a version that takes a character pointer and size, so we don't have to create a UString just to append to another UString.
  • kjs/ustring.h:
  • Property svn:eol-style set to native
File size: 8.6 KB
Line 
1/*
2 * Copyright (C) 1999-2001 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#include "config.h"
24#include "JSValue.h"
25
26#include "error_object.h"
27#include "nodes.h"
28#include <stdio.h>
29#include <string.h>
30#include <wtf/MathExtras.h>
31
32namespace KJS {
33
34#if defined NAN && defined INFINITY
35
36extern const double NaN = NAN;
37extern const double Inf = INFINITY;
38
39#else // !(defined NAN && defined INFINITY)
40
41// The trick is to define the NaN and Inf globals with a different type than the declaration.
42// This trick works because the mangled name of the globals does not include the type, although
43// I'm not sure that's guaranteed. There could be alignment issues with this, since arrays of
44// characters don't necessarily need the same alignment doubles do, but for now it seems to work.
45// It would be good to figure out a 100% clean way that still avoids code that runs at init time.
46
47// Note, we have to use union to ensure alignment. Otherwise, NaN_Bytes can start anywhere,
48// while NaN_double has to be 4-byte aligned for 32-bits.
49// With -fstrict-aliasing enabled, unions are the only safe way to do type masquerading.
50
51static const union {
52 struct {
53 unsigned char NaN_Bytes[8];
54 unsigned char Inf_Bytes[8];
55 } bytes;
56
57 struct {
58 double NaN_Double;
59 double Inf_Double;
60 } doubles;
61
62} NaNInf = { {
63#if PLATFORM(BIG_ENDIAN)
64 { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 },
65 { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }
66#elif PLATFORM(MIDDLE_ENDIAN)
67 { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 },
68 { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 }
69#else
70 { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f },
71 { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }
72#endif
73} } ;
74
75extern const double NaN = NaNInf.doubles.NaN_Double;
76extern const double Inf = NaNInf.doubles.Inf_Double;
77
78#endif // !(defined NAN && defined INFINITY)
79
80static const double D16 = 65536.0;
81static const double D32 = 4294967296.0;
82
83void* JSCell::operator new(size_t size, ExecState* exec)
84{
85#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE
86 return exec->heap()->inlineAllocate(size);
87#else
88 return exec->heap()->allocate(size);
89#endif
90}
91
92bool JSCell::getUInt32(uint32_t&) const
93{
94 return false;
95}
96
97bool JSCell::getTruncatedInt32(int32_t&) const
98{
99 return false;
100}
101
102bool JSCell::getTruncatedUInt32(uint32_t&) const
103{
104 return false;
105}
106
107// ECMA 9.4
108double JSValue::toInteger(ExecState* exec) const
109{
110 int32_t i;
111 if (getTruncatedInt32(i))
112 return i;
113 double d = toNumber(exec);
114 return isnan(d) ? 0.0 : trunc(d);
115}
116
117double JSValue::toIntegerPreserveNaN(ExecState* exec) const
118{
119 int32_t i;
120 if (getTruncatedInt32(i))
121 return i;
122 return trunc(toNumber(exec));
123}
124
125int32_t JSValue::toInt32SlowCase(double d, bool& ok)
126{
127 ok = true;
128
129 if (d >= -D32 / 2 && d < D32 / 2)
130 return static_cast<int32_t>(d);
131
132 if (isnan(d) || isinf(d)) {
133 ok = false;
134 return 0;
135 }
136
137 double d32 = fmod(trunc(d), D32);
138 if (d32 >= D32 / 2)
139 d32 -= D32;
140 else if (d32 < -D32 / 2)
141 d32 += D32;
142 return static_cast<int32_t>(d32);
143}
144
145int32_t JSValue::toInt32SlowCase(ExecState* exec, bool& ok) const
146{
147 return JSValue::toInt32SlowCase(toNumber(exec), ok);
148}
149
150uint32_t JSValue::toUInt32SlowCase(double d, bool& ok)
151{
152 ok = true;
153
154 if (d >= 0.0 && d < D32)
155 return static_cast<uint32_t>(d);
156
157 if (isnan(d) || isinf(d)) {
158 ok = false;
159 return 0;
160 }
161
162 double d32 = fmod(trunc(d), D32);
163 if (d32 < 0)
164 d32 += D32;
165 return static_cast<uint32_t>(d32);
166}
167
168uint32_t JSValue::toUInt32SlowCase(ExecState* exec, bool& ok) const
169{
170 return JSValue::toUInt32SlowCase(toNumber(exec), ok);
171}
172
173float JSValue::toFloat(ExecState* exec) const
174{
175 return static_cast<float>(toNumber(exec));
176}
177
178bool JSCell::getNumber(double& numericValue) const
179{
180 if (!isNumber())
181 return false;
182 numericValue = static_cast<const JSNumberCell*>(this)->value();
183 return true;
184}
185
186double JSCell::getNumber() const
187{
188 return isNumber() ? static_cast<const JSNumberCell*>(this)->value() : NaN;
189}
190
191bool JSCell::getString(UString&stringValue) const
192{
193 if (!isString())
194 return false;
195 stringValue = static_cast<const JSString*>(this)->value();
196 return true;
197}
198
199UString JSCell::getString() const
200{
201 return isString() ? static_cast<const JSString*>(this)->value() : UString();
202}
203
204JSObject* JSCell::getObject()
205{
206 return isObject() ? static_cast<JSObject*>(this) : 0;
207}
208
209const JSObject* JSCell::getObject() const
210{
211 return isObject() ? static_cast<const JSObject*>(this) : 0;
212}
213
214CallType JSCell::getCallData(CallData&)
215{
216 return CallTypeNone;
217}
218
219ConstructType JSCell::getConstructData(ConstructData&)
220{
221 return ConstructTypeNone;
222}
223
224bool JSCell::getOwnPropertySlot(ExecState* exec, const Identifier& identifier, PropertySlot& slot)
225{
226 // This is not a general purpose implementation of getOwnPropertySlot.
227 // It should only be called by JSValue::get.
228 // It calls getPropertySlot, not getOwnPropertySlot.
229 JSObject* object = toObject(exec);
230 slot.setBase(object);
231 if (!object->getPropertySlot(exec, identifier, slot))
232 slot.setUndefined();
233 return true;
234}
235
236bool JSCell::getOwnPropertySlot(ExecState* exec, unsigned identifier, PropertySlot& slot)
237{
238 // This is not a general purpose implementation of getOwnPropertySlot.
239 // It should only be called by JSValue::get.
240 // It calls getPropertySlot, not getOwnPropertySlot.
241 JSObject* object = toObject(exec);
242 slot.setBase(object);
243 if (!object->getPropertySlot(exec, identifier, slot))
244 slot.setUndefined();
245 return true;
246}
247
248void JSCell::put(ExecState* exec, const Identifier& identifier, JSValue* value)
249{
250 toObject(exec)->put(exec, identifier, value);
251}
252
253void JSCell::put(ExecState* exec, unsigned identifier, JSValue* value)
254{
255 toObject(exec)->put(exec, identifier, value);
256}
257
258bool JSCell::deleteProperty(ExecState* exec, const Identifier& identifier)
259{
260 return toObject(exec)->deleteProperty(exec, identifier);
261}
262
263bool JSCell::deleteProperty(ExecState* exec, unsigned identifier)
264{
265 return toObject(exec)->deleteProperty(exec, identifier);
266}
267
268JSObject* JSCell::toThisObject(ExecState* exec) const
269{
270 return toObject(exec);
271}
272
273UString JSCell::toThisString(ExecState* exec) const
274{
275 return toThisObject(exec)->toString(exec);
276}
277
278JSString* JSCell::toThisJSString(ExecState* exec)
279{
280 return jsString(exec, toThisString(exec));
281}
282
283const ClassInfo* JSCell::classInfo() const
284{
285 return 0;
286}
287
288JSValue* JSCell::getJSNumber()
289{
290 return 0;
291}
292
293JSString* jsString(ExecState* exec, const char* s)
294{
295 return new (exec) JSString(s ? s : "");
296}
297
298JSString* jsString(ExecState* exec, const UString& s)
299{
300 return s.isNull() ? new (exec) JSString("") : new (exec) JSString(s);
301}
302
303JSString* jsOwnedString(ExecState* exec, const UString& s)
304{
305 return s.isNull() ? new (exec) JSString("", JSString::HasOtherOwner) : new (exec) JSString(s, JSString::HasOtherOwner);
306}
307
308JSValue* call(ExecState* exec, JSValue* functionObject, CallType callType, const CallData& callData, JSValue* thisValue, const ArgList& args)
309{
310 if (callType == CallTypeNative)
311 return callData.native.function(exec, static_cast<JSObject*>(functionObject), thisValue, args);
312 ASSERT(callType == CallTypeJS);
313 // FIXME: Can this be done more efficiently using the callData?
314 return static_cast<JSFunction*>(functionObject)->call(exec, thisValue, args);
315}
316
317JSObject* construct(ExecState* exec, JSValue* object, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
318{
319 if (constructType == ConstructTypeNative)
320 return constructData.native.function(exec, static_cast<JSObject*>(object), args);
321 ASSERT(constructType == ConstructTypeJS);
322 // FIXME: Can this be done more efficiently using the constructData?
323 return static_cast<JSFunction*>(object)->construct(exec, args);
324}
325
326} // namespace KJS
Note: See TracBrowser for help on using the repository browser.