/[jscoverage]/trunk/js/jsbuiltins.cpp
ViewVC logotype

Contents of /trunk/js/jsbuiltins.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 507 - (show annotations)
Sun Jan 10 07:23:34 2010 UTC (9 years, 9 months ago) by siliconforks
File size: 13437 byte(s)
Update SpiderMonkey from Firefox 3.6rc1.

1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; -*-
2 * vim: set ts=8 sw=4 et tw=99:
3 *
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18 * May 28, 2008.
19 *
20 * The Initial Developer of the Original Code is
21 * Andreas Gal <gal@mozilla.com>
22 *
23 * Contributor(s):
24 * Brendan Eich <brendan@mozilla.org>
25 * Mike Shaver <shaver@mozilla.org>
26 * David Anderson <danderson@mozilla.com>
27 *
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
39 *
40 * ***** END LICENSE BLOCK ***** */
41
42 #include <math.h>
43
44 #include "jsapi.h"
45 #include "jsstdint.h"
46 #include "jsarray.h"
47 #include "jsbool.h"
48 #include "jscntxt.h"
49 #include "jsgc.h"
50 #include "jsiter.h"
51 #include "jsnum.h"
52 #include "jslibmath.h"
53 #include "jsmath.h"
54 #include "jsnum.h"
55 #include "prmjtime.h"
56 #include "jsdate.h"
57 #include "jsscope.h"
58 #include "jsstr.h"
59 #include "jsbuiltins.h"
60 #include "jstracer.h"
61 #include "jsvector.h"
62
63 #include "jsatominlines.h"
64 #include "jsobjinlines.h"
65
66 using namespace avmplus;
67 using namespace nanojit;
68
69 extern jsdouble js_NaN;
70
71 JS_FRIEND_API(void)
72 js_SetTraceableNativeFailed(JSContext *cx)
73 {
74 js_SetBuiltinError(cx);
75 }
76
77 /*
78 * NB: bool FASTCALL is not compatible with Nanojit's calling convention usage.
79 * Do not use bool FASTCALL, use JSBool only!
80 */
81
82 jsdouble FASTCALL
83 js_dmod(jsdouble a, jsdouble b)
84 {
85 if (b == 0.0) {
86 jsdpun u;
87 u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
88 u.s.lo = 0xffffffff;
89 return u.d;
90 }
91 return js_fmod(a, b);
92 }
93 JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_dmod, DOUBLE, DOUBLE, 1, 1)
94
95 int32 FASTCALL
96 js_imod(int32 a, int32 b)
97 {
98 if (a < 0 || b <= 0)
99 return -1;
100 int r = a % b;
101 return r;
102 }
103 JS_DEFINE_CALLINFO_2(extern, INT32, js_imod, INT32, INT32, 1, 1)
104
105 /* The following boxing/unboxing primitives we can't emit inline because
106 they either interact with the GC and depend on Spidermonkey's 32-bit
107 integer representation. */
108
109 jsval FASTCALL
110 js_BoxDouble(JSContext* cx, jsdouble d)
111 {
112 int32 i;
113 if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i))
114 return INT_TO_JSVAL(i);
115 JS_ASSERT(JS_ON_TRACE(cx));
116 jsval v; /* not rooted but ok here because we know GC won't run */
117 if (!js_NewDoubleInRootedValue(cx, d, &v))
118 return JSVAL_ERROR_COOKIE;
119 return v;
120 }
121 JS_DEFINE_CALLINFO_2(extern, JSVAL, js_BoxDouble, CONTEXT, DOUBLE, 1, 1)
122
123 jsval FASTCALL
124 js_BoxInt32(JSContext* cx, int32 i)
125 {
126 if (JS_LIKELY(INT_FITS_IN_JSVAL(i)))
127 return INT_TO_JSVAL(i);
128 JS_ASSERT(JS_ON_TRACE(cx));
129 jsval v; /* not rooted but ok here because we know GC won't run */
130 jsdouble d = (jsdouble)i;
131 if (!js_NewDoubleInRootedValue(cx, d, &v))
132 return JSVAL_ERROR_COOKIE;
133 return v;
134 }
135 JS_DEFINE_CALLINFO_2(extern, JSVAL, js_BoxInt32, CONTEXT, INT32, 1, 1)
136
137 jsdouble FASTCALL
138 js_UnboxDouble(jsval v)
139 {
140 if (JS_LIKELY(JSVAL_IS_INT(v)))
141 return (jsdouble)JSVAL_TO_INT(v);
142 return *JSVAL_TO_DOUBLE(v);
143 }
144 JS_DEFINE_CALLINFO_1(extern, DOUBLE, js_UnboxDouble, JSVAL, 1, 1)
145
146 int32 FASTCALL
147 js_UnboxInt32(jsval v)
148 {
149 if (JS_LIKELY(JSVAL_IS_INT(v)))
150 return JSVAL_TO_INT(v);
151 return js_DoubleToECMAInt32(*JSVAL_TO_DOUBLE(v));
152 }
153 JS_DEFINE_CALLINFO_1(extern, INT32, js_UnboxInt32, JSVAL, 1, 1)
154
155 int32 FASTCALL
156 js_DoubleToInt32(jsdouble d)
157 {
158 return js_DoubleToECMAInt32(d);
159 }
160 JS_DEFINE_CALLINFO_1(extern, INT32, js_DoubleToInt32, DOUBLE, 1, 1)
161
162 uint32 FASTCALL
163 js_DoubleToUint32(jsdouble d)
164 {
165 return js_DoubleToECMAUint32(d);
166 }
167 JS_DEFINE_CALLINFO_1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, 1)
168
169 jsdouble FASTCALL
170 js_StringToNumber(JSContext* cx, JSString* str)
171 {
172 const jschar* bp;
173 const jschar* end;
174 const jschar* ep;
175 jsdouble d;
176
177 str->getCharsAndEnd(bp, end);
178 if ((!js_strtod(cx, bp, end, &ep, &d) ||
179 js_SkipWhiteSpace(ep, end) != end) &&
180 (!js_strtointeger(cx, bp, end, &ep, 0, &d) ||
181 js_SkipWhiteSpace(ep, end) != end)) {
182 return js_NaN;
183 }
184 return d;
185 }
186 JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, 1, 1)
187
188 int32 FASTCALL
189 js_StringToInt32(JSContext* cx, JSString* str)
190 {
191 const jschar* bp;
192 const jschar* end;
193 const jschar* ep;
194 jsdouble d;
195
196 if (str->length() == 1) {
197 jschar c = str->chars()[0];
198 if ('0' <= c && c <= '9')
199 return c - '0';
200 return 0;
201 }
202
203 str->getCharsAndEnd(bp, end);
204 if ((!js_strtod(cx, bp, end, &ep, &d) ||
205 js_SkipWhiteSpace(ep, end) != end) &&
206 (!js_strtointeger(cx, bp, end, &ep, 0, &d) ||
207 js_SkipWhiteSpace(ep, end) != end)) {
208 return 0;
209 }
210 return js_DoubleToECMAInt32(d);
211 }
212 JS_DEFINE_CALLINFO_2(extern, INT32, js_StringToInt32, CONTEXT, STRING, 1, 1)
213
214 SideExit* FASTCALL
215 js_CallTree(InterpState* state, Fragment* f)
216 {
217 union { NIns *code; GuardRecord* (FASTCALL *func)(InterpState*, Fragment*); } u;
218
219 u.code = f->code();
220 JS_ASSERT(u.code);
221
222 GuardRecord* rec;
223 #if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32)
224 SIMULATE_FASTCALL(rec, state, NULL, u.func);
225 #else
226 rec = u.func(state, NULL);
227 #endif
228 VMSideExit* lr = (VMSideExit*)rec->exit;
229
230 if (lr->exitType == NESTED_EXIT) {
231 /* This only occurs once a tree call guard mismatches and we unwind the tree call stack.
232 We store the first (innermost) tree call guard in state and we will try to grow
233 the outer tree the failing call was in starting at that guard. */
234 if (!state->lastTreeCallGuard) {
235 state->lastTreeCallGuard = lr;
236 FrameInfo** rp = (FrameInfo**)state->rp;
237 state->rpAtLastTreeCall = rp + lr->calldepth;
238 }
239 } else {
240 /* If the tree exits on a regular (non-nested) guard, keep updating lastTreeExitGuard
241 with that guard. If we mismatch on a tree call guard, this will contain the last
242 non-nested guard we encountered, which is the innermost loop or branch guard. */
243 state->lastTreeExitGuard = lr;
244 }
245
246 return lr;
247 }
248 JS_DEFINE_CALLINFO_2(extern, SIDEEXIT, js_CallTree, INTERPSTATE, FRAGMENT, 0, 0)
249
250 JSBool FASTCALL
251 js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
252 {
253 JS_ASSERT(OBJ_IS_NATIVE(obj));
254 JS_LOCK_OBJ(cx, obj);
255
256 JSScope* scope = OBJ_SCOPE(obj);
257 uint32 slot;
258 if (scope->owned()) {
259 JS_ASSERT(!scope->has(sprop));
260 } else {
261 scope = js_GetMutableScope(cx, obj);
262 if (!scope)
263 goto exit_trace;
264 }
265
266 slot = sprop->slot;
267 if (!scope->table && sprop->parent == scope->lastProp && slot == scope->freeslot) {
268 if (slot < STOBJ_NSLOTS(obj) && !OBJ_GET_CLASS(cx, obj)->reserveSlots) {
269 JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, scope->freeslot)));
270 ++scope->freeslot;
271 } else {
272 if (!js_AllocSlot(cx, obj, &slot))
273 goto exit_trace;
274
275 if (slot != sprop->slot) {
276 js_FreeSlot(cx, obj, slot);
277 goto exit_trace;
278 }
279 }
280
281 scope->extend(cx, sprop);
282 } else {
283 JSScopeProperty *sprop2 = scope->add(cx, sprop->id,
284 sprop->getter, sprop->setter,
285 SPROP_INVALID_SLOT, sprop->attrs,
286 sprop->flags, sprop->shortid);
287 if (sprop2 != sprop)
288 goto exit_trace;
289 }
290
291 if (js_IsPropertyCacheDisabled(cx))
292 goto exit_trace;
293
294 JS_UNLOCK_SCOPE(cx, scope);
295 return JS_TRUE;
296
297 exit_trace:
298 JS_UNLOCK_SCOPE(cx, scope);
299 return JS_FALSE;
300 }
301 JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddProperty, CONTEXT, OBJECT, SCOPEPROP, 0, 0)
302
303 static JSBool
304 HasProperty(JSContext* cx, JSObject* obj, jsid id)
305 {
306 // Check that we know how the lookup op will behave.
307 for (JSObject* pobj = obj; pobj; pobj = OBJ_GET_PROTO(cx, pobj)) {
308 if (pobj->map->ops->lookupProperty != js_LookupProperty)
309 return JSVAL_TO_SPECIAL(JSVAL_VOID);
310 JSClass* clasp = OBJ_GET_CLASS(cx, pobj);
311 if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass)
312 return JSVAL_TO_SPECIAL(JSVAL_VOID);
313 }
314
315 JSObject* obj2;
316 JSProperty* prop;
317 if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0)
318 return JSVAL_TO_SPECIAL(JSVAL_VOID);
319 if (prop)
320 obj2->dropProperty(cx, prop);
321 return prop != NULL;
322 }
323
324 JSBool FASTCALL
325 js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr)
326 {
327 jsid id;
328 if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id))
329 return JSVAL_TO_BOOLEAN(JSVAL_VOID);
330
331 return HasProperty(cx, obj, id);
332 }
333 JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedProperty, CONTEXT, OBJECT, STRING, 0, 0)
334
335 JSBool FASTCALL
336 js_HasNamedPropertyInt32(JSContext* cx, JSObject* obj, int32 index)
337 {
338 jsid id;
339 if (!js_Int32ToId(cx, index, &id))
340 return JSVAL_TO_BOOLEAN(JSVAL_VOID);
341
342 return HasProperty(cx, obj, id);
343 }
344 JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, INT32, 0, 0)
345
346 JSString* FASTCALL
347 js_TypeOfObject(JSContext* cx, JSObject* obj)
348 {
349 JSType type = JS_TypeOfValue(cx, OBJECT_TO_JSVAL(obj));
350 return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]);
351 }
352 JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT, 1, 1)
353
354 JSString* FASTCALL
355 js_TypeOfBoolean(JSContext* cx, int32 unboxed)
356 {
357 /* Watch out for pseudo-booleans. */
358 jsval boxed = SPECIAL_TO_JSVAL(unboxed);
359 JS_ASSERT(JSVAL_IS_VOID(boxed) || JSVAL_IS_BOOLEAN(boxed));
360 JSType type = JS_TypeOfValue(cx, boxed);
361 return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]);
362 }
363 JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfBoolean, CONTEXT, INT32, 1, 1)
364
365 jsdouble FASTCALL
366 js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed)
367 {
368 if (unboxed == JSVAL_TO_SPECIAL(JSVAL_VOID))
369 return js_NaN;
370 JS_ASSERT(unboxed == JS_TRUE || unboxed == JS_FALSE);
371 return unboxed;
372 }
373 JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_BooleanOrUndefinedToNumber, CONTEXT, INT32, 1, 1)
374
375 JSString* FASTCALL
376 js_BooleanOrUndefinedToString(JSContext *cx, int32 unboxed)
377 {
378 JS_ASSERT(uint32(unboxed) <= 2);
379 return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[unboxed]);
380 }
381 JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanOrUndefinedToString, CONTEXT, INT32, 1, 1)
382
383 JSObject* FASTCALL
384 js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent)
385 {
386 JS_ASSERT(HAS_FUNCTION_CLASS(funobj));
387 JS_ASSERT(HAS_FUNCTION_CLASS(proto));
388 JS_ASSERT(JS_ON_TRACE(cx));
389
390 JSFunction *fun = (JSFunction*) funobj;
391 JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
392
393 JSObject* closure = js_NewGCObject(cx, GCX_OBJECT);
394 if (!closure)
395 return NULL;
396
397 closure->initSharingEmptyScope(&js_FunctionClass, proto, parent,
398 reinterpret_cast<jsval>(fun));
399 return closure;
400 }
401 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT, 0, 0)
402
403 JSString* FASTCALL
404 js_ConcatN(JSContext *cx, JSString **strArray, uint32 size)
405 {
406 /* Calculate total size. */
407 size_t numChar = 1;
408 for (uint32 i = 0; i < size; ++i) {
409 size_t before = numChar;
410 numChar += strArray[i]->length();
411 if (numChar < before)
412 return NULL;
413 }
414
415
416 /* Allocate buffer. */
417 if (numChar & js::tl::MulOverflowMask<sizeof(jschar)>::result)
418 return NULL;
419 jschar *buf = (jschar *)cx->malloc(numChar * sizeof(jschar));
420 if (!buf)
421 return NULL;
422
423 /* Fill buffer. */
424 jschar *ptr = buf;
425 for (uint32 i = 0; i < size; ++i) {
426 const jschar *chars;
427 size_t length;
428 strArray[i]->getCharsAndLength(chars, length);
429 js_strncpy(ptr, chars, length);
430 ptr += length;
431 }
432 *ptr = '\0';
433
434 /* Create string. */
435 JSString *str = js_NewString(cx, buf, numChar - 1);
436 if (!str)
437 cx->free(buf);
438 return str;
439 }
440 JS_DEFINE_CALLINFO_3(extern, STRING, js_ConcatN, CONTEXT, STRINGPTR, UINT32, 0, 0)

  ViewVC Help
Powered by ViewVC 1.1.24