1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; -*-
2 * vim: set ts=8 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * Andreas Gal <gal@mozilla.com>
24 * Brendan Eich <brendan@mozilla.org>
25 * Mike Shaver <shaver@mozilla.org>
26 * David Anderson <danderson@mozilla.com>
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.
40 * ***** END LICENSE BLOCK ***** */
51 #include "jslibmath.h"
58 #include "jsbuiltins.h"
61 using namespace avmplus
;
62 using namespace nanojit
;
64 extern jsdouble js_NaN
;
67 js_SetTraceableNativeFailed(JSContext
*cx
)
69 js_SetBuiltinError(cx
);
73 * NB: bool FASTCALL is not compatible with Nanojit's calling convention usage.
74 * Do not use bool FASTCALL, use JSBool only!
78 js_dmod(jsdouble a
, jsdouble b
)
82 u
.s
.hi
= JSDOUBLE_HI32_EXPMASK
| JSDOUBLE_HI32_MANTMASK
;
88 /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
89 if (JSDOUBLE_IS_FINITE(a
) && JSDOUBLE_IS_INFINITE(b
))
96 JS_DEFINE_CALLINFO_2(extern, DOUBLE
, js_dmod
, DOUBLE
, DOUBLE
, 1, 1)
99 js_imod(int32 a
, int32 b
)
106 JS_DEFINE_CALLINFO_2(extern, INT32
, js_imod
, INT32
, INT32
, 1, 1)
108 /* The following boxing/unboxing primitives we can't emit inline because
109 they either interact with the GC and depend on Spidermonkey's 32-bit
110 integer representation. */
113 js_BoxDouble(JSContext
* cx
, jsdouble d
)
116 if (JSDOUBLE_IS_INT(d
, i
) && INT_FITS_IN_JSVAL(i
))
117 return INT_TO_JSVAL(i
);
118 JS_ASSERT(JS_ON_TRACE(cx
));
119 jsval v
; /* not rooted but ok here because we know GC won't run */
120 if (!js_NewDoubleInRootedValue(cx
, d
, &v
))
121 return JSVAL_ERROR_COOKIE
;
124 JS_DEFINE_CALLINFO_2(extern, JSVAL
, js_BoxDouble
, CONTEXT
, DOUBLE
, 1, 1)
127 js_BoxInt32(JSContext
* cx
, int32 i
)
129 if (JS_LIKELY(INT_FITS_IN_JSVAL(i
)))
130 return INT_TO_JSVAL(i
);
131 JS_ASSERT(JS_ON_TRACE(cx
));
132 jsval v
; /* not rooted but ok here because we know GC won't run */
133 jsdouble d
= (jsdouble
)i
;
134 if (!js_NewDoubleInRootedValue(cx
, d
, &v
))
135 return JSVAL_ERROR_COOKIE
;
138 JS_DEFINE_CALLINFO_2(extern, JSVAL
, js_BoxInt32
, CONTEXT
, INT32
, 1, 1)
141 js_UnboxDouble(jsval v
)
143 if (JS_LIKELY(JSVAL_IS_INT(v
)))
144 return (jsdouble
)JSVAL_TO_INT(v
);
145 return *JSVAL_TO_DOUBLE(v
);
147 JS_DEFINE_CALLINFO_1(extern, DOUBLE
, js_UnboxDouble
, JSVAL
, 1, 1)
150 js_UnboxInt32(jsval v
)
152 if (JS_LIKELY(JSVAL_IS_INT(v
)))
153 return JSVAL_TO_INT(v
);
154 return js_DoubleToECMAInt32(*JSVAL_TO_DOUBLE(v
));
156 JS_DEFINE_CALLINFO_1(extern, INT32
, js_UnboxInt32
, JSVAL
, 1, 1)
159 js_DoubleToInt32(jsdouble d
)
161 return js_DoubleToECMAInt32(d
);
163 JS_DEFINE_CALLINFO_1(extern, INT32
, js_DoubleToInt32
, DOUBLE
, 1, 1)
166 js_DoubleToUint32(jsdouble d
)
168 return js_DoubleToECMAUint32(d
);
170 JS_DEFINE_CALLINFO_1(extern, UINT32
, js_DoubleToUint32
, DOUBLE
, 1, 1)
173 js_StringToNumber(JSContext
* cx
, JSString
* str
)
180 str
->getCharsAndEnd(bp
, end
);
181 if ((!js_strtod(cx
, bp
, end
, &ep
, &d
) ||
182 js_SkipWhiteSpace(ep
, end
) != end
) &&
183 (!js_strtointeger(cx
, bp
, end
, &ep
, 0, &d
) ||
184 js_SkipWhiteSpace(ep
, end
) != end
)) {
189 JS_DEFINE_CALLINFO_2(extern, DOUBLE
, js_StringToNumber
, CONTEXT
, STRING
, 1, 1)
192 js_StringToInt32(JSContext
* cx
, JSString
* str
)
199 str
->getCharsAndEnd(bp
, end
);
200 if ((!js_strtod(cx
, bp
, end
, &ep
, &d
) ||
201 js_SkipWhiteSpace(ep
, end
) != end
) &&
202 (!js_strtointeger(cx
, bp
, end
, &ep
, 0, &d
) ||
203 js_SkipWhiteSpace(ep
, end
) != end
)) {
206 return js_DoubleToECMAInt32(d
);
208 JS_DEFINE_CALLINFO_2(extern, INT32
, js_StringToInt32
, CONTEXT
, STRING
, 1, 1)
211 js_CallTree(InterpState
* state
, Fragment
* f
)
213 union { NIns
*code
; GuardRecord
* (FASTCALL
*func
)(InterpState
*, Fragment
*); } u
;
219 #if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32)
220 SIMULATE_FASTCALL(rec
, state
, NULL
, u
.func
);
222 rec
= u
.func(state
, NULL
);
224 VMSideExit
* lr
= (VMSideExit
*)rec
->exit
;
226 if (lr
->exitType
== NESTED_EXIT
) {
227 /* This only occurs once a tree call guard mismatches and we unwind the tree call stack.
228 We store the first (innermost) tree call guard in state and we will try to grow
229 the outer tree the failing call was in starting at that guard. */
230 if (!state
->lastTreeCallGuard
) {
231 state
->lastTreeCallGuard
= lr
;
232 FrameInfo
** rp
= (FrameInfo
**)state
->rp
;
233 state
->rpAtLastTreeCall
= rp
+ lr
->calldepth
;
236 /* If the tree exits on a regular (non-nested) guard, keep updating lastTreeExitGuard
237 with that guard. If we mismatch on a tree call guard, this will contain the last
238 non-nested guard we encountered, which is the innermost loop or branch guard. */
239 state
->lastTreeExitGuard
= lr
;
244 JS_DEFINE_CALLINFO_2(extern, SIDEEXIT
, js_CallTree
, INTERPSTATE
, FRAGMENT
, 0, 0)
247 js_AddProperty(JSContext
* cx
, JSObject
* obj
, JSScopeProperty
* sprop
)
249 JS_ASSERT(OBJ_IS_NATIVE(obj
));
250 JS_ASSERT(SPROP_HAS_STUB_SETTER(sprop
));
252 JS_LOCK_OBJ(cx
, obj
);
254 JSScope
* scope
= OBJ_SCOPE(obj
);
256 if (scope
->object
== obj
) {
257 if (sprop
== scope
->lastProp
|| SCOPE_HAS_PROPERTY(scope
, sprop
))
260 scope
= js_GetMutableScope(cx
, obj
);
266 if (!scope
->table
&& sprop
->parent
== scope
->lastProp
&& slot
== scope
->freeslot
) {
267 if (slot
< STOBJ_NSLOTS(obj
) && !OBJ_GET_CLASS(cx
, obj
)->reserveSlots
) {
268 JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj
, scope
->freeslot
)));
271 if (!js_AllocSlot(cx
, obj
, &slot
))
274 if (slot
!= sprop
->slot
) {
275 js_FreeSlot(cx
, obj
, slot
);
280 js_ExtendScopeShape(cx
, scope
, sprop
);
282 scope
->lastProp
= sprop
;
284 JSScopeProperty
*sprop2
= js_AddScopeProperty(cx
, scope
, sprop
->id
,
295 if (js_IsPropertyCacheDisabled(cx
))
298 JS_UNLOCK_SCOPE(cx
, scope
);
302 JS_UNLOCK_SCOPE(cx
, scope
);
305 JS_DEFINE_CALLINFO_3(extern, BOOL
, js_AddProperty
, CONTEXT
, OBJECT
, SCOPEPROP
, 0, 0)
308 HasProperty(JSContext
* cx
, JSObject
* obj
, jsid id
)
310 // Check that we know how the lookup op will behave.
311 for (JSObject
* pobj
= obj
; pobj
; pobj
= OBJ_GET_PROTO(cx
, pobj
)) {
312 if (pobj
->map
->ops
->lookupProperty
!= js_LookupProperty
)
313 return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID
);
314 JSClass
* clasp
= OBJ_GET_CLASS(cx
, pobj
);
315 if (clasp
->resolve
!= JS_ResolveStub
&& clasp
!= &js_StringClass
)
316 return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID
);
321 if (!js_LookupPropertyWithFlags(cx
, obj
, id
, JSRESOLVE_QUALIFIED
, &obj2
, &prop
))
322 return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID
);
324 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
329 js_HasNamedProperty(JSContext
* cx
, JSObject
* obj
, JSString
* idstr
)
332 if (!js_ValueToStringId(cx
, STRING_TO_JSVAL(idstr
), &id
))
333 return JSVAL_TO_BOOLEAN(JSVAL_VOID
);
335 return HasProperty(cx
, obj
, id
);
337 JS_DEFINE_CALLINFO_3(extern, BOOL
, js_HasNamedProperty
, CONTEXT
, OBJECT
, STRING
, 0, 0)
340 js_HasNamedPropertyInt32(JSContext
* cx
, JSObject
* obj
, int32 index
)
343 if (!js_Int32ToId(cx
, index
, &id
))
344 return JSVAL_TO_BOOLEAN(JSVAL_VOID
);
346 return HasProperty(cx
, obj
, id
);
348 JS_DEFINE_CALLINFO_3(extern, BOOL
, js_HasNamedPropertyInt32
, CONTEXT
, OBJECT
, INT32
, 0, 0)
351 js_CallGetter(JSContext
* cx
, JSObject
* obj
, JSScopeProperty
* sprop
)
353 JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop
));
355 if (!js_GetSprop(cx
, sprop
, obj
, &v
))
356 return JSVAL_ERROR_COOKIE
;
359 JS_DEFINE_CALLINFO_3(extern, JSVAL
, js_CallGetter
, CONTEXT
, OBJECT
, SCOPEPROP
, 0, 0)
362 js_TypeOfObject(JSContext
* cx
, JSObject
* obj
)
364 JSType type
= JS_TypeOfValue(cx
, OBJECT_TO_JSVAL(obj
));
365 return ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[type
]);
367 JS_DEFINE_CALLINFO_2(extern, STRING
, js_TypeOfObject
, CONTEXT
, OBJECT
, 1, 1)
370 js_TypeOfBoolean(JSContext
* cx
, int32 unboxed
)
372 /* Watch out for pseudo-booleans. */
373 jsval boxed
= PSEUDO_BOOLEAN_TO_JSVAL(unboxed
);
374 JS_ASSERT(JSVAL_IS_VOID(boxed
) || JSVAL_IS_BOOLEAN(boxed
));
375 JSType type
= JS_TypeOfValue(cx
, boxed
);
376 return ATOM_TO_STRING(cx
->runtime
->atomState
.typeAtoms
[type
]);
378 JS_DEFINE_CALLINFO_2(extern, STRING
, js_TypeOfBoolean
, CONTEXT
, INT32
, 1, 1)
381 js_BooleanOrUndefinedToNumber(JSContext
* cx
, int32 unboxed
)
383 if (unboxed
== JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID
))
385 JS_ASSERT(unboxed
== JS_TRUE
|| unboxed
== JS_FALSE
);
388 JS_DEFINE_CALLINFO_2(extern, DOUBLE
, js_BooleanOrUndefinedToNumber
, CONTEXT
, INT32
, 1, 1)
391 js_BooleanOrUndefinedToString(JSContext
*cx
, int32 unboxed
)
393 JS_ASSERT(uint32(unboxed
) <= 2);
394 return ATOM_TO_STRING(cx
->runtime
->atomState
.booleanAtoms
[unboxed
]);
396 JS_DEFINE_CALLINFO_2(extern, STRING
, js_BooleanOrUndefinedToString
, CONTEXT
, INT32
, 1, 1)
399 js_Arguments(JSContext
* cx
, JSObject
* parent
, JSObject
* cached
)
403 return js_NewObject(cx
, &js_ArgumentsClass
, NULL
, NULL
, 0);
405 JS_DEFINE_CALLINFO_3(extern, OBJECT
, js_Arguments
, CONTEXT
, OBJECT
, OBJECT
, 0, 0)
408 js_NewNullClosure(JSContext
* cx
, JSObject
* funobj
, JSObject
* proto
, JSObject
* parent
)
410 JS_ASSERT(HAS_FUNCTION_CLASS(funobj
));
411 JS_ASSERT(HAS_FUNCTION_CLASS(proto
));
412 JS_ASSERT(JS_ON_TRACE(cx
));
414 JSFunction
*fun
= (JSFunction
*) funobj
;
415 JS_ASSERT(GET_FUNCTION_PRIVATE(cx
, funobj
) == fun
);
417 JSObject
* closure
= (JSObject
*) js_NewGCThing(cx
, GCX_OBJECT
, sizeof(JSObject
));
421 js_HoldScope(OBJ_SCOPE(proto
));
422 closure
->map
= proto
->map
;
423 closure
->classword
= jsuword(&js_FunctionClass
);
424 closure
->fslots
[JSSLOT_PROTO
] = OBJECT_TO_JSVAL(proto
);
425 closure
->fslots
[JSSLOT_PARENT
] = OBJECT_TO_JSVAL(parent
);
426 closure
->fslots
[JSSLOT_PRIVATE
] = PRIVATE_TO_JSVAL(fun
);
427 for (unsigned i
= JSSLOT_PRIVATE
+ 1; i
!= JS_INITIAL_NSLOTS
; ++i
)
428 closure
->fslots
[i
] = JSVAL_VOID
;
429 closure
->dslots
= NULL
;
432 JS_DEFINE_CALLINFO_4(extern, OBJECT
, js_NewNullClosure
, CONTEXT
, OBJECT
, OBJECT
, OBJECT
, 0, 0)