Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsbuiltins.cpp
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; -*-
2  * vim: set ts=4 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 #include "jsscopeinlines.h"
66 #include "jscntxtinlines.h"
67
68 using namespace avmplus;
69 using namespace nanojit;
70 using namespace js;
71
72 JS_FRIEND_API(void)
73 js_SetTraceableNativeFailed(JSContext *cx)
74 {
75     /*
76      * We might not be on trace (we might have deep bailed) so we hope
77      * cx->compartment is correct.
78      */
79     SetBuiltinError(JS_TRACE_MONITOR_FROM_CONTEXT(cx));
80 }
81
82 /*
83  * NB: bool FASTCALL is not compatible with Nanojit's calling convention usage.
84  * Do not use bool FASTCALL, use JSBool only!
85  */
86
87 jsdouble FASTCALL
88 js_dmod(jsdouble a, jsdouble b)
89 {
90     if (b == 0.0) {
91         jsdpun u;
92         u.s.hi = JSDOUBLE_HI32_NAN;
93         u.s.lo = JSDOUBLE_LO32_NAN;
94         return u.d;
95     }
96     return js_fmod(a, b);
97 }
98 JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_dmod, DOUBLE, DOUBLE, 1, ACCSET_NONE)
99
100 int32 FASTCALL
101 js_imod(int32 a, int32 b)
102 {
103     if (a < 0 || b <= 0)
104         return -1;
105     int r = a % b;
106     return r;
107 }
108 JS_DEFINE_CALLINFO_2(extern, INT32, js_imod, INT32, INT32, 1, ACCSET_NONE)
109
110 #if JS_BITS_PER_WORD == 32
111
112 jsdouble FASTCALL
113 js_UnboxDouble(uint32 tag, uint32 payload)
114 {
115     if (tag == JSVAL_TAG_INT32)
116         return (double)(int32)payload;
117
118     jsval_layout l;
119     l.s.tag = (JSValueTag)tag;
120     l.s.payload.u32 = payload;
121     return l.asDouble;
122 }
123 JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_UnboxDouble, UINT32, UINT32, 1, ACCSET_NONE)
124
125 int32 FASTCALL
126 js_UnboxInt32(uint32 tag, uint32 payload)
127 {
128     if (tag == JSVAL_TAG_INT32)
129         return (int32)payload;
130
131     jsval_layout l;
132     l.s.tag = (JSValueTag)tag;
133     l.s.payload.u32 = payload;
134     return js_DoubleToECMAInt32(l.asDouble);
135 }
136 JS_DEFINE_CALLINFO_2(extern, INT32, js_UnboxInt32, UINT32, UINT32, 1, ACCSET_NONE)
137
138 #elif JS_BITS_PER_WORD == 64
139
140 jsdouble FASTCALL
141 js_UnboxDouble(Value v)
142 {
143     if (v.isInt32())
144         return (jsdouble)v.toInt32();
145     return v.toDouble();
146 }
147 JS_DEFINE_CALLINFO_1(extern, DOUBLE, js_UnboxDouble, JSVAL, 1, ACCSET_NONE)
148
149 int32 FASTCALL
150 js_UnboxInt32(Value v)
151 {
152     if (v.isInt32())
153         return v.toInt32();
154     return js_DoubleToECMAInt32(v.toDouble());
155 }
156 JS_DEFINE_CALLINFO_1(extern, INT32, js_UnboxInt32, VALUE, 1, ACCSET_NONE)
157
158 #endif
159
160 int32 FASTCALL
161 js_DoubleToInt32(jsdouble d)
162 {
163     return js_DoubleToECMAInt32(d);
164 }
165 JS_DEFINE_CALLINFO_1(extern, INT32, js_DoubleToInt32, DOUBLE, 1, ACCSET_NONE)
166
167 uint32 FASTCALL
168 js_DoubleToUint32(jsdouble d)
169 {
170     return js_DoubleToECMAUint32(d);
171 }
172 JS_DEFINE_CALLINFO_1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, ACCSET_NONE)
173
174 /*
175  * js_StringToNumber and js_StringToInt32 store into their second argument, so
176  * they need to be annotated accordingly.  To be future-proof, we use
177  * ACCSET_STORE_ANY so that new callers don't have to remember to update the
178  * annotation.
179  */
180 jsdouble FASTCALL
181 js_StringToNumber(JSContext* cx, JSString* str, JSBool *ok)
182 {
183     double out = 0;  /* silence warnings. */
184     *ok = StringToNumberType<jsdouble>(cx, str, &out);
185     return out;
186 }
187 JS_DEFINE_CALLINFO_3(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, BOOLPTR,
188                      0, ACCSET_STORE_ANY)
189
190 int32 FASTCALL
191 js_StringToInt32(JSContext* cx, JSString* str, JSBool *ok)
192 {
193     int32 out = 0;  /* silence warnings. */
194     *ok = StringToNumberType<int32>(cx, str, &out);
195     return out;
196 }
197 JS_DEFINE_CALLINFO_3(extern, INT32, js_StringToInt32, CONTEXT, STRING, BOOLPTR,
198                      0, ACCSET_STORE_ANY)
199
200 /* Nb: it's always safe to set isDefinitelyAtom to false if you're unsure or don't know. */
201 static inline JSBool
202 AddPropertyHelper(JSContext* cx, JSObject* obj, Shape* shape, bool isDefinitelyAtom)
203 {
204     JS_ASSERT(shape->previous() == obj->lastProperty());
205
206     if (obj->nativeEmpty()) {
207         if (!obj->ensureClassReservedSlotsForEmptyObject(cx))
208             return false;
209     }
210
211     uint32 slot;
212     slot = shape->slot;
213     JS_ASSERT(slot == obj->slotSpan());
214
215     if (slot < obj->numSlots()) {
216         JS_ASSERT(obj->getSlot(slot).isUndefined());
217     } else {
218         if (!obj->allocSlot(cx, &slot))
219             return false;
220         JS_ASSERT(slot == shape->slot);
221     }
222
223     obj->extend(cx, shape, isDefinitelyAtom);
224     return !js_IsPropertyCacheDisabled(cx);
225 }
226
227 JSBool FASTCALL
228 js_AddProperty(JSContext* cx, JSObject* obj, Shape* shape)
229 {
230     return AddPropertyHelper(cx, obj, shape, /* isDefinitelyAtom = */false);
231 }
232 JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddProperty, CONTEXT, OBJECT, SHAPE, 0, ACCSET_STORE_ANY)
233
234 JSBool FASTCALL
235 js_AddAtomProperty(JSContext* cx, JSObject* obj, Shape* shape)
236 {
237     return AddPropertyHelper(cx, obj, shape, /* isDefinitelyAtom = */true);
238 }
239 JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddAtomProperty, CONTEXT, OBJECT, SHAPE, 0, ACCSET_STORE_ANY)
240
241 static JSBool
242 HasProperty(JSContext* cx, JSObject* obj, jsid id)
243 {
244     // Check that we know how the lookup op will behave.
245     for (JSObject* pobj = obj; pobj; pobj = pobj->getProto()) {
246         if (pobj->getOps()->lookupProperty)
247             return JS_NEITHER;
248         Class* clasp = pobj->getClass();
249         if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass)
250             return JS_NEITHER;
251     }
252
253     JSObject* obj2;
254     JSProperty* prop;
255     if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0)
256         return JS_NEITHER;
257     return prop != NULL;
258 }
259
260 JSBool FASTCALL
261 js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr)
262 {
263     JSAtom *atom = js_AtomizeString(cx, idstr, 0);
264     if (!atom)
265         return JS_NEITHER;
266
267     return HasProperty(cx, obj, ATOM_TO_JSID(atom));
268 }
269 JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedProperty, CONTEXT, OBJECT, STRING,
270                      0, ACCSET_STORE_ANY)
271
272 JSBool FASTCALL
273 js_HasNamedPropertyInt32(JSContext* cx, JSObject* obj, int32 index)
274 {
275     jsid id;
276     if (!js_Int32ToId(cx, index, &id))
277         return JS_NEITHER;
278
279     return HasProperty(cx, obj, id);
280 }
281 JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, INT32,
282                      0, ACCSET_STORE_ANY)
283
284 JSString* FASTCALL
285 js_TypeOfObject(JSContext* cx, JSObject* obj)
286 {
287     JS_ASSERT(obj);
288     return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[obj->typeOf(cx)]);
289 }
290 JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT, 1, ACCSET_NONE)
291
292 JSString* FASTCALL
293 js_BooleanIntToString(JSContext *cx, int32 unboxed)
294 {
295     JS_ASSERT(uint32(unboxed) <= 1);
296     return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[unboxed]);
297 }
298 JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanIntToString, CONTEXT, INT32, 1, ACCSET_NONE)
299
300 JSObject* FASTCALL
301 js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent)
302 {
303     JS_ASSERT(funobj->isFunction());
304     JS_ASSERT(proto->isFunction());
305     JS_ASSERT(JS_ON_TRACE(cx));
306
307     JSFunction *fun = (JSFunction*) funobj;
308     JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
309
310     JSObject* closure = js_NewGCObject(cx, gc::FINALIZE_OBJECT2);
311     if (!closure)
312         return NULL;
313
314     if (!closure->initSharingEmptyShape(cx, &js_FunctionClass, proto, parent,
315                                         fun, gc::FINALIZE_OBJECT2)) {
316         return NULL;
317     }
318     return closure;
319 }
320 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT,
321                      0, ACCSET_STORE_ANY)
322