1 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; -*- |
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; -*- |
2 |
* vim: set ts=8 sw=4 et tw=99: |
* vim: set ts=8 sw=4 et tw=99: |
3 |
* |
* |
4 |
* ***** BEGIN LICENSE BLOCK ***** |
* ***** BEGIN LICENSE BLOCK ***** |
39 |
* |
* |
40 |
* ***** END LICENSE BLOCK ***** */ |
* ***** END LICENSE BLOCK ***** */ |
41 |
|
|
|
#include "jsstddef.h" |
|
42 |
#include <math.h> |
#include <math.h> |
43 |
|
|
44 |
#include "jsapi.h" |
#include "jsapi.h" |
45 |
|
#include "jsstdint.h" |
46 |
#include "jsarray.h" |
#include "jsarray.h" |
47 |
#include "jsbool.h" |
#include "jsbool.h" |
48 |
#include "jscntxt.h" |
#include "jscntxt.h" |
49 |
#include "jsgc.h" |
#include "jsgc.h" |
50 |
#include "jsiter.h" |
#include "jsiter.h" |
51 |
|
#include "jsnum.h" |
52 |
#include "jslibmath.h" |
#include "jslibmath.h" |
53 |
#include "jsmath.h" |
#include "jsmath.h" |
54 |
#include "jsnum.h" |
#include "jsnum.h" |
58 |
#include "jsstr.h" |
#include "jsstr.h" |
59 |
#include "jsbuiltins.h" |
#include "jsbuiltins.h" |
60 |
#include "jstracer.h" |
#include "jstracer.h" |
61 |
|
#include "jsvector.h" |
62 |
|
|
63 |
|
#include "jsatominlines.h" |
64 |
|
#include "jsobjinlines.h" |
65 |
|
|
66 |
using namespace avmplus; |
using namespace avmplus; |
67 |
using namespace nanojit; |
using namespace nanojit; |
88 |
u.s.lo = 0xffffffff; |
u.s.lo = 0xffffffff; |
89 |
return u.d; |
return u.d; |
90 |
} |
} |
91 |
jsdouble r; |
return js_fmod(a, b); |
|
#ifdef XP_WIN |
|
|
/* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */ |
|
|
if (JSDOUBLE_IS_FINITE(a) && JSDOUBLE_IS_INFINITE(b)) |
|
|
r = a; |
|
|
else |
|
|
#endif |
|
|
r = fmod(a, b); |
|
|
return r; |
|
92 |
} |
} |
93 |
|
JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_dmod, DOUBLE, DOUBLE, 1, 1) |
94 |
|
|
95 |
int32 FASTCALL |
int32 FASTCALL |
96 |
js_imod(int32 a, int32 b) |
js_imod(int32 a, int32 b) |
100 |
int r = a % b; |
int r = a % b; |
101 |
return r; |
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 |
/* 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 |
they either interact with the GC and depend on Spidermonkey's 32-bit |
118 |
return JSVAL_ERROR_COOKIE; |
return JSVAL_ERROR_COOKIE; |
119 |
return v; |
return v; |
120 |
} |
} |
121 |
|
JS_DEFINE_CALLINFO_2(extern, JSVAL, js_BoxDouble, CONTEXT, DOUBLE, 1, 1) |
122 |
|
|
123 |
jsval FASTCALL |
jsval FASTCALL |
124 |
js_BoxInt32(JSContext* cx, int32 i) |
js_BoxInt32(JSContext* cx, int32 i) |
131 |
if (!js_NewDoubleInRootedValue(cx, d, &v)) |
if (!js_NewDoubleInRootedValue(cx, d, &v)) |
132 |
return JSVAL_ERROR_COOKIE; |
return JSVAL_ERROR_COOKIE; |
133 |
return v; |
return v; |
134 |
} |
} |
135 |
|
JS_DEFINE_CALLINFO_2(extern, JSVAL, js_BoxInt32, CONTEXT, INT32, 1, 1) |
136 |
|
|
137 |
jsdouble FASTCALL |
jsdouble FASTCALL |
138 |
js_UnboxDouble(jsval v) |
js_UnboxDouble(jsval v) |
141 |
return (jsdouble)JSVAL_TO_INT(v); |
return (jsdouble)JSVAL_TO_INT(v); |
142 |
return *JSVAL_TO_DOUBLE(v); |
return *JSVAL_TO_DOUBLE(v); |
143 |
} |
} |
144 |
|
JS_DEFINE_CALLINFO_1(extern, DOUBLE, js_UnboxDouble, JSVAL, 1, 1) |
145 |
|
|
146 |
int32 FASTCALL |
int32 FASTCALL |
147 |
js_UnboxInt32(jsval v) |
js_UnboxInt32(jsval v) |
150 |
return JSVAL_TO_INT(v); |
return JSVAL_TO_INT(v); |
151 |
return js_DoubleToECMAInt32(*JSVAL_TO_DOUBLE(v)); |
return js_DoubleToECMAInt32(*JSVAL_TO_DOUBLE(v)); |
152 |
} |
} |
153 |
|
JS_DEFINE_CALLINFO_1(extern, INT32, js_UnboxInt32, JSVAL, 1, 1) |
154 |
|
|
155 |
int32 FASTCALL |
int32 FASTCALL |
156 |
js_DoubleToInt32(jsdouble d) |
js_DoubleToInt32(jsdouble d) |
157 |
{ |
{ |
158 |
return js_DoubleToECMAInt32(d); |
return js_DoubleToECMAInt32(d); |
159 |
} |
} |
160 |
|
JS_DEFINE_CALLINFO_1(extern, INT32, js_DoubleToInt32, DOUBLE, 1, 1) |
161 |
|
|
162 |
uint32 FASTCALL |
uint32 FASTCALL |
163 |
js_DoubleToUint32(jsdouble d) |
js_DoubleToUint32(jsdouble d) |
164 |
{ |
{ |
165 |
return js_DoubleToECMAUint32(d); |
return js_DoubleToECMAUint32(d); |
166 |
} |
} |
167 |
|
JS_DEFINE_CALLINFO_1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, 1) |
168 |
|
|
169 |
jsdouble FASTCALL |
jsdouble FASTCALL |
170 |
js_StringToNumber(JSContext* cx, JSString* str) |
js_StringToNumber(JSContext* cx, JSString* str) |
174 |
const jschar* ep; |
const jschar* ep; |
175 |
jsdouble d; |
jsdouble d; |
176 |
|
|
177 |
JSSTRING_CHARS_AND_END(str, bp, end); |
str->getCharsAndEnd(bp, end); |
178 |
if ((!js_strtod(cx, bp, end, &ep, &d) || |
if ((!js_strtod(cx, bp, end, &ep, &d) || |
179 |
js_SkipWhiteSpace(ep, end) != end) && |
js_SkipWhiteSpace(ep, end) != end) && |
180 |
(!js_strtointeger(cx, bp, end, &ep, 0, &d) || |
(!js_strtointeger(cx, bp, end, &ep, 0, &d) || |
183 |
} |
} |
184 |
return d; |
return d; |
185 |
} |
} |
186 |
|
JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, 1, 1) |
187 |
|
|
188 |
int32 FASTCALL |
int32 FASTCALL |
189 |
js_StringToInt32(JSContext* cx, JSString* str) |
js_StringToInt32(JSContext* cx, JSString* str) |
192 |
const jschar* end; |
const jschar* end; |
193 |
const jschar* ep; |
const jschar* ep; |
194 |
jsdouble d; |
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 |
JSSTRING_CHARS_AND_END(str, bp, end); |
str->getCharsAndEnd(bp, end); |
204 |
if ((!js_strtod(cx, bp, end, &ep, &d) || |
if ((!js_strtod(cx, bp, end, &ep, &d) || |
205 |
js_SkipWhiteSpace(ep, end) != end) && |
js_SkipWhiteSpace(ep, end) != end) && |
206 |
(!js_strtointeger(cx, bp, end, &ep, 0, &d) || |
(!js_strtointeger(cx, bp, end, &ep, 0, &d) || |
209 |
} |
} |
210 |
return js_DoubleToECMAInt32(d); |
return js_DoubleToECMAInt32(d); |
211 |
} |
} |
212 |
|
JS_DEFINE_CALLINFO_2(extern, INT32, js_StringToInt32, CONTEXT, STRING, 1, 1) |
213 |
|
|
214 |
SideExit* FASTCALL |
SideExit* FASTCALL |
215 |
js_CallTree(InterpState* state, Fragment* f) |
js_CallTree(InterpState* state, Fragment* f) |
245 |
|
|
246 |
return lr; |
return lr; |
247 |
} |
} |
248 |
|
JS_DEFINE_CALLINFO_2(extern, SIDEEXIT, js_CallTree, INTERPSTATE, FRAGMENT, 0, 0) |
249 |
|
|
250 |
JSBool FASTCALL |
JSBool FASTCALL |
251 |
js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop) |
js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop) |
252 |
{ |
{ |
253 |
JS_ASSERT(OBJ_IS_NATIVE(obj)); |
JS_ASSERT(OBJ_IS_NATIVE(obj)); |
|
JS_ASSERT(SPROP_HAS_STUB_SETTER(sprop)); |
|
|
|
|
254 |
JS_LOCK_OBJ(cx, obj); |
JS_LOCK_OBJ(cx, obj); |
255 |
|
|
256 |
JSScope* scope = OBJ_SCOPE(obj); |
JSScope* scope = OBJ_SCOPE(obj); |
257 |
uint32 slot; |
uint32 slot; |
258 |
if (scope->object == obj) { |
if (scope->owned()) { |
259 |
JS_ASSERT(!SCOPE_HAS_PROPERTY(scope, sprop)); |
JS_ASSERT(!scope->has(sprop)); |
260 |
} else { |
} else { |
261 |
scope = js_GetMutableScope(cx, obj); |
scope = js_GetMutableScope(cx, obj); |
262 |
if (!scope) |
if (!scope) |
278 |
} |
} |
279 |
} |
} |
280 |
|
|
281 |
js_ExtendScopeShape(cx, scope, sprop); |
scope->extend(cx, sprop); |
|
++scope->entryCount; |
|
|
scope->lastProp = sprop; |
|
282 |
} else { |
} else { |
283 |
JSScopeProperty *sprop2 = js_AddScopeProperty(cx, scope, sprop->id, |
JSScopeProperty *sprop2 = scope->add(cx, sprop->id, |
284 |
sprop->getter, |
sprop->getter, sprop->setter, |
285 |
sprop->setter, |
SPROP_INVALID_SLOT, sprop->attrs, |
286 |
SPROP_INVALID_SLOT, |
sprop->flags, sprop->shortid); |
|
sprop->attrs, |
|
|
sprop->flags, |
|
|
sprop->shortid); |
|
287 |
if (sprop2 != sprop) |
if (sprop2 != sprop) |
288 |
goto exit_trace; |
goto exit_trace; |
289 |
} |
} |
298 |
JS_UNLOCK_SCOPE(cx, scope); |
JS_UNLOCK_SCOPE(cx, scope); |
299 |
return JS_FALSE; |
return JS_FALSE; |
300 |
} |
} |
301 |
|
JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddProperty, CONTEXT, OBJECT, SCOPEPROP, 0, 0) |
302 |
|
|
303 |
static JSBool |
static JSBool |
304 |
HasProperty(JSContext* cx, JSObject* obj, jsid id) |
HasProperty(JSContext* cx, JSObject* obj, jsid id) |
306 |
// Check that we know how the lookup op will behave. |
// Check that we know how the lookup op will behave. |
307 |
for (JSObject* pobj = obj; pobj; pobj = OBJ_GET_PROTO(cx, pobj)) { |
for (JSObject* pobj = obj; pobj; pobj = OBJ_GET_PROTO(cx, pobj)) { |
308 |
if (pobj->map->ops->lookupProperty != js_LookupProperty) |
if (pobj->map->ops->lookupProperty != js_LookupProperty) |
309 |
return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID); |
return JSVAL_TO_SPECIAL(JSVAL_VOID); |
310 |
JSClass* clasp = OBJ_GET_CLASS(cx, pobj); |
JSClass* clasp = OBJ_GET_CLASS(cx, pobj); |
311 |
if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass) |
if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass) |
312 |
return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID); |
return JSVAL_TO_SPECIAL(JSVAL_VOID); |
313 |
} |
} |
314 |
|
|
315 |
JSObject* obj2; |
JSObject* obj2; |
316 |
JSProperty* prop; |
JSProperty* prop; |
317 |
if (!js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop)) |
if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0) |
318 |
return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID); |
return JSVAL_TO_SPECIAL(JSVAL_VOID); |
319 |
if (prop) |
if (prop) |
320 |
OBJ_DROP_PROPERTY(cx, obj2, prop); |
obj2->dropProperty(cx, prop); |
321 |
return prop != NULL; |
return prop != NULL; |
322 |
} |
} |
323 |
|
|
330 |
|
|
331 |
return HasProperty(cx, obj, id); |
return HasProperty(cx, obj, id); |
332 |
} |
} |
333 |
|
JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedProperty, CONTEXT, OBJECT, STRING, 0, 0) |
334 |
|
|
335 |
JSBool FASTCALL |
JSBool FASTCALL |
336 |
js_HasNamedPropertyInt32(JSContext* cx, JSObject* obj, int32 index) |
js_HasNamedPropertyInt32(JSContext* cx, JSObject* obj, int32 index) |
341 |
|
|
342 |
return HasProperty(cx, obj, id); |
return HasProperty(cx, obj, id); |
343 |
} |
} |
344 |
|
JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, INT32, 0, 0) |
|
jsval FASTCALL |
|
|
js_CallGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop) |
|
|
{ |
|
|
JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop)); |
|
|
jsval v; |
|
|
if (!js_GetSprop(cx, sprop, obj, &v)) |
|
|
return JSVAL_ERROR_COOKIE; |
|
|
return v; |
|
|
} |
|
345 |
|
|
346 |
JSString* FASTCALL |
JSString* FASTCALL |
347 |
js_TypeOfObject(JSContext* cx, JSObject* obj) |
js_TypeOfObject(JSContext* cx, JSObject* obj) |
349 |
JSType type = JS_TypeOfValue(cx, OBJECT_TO_JSVAL(obj)); |
JSType type = JS_TypeOfValue(cx, OBJECT_TO_JSVAL(obj)); |
350 |
return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]); |
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 |
JSString* FASTCALL |
355 |
js_TypeOfBoolean(JSContext* cx, int32 unboxed) |
js_TypeOfBoolean(JSContext* cx, int32 unboxed) |
356 |
{ |
{ |
357 |
/* Watch out for pseudo-booleans. */ |
/* Watch out for pseudo-booleans. */ |
358 |
jsval boxed = PSEUDO_BOOLEAN_TO_JSVAL(unboxed); |
jsval boxed = SPECIAL_TO_JSVAL(unboxed); |
359 |
JS_ASSERT(JSVAL_IS_VOID(boxed) || JSVAL_IS_BOOLEAN(boxed)); |
JS_ASSERT(JSVAL_IS_VOID(boxed) || JSVAL_IS_BOOLEAN(boxed)); |
360 |
JSType type = JS_TypeOfValue(cx, boxed); |
JSType type = JS_TypeOfValue(cx, boxed); |
361 |
return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]); |
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 |
jsdouble FASTCALL |
366 |
js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed) |
js_BooleanOrUndefinedToNumber(JSContext* cx, int32 unboxed) |
367 |
{ |
{ |
368 |
if (unboxed == JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID)) |
if (unboxed == JSVAL_TO_SPECIAL(JSVAL_VOID)) |
369 |
return js_NaN; |
return js_NaN; |
370 |
JS_ASSERT(unboxed == JS_TRUE || unboxed == JS_FALSE); |
JS_ASSERT(unboxed == JS_TRUE || unboxed == JS_FALSE); |
371 |
return unboxed; |
return unboxed; |
372 |
} |
} |
373 |
|
JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_BooleanOrUndefinedToNumber, CONTEXT, INT32, 1, 1) |
374 |
|
|
375 |
JSString* FASTCALL |
JSString* FASTCALL |
376 |
js_BooleanOrUndefinedToString(JSContext *cx, int32 unboxed) |
js_BooleanOrUndefinedToString(JSContext *cx, int32 unboxed) |
378 |
JS_ASSERT(uint32(unboxed) <= 2); |
JS_ASSERT(uint32(unboxed) <= 2); |
379 |
return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[unboxed]); |
return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[unboxed]); |
380 |
} |
} |
381 |
|
JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanOrUndefinedToString, CONTEXT, INT32, 1, 1) |
|
JSObject* FASTCALL |
|
|
js_Arguments(JSContext* cx) |
|
|
{ |
|
|
return NULL; |
|
|
} |
|
382 |
|
|
383 |
JSObject* FASTCALL |
JSObject* FASTCALL |
384 |
js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent) |
js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent) |
390 |
JSFunction *fun = (JSFunction*) funobj; |
JSFunction *fun = (JSFunction*) funobj; |
391 |
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun); |
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun); |
392 |
|
|
393 |
JSObject* closure = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject)); |
JSObject* closure = js_NewGCObject(cx, GCX_OBJECT); |
394 |
if (!closure) |
if (!closure) |
395 |
return NULL; |
return NULL; |
396 |
|
|
397 |
js_HoldScope(OBJ_SCOPE(proto)); |
closure->initSharingEmptyScope(&js_FunctionClass, proto, parent, |
398 |
closure->map = proto->map; |
reinterpret_cast<jsval>(fun)); |
|
closure->classword = jsuword(&js_FunctionClass); |
|
|
closure->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto); |
|
|
closure->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent); |
|
|
closure->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun); |
|
|
for (unsigned i = JSSLOT_PRIVATE + 1; i != JS_INITIAL_NSLOTS; ++i) |
|
|
closure->fslots[i] = JSVAL_VOID; |
|
|
closure->dslots = NULL; |
|
399 |
return closure; |
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 |
#define BUILTIN1 JS_DEFINE_CALLINFO_1 |
|
416 |
#define BUILTIN2 JS_DEFINE_CALLINFO_2 |
/* Allocate buffer. */ |
417 |
#define BUILTIN3 JS_DEFINE_CALLINFO_3 |
if (numChar & js::tl::MulOverflowMask<sizeof(jschar)>::result) |
418 |
#define BUILTIN4 JS_DEFINE_CALLINFO_4 |
return NULL; |
419 |
#define BUILTIN5 JS_DEFINE_CALLINFO_5 |
jschar *buf = (jschar *)cx->malloc(numChar * sizeof(jschar)); |
420 |
#include "builtins.tbl" |
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) |