diff options
Diffstat (limited to 'js/src/jsbuiltins.cpp')
-rw-r--r-- | js/src/jsbuiltins.cpp | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/js/src/jsbuiltins.cpp b/js/src/jsbuiltins.cpp new file mode 100644 index 0000000..605d287 --- /dev/null +++ b/js/src/jsbuiltins.cpp @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; -*- + * vim: set ts=4 sw=4 et tw=99: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * May 28, 2008. + * + * The Initial Developer of the Original Code is + * Andreas Gal <gal@mozilla.com> + * + * Contributor(s): + * Brendan Eich <brendan@mozilla.org> + * Mike Shaver <shaver@mozilla.org> + * David Anderson <danderson@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <math.h> + +#include "jsapi.h" +#include "jsstdint.h" +#include "jsarray.h" +#include "jsbool.h" +#include "jscntxt.h" +#include "jsgc.h" +#include "jsiter.h" +#include "jsnum.h" +#include "jslibmath.h" +#include "jsmath.h" +#include "jsnum.h" +#include "prmjtime.h" +#include "jsdate.h" +#include "jsscope.h" +#include "jsstr.h" +#include "jsbuiltins.h" +#include "jstracer.h" +#include "jsvector.h" + +#include "jsatominlines.h" +#include "jsobjinlines.h" +#include "jsscopeinlines.h" +#include "jscntxtinlines.h" + +using namespace avmplus; +using namespace nanojit; +using namespace js; + +JS_FRIEND_API(void) +js_SetTraceableNativeFailed(JSContext *cx) +{ + /* + * We might not be on trace (we might have deep bailed) so we hope + * cx->compartment is correct. + */ + SetBuiltinError(JS_TRACE_MONITOR_FROM_CONTEXT(cx)); +} + +/* + * NB: bool FASTCALL is not compatible with Nanojit's calling convention usage. + * Do not use bool FASTCALL, use JSBool only! + */ + +jsdouble FASTCALL +js_dmod(jsdouble a, jsdouble b) +{ + if (b == 0.0) { + jsdpun u; + u.s.hi = JSDOUBLE_HI32_NAN; + u.s.lo = JSDOUBLE_LO32_NAN; + return u.d; + } + return js_fmod(a, b); +} +JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_dmod, DOUBLE, DOUBLE, 1, ACCSET_NONE) + +int32 FASTCALL +js_imod(int32 a, int32 b) +{ + if (a < 0 || b <= 0) + return -1; + int r = a % b; + return r; +} +JS_DEFINE_CALLINFO_2(extern, INT32, js_imod, INT32, INT32, 1, ACCSET_NONE) + +#if JS_BITS_PER_WORD == 32 + +jsdouble FASTCALL +js_UnboxDouble(uint32 tag, uint32 payload) +{ + if (tag == JSVAL_TAG_INT32) + return (double)(int32)payload; + + jsval_layout l; + l.s.tag = (JSValueTag)tag; + l.s.payload.u32 = payload; + return l.asDouble; +} +JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_UnboxDouble, UINT32, UINT32, 1, ACCSET_NONE) + +int32 FASTCALL +js_UnboxInt32(uint32 tag, uint32 payload) +{ + if (tag == JSVAL_TAG_INT32) + return (int32)payload; + + jsval_layout l; + l.s.tag = (JSValueTag)tag; + l.s.payload.u32 = payload; + return js_DoubleToECMAInt32(l.asDouble); +} +JS_DEFINE_CALLINFO_2(extern, INT32, js_UnboxInt32, UINT32, UINT32, 1, ACCSET_NONE) + +#elif JS_BITS_PER_WORD == 64 + +jsdouble FASTCALL +js_UnboxDouble(Value v) +{ + if (v.isInt32()) + return (jsdouble)v.toInt32(); + return v.toDouble(); +} +JS_DEFINE_CALLINFO_1(extern, DOUBLE, js_UnboxDouble, JSVAL, 1, ACCSET_NONE) + +int32 FASTCALL +js_UnboxInt32(Value v) +{ + if (v.isInt32()) + return v.toInt32(); + return js_DoubleToECMAInt32(v.toDouble()); +} +JS_DEFINE_CALLINFO_1(extern, INT32, js_UnboxInt32, VALUE, 1, ACCSET_NONE) + +#endif + +int32 FASTCALL +js_DoubleToInt32(jsdouble d) +{ + return js_DoubleToECMAInt32(d); +} +JS_DEFINE_CALLINFO_1(extern, INT32, js_DoubleToInt32, DOUBLE, 1, ACCSET_NONE) + +uint32 FASTCALL +js_DoubleToUint32(jsdouble d) +{ + return js_DoubleToECMAUint32(d); +} +JS_DEFINE_CALLINFO_1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, ACCSET_NONE) + +/* + * js_StringToNumber and js_StringToInt32 store into their second argument, so + * they need to be annotated accordingly. To be future-proof, we use + * ACCSET_STORE_ANY so that new callers don't have to remember to update the + * annotation. + */ +jsdouble FASTCALL +js_StringToNumber(JSContext* cx, JSString* str, JSBool *ok) +{ + double out = 0; /* silence warnings. */ + *ok = StringToNumberType<jsdouble>(cx, str, &out); + return out; +} +JS_DEFINE_CALLINFO_3(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, BOOLPTR, + 0, ACCSET_STORE_ANY) + +int32 FASTCALL +js_StringToInt32(JSContext* cx, JSString* str, JSBool *ok) +{ + int32 out = 0; /* silence warnings. */ + *ok = StringToNumberType<int32>(cx, str, &out); + return out; +} +JS_DEFINE_CALLINFO_3(extern, INT32, js_StringToInt32, CONTEXT, STRING, BOOLPTR, + 0, ACCSET_STORE_ANY) + +/* Nb: it's always safe to set isDefinitelyAtom to false if you're unsure or don't know. */ +static inline JSBool +AddPropertyHelper(JSContext* cx, JSObject* obj, Shape* shape, bool isDefinitelyAtom) +{ + JS_ASSERT(shape->previous() == obj->lastProperty()); + + if (obj->nativeEmpty()) { + if (!obj->ensureClassReservedSlotsForEmptyObject(cx)) + return false; + } + + uint32 slot; + slot = shape->slot; + JS_ASSERT(slot == obj->slotSpan()); + + if (slot < obj->numSlots()) { + JS_ASSERT(obj->getSlot(slot).isUndefined()); + } else { + if (!obj->allocSlot(cx, &slot)) + return false; + JS_ASSERT(slot == shape->slot); + } + + obj->extend(cx, shape, isDefinitelyAtom); + return !js_IsPropertyCacheDisabled(cx); +} + +JSBool FASTCALL +js_AddProperty(JSContext* cx, JSObject* obj, Shape* shape) +{ + return AddPropertyHelper(cx, obj, shape, /* isDefinitelyAtom = */false); +} +JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddProperty, CONTEXT, OBJECT, SHAPE, 0, ACCSET_STORE_ANY) + +JSBool FASTCALL +js_AddAtomProperty(JSContext* cx, JSObject* obj, Shape* shape) +{ + return AddPropertyHelper(cx, obj, shape, /* isDefinitelyAtom = */true); +} +JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddAtomProperty, CONTEXT, OBJECT, SHAPE, 0, ACCSET_STORE_ANY) + +static JSBool +HasProperty(JSContext* cx, JSObject* obj, jsid id) +{ + // Check that we know how the lookup op will behave. + for (JSObject* pobj = obj; pobj; pobj = pobj->getProto()) { + if (pobj->getOps()->lookupProperty) + return JS_NEITHER; + Class* clasp = pobj->getClass(); + if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass) + return JS_NEITHER; + } + + JSObject* obj2; + JSProperty* prop; + if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0) + return JS_NEITHER; + return prop != NULL; +} + +JSBool FASTCALL +js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr) +{ + JSAtom *atom = js_AtomizeString(cx, idstr, 0); + if (!atom) + return JS_NEITHER; + + return HasProperty(cx, obj, ATOM_TO_JSID(atom)); +} +JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedProperty, CONTEXT, OBJECT, STRING, + 0, ACCSET_STORE_ANY) + +JSBool FASTCALL +js_HasNamedPropertyInt32(JSContext* cx, JSObject* obj, int32 index) +{ + jsid id; + if (!js_Int32ToId(cx, index, &id)) + return JS_NEITHER; + + return HasProperty(cx, obj, id); +} +JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, INT32, + 0, ACCSET_STORE_ANY) + +JSString* FASTCALL +js_TypeOfObject(JSContext* cx, JSObject* obj) +{ + JS_ASSERT(obj); + return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[obj->typeOf(cx)]); +} +JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT, 1, ACCSET_NONE) + +JSString* FASTCALL +js_BooleanIntToString(JSContext *cx, int32 unboxed) +{ + JS_ASSERT(uint32(unboxed) <= 1); + return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[unboxed]); +} +JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanIntToString, CONTEXT, INT32, 1, ACCSET_NONE) + +JSObject* FASTCALL +js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent) +{ + JS_ASSERT(funobj->isFunction()); + JS_ASSERT(proto->isFunction()); + JS_ASSERT(JS_ON_TRACE(cx)); + + JSFunction *fun = (JSFunction*) funobj; + JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun); + + JSObject* closure = js_NewGCObject(cx, gc::FINALIZE_OBJECT2); + if (!closure) + return NULL; + + if (!closure->initSharingEmptyShape(cx, &js_FunctionClass, proto, parent, + fun, gc::FINALIZE_OBJECT2)) { + return NULL; + } + return closure; +} +JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT, + 0, ACCSET_STORE_ANY) + |