Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * vim: set ts=8 sts=4 et sw=4 tw=99: |
michael@0 | 3 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #ifndef jsfriendapi_h |
michael@0 | 8 | #define jsfriendapi_h |
michael@0 | 9 | |
michael@0 | 10 | #include "mozilla/Casting.h" |
michael@0 | 11 | #include "mozilla/MemoryReporting.h" |
michael@0 | 12 | #include "mozilla/TypedEnum.h" |
michael@0 | 13 | |
michael@0 | 14 | #include "jsbytecode.h" |
michael@0 | 15 | #include "jspubtd.h" |
michael@0 | 16 | |
michael@0 | 17 | #include "js/CallArgs.h" |
michael@0 | 18 | #include "js/CallNonGenericMethod.h" |
michael@0 | 19 | #include "js/Class.h" |
michael@0 | 20 | |
michael@0 | 21 | /* |
michael@0 | 22 | * This macro checks if the stack pointer has exceeded a given limit. If |
michael@0 | 23 | * |tolerance| is non-zero, it returns true only if the stack pointer has |
michael@0 | 24 | * exceeded the limit by more than |tolerance| bytes. |
michael@0 | 25 | */ |
michael@0 | 26 | #if JS_STACK_GROWTH_DIRECTION > 0 |
michael@0 | 27 | # define JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, sp, tolerance) \ |
michael@0 | 28 | ((uintptr_t)(sp) < (limit)+(tolerance)) |
michael@0 | 29 | #else |
michael@0 | 30 | # define JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, sp, tolerance) \ |
michael@0 | 31 | ((uintptr_t)(sp) > (limit)-(tolerance)) |
michael@0 | 32 | #endif |
michael@0 | 33 | |
michael@0 | 34 | #define JS_CHECK_STACK_SIZE(limit, lval) JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, lval, 0) |
michael@0 | 35 | |
michael@0 | 36 | class JSAtom; |
michael@0 | 37 | struct JSErrorFormatString; |
michael@0 | 38 | class JSLinearString; |
michael@0 | 39 | struct JSJitInfo; |
michael@0 | 40 | class JSErrorReport; |
michael@0 | 41 | |
michael@0 | 42 | namespace JS { |
michael@0 | 43 | template <class T> |
michael@0 | 44 | class Heap; |
michael@0 | 45 | } /* namespace JS */ |
michael@0 | 46 | |
michael@0 | 47 | namespace js { |
michael@0 | 48 | class JS_FRIEND_API(BaseProxyHandler); |
michael@0 | 49 | } /* namespace js */ |
michael@0 | 50 | |
michael@0 | 51 | extern JS_FRIEND_API(void) |
michael@0 | 52 | JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data); |
michael@0 | 53 | |
michael@0 | 54 | extern JS_FRIEND_API(JSString *) |
michael@0 | 55 | JS_GetAnonymousString(JSRuntime *rt); |
michael@0 | 56 | |
michael@0 | 57 | extern JS_FRIEND_API(void) |
michael@0 | 58 | JS_SetIsWorkerRuntime(JSRuntime *rt); |
michael@0 | 59 | |
michael@0 | 60 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 61 | JS_FindCompilationScope(JSContext *cx, JS::HandleObject obj); |
michael@0 | 62 | |
michael@0 | 63 | extern JS_FRIEND_API(JSFunction *) |
michael@0 | 64 | JS_GetObjectFunction(JSObject *obj); |
michael@0 | 65 | |
michael@0 | 66 | extern JS_FRIEND_API(bool) |
michael@0 | 67 | JS_SplicePrototype(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto); |
michael@0 | 68 | |
michael@0 | 69 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 70 | JS_NewObjectWithUniqueType(JSContext *cx, const JSClass *clasp, JS::HandleObject proto, |
michael@0 | 71 | JS::HandleObject parent); |
michael@0 | 72 | |
michael@0 | 73 | extern JS_FRIEND_API(uint32_t) |
michael@0 | 74 | JS_ObjectCountDynamicSlots(JS::HandleObject obj); |
michael@0 | 75 | |
michael@0 | 76 | extern JS_FRIEND_API(size_t) |
michael@0 | 77 | JS_SetProtoCalled(JSContext *cx); |
michael@0 | 78 | |
michael@0 | 79 | extern JS_FRIEND_API(size_t) |
michael@0 | 80 | JS_GetCustomIteratorCount(JSContext *cx); |
michael@0 | 81 | |
michael@0 | 82 | extern JS_FRIEND_API(bool) |
michael@0 | 83 | JS_NondeterministicGetWeakMapKeys(JSContext *cx, JS::HandleObject obj, JS::MutableHandleObject ret); |
michael@0 | 84 | |
michael@0 | 85 | /* |
michael@0 | 86 | * Determine whether the given object is backed by a DeadObjectProxy. |
michael@0 | 87 | * |
michael@0 | 88 | * Such objects hold no other objects (they have no outgoing reference edges) |
michael@0 | 89 | * and will throw if you touch them (e.g. by reading/writing a property). |
michael@0 | 90 | */ |
michael@0 | 91 | extern JS_FRIEND_API(bool) |
michael@0 | 92 | JS_IsDeadWrapper(JSObject *obj); |
michael@0 | 93 | |
michael@0 | 94 | /* |
michael@0 | 95 | * Used by the cycle collector to trace through the shape and all |
michael@0 | 96 | * shapes it reaches, marking all non-shape children found in the |
michael@0 | 97 | * process. Uses bounded stack space. |
michael@0 | 98 | */ |
michael@0 | 99 | extern JS_FRIEND_API(void) |
michael@0 | 100 | JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape); |
michael@0 | 101 | |
michael@0 | 102 | enum { |
michael@0 | 103 | JS_TELEMETRY_GC_REASON, |
michael@0 | 104 | JS_TELEMETRY_GC_IS_COMPARTMENTAL, |
michael@0 | 105 | JS_TELEMETRY_GC_MS, |
michael@0 | 106 | JS_TELEMETRY_GC_MAX_PAUSE_MS, |
michael@0 | 107 | JS_TELEMETRY_GC_MARK_MS, |
michael@0 | 108 | JS_TELEMETRY_GC_SWEEP_MS, |
michael@0 | 109 | JS_TELEMETRY_GC_MARK_ROOTS_MS, |
michael@0 | 110 | JS_TELEMETRY_GC_MARK_GRAY_MS, |
michael@0 | 111 | JS_TELEMETRY_GC_SLICE_MS, |
michael@0 | 112 | JS_TELEMETRY_GC_MMU_50, |
michael@0 | 113 | JS_TELEMETRY_GC_RESET, |
michael@0 | 114 | JS_TELEMETRY_GC_INCREMENTAL_DISABLED, |
michael@0 | 115 | JS_TELEMETRY_GC_NON_INCREMENTAL, |
michael@0 | 116 | JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, |
michael@0 | 117 | JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS |
michael@0 | 118 | }; |
michael@0 | 119 | |
michael@0 | 120 | typedef void |
michael@0 | 121 | (* JSAccumulateTelemetryDataCallback)(int id, uint32_t sample); |
michael@0 | 122 | |
michael@0 | 123 | extern JS_FRIEND_API(void) |
michael@0 | 124 | JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback); |
michael@0 | 125 | |
michael@0 | 126 | extern JS_FRIEND_API(JSPrincipals *) |
michael@0 | 127 | JS_GetCompartmentPrincipals(JSCompartment *compartment); |
michael@0 | 128 | |
michael@0 | 129 | extern JS_FRIEND_API(void) |
michael@0 | 130 | JS_SetCompartmentPrincipals(JSCompartment *compartment, JSPrincipals *principals); |
michael@0 | 131 | |
michael@0 | 132 | /* Safe to call with input obj == nullptr. Returns non-nullptr iff obj != nullptr. */ |
michael@0 | 133 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 134 | JS_ObjectToInnerObject(JSContext *cx, JS::HandleObject obj); |
michael@0 | 135 | |
michael@0 | 136 | /* Requires obj != nullptr. */ |
michael@0 | 137 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 138 | JS_ObjectToOuterObject(JSContext *cx, JS::HandleObject obj); |
michael@0 | 139 | |
michael@0 | 140 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 141 | JS_CloneObject(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto, |
michael@0 | 142 | JS::HandleObject parent); |
michael@0 | 143 | |
michael@0 | 144 | extern JS_FRIEND_API(JSString *) |
michael@0 | 145 | JS_BasicObjectToString(JSContext *cx, JS::HandleObject obj); |
michael@0 | 146 | |
michael@0 | 147 | extern JS_FRIEND_API(bool) |
michael@0 | 148 | js_GetterOnlyPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool strict, |
michael@0 | 149 | JS::MutableHandleValue vp); |
michael@0 | 150 | |
michael@0 | 151 | JS_FRIEND_API(void) |
michael@0 | 152 | js_ReportOverRecursed(JSContext *maybecx); |
michael@0 | 153 | |
michael@0 | 154 | JS_FRIEND_API(bool) |
michael@0 | 155 | js_ObjectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue); |
michael@0 | 156 | |
michael@0 | 157 | JS_FRIEND_API(const char *) |
michael@0 | 158 | js_ObjectClassName(JSContext *cx, JS::HandleObject obj); |
michael@0 | 159 | |
michael@0 | 160 | namespace js { |
michael@0 | 161 | |
michael@0 | 162 | JS_FRIEND_API(bool) |
michael@0 | 163 | AddRawValueRoot(JSContext *cx, JS::Value *vp, const char *name); |
michael@0 | 164 | |
michael@0 | 165 | JS_FRIEND_API(void) |
michael@0 | 166 | RemoveRawValueRoot(JSContext *cx, JS::Value *vp); |
michael@0 | 167 | |
michael@0 | 168 | } /* namespace js */ |
michael@0 | 169 | |
michael@0 | 170 | #ifdef JS_DEBUG |
michael@0 | 171 | |
michael@0 | 172 | /* |
michael@0 | 173 | * Routines to print out values during debugging. These are FRIEND_API to help |
michael@0 | 174 | * the debugger find them and to support temporarily hacking js_Dump* calls |
michael@0 | 175 | * into other code. |
michael@0 | 176 | */ |
michael@0 | 177 | |
michael@0 | 178 | extern JS_FRIEND_API(void) |
michael@0 | 179 | js_DumpString(JSString *str); |
michael@0 | 180 | |
michael@0 | 181 | extern JS_FRIEND_API(void) |
michael@0 | 182 | js_DumpAtom(JSAtom *atom); |
michael@0 | 183 | |
michael@0 | 184 | extern JS_FRIEND_API(void) |
michael@0 | 185 | js_DumpObject(JSObject *obj); |
michael@0 | 186 | |
michael@0 | 187 | extern JS_FRIEND_API(void) |
michael@0 | 188 | js_DumpChars(const jschar *s, size_t n); |
michael@0 | 189 | #endif |
michael@0 | 190 | |
michael@0 | 191 | /* |
michael@0 | 192 | * Copies all own properties from |obj| to |target|. |obj| must be a "native" |
michael@0 | 193 | * object (that is to say, normal-ish - not an Array or a Proxy). |
michael@0 | 194 | * |
michael@0 | 195 | * This function immediately enters a compartment, and does not impose any |
michael@0 | 196 | * restrictions on the compartment of |cx|. |
michael@0 | 197 | */ |
michael@0 | 198 | extern JS_FRIEND_API(bool) |
michael@0 | 199 | JS_CopyPropertiesFrom(JSContext *cx, JS::HandleObject target, JS::HandleObject obj); |
michael@0 | 200 | |
michael@0 | 201 | /* |
michael@0 | 202 | * Single-property version of the above. This function asserts that an |own| |
michael@0 | 203 | * property of the given name exists on |obj|. |
michael@0 | 204 | * |
michael@0 | 205 | * On entry, |cx| must be same-compartment with |obj|. |
michael@0 | 206 | */ |
michael@0 | 207 | extern JS_FRIEND_API(bool) |
michael@0 | 208 | JS_CopyPropertyFrom(JSContext *cx, JS::HandleId id, JS::HandleObject target, |
michael@0 | 209 | JS::HandleObject obj); |
michael@0 | 210 | |
michael@0 | 211 | extern JS_FRIEND_API(bool) |
michael@0 | 212 | JS_WrapPropertyDescriptor(JSContext *cx, JS::MutableHandle<JSPropertyDescriptor> desc); |
michael@0 | 213 | |
michael@0 | 214 | extern JS_FRIEND_API(bool) |
michael@0 | 215 | JS_WrapAutoIdVector(JSContext *cx, JS::AutoIdVector &props); |
michael@0 | 216 | |
michael@0 | 217 | extern JS_FRIEND_API(bool) |
michael@0 | 218 | JS_EnumerateState(JSContext *cx, JS::HandleObject obj, JSIterateOp enum_op, |
michael@0 | 219 | JS::MutableHandleValue statep, JS::MutableHandleId idp); |
michael@0 | 220 | |
michael@0 | 221 | struct JSFunctionSpecWithHelp { |
michael@0 | 222 | const char *name; |
michael@0 | 223 | JSNative call; |
michael@0 | 224 | uint16_t nargs; |
michael@0 | 225 | uint16_t flags; |
michael@0 | 226 | const char *usage; |
michael@0 | 227 | const char *help; |
michael@0 | 228 | }; |
michael@0 | 229 | |
michael@0 | 230 | #define JS_FN_HELP(name,call,nargs,flags,usage,help) \ |
michael@0 | 231 | {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, usage, help} |
michael@0 | 232 | #define JS_FS_HELP_END \ |
michael@0 | 233 | {nullptr, nullptr, 0, 0, nullptr, nullptr} |
michael@0 | 234 | |
michael@0 | 235 | extern JS_FRIEND_API(bool) |
michael@0 | 236 | JS_DefineFunctionsWithHelp(JSContext *cx, JS::HandleObject obj, const JSFunctionSpecWithHelp *fs); |
michael@0 | 237 | |
michael@0 | 238 | namespace js { |
michael@0 | 239 | |
michael@0 | 240 | /* |
michael@0 | 241 | * Helper Macros for creating JSClasses that function as proxies. |
michael@0 | 242 | * |
michael@0 | 243 | * NB: The macro invocation must be surrounded by braces, so as to |
michael@0 | 244 | * allow for potention JSClass extensions. |
michael@0 | 245 | */ |
michael@0 | 246 | #define PROXY_MAKE_EXT(outerObject, innerObject, iteratorObject, \ |
michael@0 | 247 | isWrappedNative) \ |
michael@0 | 248 | { \ |
michael@0 | 249 | outerObject, \ |
michael@0 | 250 | innerObject, \ |
michael@0 | 251 | iteratorObject, \ |
michael@0 | 252 | isWrappedNative, \ |
michael@0 | 253 | js::proxy_WeakmapKeyDelegate \ |
michael@0 | 254 | } |
michael@0 | 255 | |
michael@0 | 256 | #define PROXY_CLASS_WITH_EXT(name, extraSlots, flags, callOp, constructOp, ext) \ |
michael@0 | 257 | { \ |
michael@0 | 258 | name, \ |
michael@0 | 259 | js::Class::NON_NATIVE | \ |
michael@0 | 260 | JSCLASS_IS_PROXY | \ |
michael@0 | 261 | JSCLASS_IMPLEMENTS_BARRIERS | \ |
michael@0 | 262 | JSCLASS_HAS_RESERVED_SLOTS(js::PROXY_MINIMUM_SLOTS + (extraSlots)) | \ |
michael@0 | 263 | flags, \ |
michael@0 | 264 | JS_PropertyStub, /* addProperty */ \ |
michael@0 | 265 | JS_DeletePropertyStub, /* delProperty */ \ |
michael@0 | 266 | JS_PropertyStub, /* getProperty */ \ |
michael@0 | 267 | JS_StrictPropertyStub, /* setProperty */ \ |
michael@0 | 268 | JS_EnumerateStub, \ |
michael@0 | 269 | JS_ResolveStub, \ |
michael@0 | 270 | js::proxy_Convert, \ |
michael@0 | 271 | js::proxy_Finalize, /* finalize */ \ |
michael@0 | 272 | callOp, /* call */ \ |
michael@0 | 273 | js::proxy_HasInstance, /* hasInstance */ \ |
michael@0 | 274 | constructOp, /* construct */ \ |
michael@0 | 275 | js::proxy_Trace, /* trace */ \ |
michael@0 | 276 | JS_NULL_CLASS_SPEC, \ |
michael@0 | 277 | ext, \ |
michael@0 | 278 | { \ |
michael@0 | 279 | js::proxy_LookupGeneric, \ |
michael@0 | 280 | js::proxy_LookupProperty, \ |
michael@0 | 281 | js::proxy_LookupElement, \ |
michael@0 | 282 | js::proxy_DefineGeneric, \ |
michael@0 | 283 | js::proxy_DefineProperty, \ |
michael@0 | 284 | js::proxy_DefineElement, \ |
michael@0 | 285 | js::proxy_GetGeneric, \ |
michael@0 | 286 | js::proxy_GetProperty, \ |
michael@0 | 287 | js::proxy_GetElement, \ |
michael@0 | 288 | js::proxy_SetGeneric, \ |
michael@0 | 289 | js::proxy_SetProperty, \ |
michael@0 | 290 | js::proxy_SetElement, \ |
michael@0 | 291 | js::proxy_GetGenericAttributes, \ |
michael@0 | 292 | js::proxy_SetGenericAttributes, \ |
michael@0 | 293 | js::proxy_DeleteProperty, \ |
michael@0 | 294 | js::proxy_DeleteElement, \ |
michael@0 | 295 | js::proxy_Watch, js::proxy_Unwatch, \ |
michael@0 | 296 | js::proxy_Slice, \ |
michael@0 | 297 | nullptr, /* enumerate */ \ |
michael@0 | 298 | nullptr, /* thisObject */ \ |
michael@0 | 299 | } \ |
michael@0 | 300 | } |
michael@0 | 301 | |
michael@0 | 302 | #define PROXY_CLASS_DEF(name, extraSlots, flags, callOp, constructOp) \ |
michael@0 | 303 | PROXY_CLASS_WITH_EXT(name, extraSlots, flags, callOp, constructOp, \ |
michael@0 | 304 | PROXY_MAKE_EXT( \ |
michael@0 | 305 | nullptr, /* outerObject */ \ |
michael@0 | 306 | nullptr, /* innerObject */ \ |
michael@0 | 307 | nullptr, /* iteratorObject */ \ |
michael@0 | 308 | false /* isWrappedNative */ \ |
michael@0 | 309 | )) |
michael@0 | 310 | |
michael@0 | 311 | /* |
michael@0 | 312 | * Proxy stubs, similar to JS_*Stub, for embedder proxy class definitions. |
michael@0 | 313 | * |
michael@0 | 314 | * NB: Should not be called directly. |
michael@0 | 315 | */ |
michael@0 | 316 | |
michael@0 | 317 | extern JS_FRIEND_API(bool) |
michael@0 | 318 | proxy_LookupGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp, |
michael@0 | 319 | JS::MutableHandle<Shape*> propp); |
michael@0 | 320 | extern JS_FRIEND_API(bool) |
michael@0 | 321 | proxy_LookupProperty(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name, |
michael@0 | 322 | JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp); |
michael@0 | 323 | extern JS_FRIEND_API(bool) |
michael@0 | 324 | proxy_LookupElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleObject objp, |
michael@0 | 325 | JS::MutableHandle<Shape*> propp); |
michael@0 | 326 | extern JS_FRIEND_API(bool) |
michael@0 | 327 | proxy_DefineGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, |
michael@0 | 328 | JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); |
michael@0 | 329 | extern JS_FRIEND_API(bool) |
michael@0 | 330 | proxy_DefineProperty(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name, |
michael@0 | 331 | JS::HandleValue value, JSPropertyOp getter, JSStrictPropertyOp setter, |
michael@0 | 332 | unsigned attrs); |
michael@0 | 333 | extern JS_FRIEND_API(bool) |
michael@0 | 334 | proxy_DefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value, |
michael@0 | 335 | JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); |
michael@0 | 336 | extern JS_FRIEND_API(bool) |
michael@0 | 337 | proxy_GetGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id, |
michael@0 | 338 | JS::MutableHandleValue vp); |
michael@0 | 339 | extern JS_FRIEND_API(bool) |
michael@0 | 340 | proxy_GetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, |
michael@0 | 341 | JS::Handle<PropertyName*> name, JS::MutableHandleValue vp); |
michael@0 | 342 | extern JS_FRIEND_API(bool) |
michael@0 | 343 | proxy_GetElement(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, uint32_t index, |
michael@0 | 344 | JS::MutableHandleValue vp); |
michael@0 | 345 | extern JS_FRIEND_API(bool) |
michael@0 | 346 | proxy_SetGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, |
michael@0 | 347 | JS::MutableHandleValue bp, bool strict); |
michael@0 | 348 | extern JS_FRIEND_API(bool) |
michael@0 | 349 | proxy_SetProperty(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name, |
michael@0 | 350 | JS::MutableHandleValue bp, bool strict); |
michael@0 | 351 | extern JS_FRIEND_API(bool) |
michael@0 | 352 | proxy_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp, |
michael@0 | 353 | bool strict); |
michael@0 | 354 | extern JS_FRIEND_API(bool) |
michael@0 | 355 | proxy_GetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp); |
michael@0 | 356 | extern JS_FRIEND_API(bool) |
michael@0 | 357 | proxy_SetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp); |
michael@0 | 358 | extern JS_FRIEND_API(bool) |
michael@0 | 359 | proxy_DeleteProperty(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name, |
michael@0 | 360 | bool *succeeded); |
michael@0 | 361 | extern JS_FRIEND_API(bool) |
michael@0 | 362 | proxy_DeleteElement(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *succeeded); |
michael@0 | 363 | |
michael@0 | 364 | extern JS_FRIEND_API(void) |
michael@0 | 365 | proxy_Trace(JSTracer *trc, JSObject *obj); |
michael@0 | 366 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 367 | proxy_WeakmapKeyDelegate(JSObject *obj); |
michael@0 | 368 | extern JS_FRIEND_API(bool) |
michael@0 | 369 | proxy_Convert(JSContext *cx, JS::HandleObject proxy, JSType hint, JS::MutableHandleValue vp); |
michael@0 | 370 | extern JS_FRIEND_API(void) |
michael@0 | 371 | proxy_Finalize(FreeOp *fop, JSObject *obj); |
michael@0 | 372 | extern JS_FRIEND_API(bool) |
michael@0 | 373 | proxy_HasInstance(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool *bp); |
michael@0 | 374 | extern JS_FRIEND_API(bool) |
michael@0 | 375 | proxy_Call(JSContext *cx, unsigned argc, JS::Value *vp); |
michael@0 | 376 | extern JS_FRIEND_API(bool) |
michael@0 | 377 | proxy_Construct(JSContext *cx, unsigned argc, JS::Value *vp); |
michael@0 | 378 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 379 | proxy_innerObject(JSContext *cx, JS::HandleObject obj); |
michael@0 | 380 | extern JS_FRIEND_API(bool) |
michael@0 | 381 | proxy_Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); |
michael@0 | 382 | extern JS_FRIEND_API(bool) |
michael@0 | 383 | proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id); |
michael@0 | 384 | extern JS_FRIEND_API(bool) |
michael@0 | 385 | proxy_Slice(JSContext *cx, JS::HandleObject proxy, uint32_t begin, uint32_t end, |
michael@0 | 386 | JS::HandleObject result); |
michael@0 | 387 | |
michael@0 | 388 | /* |
michael@0 | 389 | * A class of objects that return source code on demand. |
michael@0 | 390 | * |
michael@0 | 391 | * When code is compiled with setSourceIsLazy(true), SpiderMonkey doesn't |
michael@0 | 392 | * retain the source code (and doesn't do lazy bytecode generation). If we ever |
michael@0 | 393 | * need the source code, say, in response to a call to Function.prototype. |
michael@0 | 394 | * toSource or Debugger.Source.prototype.text, then we call the 'load' member |
michael@0 | 395 | * function of the instance of this class that has hopefully been registered |
michael@0 | 396 | * with the runtime, passing the code's URL, and hope that it will be able to |
michael@0 | 397 | * find the source. |
michael@0 | 398 | */ |
michael@0 | 399 | class SourceHook { |
michael@0 | 400 | public: |
michael@0 | 401 | virtual ~SourceHook() { } |
michael@0 | 402 | |
michael@0 | 403 | /* |
michael@0 | 404 | * Set |*src| and |*length| to refer to the source code for |filename|. |
michael@0 | 405 | * On success, the caller owns the buffer to which |*src| points, and |
michael@0 | 406 | * should use JS_free to free it. |
michael@0 | 407 | */ |
michael@0 | 408 | virtual bool load(JSContext *cx, const char *filename, jschar **src, size_t *length) = 0; |
michael@0 | 409 | }; |
michael@0 | 410 | |
michael@0 | 411 | /* |
michael@0 | 412 | * Have |rt| use |hook| to retrieve lazily-retrieved source code. See the |
michael@0 | 413 | * comments for SourceHook. The runtime takes ownership of the hook, and |
michael@0 | 414 | * will delete it when the runtime itself is deleted, or when a new hook is |
michael@0 | 415 | * set. |
michael@0 | 416 | */ |
michael@0 | 417 | extern JS_FRIEND_API(void) |
michael@0 | 418 | SetSourceHook(JSRuntime *rt, SourceHook *hook); |
michael@0 | 419 | |
michael@0 | 420 | /* Remove |rt|'s source hook, and return it. The caller now owns the hook. */ |
michael@0 | 421 | extern JS_FRIEND_API(SourceHook *) |
michael@0 | 422 | ForgetSourceHook(JSRuntime *rt); |
michael@0 | 423 | |
michael@0 | 424 | extern JS_FRIEND_API(JS::Zone *) |
michael@0 | 425 | GetCompartmentZone(JSCompartment *comp); |
michael@0 | 426 | |
michael@0 | 427 | typedef bool |
michael@0 | 428 | (* PreserveWrapperCallback)(JSContext *cx, JSObject *obj); |
michael@0 | 429 | |
michael@0 | 430 | typedef enum { |
michael@0 | 431 | CollectNurseryBeforeDump, |
michael@0 | 432 | IgnoreNurseryObjects |
michael@0 | 433 | } DumpHeapNurseryBehaviour; |
michael@0 | 434 | |
michael@0 | 435 | /* |
michael@0 | 436 | * Dump the complete object graph of heap-allocated things. |
michael@0 | 437 | * fp is the file for the dump output. |
michael@0 | 438 | */ |
michael@0 | 439 | extern JS_FRIEND_API(void) |
michael@0 | 440 | DumpHeapComplete(JSRuntime *rt, FILE *fp, DumpHeapNurseryBehaviour nurseryBehaviour); |
michael@0 | 441 | |
michael@0 | 442 | #ifdef JS_OLD_GETTER_SETTER_METHODS |
michael@0 | 443 | JS_FRIEND_API(bool) obj_defineGetter(JSContext *cx, unsigned argc, JS::Value *vp); |
michael@0 | 444 | JS_FRIEND_API(bool) obj_defineSetter(JSContext *cx, unsigned argc, JS::Value *vp); |
michael@0 | 445 | #endif |
michael@0 | 446 | |
michael@0 | 447 | extern JS_FRIEND_API(bool) |
michael@0 | 448 | IsSystemCompartment(JSCompartment *comp); |
michael@0 | 449 | |
michael@0 | 450 | extern JS_FRIEND_API(bool) |
michael@0 | 451 | IsSystemZone(JS::Zone *zone); |
michael@0 | 452 | |
michael@0 | 453 | extern JS_FRIEND_API(bool) |
michael@0 | 454 | IsAtomsCompartment(JSCompartment *comp); |
michael@0 | 455 | |
michael@0 | 456 | /* |
michael@0 | 457 | * Check whether it is OK to assign an undeclared variable with the name |
michael@0 | 458 | * |propname| at the current location in script. It is not an error if there is |
michael@0 | 459 | * no current script location, or if that location is not an assignment to an |
michael@0 | 460 | * undeclared variable. Reports an error if one needs to be reported (and, |
michael@0 | 461 | * particularly, always reports when it returns false). |
michael@0 | 462 | */ |
michael@0 | 463 | extern JS_FRIEND_API(bool) |
michael@0 | 464 | ReportIfUndeclaredVarAssignment(JSContext *cx, JS::HandleString propname); |
michael@0 | 465 | |
michael@0 | 466 | /* |
michael@0 | 467 | * Returns whether we're in a non-strict property set (in that we're in a |
michael@0 | 468 | * non-strict script and the bytecode we're on is a property set). The return |
michael@0 | 469 | * value does NOT indicate any sort of exception was thrown: it's just a |
michael@0 | 470 | * boolean. |
michael@0 | 471 | */ |
michael@0 | 472 | extern JS_FRIEND_API(bool) |
michael@0 | 473 | IsInNonStrictPropertySet(JSContext *cx); |
michael@0 | 474 | |
michael@0 | 475 | struct WeakMapTracer; |
michael@0 | 476 | |
michael@0 | 477 | /* |
michael@0 | 478 | * Weak map tracer callback, called once for every binding of every |
michael@0 | 479 | * weak map that was live at the time of the last garbage collection. |
michael@0 | 480 | * |
michael@0 | 481 | * m will be nullptr if the weak map is not contained in a JS Object. |
michael@0 | 482 | */ |
michael@0 | 483 | typedef void |
michael@0 | 484 | (* WeakMapTraceCallback)(WeakMapTracer *trc, JSObject *m, |
michael@0 | 485 | void *k, JSGCTraceKind kkind, |
michael@0 | 486 | void *v, JSGCTraceKind vkind); |
michael@0 | 487 | |
michael@0 | 488 | struct WeakMapTracer { |
michael@0 | 489 | JSRuntime *runtime; |
michael@0 | 490 | WeakMapTraceCallback callback; |
michael@0 | 491 | |
michael@0 | 492 | WeakMapTracer(JSRuntime *rt, WeakMapTraceCallback cb) |
michael@0 | 493 | : runtime(rt), callback(cb) {} |
michael@0 | 494 | }; |
michael@0 | 495 | |
michael@0 | 496 | extern JS_FRIEND_API(void) |
michael@0 | 497 | TraceWeakMaps(WeakMapTracer *trc); |
michael@0 | 498 | |
michael@0 | 499 | extern JS_FRIEND_API(bool) |
michael@0 | 500 | AreGCGrayBitsValid(JSRuntime *rt); |
michael@0 | 501 | |
michael@0 | 502 | extern JS_FRIEND_API(bool) |
michael@0 | 503 | ZoneGlobalsAreAllGray(JS::Zone *zone); |
michael@0 | 504 | |
michael@0 | 505 | typedef void |
michael@0 | 506 | (*GCThingCallback)(void *closure, void *gcthing); |
michael@0 | 507 | |
michael@0 | 508 | extern JS_FRIEND_API(void) |
michael@0 | 509 | VisitGrayWrapperTargets(JS::Zone *zone, GCThingCallback callback, void *closure); |
michael@0 | 510 | |
michael@0 | 511 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 512 | GetWeakmapKeyDelegate(JSObject *key); |
michael@0 | 513 | |
michael@0 | 514 | JS_FRIEND_API(JSGCTraceKind) |
michael@0 | 515 | GCThingTraceKind(void *thing); |
michael@0 | 516 | |
michael@0 | 517 | /* |
michael@0 | 518 | * Invoke cellCallback on every gray JS_OBJECT in the given zone. |
michael@0 | 519 | */ |
michael@0 | 520 | extern JS_FRIEND_API(void) |
michael@0 | 521 | IterateGrayObjects(JS::Zone *zone, GCThingCallback cellCallback, void *data); |
michael@0 | 522 | |
michael@0 | 523 | #ifdef JS_HAS_CTYPES |
michael@0 | 524 | extern JS_FRIEND_API(size_t) |
michael@0 | 525 | SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject *obj); |
michael@0 | 526 | #endif |
michael@0 | 527 | |
michael@0 | 528 | extern JS_FRIEND_API(JSCompartment *) |
michael@0 | 529 | GetAnyCompartmentInZone(JS::Zone *zone); |
michael@0 | 530 | |
michael@0 | 531 | /* |
michael@0 | 532 | * Shadow declarations of JS internal structures, for access by inline access |
michael@0 | 533 | * functions below. Do not use these structures in any other way. When adding |
michael@0 | 534 | * new fields for access by inline methods, make sure to add static asserts to |
michael@0 | 535 | * the original header file to ensure that offsets are consistent. |
michael@0 | 536 | */ |
michael@0 | 537 | namespace shadow { |
michael@0 | 538 | |
michael@0 | 539 | struct TypeObject { |
michael@0 | 540 | const Class *clasp; |
michael@0 | 541 | JSObject *proto; |
michael@0 | 542 | }; |
michael@0 | 543 | |
michael@0 | 544 | struct BaseShape { |
michael@0 | 545 | const js::Class *clasp_; |
michael@0 | 546 | JSObject *parent; |
michael@0 | 547 | JSObject *_1; |
michael@0 | 548 | JSCompartment *compartment; |
michael@0 | 549 | }; |
michael@0 | 550 | |
michael@0 | 551 | class Shape { |
michael@0 | 552 | public: |
michael@0 | 553 | shadow::BaseShape *base; |
michael@0 | 554 | jsid _1; |
michael@0 | 555 | uint32_t slotInfo; |
michael@0 | 556 | |
michael@0 | 557 | static const uint32_t FIXED_SLOTS_SHIFT = 27; |
michael@0 | 558 | }; |
michael@0 | 559 | |
michael@0 | 560 | struct Object { |
michael@0 | 561 | shadow::Shape *shape; |
michael@0 | 562 | shadow::TypeObject *type; |
michael@0 | 563 | JS::Value *slots; |
michael@0 | 564 | JS::Value *_1; |
michael@0 | 565 | |
michael@0 | 566 | size_t numFixedSlots() const { return shape->slotInfo >> Shape::FIXED_SLOTS_SHIFT; } |
michael@0 | 567 | JS::Value *fixedSlots() const { |
michael@0 | 568 | return (JS::Value *)(uintptr_t(this) + sizeof(shadow::Object)); |
michael@0 | 569 | } |
michael@0 | 570 | |
michael@0 | 571 | JS::Value &slotRef(size_t slot) const { |
michael@0 | 572 | size_t nfixed = numFixedSlots(); |
michael@0 | 573 | if (slot < nfixed) |
michael@0 | 574 | return fixedSlots()[slot]; |
michael@0 | 575 | return slots[slot - nfixed]; |
michael@0 | 576 | } |
michael@0 | 577 | |
michael@0 | 578 | // Reserved slots with index < MAX_FIXED_SLOTS are guaranteed to |
michael@0 | 579 | // be fixed slots. |
michael@0 | 580 | static const uint32_t MAX_FIXED_SLOTS = 16; |
michael@0 | 581 | }; |
michael@0 | 582 | |
michael@0 | 583 | struct Function { |
michael@0 | 584 | Object base; |
michael@0 | 585 | uint16_t nargs; |
michael@0 | 586 | uint16_t flags; |
michael@0 | 587 | /* Used only for natives */ |
michael@0 | 588 | JSNative native; |
michael@0 | 589 | const JSJitInfo *jitinfo; |
michael@0 | 590 | void *_1; |
michael@0 | 591 | }; |
michael@0 | 592 | |
michael@0 | 593 | struct Atom { |
michael@0 | 594 | static const size_t LENGTH_SHIFT = 4; |
michael@0 | 595 | size_t lengthAndFlags; |
michael@0 | 596 | const jschar *chars; |
michael@0 | 597 | }; |
michael@0 | 598 | |
michael@0 | 599 | } /* namespace shadow */ |
michael@0 | 600 | |
michael@0 | 601 | // This is equal to |&JSObject::class_|. Use it in places where you don't want |
michael@0 | 602 | // to #include jsobj.h. |
michael@0 | 603 | extern JS_FRIEND_DATA(const js::Class* const) ObjectClassPtr; |
michael@0 | 604 | |
michael@0 | 605 | inline const js::Class * |
michael@0 | 606 | GetObjectClass(JSObject *obj) |
michael@0 | 607 | { |
michael@0 | 608 | return reinterpret_cast<const shadow::Object*>(obj)->type->clasp; |
michael@0 | 609 | } |
michael@0 | 610 | |
michael@0 | 611 | inline const JSClass * |
michael@0 | 612 | GetObjectJSClass(JSObject *obj) |
michael@0 | 613 | { |
michael@0 | 614 | return js::Jsvalify(GetObjectClass(obj)); |
michael@0 | 615 | } |
michael@0 | 616 | |
michael@0 | 617 | inline bool |
michael@0 | 618 | IsInnerObject(JSObject *obj) { |
michael@0 | 619 | return !!GetObjectClass(obj)->ext.outerObject; |
michael@0 | 620 | } |
michael@0 | 621 | |
michael@0 | 622 | inline bool |
michael@0 | 623 | IsOuterObject(JSObject *obj) { |
michael@0 | 624 | return !!GetObjectClass(obj)->ext.innerObject; |
michael@0 | 625 | } |
michael@0 | 626 | |
michael@0 | 627 | JS_FRIEND_API(bool) |
michael@0 | 628 | IsFunctionObject(JSObject *obj); |
michael@0 | 629 | |
michael@0 | 630 | JS_FRIEND_API(bool) |
michael@0 | 631 | IsScopeObject(JSObject *obj); |
michael@0 | 632 | |
michael@0 | 633 | JS_FRIEND_API(bool) |
michael@0 | 634 | IsCallObject(JSObject *obj); |
michael@0 | 635 | |
michael@0 | 636 | inline JSObject * |
michael@0 | 637 | GetObjectParent(JSObject *obj) |
michael@0 | 638 | { |
michael@0 | 639 | JS_ASSERT(!IsScopeObject(obj)); |
michael@0 | 640 | return reinterpret_cast<shadow::Object*>(obj)->shape->base->parent; |
michael@0 | 641 | } |
michael@0 | 642 | |
michael@0 | 643 | static MOZ_ALWAYS_INLINE JSCompartment * |
michael@0 | 644 | GetObjectCompartment(JSObject *obj) |
michael@0 | 645 | { |
michael@0 | 646 | return reinterpret_cast<shadow::Object*>(obj)->shape->base->compartment; |
michael@0 | 647 | } |
michael@0 | 648 | |
michael@0 | 649 | JS_FRIEND_API(JSObject *) |
michael@0 | 650 | GetObjectParentMaybeScope(JSObject *obj); |
michael@0 | 651 | |
michael@0 | 652 | JS_FRIEND_API(JSObject *) |
michael@0 | 653 | GetGlobalForObjectCrossCompartment(JSObject *obj); |
michael@0 | 654 | |
michael@0 | 655 | // Sidestep the activeContext checking implicitly performed in |
michael@0 | 656 | // JS_SetPendingException. |
michael@0 | 657 | JS_FRIEND_API(void) |
michael@0 | 658 | SetPendingExceptionCrossContext(JSContext *cx, JS::HandleValue v); |
michael@0 | 659 | |
michael@0 | 660 | JS_FRIEND_API(void) |
michael@0 | 661 | AssertSameCompartment(JSContext *cx, JSObject *obj); |
michael@0 | 662 | |
michael@0 | 663 | #ifdef JS_DEBUG |
michael@0 | 664 | JS_FRIEND_API(void) |
michael@0 | 665 | AssertSameCompartment(JSObject *objA, JSObject *objB); |
michael@0 | 666 | #else |
michael@0 | 667 | inline void AssertSameCompartment(JSObject *objA, JSObject *objB) {} |
michael@0 | 668 | #endif |
michael@0 | 669 | |
michael@0 | 670 | // For legacy consumers only. This whole concept is going away soon. |
michael@0 | 671 | JS_FRIEND_API(JSObject *) |
michael@0 | 672 | DefaultObjectForContextOrNull(JSContext *cx); |
michael@0 | 673 | |
michael@0 | 674 | JS_FRIEND_API(void) |
michael@0 | 675 | SetDefaultObjectForContext(JSContext *cx, JSObject *obj); |
michael@0 | 676 | |
michael@0 | 677 | JS_FRIEND_API(void) |
michael@0 | 678 | NotifyAnimationActivity(JSObject *obj); |
michael@0 | 679 | |
michael@0 | 680 | /* |
michael@0 | 681 | * Return the outermost enclosing function (script) of the scripted caller. |
michael@0 | 682 | * This function returns nullptr in several cases: |
michael@0 | 683 | * - no script is running on the context |
michael@0 | 684 | * - the caller is in global or eval code |
michael@0 | 685 | * In particular, this function will "stop" its outermost search at eval() and |
michael@0 | 686 | * thus it will really return the outermost enclosing function *since the |
michael@0 | 687 | * innermost eval*. |
michael@0 | 688 | */ |
michael@0 | 689 | JS_FRIEND_API(JSScript *) |
michael@0 | 690 | GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx); |
michael@0 | 691 | |
michael@0 | 692 | JS_FRIEND_API(JSFunction *) |
michael@0 | 693 | DefineFunctionWithReserved(JSContext *cx, JSObject *obj, const char *name, JSNative call, |
michael@0 | 694 | unsigned nargs, unsigned attrs); |
michael@0 | 695 | |
michael@0 | 696 | JS_FRIEND_API(JSFunction *) |
michael@0 | 697 | NewFunctionWithReserved(JSContext *cx, JSNative call, unsigned nargs, unsigned flags, |
michael@0 | 698 | JSObject *parent, const char *name); |
michael@0 | 699 | |
michael@0 | 700 | JS_FRIEND_API(JSFunction *) |
michael@0 | 701 | NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, |
michael@0 | 702 | JSObject *parent, jsid id); |
michael@0 | 703 | |
michael@0 | 704 | JS_FRIEND_API(JSObject *) |
michael@0 | 705 | InitClassWithReserved(JSContext *cx, JSObject *obj, JSObject *parent_proto, |
michael@0 | 706 | const JSClass *clasp, JSNative constructor, unsigned nargs, |
michael@0 | 707 | const JSPropertySpec *ps, const JSFunctionSpec *fs, |
michael@0 | 708 | const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs); |
michael@0 | 709 | |
michael@0 | 710 | JS_FRIEND_API(const JS::Value &) |
michael@0 | 711 | GetFunctionNativeReserved(JSObject *fun, size_t which); |
michael@0 | 712 | |
michael@0 | 713 | JS_FRIEND_API(void) |
michael@0 | 714 | SetFunctionNativeReserved(JSObject *fun, size_t which, const JS::Value &val); |
michael@0 | 715 | |
michael@0 | 716 | JS_FRIEND_API(bool) |
michael@0 | 717 | GetObjectProto(JSContext *cx, JS::HandleObject obj, JS::MutableHandleObject proto); |
michael@0 | 718 | |
michael@0 | 719 | JS_FRIEND_API(bool) |
michael@0 | 720 | GetOriginalEval(JSContext *cx, JS::HandleObject scope, |
michael@0 | 721 | JS::MutableHandleObject eval); |
michael@0 | 722 | |
michael@0 | 723 | inline void * |
michael@0 | 724 | GetObjectPrivate(JSObject *obj) |
michael@0 | 725 | { |
michael@0 | 726 | const shadow::Object *nobj = reinterpret_cast<const shadow::Object*>(obj); |
michael@0 | 727 | void **addr = reinterpret_cast<void**>(&nobj->fixedSlots()[nobj->numFixedSlots()]); |
michael@0 | 728 | return *addr; |
michael@0 | 729 | } |
michael@0 | 730 | |
michael@0 | 731 | /* |
michael@0 | 732 | * Get a slot that is both reserved for object's clasp *and* is fixed (fits |
michael@0 | 733 | * within the maximum capacity for the object's fixed slots). |
michael@0 | 734 | */ |
michael@0 | 735 | inline const JS::Value & |
michael@0 | 736 | GetReservedSlot(JSObject *obj, size_t slot) |
michael@0 | 737 | { |
michael@0 | 738 | JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); |
michael@0 | 739 | return reinterpret_cast<const shadow::Object *>(obj)->slotRef(slot); |
michael@0 | 740 | } |
michael@0 | 741 | |
michael@0 | 742 | JS_FRIEND_API(void) |
michael@0 | 743 | SetReservedSlotWithBarrier(JSObject *obj, size_t slot, const JS::Value &value); |
michael@0 | 744 | |
michael@0 | 745 | inline void |
michael@0 | 746 | SetReservedSlot(JSObject *obj, size_t slot, const JS::Value &value) |
michael@0 | 747 | { |
michael@0 | 748 | JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); |
michael@0 | 749 | shadow::Object *sobj = reinterpret_cast<shadow::Object *>(obj); |
michael@0 | 750 | if (sobj->slotRef(slot).isMarkable() |
michael@0 | 751 | #ifdef JSGC_GENERATIONAL |
michael@0 | 752 | || value.isMarkable() |
michael@0 | 753 | #endif |
michael@0 | 754 | ) |
michael@0 | 755 | { |
michael@0 | 756 | SetReservedSlotWithBarrier(obj, slot, value); |
michael@0 | 757 | } else { |
michael@0 | 758 | sobj->slotRef(slot) = value; |
michael@0 | 759 | } |
michael@0 | 760 | } |
michael@0 | 761 | |
michael@0 | 762 | JS_FRIEND_API(uint32_t) |
michael@0 | 763 | GetObjectSlotSpan(JSObject *obj); |
michael@0 | 764 | |
michael@0 | 765 | inline const JS::Value & |
michael@0 | 766 | GetObjectSlot(JSObject *obj, size_t slot) |
michael@0 | 767 | { |
michael@0 | 768 | JS_ASSERT(slot < GetObjectSlotSpan(obj)); |
michael@0 | 769 | return reinterpret_cast<const shadow::Object *>(obj)->slotRef(slot); |
michael@0 | 770 | } |
michael@0 | 771 | |
michael@0 | 772 | inline const jschar * |
michael@0 | 773 | GetAtomChars(JSAtom *atom) |
michael@0 | 774 | { |
michael@0 | 775 | return reinterpret_cast<shadow::Atom *>(atom)->chars; |
michael@0 | 776 | } |
michael@0 | 777 | |
michael@0 | 778 | inline size_t |
michael@0 | 779 | GetAtomLength(JSAtom *atom) |
michael@0 | 780 | { |
michael@0 | 781 | using shadow::Atom; |
michael@0 | 782 | return reinterpret_cast<Atom*>(atom)->lengthAndFlags >> Atom::LENGTH_SHIFT; |
michael@0 | 783 | } |
michael@0 | 784 | |
michael@0 | 785 | inline JSLinearString * |
michael@0 | 786 | AtomToLinearString(JSAtom *atom) |
michael@0 | 787 | { |
michael@0 | 788 | return reinterpret_cast<JSLinearString *>(atom); |
michael@0 | 789 | } |
michael@0 | 790 | |
michael@0 | 791 | JS_FRIEND_API(bool) |
michael@0 | 792 | GetPropertyNames(JSContext *cx, JSObject *obj, unsigned flags, JS::AutoIdVector *props); |
michael@0 | 793 | |
michael@0 | 794 | JS_FRIEND_API(bool) |
michael@0 | 795 | AppendUnique(JSContext *cx, JS::AutoIdVector &base, JS::AutoIdVector &others); |
michael@0 | 796 | |
michael@0 | 797 | JS_FRIEND_API(bool) |
michael@0 | 798 | GetGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, JS::Value *vp); |
michael@0 | 799 | |
michael@0 | 800 | JS_FRIEND_API(bool) |
michael@0 | 801 | StringIsArrayIndex(JSLinearString *str, uint32_t *indexp); |
michael@0 | 802 | |
michael@0 | 803 | JS_FRIEND_API(void) |
michael@0 | 804 | SetPreserveWrapperCallback(JSRuntime *rt, PreserveWrapperCallback callback); |
michael@0 | 805 | |
michael@0 | 806 | JS_FRIEND_API(bool) |
michael@0 | 807 | IsObjectInContextCompartment(JSObject *obj, const JSContext *cx); |
michael@0 | 808 | |
michael@0 | 809 | /* |
michael@0 | 810 | * NB: these flag bits are encoded into the bytecode stream in the immediate |
michael@0 | 811 | * operand of JSOP_ITER, so don't change them without advancing vm/Xdr.h's |
michael@0 | 812 | * XDR_BYTECODE_VERSION. |
michael@0 | 813 | */ |
michael@0 | 814 | #define JSITER_ENUMERATE 0x1 /* for-in compatible hidden default iterator */ |
michael@0 | 815 | #define JSITER_FOREACH 0x2 /* return [key, value] pair rather than key */ |
michael@0 | 816 | #define JSITER_KEYVALUE 0x4 /* destructuring for-in wants [key, value] */ |
michael@0 | 817 | #define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */ |
michael@0 | 818 | #define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */ |
michael@0 | 819 | |
michael@0 | 820 | JS_FRIEND_API(bool) |
michael@0 | 821 | RunningWithTrustedPrincipals(JSContext *cx); |
michael@0 | 822 | |
michael@0 | 823 | inline uintptr_t |
michael@0 | 824 | GetNativeStackLimit(JSContext *cx) |
michael@0 | 825 | { |
michael@0 | 826 | StackKind kind = RunningWithTrustedPrincipals(cx) ? StackForTrustedScript |
michael@0 | 827 | : StackForUntrustedScript; |
michael@0 | 828 | PerThreadDataFriendFields *mainThread = |
michael@0 | 829 | PerThreadDataFriendFields::getMainThread(GetRuntime(cx)); |
michael@0 | 830 | return mainThread->nativeStackLimit[kind]; |
michael@0 | 831 | } |
michael@0 | 832 | |
michael@0 | 833 | /* |
michael@0 | 834 | * These macros report a stack overflow and run |onerror| if we are close to |
michael@0 | 835 | * using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a little |
michael@0 | 836 | * extra space so that we can ensure that crucial code is able to run. |
michael@0 | 837 | */ |
michael@0 | 838 | |
michael@0 | 839 | #define JS_CHECK_RECURSION(cx, onerror) \ |
michael@0 | 840 | JS_BEGIN_MACRO \ |
michael@0 | 841 | int stackDummy_; \ |
michael@0 | 842 | if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_)) { \ |
michael@0 | 843 | js_ReportOverRecursed(cx); \ |
michael@0 | 844 | onerror; \ |
michael@0 | 845 | } \ |
michael@0 | 846 | JS_END_MACRO |
michael@0 | 847 | |
michael@0 | 848 | #define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \ |
michael@0 | 849 | JS_BEGIN_MACRO \ |
michael@0 | 850 | int stackDummy_; \ |
michael@0 | 851 | if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_)) { \ |
michael@0 | 852 | onerror; \ |
michael@0 | 853 | } \ |
michael@0 | 854 | JS_END_MACRO |
michael@0 | 855 | |
michael@0 | 856 | #define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror) \ |
michael@0 | 857 | JS_BEGIN_MACRO \ |
michael@0 | 858 | if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \ |
michael@0 | 859 | onerror; \ |
michael@0 | 860 | } \ |
michael@0 | 861 | JS_END_MACRO |
michael@0 | 862 | |
michael@0 | 863 | #define JS_CHECK_RECURSION_WITH_SP(cx, sp, onerror) \ |
michael@0 | 864 | JS_BEGIN_MACRO \ |
michael@0 | 865 | if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \ |
michael@0 | 866 | js_ReportOverRecursed(cx); \ |
michael@0 | 867 | onerror; \ |
michael@0 | 868 | } \ |
michael@0 | 869 | JS_END_MACRO |
michael@0 | 870 | |
michael@0 | 871 | #define JS_CHECK_CHROME_RECURSION(cx, onerror) \ |
michael@0 | 872 | JS_BEGIN_MACRO \ |
michael@0 | 873 | int stackDummy_; \ |
michael@0 | 874 | if (!JS_CHECK_STACK_SIZE_WITH_TOLERANCE(js::GetNativeStackLimit(cx), \ |
michael@0 | 875 | &stackDummy_, \ |
michael@0 | 876 | 1024 * sizeof(size_t))) \ |
michael@0 | 877 | { \ |
michael@0 | 878 | js_ReportOverRecursed(cx); \ |
michael@0 | 879 | onerror; \ |
michael@0 | 880 | } \ |
michael@0 | 881 | JS_END_MACRO |
michael@0 | 882 | |
michael@0 | 883 | JS_FRIEND_API(void) |
michael@0 | 884 | StartPCCountProfiling(JSContext *cx); |
michael@0 | 885 | |
michael@0 | 886 | JS_FRIEND_API(void) |
michael@0 | 887 | StopPCCountProfiling(JSContext *cx); |
michael@0 | 888 | |
michael@0 | 889 | JS_FRIEND_API(void) |
michael@0 | 890 | PurgePCCounts(JSContext *cx); |
michael@0 | 891 | |
michael@0 | 892 | JS_FRIEND_API(size_t) |
michael@0 | 893 | GetPCCountScriptCount(JSContext *cx); |
michael@0 | 894 | |
michael@0 | 895 | JS_FRIEND_API(JSString *) |
michael@0 | 896 | GetPCCountScriptSummary(JSContext *cx, size_t script); |
michael@0 | 897 | |
michael@0 | 898 | JS_FRIEND_API(JSString *) |
michael@0 | 899 | GetPCCountScriptContents(JSContext *cx, size_t script); |
michael@0 | 900 | |
michael@0 | 901 | #ifdef JS_THREADSAFE |
michael@0 | 902 | JS_FRIEND_API(bool) |
michael@0 | 903 | ContextHasOutstandingRequests(const JSContext *cx); |
michael@0 | 904 | #endif |
michael@0 | 905 | |
michael@0 | 906 | typedef void |
michael@0 | 907 | (* ActivityCallback)(void *arg, bool active); |
michael@0 | 908 | |
michael@0 | 909 | /* |
michael@0 | 910 | * Sets a callback that is run whenever the runtime goes idle - the |
michael@0 | 911 | * last active request ceases - and begins activity - when it was |
michael@0 | 912 | * idle and a request begins. |
michael@0 | 913 | */ |
michael@0 | 914 | JS_FRIEND_API(void) |
michael@0 | 915 | SetActivityCallback(JSRuntime *rt, ActivityCallback cb, void *arg); |
michael@0 | 916 | |
michael@0 | 917 | extern JS_FRIEND_API(const JSStructuredCloneCallbacks *) |
michael@0 | 918 | GetContextStructuredCloneCallbacks(JSContext *cx); |
michael@0 | 919 | |
michael@0 | 920 | extern JS_FRIEND_API(bool) |
michael@0 | 921 | IsContextRunningJS(JSContext *cx); |
michael@0 | 922 | |
michael@0 | 923 | typedef bool |
michael@0 | 924 | (* DOMInstanceClassMatchesProto)(JSObject *protoObject, uint32_t protoID, uint32_t depth); |
michael@0 | 925 | struct JSDOMCallbacks { |
michael@0 | 926 | DOMInstanceClassMatchesProto instanceClassMatchesProto; |
michael@0 | 927 | }; |
michael@0 | 928 | typedef struct JSDOMCallbacks DOMCallbacks; |
michael@0 | 929 | |
michael@0 | 930 | extern JS_FRIEND_API(void) |
michael@0 | 931 | SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks); |
michael@0 | 932 | |
michael@0 | 933 | extern JS_FRIEND_API(const DOMCallbacks *) |
michael@0 | 934 | GetDOMCallbacks(JSRuntime *rt); |
michael@0 | 935 | |
michael@0 | 936 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 937 | GetTestingFunctions(JSContext *cx); |
michael@0 | 938 | |
michael@0 | 939 | /* |
michael@0 | 940 | * Helper to convert FreeOp to JSFreeOp when the definition of FreeOp is not |
michael@0 | 941 | * available and the compiler does not know that FreeOp inherits from |
michael@0 | 942 | * JSFreeOp. |
michael@0 | 943 | */ |
michael@0 | 944 | inline JSFreeOp * |
michael@0 | 945 | CastToJSFreeOp(FreeOp *fop) |
michael@0 | 946 | { |
michael@0 | 947 | return reinterpret_cast<JSFreeOp *>(fop); |
michael@0 | 948 | } |
michael@0 | 949 | |
michael@0 | 950 | /* Implemented in jsexn.cpp. */ |
michael@0 | 951 | |
michael@0 | 952 | /* |
michael@0 | 953 | * Get an error type name from a JSExnType constant. |
michael@0 | 954 | * Returns nullptr for invalid arguments and JSEXN_INTERNALERR |
michael@0 | 955 | */ |
michael@0 | 956 | extern JS_FRIEND_API(const jschar*) |
michael@0 | 957 | GetErrorTypeName(JSRuntime* rt, int16_t exnType); |
michael@0 | 958 | |
michael@0 | 959 | #ifdef JS_DEBUG |
michael@0 | 960 | extern JS_FRIEND_API(unsigned) |
michael@0 | 961 | GetEnterCompartmentDepth(JSContext* cx); |
michael@0 | 962 | #endif |
michael@0 | 963 | |
michael@0 | 964 | /* Implemented in jswrapper.cpp. */ |
michael@0 | 965 | typedef enum NukeReferencesToWindow { |
michael@0 | 966 | NukeWindowReferences, |
michael@0 | 967 | DontNukeWindowReferences |
michael@0 | 968 | } NukeReferencesToWindow; |
michael@0 | 969 | |
michael@0 | 970 | /* |
michael@0 | 971 | * These filters are designed to be ephemeral stack classes, and thus don't |
michael@0 | 972 | * do any rooting or holding of their members. |
michael@0 | 973 | */ |
michael@0 | 974 | struct CompartmentFilter { |
michael@0 | 975 | virtual bool match(JSCompartment *c) const = 0; |
michael@0 | 976 | }; |
michael@0 | 977 | |
michael@0 | 978 | struct AllCompartments : public CompartmentFilter { |
michael@0 | 979 | virtual bool match(JSCompartment *c) const { return true; } |
michael@0 | 980 | }; |
michael@0 | 981 | |
michael@0 | 982 | struct ContentCompartmentsOnly : public CompartmentFilter { |
michael@0 | 983 | virtual bool match(JSCompartment *c) const { |
michael@0 | 984 | return !IsSystemCompartment(c); |
michael@0 | 985 | } |
michael@0 | 986 | }; |
michael@0 | 987 | |
michael@0 | 988 | struct ChromeCompartmentsOnly : public CompartmentFilter { |
michael@0 | 989 | virtual bool match(JSCompartment *c) const { |
michael@0 | 990 | return IsSystemCompartment(c); |
michael@0 | 991 | } |
michael@0 | 992 | }; |
michael@0 | 993 | |
michael@0 | 994 | struct SingleCompartment : public CompartmentFilter { |
michael@0 | 995 | JSCompartment *ours; |
michael@0 | 996 | SingleCompartment(JSCompartment *c) : ours(c) {} |
michael@0 | 997 | virtual bool match(JSCompartment *c) const { return c == ours; } |
michael@0 | 998 | }; |
michael@0 | 999 | |
michael@0 | 1000 | struct CompartmentsWithPrincipals : public CompartmentFilter { |
michael@0 | 1001 | JSPrincipals *principals; |
michael@0 | 1002 | CompartmentsWithPrincipals(JSPrincipals *p) : principals(p) {} |
michael@0 | 1003 | virtual bool match(JSCompartment *c) const { |
michael@0 | 1004 | return JS_GetCompartmentPrincipals(c) == principals; |
michael@0 | 1005 | } |
michael@0 | 1006 | }; |
michael@0 | 1007 | |
michael@0 | 1008 | extern JS_FRIEND_API(bool) |
michael@0 | 1009 | NukeCrossCompartmentWrappers(JSContext* cx, |
michael@0 | 1010 | const CompartmentFilter& sourceFilter, |
michael@0 | 1011 | const CompartmentFilter& targetFilter, |
michael@0 | 1012 | NukeReferencesToWindow nukeReferencesToWindow); |
michael@0 | 1013 | |
michael@0 | 1014 | /* Specify information about DOMProxy proxies in the DOM, for use by ICs. */ |
michael@0 | 1015 | |
michael@0 | 1016 | /* |
michael@0 | 1017 | * The DOMProxyShadowsCheck function will be called to check if the property for |
michael@0 | 1018 | * id should be gotten from the prototype, or if there is an own property that |
michael@0 | 1019 | * shadows it. |
michael@0 | 1020 | * If DoesntShadow is returned then the slot at listBaseExpandoSlot should |
michael@0 | 1021 | * either be undefined or point to an expando object that would contain the own |
michael@0 | 1022 | * property. |
michael@0 | 1023 | * If DoesntShadowUnique is returned then the slot at listBaseExpandoSlot should |
michael@0 | 1024 | * contain a private pointer to a ExpandoAndGeneration, which contains a |
michael@0 | 1025 | * JS::Value that should either be undefined or point to an expando object, and |
michael@0 | 1026 | * a uint32 value. If that value changes then the IC for getting a property will |
michael@0 | 1027 | * be invalidated. |
michael@0 | 1028 | */ |
michael@0 | 1029 | |
michael@0 | 1030 | struct ExpandoAndGeneration { |
michael@0 | 1031 | ExpandoAndGeneration() |
michael@0 | 1032 | : expando(JS::UndefinedValue()), |
michael@0 | 1033 | generation(0) |
michael@0 | 1034 | {} |
michael@0 | 1035 | |
michael@0 | 1036 | void Unlink() |
michael@0 | 1037 | { |
michael@0 | 1038 | ++generation; |
michael@0 | 1039 | expando.setUndefined(); |
michael@0 | 1040 | } |
michael@0 | 1041 | |
michael@0 | 1042 | static size_t offsetOfExpando() |
michael@0 | 1043 | { |
michael@0 | 1044 | return offsetof(ExpandoAndGeneration, expando); |
michael@0 | 1045 | } |
michael@0 | 1046 | |
michael@0 | 1047 | static size_t offsetOfGeneration() |
michael@0 | 1048 | { |
michael@0 | 1049 | return offsetof(ExpandoAndGeneration, generation); |
michael@0 | 1050 | } |
michael@0 | 1051 | |
michael@0 | 1052 | JS::Heap<JS::Value> expando; |
michael@0 | 1053 | uint32_t generation; |
michael@0 | 1054 | }; |
michael@0 | 1055 | |
michael@0 | 1056 | typedef enum DOMProxyShadowsResult { |
michael@0 | 1057 | ShadowCheckFailed, |
michael@0 | 1058 | Shadows, |
michael@0 | 1059 | DoesntShadow, |
michael@0 | 1060 | DoesntShadowUnique |
michael@0 | 1061 | } DOMProxyShadowsResult; |
michael@0 | 1062 | typedef DOMProxyShadowsResult |
michael@0 | 1063 | (* DOMProxyShadowsCheck)(JSContext* cx, JS::HandleObject object, JS::HandleId id); |
michael@0 | 1064 | JS_FRIEND_API(void) |
michael@0 | 1065 | SetDOMProxyInformation(const void *domProxyHandlerFamily, uint32_t domProxyExpandoSlot, |
michael@0 | 1066 | DOMProxyShadowsCheck domProxyShadowsCheck); |
michael@0 | 1067 | |
michael@0 | 1068 | const void *GetDOMProxyHandlerFamily(); |
michael@0 | 1069 | uint32_t GetDOMProxyExpandoSlot(); |
michael@0 | 1070 | DOMProxyShadowsCheck GetDOMProxyShadowsCheck(); |
michael@0 | 1071 | |
michael@0 | 1072 | } /* namespace js */ |
michael@0 | 1073 | |
michael@0 | 1074 | /* Implemented in jsdate.cpp. */ |
michael@0 | 1075 | |
michael@0 | 1076 | /* |
michael@0 | 1077 | * Detect whether the internal date value is NaN. (Because failure is |
michael@0 | 1078 | * out-of-band for js_DateGet*) |
michael@0 | 1079 | */ |
michael@0 | 1080 | extern JS_FRIEND_API(bool) |
michael@0 | 1081 | js_DateIsValid(JSObject* obj); |
michael@0 | 1082 | |
michael@0 | 1083 | extern JS_FRIEND_API(double) |
michael@0 | 1084 | js_DateGetMsecSinceEpoch(JSObject *obj); |
michael@0 | 1085 | |
michael@0 | 1086 | /* Implemented in jscntxt.cpp. */ |
michael@0 | 1087 | |
michael@0 | 1088 | /* |
michael@0 | 1089 | * Report an exception, which is currently realized as a printf-style format |
michael@0 | 1090 | * string and its arguments. |
michael@0 | 1091 | */ |
michael@0 | 1092 | typedef enum JSErrNum { |
michael@0 | 1093 | #define MSG_DEF(name, number, count, exception, format) \ |
michael@0 | 1094 | name = number, |
michael@0 | 1095 | #include "js.msg" |
michael@0 | 1096 | #undef MSG_DEF |
michael@0 | 1097 | JSErr_Limit |
michael@0 | 1098 | } JSErrNum; |
michael@0 | 1099 | |
michael@0 | 1100 | extern JS_FRIEND_API(const JSErrorFormatString *) |
michael@0 | 1101 | js_GetErrorMessage(void *userRef, const char *locale, const unsigned errorNumber); |
michael@0 | 1102 | |
michael@0 | 1103 | namespace js { |
michael@0 | 1104 | |
michael@0 | 1105 | // Creates a string of the form |ErrorType: ErrorMessage| for a JSErrorReport, |
michael@0 | 1106 | // which generally matches the toString() behavior of an ErrorObject. |
michael@0 | 1107 | extern JS_FRIEND_API(JSString *) |
michael@0 | 1108 | ErrorReportToString(JSContext *cx, JSErrorReport *reportp); |
michael@0 | 1109 | |
michael@0 | 1110 | } /* namespace js */ |
michael@0 | 1111 | |
michael@0 | 1112 | |
michael@0 | 1113 | /* Implemented in jsclone.cpp. */ |
michael@0 | 1114 | |
michael@0 | 1115 | extern JS_FRIEND_API(uint64_t) |
michael@0 | 1116 | js_GetSCOffset(JSStructuredCloneWriter* writer); |
michael@0 | 1117 | |
michael@0 | 1118 | /* Typed Array functions, implemented in jstypedarray.cpp */ |
michael@0 | 1119 | |
michael@0 | 1120 | namespace js { |
michael@0 | 1121 | namespace ArrayBufferView { |
michael@0 | 1122 | |
michael@0 | 1123 | enum ViewType { |
michael@0 | 1124 | TYPE_INT8 = 0, |
michael@0 | 1125 | TYPE_UINT8, |
michael@0 | 1126 | TYPE_INT16, |
michael@0 | 1127 | TYPE_UINT16, |
michael@0 | 1128 | TYPE_INT32, |
michael@0 | 1129 | TYPE_UINT32, |
michael@0 | 1130 | TYPE_FLOAT32, |
michael@0 | 1131 | TYPE_FLOAT64, |
michael@0 | 1132 | |
michael@0 | 1133 | /* |
michael@0 | 1134 | * Special type that is a uint8_t, but assignments are clamped to [0, 256). |
michael@0 | 1135 | * Treat the raw data type as a uint8_t. |
michael@0 | 1136 | */ |
michael@0 | 1137 | TYPE_UINT8_CLAMPED, |
michael@0 | 1138 | |
michael@0 | 1139 | /* |
michael@0 | 1140 | * Type returned for a DataView. Note that there is no single element type |
michael@0 | 1141 | * in this case. |
michael@0 | 1142 | */ |
michael@0 | 1143 | TYPE_DATAVIEW, |
michael@0 | 1144 | |
michael@0 | 1145 | TYPE_MAX |
michael@0 | 1146 | }; |
michael@0 | 1147 | |
michael@0 | 1148 | } /* namespace ArrayBufferView */ |
michael@0 | 1149 | |
michael@0 | 1150 | } /* namespace js */ |
michael@0 | 1151 | |
michael@0 | 1152 | typedef js::ArrayBufferView::ViewType JSArrayBufferViewType; |
michael@0 | 1153 | |
michael@0 | 1154 | /* |
michael@0 | 1155 | * Create a new typed array with nelements elements. |
michael@0 | 1156 | * |
michael@0 | 1157 | * These functions (except the WithBuffer variants) fill in the array with zeros. |
michael@0 | 1158 | */ |
michael@0 | 1159 | |
michael@0 | 1160 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1161 | JS_NewInt8Array(JSContext *cx, uint32_t nelements); |
michael@0 | 1162 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1163 | JS_NewUint8Array(JSContext *cx, uint32_t nelements); |
michael@0 | 1164 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1165 | JS_NewUint8ClampedArray(JSContext *cx, uint32_t nelements); |
michael@0 | 1166 | |
michael@0 | 1167 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1168 | JS_NewInt16Array(JSContext *cx, uint32_t nelements); |
michael@0 | 1169 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1170 | JS_NewUint16Array(JSContext *cx, uint32_t nelements); |
michael@0 | 1171 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1172 | JS_NewInt32Array(JSContext *cx, uint32_t nelements); |
michael@0 | 1173 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1174 | JS_NewUint32Array(JSContext *cx, uint32_t nelements); |
michael@0 | 1175 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1176 | JS_NewFloat32Array(JSContext *cx, uint32_t nelements); |
michael@0 | 1177 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1178 | JS_NewFloat64Array(JSContext *cx, uint32_t nelements); |
michael@0 | 1179 | |
michael@0 | 1180 | /* |
michael@0 | 1181 | * Create a new typed array and copy in values from the given object. The |
michael@0 | 1182 | * object is used as if it were an array; that is, the new array (if |
michael@0 | 1183 | * successfully created) will have length given by array.length, and its |
michael@0 | 1184 | * elements will be those specified by array[0], array[1], and so on, after |
michael@0 | 1185 | * conversion to the typed array element type. |
michael@0 | 1186 | */ |
michael@0 | 1187 | |
michael@0 | 1188 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1189 | JS_NewInt8ArrayFromArray(JSContext *cx, JS::HandleObject array); |
michael@0 | 1190 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1191 | JS_NewUint8ArrayFromArray(JSContext *cx, JS::HandleObject array); |
michael@0 | 1192 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1193 | JS_NewUint8ClampedArrayFromArray(JSContext *cx, JS::HandleObject array); |
michael@0 | 1194 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1195 | JS_NewInt16ArrayFromArray(JSContext *cx, JS::HandleObject array); |
michael@0 | 1196 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1197 | JS_NewUint16ArrayFromArray(JSContext *cx, JS::HandleObject array); |
michael@0 | 1198 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1199 | JS_NewInt32ArrayFromArray(JSContext *cx, JS::HandleObject array); |
michael@0 | 1200 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1201 | JS_NewUint32ArrayFromArray(JSContext *cx, JS::HandleObject array); |
michael@0 | 1202 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1203 | JS_NewFloat32ArrayFromArray(JSContext *cx, JS::HandleObject array); |
michael@0 | 1204 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1205 | JS_NewFloat64ArrayFromArray(JSContext *cx, JS::HandleObject array); |
michael@0 | 1206 | |
michael@0 | 1207 | /* |
michael@0 | 1208 | * Create a new typed array using the given ArrayBuffer for storage. The |
michael@0 | 1209 | * length value is optional; if -1 is passed, enough elements to use up the |
michael@0 | 1210 | * remainder of the byte array is used as the default value. |
michael@0 | 1211 | */ |
michael@0 | 1212 | |
michael@0 | 1213 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1214 | JS_NewInt8ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, |
michael@0 | 1215 | uint32_t byteOffset, int32_t length); |
michael@0 | 1216 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1217 | JS_NewUint8ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, |
michael@0 | 1218 | uint32_t byteOffset, int32_t length); |
michael@0 | 1219 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1220 | JS_NewUint8ClampedArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, |
michael@0 | 1221 | uint32_t byteOffset, int32_t length); |
michael@0 | 1222 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1223 | JS_NewInt16ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, |
michael@0 | 1224 | uint32_t byteOffset, int32_t length); |
michael@0 | 1225 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1226 | JS_NewUint16ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, |
michael@0 | 1227 | uint32_t byteOffset, int32_t length); |
michael@0 | 1228 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1229 | JS_NewInt32ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, |
michael@0 | 1230 | uint32_t byteOffset, int32_t length); |
michael@0 | 1231 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1232 | JS_NewUint32ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, |
michael@0 | 1233 | uint32_t byteOffset, int32_t length); |
michael@0 | 1234 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1235 | JS_NewFloat32ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, |
michael@0 | 1236 | uint32_t byteOffset, int32_t length); |
michael@0 | 1237 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1238 | JS_NewFloat64ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, |
michael@0 | 1239 | uint32_t byteOffset, int32_t length); |
michael@0 | 1240 | |
michael@0 | 1241 | /* |
michael@0 | 1242 | * Create a new ArrayBuffer with the given byte length. |
michael@0 | 1243 | */ |
michael@0 | 1244 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1245 | JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes); |
michael@0 | 1246 | |
michael@0 | 1247 | /* |
michael@0 | 1248 | * Check whether obj supports JS_GetTypedArray* APIs. Note that this may return |
michael@0 | 1249 | * false if a security wrapper is encountered that denies the unwrapping. If |
michael@0 | 1250 | * this test or one of the JS_Is*Array tests succeeds, then it is safe to call |
michael@0 | 1251 | * the various accessor JSAPI calls defined below. |
michael@0 | 1252 | */ |
michael@0 | 1253 | extern JS_FRIEND_API(bool) |
michael@0 | 1254 | JS_IsTypedArrayObject(JSObject *obj); |
michael@0 | 1255 | |
michael@0 | 1256 | /* |
michael@0 | 1257 | * Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may |
michael@0 | 1258 | * return false if a security wrapper is encountered that denies the |
michael@0 | 1259 | * unwrapping. If this test or one of the more specific tests succeeds, then it |
michael@0 | 1260 | * is safe to call the various ArrayBufferView accessor JSAPI calls defined |
michael@0 | 1261 | * below. |
michael@0 | 1262 | */ |
michael@0 | 1263 | extern JS_FRIEND_API(bool) |
michael@0 | 1264 | JS_IsArrayBufferViewObject(JSObject *obj); |
michael@0 | 1265 | |
michael@0 | 1266 | /* |
michael@0 | 1267 | * Test for specific typed array types (ArrayBufferView subtypes) |
michael@0 | 1268 | */ |
michael@0 | 1269 | |
michael@0 | 1270 | extern JS_FRIEND_API(bool) |
michael@0 | 1271 | JS_IsInt8Array(JSObject *obj); |
michael@0 | 1272 | extern JS_FRIEND_API(bool) |
michael@0 | 1273 | JS_IsUint8Array(JSObject *obj); |
michael@0 | 1274 | extern JS_FRIEND_API(bool) |
michael@0 | 1275 | JS_IsUint8ClampedArray(JSObject *obj); |
michael@0 | 1276 | extern JS_FRIEND_API(bool) |
michael@0 | 1277 | JS_IsInt16Array(JSObject *obj); |
michael@0 | 1278 | extern JS_FRIEND_API(bool) |
michael@0 | 1279 | JS_IsUint16Array(JSObject *obj); |
michael@0 | 1280 | extern JS_FRIEND_API(bool) |
michael@0 | 1281 | JS_IsInt32Array(JSObject *obj); |
michael@0 | 1282 | extern JS_FRIEND_API(bool) |
michael@0 | 1283 | JS_IsUint32Array(JSObject *obj); |
michael@0 | 1284 | extern JS_FRIEND_API(bool) |
michael@0 | 1285 | JS_IsFloat32Array(JSObject *obj); |
michael@0 | 1286 | extern JS_FRIEND_API(bool) |
michael@0 | 1287 | JS_IsFloat64Array(JSObject *obj); |
michael@0 | 1288 | |
michael@0 | 1289 | /* |
michael@0 | 1290 | * Test for specific typed array types (ArrayBufferView subtypes) and return |
michael@0 | 1291 | * the unwrapped object if so, else nullptr. Never throws. |
michael@0 | 1292 | */ |
michael@0 | 1293 | |
michael@0 | 1294 | namespace js { |
michael@0 | 1295 | |
michael@0 | 1296 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1297 | UnwrapInt8Array(JSObject *obj); |
michael@0 | 1298 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1299 | UnwrapUint8Array(JSObject *obj); |
michael@0 | 1300 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1301 | UnwrapUint8ClampedArray(JSObject *obj); |
michael@0 | 1302 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1303 | UnwrapInt16Array(JSObject *obj); |
michael@0 | 1304 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1305 | UnwrapUint16Array(JSObject *obj); |
michael@0 | 1306 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1307 | UnwrapInt32Array(JSObject *obj); |
michael@0 | 1308 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1309 | UnwrapUint32Array(JSObject *obj); |
michael@0 | 1310 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1311 | UnwrapFloat32Array(JSObject *obj); |
michael@0 | 1312 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1313 | UnwrapFloat64Array(JSObject *obj); |
michael@0 | 1314 | |
michael@0 | 1315 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1316 | UnwrapArrayBuffer(JSObject *obj); |
michael@0 | 1317 | |
michael@0 | 1318 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1319 | UnwrapArrayBufferView(JSObject *obj); |
michael@0 | 1320 | |
michael@0 | 1321 | namespace detail { |
michael@0 | 1322 | |
michael@0 | 1323 | extern JS_FRIEND_DATA(const Class* const) Int8ArrayClassPtr; |
michael@0 | 1324 | extern JS_FRIEND_DATA(const Class* const) Uint8ArrayClassPtr; |
michael@0 | 1325 | extern JS_FRIEND_DATA(const Class* const) Uint8ClampedArrayClassPtr; |
michael@0 | 1326 | extern JS_FRIEND_DATA(const Class* const) Int16ArrayClassPtr; |
michael@0 | 1327 | extern JS_FRIEND_DATA(const Class* const) Uint16ArrayClassPtr; |
michael@0 | 1328 | extern JS_FRIEND_DATA(const Class* const) Int32ArrayClassPtr; |
michael@0 | 1329 | extern JS_FRIEND_DATA(const Class* const) Uint32ArrayClassPtr; |
michael@0 | 1330 | extern JS_FRIEND_DATA(const Class* const) Float32ArrayClassPtr; |
michael@0 | 1331 | extern JS_FRIEND_DATA(const Class* const) Float64ArrayClassPtr; |
michael@0 | 1332 | |
michael@0 | 1333 | const size_t TypedArrayLengthSlot = 4; |
michael@0 | 1334 | |
michael@0 | 1335 | } // namespace detail |
michael@0 | 1336 | |
michael@0 | 1337 | /* |
michael@0 | 1338 | * Test for specific typed array types (ArrayBufferView subtypes) and return |
michael@0 | 1339 | * the unwrapped object if so, else nullptr. Never throws. |
michael@0 | 1340 | */ |
michael@0 | 1341 | |
michael@0 | 1342 | #define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \ |
michael@0 | 1343 | inline void \ |
michael@0 | 1344 | Get ## Type ## ArrayLengthAndData(JSObject *obj, uint32_t *length, type **data) \ |
michael@0 | 1345 | { \ |
michael@0 | 1346 | JS_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \ |
michael@0 | 1347 | const JS::Value &slot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \ |
michael@0 | 1348 | *length = mozilla::SafeCast<uint32_t>(slot.toInt32()); \ |
michael@0 | 1349 | *data = static_cast<type*>(GetObjectPrivate(obj)); \ |
michael@0 | 1350 | } |
michael@0 | 1351 | |
michael@0 | 1352 | JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int8, int8_t) |
michael@0 | 1353 | JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8, uint8_t) |
michael@0 | 1354 | JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8Clamped, uint8_t) |
michael@0 | 1355 | JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int16, int16_t) |
michael@0 | 1356 | JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint16, uint16_t) |
michael@0 | 1357 | JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int32, int32_t) |
michael@0 | 1358 | JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint32, uint32_t) |
michael@0 | 1359 | JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float32, float) |
michael@0 | 1360 | JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float64, double) |
michael@0 | 1361 | |
michael@0 | 1362 | #undef JS_DEFINE_DATA_AND_LENGTH_ACCESSOR |
michael@0 | 1363 | |
michael@0 | 1364 | // This one isn't inlined because it's rather tricky (by dint of having to deal |
michael@0 | 1365 | // with a dozen-plus classes and varying slot layouts. |
michael@0 | 1366 | extern JS_FRIEND_API(void) |
michael@0 | 1367 | GetArrayBufferViewLengthAndData(JSObject *obj, uint32_t *length, uint8_t **data); |
michael@0 | 1368 | |
michael@0 | 1369 | // This one isn't inlined because there are a bunch of different ArrayBuffer |
michael@0 | 1370 | // classes that would have to be individually handled here. |
michael@0 | 1371 | extern JS_FRIEND_API(void) |
michael@0 | 1372 | GetArrayBufferLengthAndData(JSObject *obj, uint32_t *length, uint8_t **data); |
michael@0 | 1373 | |
michael@0 | 1374 | } // namespace js |
michael@0 | 1375 | |
michael@0 | 1376 | /* |
michael@0 | 1377 | * Unwrap Typed arrays all at once. Return nullptr without throwing if the |
michael@0 | 1378 | * object cannot be viewed as the correct typed array, or the typed array |
michael@0 | 1379 | * object on success, filling both outparameters. |
michael@0 | 1380 | */ |
michael@0 | 1381 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1382 | JS_GetObjectAsInt8Array(JSObject *obj, uint32_t *length, int8_t **data); |
michael@0 | 1383 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1384 | JS_GetObjectAsUint8Array(JSObject *obj, uint32_t *length, uint8_t **data); |
michael@0 | 1385 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1386 | JS_GetObjectAsUint8ClampedArray(JSObject *obj, uint32_t *length, uint8_t **data); |
michael@0 | 1387 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1388 | JS_GetObjectAsInt16Array(JSObject *obj, uint32_t *length, int16_t **data); |
michael@0 | 1389 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1390 | JS_GetObjectAsUint16Array(JSObject *obj, uint32_t *length, uint16_t **data); |
michael@0 | 1391 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1392 | JS_GetObjectAsInt32Array(JSObject *obj, uint32_t *length, int32_t **data); |
michael@0 | 1393 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1394 | JS_GetObjectAsUint32Array(JSObject *obj, uint32_t *length, uint32_t **data); |
michael@0 | 1395 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1396 | JS_GetObjectAsFloat32Array(JSObject *obj, uint32_t *length, float **data); |
michael@0 | 1397 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1398 | JS_GetObjectAsFloat64Array(JSObject *obj, uint32_t *length, double **data); |
michael@0 | 1399 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1400 | JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data); |
michael@0 | 1401 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1402 | JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data); |
michael@0 | 1403 | |
michael@0 | 1404 | /* |
michael@0 | 1405 | * Get the type of elements in a typed array, or TYPE_DATAVIEW if a DataView. |
michael@0 | 1406 | * |
michael@0 | 1407 | * |obj| must have passed a JS_IsArrayBufferView/JS_Is*Array test, or somehow |
michael@0 | 1408 | * be known that it would pass such a test: it is an ArrayBufferView or a |
michael@0 | 1409 | * wrapper of an ArrayBufferView, and the unwrapping will succeed. |
michael@0 | 1410 | */ |
michael@0 | 1411 | extern JS_FRIEND_API(JSArrayBufferViewType) |
michael@0 | 1412 | JS_GetArrayBufferViewType(JSObject *obj); |
michael@0 | 1413 | |
michael@0 | 1414 | /* |
michael@0 | 1415 | * Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may |
michael@0 | 1416 | * return false if a security wrapper is encountered that denies the |
michael@0 | 1417 | * unwrapping. If this test succeeds, then it is safe to call the various |
michael@0 | 1418 | * accessor JSAPI calls defined below. |
michael@0 | 1419 | */ |
michael@0 | 1420 | extern JS_FRIEND_API(bool) |
michael@0 | 1421 | JS_IsArrayBufferObject(JSObject *obj); |
michael@0 | 1422 | |
michael@0 | 1423 | /* |
michael@0 | 1424 | * Return the available byte length of an array buffer. |
michael@0 | 1425 | * |
michael@0 | 1426 | * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known |
michael@0 | 1427 | * that it would pass such a test: it is an ArrayBuffer or a wrapper of an |
michael@0 | 1428 | * ArrayBuffer, and the unwrapping will succeed. |
michael@0 | 1429 | */ |
michael@0 | 1430 | extern JS_FRIEND_API(uint32_t) |
michael@0 | 1431 | JS_GetArrayBufferByteLength(JSObject *obj); |
michael@0 | 1432 | |
michael@0 | 1433 | /* |
michael@0 | 1434 | * Check whether the obj is ArrayBufferObject and memory mapped. Note that this |
michael@0 | 1435 | * may return false if a security wrapper is encountered that denies the |
michael@0 | 1436 | * unwrapping. |
michael@0 | 1437 | */ |
michael@0 | 1438 | extern JS_FRIEND_API(bool) |
michael@0 | 1439 | JS_IsMappedArrayBufferObject(JSObject *obj); |
michael@0 | 1440 | |
michael@0 | 1441 | /* |
michael@0 | 1442 | * Return the number of elements in a typed array. |
michael@0 | 1443 | * |
michael@0 | 1444 | * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow |
michael@0 | 1445 | * be known that it would pass such a test: it is a typed array or a wrapper of |
michael@0 | 1446 | * a typed array, and the unwrapping will succeed. |
michael@0 | 1447 | */ |
michael@0 | 1448 | extern JS_FRIEND_API(uint32_t) |
michael@0 | 1449 | JS_GetTypedArrayLength(JSObject *obj); |
michael@0 | 1450 | |
michael@0 | 1451 | /* |
michael@0 | 1452 | * Return the byte offset from the start of an array buffer to the start of a |
michael@0 | 1453 | * typed array view. |
michael@0 | 1454 | * |
michael@0 | 1455 | * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow |
michael@0 | 1456 | * be known that it would pass such a test: it is a typed array or a wrapper of |
michael@0 | 1457 | * a typed array, and the unwrapping will succeed. |
michael@0 | 1458 | */ |
michael@0 | 1459 | extern JS_FRIEND_API(uint32_t) |
michael@0 | 1460 | JS_GetTypedArrayByteOffset(JSObject *obj); |
michael@0 | 1461 | |
michael@0 | 1462 | /* |
michael@0 | 1463 | * Return the byte length of a typed array. |
michael@0 | 1464 | * |
michael@0 | 1465 | * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow |
michael@0 | 1466 | * be known that it would pass such a test: it is a typed array or a wrapper of |
michael@0 | 1467 | * a typed array, and the unwrapping will succeed. |
michael@0 | 1468 | */ |
michael@0 | 1469 | extern JS_FRIEND_API(uint32_t) |
michael@0 | 1470 | JS_GetTypedArrayByteLength(JSObject *obj); |
michael@0 | 1471 | |
michael@0 | 1472 | /* |
michael@0 | 1473 | * Check whether obj supports JS_ArrayBufferView* APIs. Note that this may |
michael@0 | 1474 | * return false if a security wrapper is encountered that denies the |
michael@0 | 1475 | * unwrapping. |
michael@0 | 1476 | */ |
michael@0 | 1477 | extern JS_FRIEND_API(bool) |
michael@0 | 1478 | JS_IsArrayBufferViewObject(JSObject *obj); |
michael@0 | 1479 | |
michael@0 | 1480 | /* |
michael@0 | 1481 | * More generic name for JS_GetTypedArrayByteLength to cover DataViews as well |
michael@0 | 1482 | */ |
michael@0 | 1483 | extern JS_FRIEND_API(uint32_t) |
michael@0 | 1484 | JS_GetArrayBufferViewByteLength(JSObject *obj); |
michael@0 | 1485 | |
michael@0 | 1486 | /* |
michael@0 | 1487 | * Return a pointer to the start of the data referenced by a typed array. The |
michael@0 | 1488 | * data is still owned by the typed array, and should not be modified on |
michael@0 | 1489 | * another thread. Furthermore, the pointer can become invalid on GC (if the |
michael@0 | 1490 | * data is small and fits inside the array's GC header), so callers must take |
michael@0 | 1491 | * care not to hold on across anything that could GC. |
michael@0 | 1492 | * |
michael@0 | 1493 | * |obj| must have passed a JS_Is*Array test, or somehow be known that it would |
michael@0 | 1494 | * pass such a test: it is a typed array or a wrapper of a typed array, and the |
michael@0 | 1495 | * unwrapping will succeed. |
michael@0 | 1496 | */ |
michael@0 | 1497 | |
michael@0 | 1498 | extern JS_FRIEND_API(uint8_t *) |
michael@0 | 1499 | JS_GetArrayBufferData(JSObject *obj); |
michael@0 | 1500 | extern JS_FRIEND_API(int8_t *) |
michael@0 | 1501 | JS_GetInt8ArrayData(JSObject *obj); |
michael@0 | 1502 | extern JS_FRIEND_API(uint8_t *) |
michael@0 | 1503 | JS_GetUint8ArrayData(JSObject *obj); |
michael@0 | 1504 | extern JS_FRIEND_API(uint8_t *) |
michael@0 | 1505 | JS_GetUint8ClampedArrayData(JSObject *obj); |
michael@0 | 1506 | extern JS_FRIEND_API(int16_t *) |
michael@0 | 1507 | JS_GetInt16ArrayData(JSObject *obj); |
michael@0 | 1508 | extern JS_FRIEND_API(uint16_t *) |
michael@0 | 1509 | JS_GetUint16ArrayData(JSObject *obj); |
michael@0 | 1510 | extern JS_FRIEND_API(int32_t *) |
michael@0 | 1511 | JS_GetInt32ArrayData(JSObject *obj); |
michael@0 | 1512 | extern JS_FRIEND_API(uint32_t *) |
michael@0 | 1513 | JS_GetUint32ArrayData(JSObject *obj); |
michael@0 | 1514 | extern JS_FRIEND_API(float *) |
michael@0 | 1515 | JS_GetFloat32ArrayData(JSObject *obj); |
michael@0 | 1516 | extern JS_FRIEND_API(double *) |
michael@0 | 1517 | JS_GetFloat64ArrayData(JSObject *obj); |
michael@0 | 1518 | |
michael@0 | 1519 | /* |
michael@0 | 1520 | * Stable versions of the above functions where the buffer remains valid as long |
michael@0 | 1521 | * as the object is live. |
michael@0 | 1522 | */ |
michael@0 | 1523 | extern JS_FRIEND_API(uint8_t *) |
michael@0 | 1524 | JS_GetStableArrayBufferData(JSContext *cx, JS::HandleObject obj); |
michael@0 | 1525 | |
michael@0 | 1526 | /* |
michael@0 | 1527 | * Same as above, but for any kind of ArrayBufferView. Prefer the type-specific |
michael@0 | 1528 | * versions when possible. |
michael@0 | 1529 | */ |
michael@0 | 1530 | extern JS_FRIEND_API(void *) |
michael@0 | 1531 | JS_GetArrayBufferViewData(JSObject *obj); |
michael@0 | 1532 | |
michael@0 | 1533 | /* |
michael@0 | 1534 | * Return the ArrayBuffer underlying an ArrayBufferView. If the buffer has been |
michael@0 | 1535 | * neutered, this will still return the neutered buffer. |obj| must be an |
michael@0 | 1536 | * object that would return true for JS_IsArrayBufferViewObject(). |
michael@0 | 1537 | */ |
michael@0 | 1538 | extern JS_FRIEND_API(JSObject *) |
michael@0 | 1539 | JS_GetArrayBufferViewBuffer(JSContext *cx, JSObject *obj); |
michael@0 | 1540 | |
michael@0 | 1541 | typedef enum { |
michael@0 | 1542 | ChangeData, |
michael@0 | 1543 | KeepData |
michael@0 | 1544 | } NeuterDataDisposition; |
michael@0 | 1545 | |
michael@0 | 1546 | /* |
michael@0 | 1547 | * Set an ArrayBuffer's length to 0 and neuter all of its views. |
michael@0 | 1548 | * |
michael@0 | 1549 | * The |changeData| argument is a hint to inform internal behavior with respect |
michael@0 | 1550 | * to the internal pointer to the ArrayBuffer's data after being neutered. |
michael@0 | 1551 | * There is no guarantee it will be respected. But if it is respected, the |
michael@0 | 1552 | * ArrayBuffer's internal data pointer will, or will not, have changed |
michael@0 | 1553 | * accordingly. |
michael@0 | 1554 | */ |
michael@0 | 1555 | extern JS_FRIEND_API(bool) |
michael@0 | 1556 | JS_NeuterArrayBuffer(JSContext *cx, JS::HandleObject obj, |
michael@0 | 1557 | NeuterDataDisposition changeData); |
michael@0 | 1558 | |
michael@0 | 1559 | /* |
michael@0 | 1560 | * Check whether obj supports JS_GetDataView* APIs. |
michael@0 | 1561 | */ |
michael@0 | 1562 | JS_FRIEND_API(bool) |
michael@0 | 1563 | JS_IsDataViewObject(JSObject *obj); |
michael@0 | 1564 | |
michael@0 | 1565 | /* |
michael@0 | 1566 | * Return the byte offset of a data view into its array buffer. |obj| must be a |
michael@0 | 1567 | * DataView. |
michael@0 | 1568 | * |
michael@0 | 1569 | * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that |
michael@0 | 1570 | * it would pass such a test: it is a data view or a wrapper of a data view, |
michael@0 | 1571 | * and the unwrapping will succeed. |
michael@0 | 1572 | */ |
michael@0 | 1573 | JS_FRIEND_API(uint32_t) |
michael@0 | 1574 | JS_GetDataViewByteOffset(JSObject *obj); |
michael@0 | 1575 | |
michael@0 | 1576 | /* |
michael@0 | 1577 | * Return the byte length of a data view. |
michael@0 | 1578 | * |
michael@0 | 1579 | * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that |
michael@0 | 1580 | * it would pass such a test: it is a data view or a wrapper of a data view, |
michael@0 | 1581 | * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be |
michael@0 | 1582 | * unable to assert when unwrapping should be disallowed. |
michael@0 | 1583 | */ |
michael@0 | 1584 | JS_FRIEND_API(uint32_t) |
michael@0 | 1585 | JS_GetDataViewByteLength(JSObject *obj); |
michael@0 | 1586 | |
michael@0 | 1587 | /* |
michael@0 | 1588 | * Return a pointer to the beginning of the data referenced by a DataView. |
michael@0 | 1589 | * |
michael@0 | 1590 | * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that |
michael@0 | 1591 | * it would pass such a test: it is a data view or a wrapper of a data view, |
michael@0 | 1592 | * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be |
michael@0 | 1593 | * unable to assert when unwrapping should be disallowed. |
michael@0 | 1594 | */ |
michael@0 | 1595 | JS_FRIEND_API(void *) |
michael@0 | 1596 | JS_GetDataViewData(JSObject *obj); |
michael@0 | 1597 | |
michael@0 | 1598 | namespace js { |
michael@0 | 1599 | |
michael@0 | 1600 | /* |
michael@0 | 1601 | * Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the |
michael@0 | 1602 | * property |id|, using the callable object |callable| as the function to be |
michael@0 | 1603 | * called for notifications. |
michael@0 | 1604 | * |
michael@0 | 1605 | * This is an internal function exposed -- temporarily -- only so that DOM |
michael@0 | 1606 | * proxies can be watchable. Don't use it! We'll soon kill off the |
michael@0 | 1607 | * Object.prototype.{,un}watch functions, at which point this will go too. |
michael@0 | 1608 | */ |
michael@0 | 1609 | extern JS_FRIEND_API(bool) |
michael@0 | 1610 | WatchGuts(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); |
michael@0 | 1611 | |
michael@0 | 1612 | /* |
michael@0 | 1613 | * Remove a watchpoint -- in the Object.prototype.watch sense -- from |obj| for |
michael@0 | 1614 | * the property |id|. |
michael@0 | 1615 | * |
michael@0 | 1616 | * This is an internal function exposed -- temporarily -- only so that DOM |
michael@0 | 1617 | * proxies can be watchable. Don't use it! We'll soon kill off the |
michael@0 | 1618 | * Object.prototype.{,un}watch functions, at which point this will go too. |
michael@0 | 1619 | */ |
michael@0 | 1620 | extern JS_FRIEND_API(bool) |
michael@0 | 1621 | UnwatchGuts(JSContext *cx, JS::HandleObject obj, JS::HandleId id); |
michael@0 | 1622 | |
michael@0 | 1623 | } // namespace js |
michael@0 | 1624 | |
michael@0 | 1625 | /* |
michael@0 | 1626 | * A class, expected to be passed by value, which represents the CallArgs for a |
michael@0 | 1627 | * JSJitGetterOp. |
michael@0 | 1628 | */ |
michael@0 | 1629 | class JSJitGetterCallArgs : protected JS::MutableHandleValue |
michael@0 | 1630 | { |
michael@0 | 1631 | public: |
michael@0 | 1632 | explicit JSJitGetterCallArgs(const JS::CallArgs& args) |
michael@0 | 1633 | : JS::MutableHandleValue(args.rval()) |
michael@0 | 1634 | {} |
michael@0 | 1635 | |
michael@0 | 1636 | explicit JSJitGetterCallArgs(JS::RootedValue* rooted) |
michael@0 | 1637 | : JS::MutableHandleValue(rooted) |
michael@0 | 1638 | {} |
michael@0 | 1639 | |
michael@0 | 1640 | JS::MutableHandleValue rval() { |
michael@0 | 1641 | return *this; |
michael@0 | 1642 | } |
michael@0 | 1643 | }; |
michael@0 | 1644 | |
michael@0 | 1645 | /* |
michael@0 | 1646 | * A class, expected to be passed by value, which represents the CallArgs for a |
michael@0 | 1647 | * JSJitSetterOp. |
michael@0 | 1648 | */ |
michael@0 | 1649 | class JSJitSetterCallArgs : protected JS::MutableHandleValue |
michael@0 | 1650 | { |
michael@0 | 1651 | public: |
michael@0 | 1652 | explicit JSJitSetterCallArgs(const JS::CallArgs& args) |
michael@0 | 1653 | : JS::MutableHandleValue(args[0]) |
michael@0 | 1654 | {} |
michael@0 | 1655 | |
michael@0 | 1656 | JS::MutableHandleValue operator[](unsigned i) { |
michael@0 | 1657 | MOZ_ASSERT(i == 0); |
michael@0 | 1658 | return *this; |
michael@0 | 1659 | } |
michael@0 | 1660 | |
michael@0 | 1661 | unsigned length() const { return 1; } |
michael@0 | 1662 | |
michael@0 | 1663 | // Add get() or maybe hasDefined() as needed |
michael@0 | 1664 | }; |
michael@0 | 1665 | |
michael@0 | 1666 | struct JSJitMethodCallArgsTraits; |
michael@0 | 1667 | |
michael@0 | 1668 | /* |
michael@0 | 1669 | * A class, expected to be passed by reference, which represents the CallArgs |
michael@0 | 1670 | * for a JSJitMethodOp. |
michael@0 | 1671 | */ |
michael@0 | 1672 | class JSJitMethodCallArgs : protected JS::detail::CallArgsBase<JS::detail::NoUsedRval> |
michael@0 | 1673 | { |
michael@0 | 1674 | private: |
michael@0 | 1675 | typedef JS::detail::CallArgsBase<JS::detail::NoUsedRval> Base; |
michael@0 | 1676 | friend struct JSJitMethodCallArgsTraits; |
michael@0 | 1677 | |
michael@0 | 1678 | public: |
michael@0 | 1679 | explicit JSJitMethodCallArgs(const JS::CallArgs& args) { |
michael@0 | 1680 | argv_ = args.array(); |
michael@0 | 1681 | argc_ = args.length(); |
michael@0 | 1682 | } |
michael@0 | 1683 | |
michael@0 | 1684 | JS::MutableHandleValue rval() const { |
michael@0 | 1685 | return Base::rval(); |
michael@0 | 1686 | } |
michael@0 | 1687 | |
michael@0 | 1688 | unsigned length() const { return Base::length(); } |
michael@0 | 1689 | |
michael@0 | 1690 | JS::MutableHandleValue operator[](unsigned i) const { |
michael@0 | 1691 | return Base::operator[](i); |
michael@0 | 1692 | } |
michael@0 | 1693 | |
michael@0 | 1694 | bool hasDefined(unsigned i) const { |
michael@0 | 1695 | return Base::hasDefined(i); |
michael@0 | 1696 | } |
michael@0 | 1697 | |
michael@0 | 1698 | JSObject &callee() const { |
michael@0 | 1699 | // We can't use Base::callee() because that will try to poke at |
michael@0 | 1700 | // this->usedRval_, which we don't have. |
michael@0 | 1701 | return argv_[-2].toObject(); |
michael@0 | 1702 | } |
michael@0 | 1703 | |
michael@0 | 1704 | // Add get() as needed |
michael@0 | 1705 | }; |
michael@0 | 1706 | |
michael@0 | 1707 | struct JSJitMethodCallArgsTraits |
michael@0 | 1708 | { |
michael@0 | 1709 | static const size_t offsetOfArgv = offsetof(JSJitMethodCallArgs, argv_); |
michael@0 | 1710 | static const size_t offsetOfArgc = offsetof(JSJitMethodCallArgs, argc_); |
michael@0 | 1711 | }; |
michael@0 | 1712 | |
michael@0 | 1713 | /* |
michael@0 | 1714 | * This struct contains metadata passed from the DOM to the JS Engine for JIT |
michael@0 | 1715 | * optimizations on DOM property accessors. Eventually, this should be made |
michael@0 | 1716 | * available to general JSAPI users, but we are not currently ready to do so. |
michael@0 | 1717 | */ |
michael@0 | 1718 | typedef bool |
michael@0 | 1719 | (* JSJitGetterOp)(JSContext *cx, JS::HandleObject thisObj, |
michael@0 | 1720 | void *specializedThis, JSJitGetterCallArgs args); |
michael@0 | 1721 | typedef bool |
michael@0 | 1722 | (* JSJitSetterOp)(JSContext *cx, JS::HandleObject thisObj, |
michael@0 | 1723 | void *specializedThis, JSJitSetterCallArgs args); |
michael@0 | 1724 | typedef bool |
michael@0 | 1725 | (* JSJitMethodOp)(JSContext *cx, JS::HandleObject thisObj, |
michael@0 | 1726 | void *specializedThis, const JSJitMethodCallArgs& args); |
michael@0 | 1727 | |
michael@0 | 1728 | struct JSJitInfo { |
michael@0 | 1729 | enum OpType { |
michael@0 | 1730 | Getter, |
michael@0 | 1731 | Setter, |
michael@0 | 1732 | Method, |
michael@0 | 1733 | ParallelNative, |
michael@0 | 1734 | StaticMethod, |
michael@0 | 1735 | // Must be last |
michael@0 | 1736 | OpTypeCount |
michael@0 | 1737 | }; |
michael@0 | 1738 | |
michael@0 | 1739 | enum ArgType { |
michael@0 | 1740 | // Basic types |
michael@0 | 1741 | String = (1 << 0), |
michael@0 | 1742 | Integer = (1 << 1), // Only 32-bit or less |
michael@0 | 1743 | Double = (1 << 2), // Maybe we want to add Float sometime too |
michael@0 | 1744 | Boolean = (1 << 3), |
michael@0 | 1745 | Object = (1 << 4), |
michael@0 | 1746 | Null = (1 << 5), |
michael@0 | 1747 | |
michael@0 | 1748 | // And derived types |
michael@0 | 1749 | Numeric = Integer | Double, |
michael@0 | 1750 | // Should "Primitive" use the WebIDL definition, which |
michael@0 | 1751 | // excludes string and null, or the typical JS one that includes them? |
michael@0 | 1752 | Primitive = Numeric | Boolean | Null | String, |
michael@0 | 1753 | ObjectOrNull = Object | Null, |
michael@0 | 1754 | Any = ObjectOrNull | Primitive, |
michael@0 | 1755 | |
michael@0 | 1756 | // Our sentinel value. |
michael@0 | 1757 | ArgTypeListEnd = (1 << 31) |
michael@0 | 1758 | }; |
michael@0 | 1759 | |
michael@0 | 1760 | static_assert(Any & String, "Any must include String."); |
michael@0 | 1761 | static_assert(Any & Integer, "Any must include Integer."); |
michael@0 | 1762 | static_assert(Any & Double, "Any must include Double."); |
michael@0 | 1763 | static_assert(Any & Boolean, "Any must include Boolean."); |
michael@0 | 1764 | static_assert(Any & Object, "Any must include Object."); |
michael@0 | 1765 | static_assert(Any & Null, "Any must include Null."); |
michael@0 | 1766 | |
michael@0 | 1767 | enum AliasSet { |
michael@0 | 1768 | // An enum that describes what this getter/setter/method aliases. This |
michael@0 | 1769 | // determines what things can be hoisted past this call, and if this |
michael@0 | 1770 | // call is movable what it can be hoisted past. |
michael@0 | 1771 | |
michael@0 | 1772 | // Alias nothing: a constant value, getting it can't affect any other |
michael@0 | 1773 | // values, nothing can affect it. |
michael@0 | 1774 | AliasNone, |
michael@0 | 1775 | |
michael@0 | 1776 | // Alias things that can modify the DOM but nothing else. Doing the |
michael@0 | 1777 | // call can't affect the behavior of any other function. |
michael@0 | 1778 | AliasDOMSets, |
michael@0 | 1779 | |
michael@0 | 1780 | // Alias the world. Calling this can change arbitrary values anywhere |
michael@0 | 1781 | // in the system. Most things fall in this bucket. |
michael@0 | 1782 | AliasEverything, |
michael@0 | 1783 | |
michael@0 | 1784 | // Must be last. |
michael@0 | 1785 | AliasSetCount |
michael@0 | 1786 | }; |
michael@0 | 1787 | |
michael@0 | 1788 | bool hasParallelNative() const |
michael@0 | 1789 | { |
michael@0 | 1790 | return type() == ParallelNative; |
michael@0 | 1791 | } |
michael@0 | 1792 | |
michael@0 | 1793 | bool needsOuterizedThisObject() const |
michael@0 | 1794 | { |
michael@0 | 1795 | return type() != Getter && type() != Setter; |
michael@0 | 1796 | } |
michael@0 | 1797 | |
michael@0 | 1798 | bool isTypedMethodJitInfo() const |
michael@0 | 1799 | { |
michael@0 | 1800 | return isTypedMethod; |
michael@0 | 1801 | } |
michael@0 | 1802 | |
michael@0 | 1803 | OpType type() const |
michael@0 | 1804 | { |
michael@0 | 1805 | return OpType(type_); |
michael@0 | 1806 | } |
michael@0 | 1807 | |
michael@0 | 1808 | AliasSet aliasSet() const |
michael@0 | 1809 | { |
michael@0 | 1810 | return AliasSet(aliasSet_); |
michael@0 | 1811 | } |
michael@0 | 1812 | |
michael@0 | 1813 | JSValueType returnType() const |
michael@0 | 1814 | { |
michael@0 | 1815 | return JSValueType(returnType_); |
michael@0 | 1816 | } |
michael@0 | 1817 | |
michael@0 | 1818 | union { |
michael@0 | 1819 | JSJitGetterOp getter; |
michael@0 | 1820 | JSJitSetterOp setter; |
michael@0 | 1821 | JSJitMethodOp method; |
michael@0 | 1822 | /* An alternative native that's safe to call in parallel mode. */ |
michael@0 | 1823 | JSParallelNative parallelNative; |
michael@0 | 1824 | /* A DOM static method, used for Promise wrappers */ |
michael@0 | 1825 | JSNative staticMethod; |
michael@0 | 1826 | }; |
michael@0 | 1827 | |
michael@0 | 1828 | uint16_t protoID; |
michael@0 | 1829 | uint16_t depth; |
michael@0 | 1830 | |
michael@0 | 1831 | // These fields are carefully packed to take up 4 bytes. If you need more |
michael@0 | 1832 | // bits for whatever reason, please see if you can steal bits from existing |
michael@0 | 1833 | // fields before adding more members to this structure. |
michael@0 | 1834 | |
michael@0 | 1835 | #define JITINFO_OP_TYPE_BITS 4 |
michael@0 | 1836 | #define JITINFO_ALIAS_SET_BITS 4 |
michael@0 | 1837 | #define JITINFO_RETURN_TYPE_BITS 8 |
michael@0 | 1838 | |
michael@0 | 1839 | // The OpType that says what sort of function we are. |
michael@0 | 1840 | uint32_t type_ : JITINFO_OP_TYPE_BITS; |
michael@0 | 1841 | |
michael@0 | 1842 | // The alias set for this op. This is a _minimal_ alias set; in |
michael@0 | 1843 | // particular for a method it does not include whatever argument |
michael@0 | 1844 | // conversions might do. That's covered by argTypes and runtime |
michael@0 | 1845 | // analysis of the actual argument types being passed in. |
michael@0 | 1846 | uint32_t aliasSet_ : JITINFO_ALIAS_SET_BITS; |
michael@0 | 1847 | |
michael@0 | 1848 | // The return type tag. Might be JSVAL_TYPE_UNKNOWN. |
michael@0 | 1849 | uint32_t returnType_ : JITINFO_RETURN_TYPE_BITS; |
michael@0 | 1850 | |
michael@0 | 1851 | static_assert(OpTypeCount <= (1 << JITINFO_OP_TYPE_BITS), |
michael@0 | 1852 | "Not enough space for OpType"); |
michael@0 | 1853 | static_assert(AliasSetCount <= (1 << JITINFO_ALIAS_SET_BITS), |
michael@0 | 1854 | "Not enough space for AliasSet"); |
michael@0 | 1855 | static_assert((sizeof(JSValueType) * 8) <= JITINFO_RETURN_TYPE_BITS, |
michael@0 | 1856 | "Not enough space for JSValueType"); |
michael@0 | 1857 | |
michael@0 | 1858 | #undef JITINFO_RETURN_TYPE_BITS |
michael@0 | 1859 | #undef JITINFO_ALIAS_SET_BITS |
michael@0 | 1860 | #undef JITINFO_OP_TYPE_BITS |
michael@0 | 1861 | |
michael@0 | 1862 | uint32_t isInfallible : 1; /* Is op fallible? False in setters. */ |
michael@0 | 1863 | uint32_t isMovable : 1; /* Is op movable? To be movable the op must |
michael@0 | 1864 | not AliasEverything, but even that might |
michael@0 | 1865 | not be enough (e.g. in cases when it can |
michael@0 | 1866 | throw). */ |
michael@0 | 1867 | // XXXbz should we have a JSValueType for the type of the member? |
michael@0 | 1868 | uint32_t isInSlot : 1; /* True if this is a getter that can get a member |
michael@0 | 1869 | from a slot of the "this" object directly. */ |
michael@0 | 1870 | uint32_t isTypedMethod : 1; /* True if this is an instance of |
michael@0 | 1871 | JSTypedMethodJitInfo. */ |
michael@0 | 1872 | uint32_t slotIndex : 12; /* If isInSlot is true, the index of the slot to |
michael@0 | 1873 | get the value from. Otherwise 0. */ |
michael@0 | 1874 | }; |
michael@0 | 1875 | |
michael@0 | 1876 | static_assert(sizeof(JSJitInfo) == (sizeof(void*) + 2 * sizeof(uint32_t)), |
michael@0 | 1877 | "There are several thousand instances of JSJitInfo stored in " |
michael@0 | 1878 | "a binary. Please don't increase its space requirements without " |
michael@0 | 1879 | "verifying that there is no other way forward (better packing, " |
michael@0 | 1880 | "smaller datatypes for fields, subclassing, etc.)."); |
michael@0 | 1881 | |
michael@0 | 1882 | struct JSTypedMethodJitInfo |
michael@0 | 1883 | { |
michael@0 | 1884 | // We use C-style inheritance here, rather than C++ style inheritance |
michael@0 | 1885 | // because not all compilers support brace-initialization for non-aggregate |
michael@0 | 1886 | // classes. Using C++ style inheritance and constructors instead of |
michael@0 | 1887 | // brace-initialization would also force the creation of static |
michael@0 | 1888 | // constructors (on some compilers) when JSJitInfo and JSTypedMethodJitInfo |
michael@0 | 1889 | // structures are declared. Since there can be several thousand of these |
michael@0 | 1890 | // structures present and we want to have roughly equivalent performance |
michael@0 | 1891 | // across a range of compilers, we do things manually. |
michael@0 | 1892 | JSJitInfo base; |
michael@0 | 1893 | |
michael@0 | 1894 | const JSJitInfo::ArgType* const argTypes; /* For a method, a list of sets of |
michael@0 | 1895 | types that the function |
michael@0 | 1896 | expects. This can be used, |
michael@0 | 1897 | for example, to figure out |
michael@0 | 1898 | when argument coercions can |
michael@0 | 1899 | have side-effects. */ |
michael@0 | 1900 | }; |
michael@0 | 1901 | |
michael@0 | 1902 | namespace JS { |
michael@0 | 1903 | namespace detail { |
michael@0 | 1904 | |
michael@0 | 1905 | /* NEVER DEFINED, DON'T USE. For use by JS_CAST_PARALLEL_NATIVE_TO only. */ |
michael@0 | 1906 | inline int CheckIsParallelNative(JSParallelNative parallelNative); |
michael@0 | 1907 | |
michael@0 | 1908 | } // namespace detail |
michael@0 | 1909 | } // namespace JS |
michael@0 | 1910 | |
michael@0 | 1911 | #define JS_CAST_PARALLEL_NATIVE_TO(v, To) \ |
michael@0 | 1912 | (static_cast<void>(sizeof(JS::detail::CheckIsParallelNative(v))), \ |
michael@0 | 1913 | reinterpret_cast<To>(v)) |
michael@0 | 1914 | |
michael@0 | 1915 | /* |
michael@0 | 1916 | * You may ask yourself: why do we define a wrapper around a wrapper here? |
michael@0 | 1917 | * The answer is that some compilers don't understand initializing a union |
michael@0 | 1918 | * as we do below with a construct like: |
michael@0 | 1919 | * |
michael@0 | 1920 | * reinterpret_cast<JSJitGetterOp>(JSParallelNativeThreadSafeWrapper<op>) |
michael@0 | 1921 | * |
michael@0 | 1922 | * (We need the reinterpret_cast because we must initialize the union with |
michael@0 | 1923 | * a datum of the type of the union's first member.) |
michael@0 | 1924 | * |
michael@0 | 1925 | * Presumably this has something to do with template instantiation. |
michael@0 | 1926 | * Initializing with a normal function pointer seems to work fine. Hence |
michael@0 | 1927 | * the ugliness that you see before you. |
michael@0 | 1928 | */ |
michael@0 | 1929 | #define JS_JITINFO_NATIVE_PARALLEL(infoName, parallelOp) \ |
michael@0 | 1930 | const JSJitInfo infoName = \ |
michael@0 | 1931 | {{JS_CAST_PARALLEL_NATIVE_TO(parallelOp, JSJitGetterOp)},0,0,JSJitInfo::ParallelNative,JSJitInfo::AliasEverything,JSVAL_TYPE_MISSING,false,false,false,false,0} |
michael@0 | 1932 | |
michael@0 | 1933 | #define JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(infoName, wrapperName, serialOp) \ |
michael@0 | 1934 | bool wrapperName##_ParallelNativeThreadSafeWrapper(js::ForkJoinContext *cx, unsigned argc, \ |
michael@0 | 1935 | JS::Value *vp) \ |
michael@0 | 1936 | { \ |
michael@0 | 1937 | return JSParallelNativeThreadSafeWrapper<serialOp>(cx, argc, vp); \ |
michael@0 | 1938 | } \ |
michael@0 | 1939 | JS_JITINFO_NATIVE_PARALLEL(infoName, wrapperName##_ParallelNativeThreadSafeWrapper) |
michael@0 | 1940 | |
michael@0 | 1941 | static MOZ_ALWAYS_INLINE const JSJitInfo * |
michael@0 | 1942 | FUNCTION_VALUE_TO_JITINFO(const JS::Value& v) |
michael@0 | 1943 | { |
michael@0 | 1944 | JS_ASSERT(js::GetObjectClass(&v.toObject()) == js::FunctionClassPtr); |
michael@0 | 1945 | return reinterpret_cast<js::shadow::Function *>(&v.toObject())->jitinfo; |
michael@0 | 1946 | } |
michael@0 | 1947 | |
michael@0 | 1948 | /* Statically asserted in jsfun.h. */ |
michael@0 | 1949 | static const unsigned JS_FUNCTION_INTERPRETED_BIT = 0x1; |
michael@0 | 1950 | |
michael@0 | 1951 | static MOZ_ALWAYS_INLINE void |
michael@0 | 1952 | SET_JITINFO(JSFunction * func, const JSJitInfo *info) |
michael@0 | 1953 | { |
michael@0 | 1954 | js::shadow::Function *fun = reinterpret_cast<js::shadow::Function *>(func); |
michael@0 | 1955 | JS_ASSERT(!(fun->flags & JS_FUNCTION_INTERPRETED_BIT)); |
michael@0 | 1956 | fun->jitinfo = info; |
michael@0 | 1957 | } |
michael@0 | 1958 | |
michael@0 | 1959 | /* |
michael@0 | 1960 | * Engine-internal extensions of jsid. This code is here only until we |
michael@0 | 1961 | * eliminate Gecko's dependencies on it! |
michael@0 | 1962 | */ |
michael@0 | 1963 | |
michael@0 | 1964 | static MOZ_ALWAYS_INLINE jsid |
michael@0 | 1965 | JSID_FROM_BITS(size_t bits) |
michael@0 | 1966 | { |
michael@0 | 1967 | jsid id; |
michael@0 | 1968 | JSID_BITS(id) = bits; |
michael@0 | 1969 | return id; |
michael@0 | 1970 | } |
michael@0 | 1971 | |
michael@0 | 1972 | namespace js { |
michael@0 | 1973 | namespace detail { |
michael@0 | 1974 | bool IdMatchesAtom(jsid id, JSAtom *atom); |
michael@0 | 1975 | } |
michael@0 | 1976 | } |
michael@0 | 1977 | |
michael@0 | 1978 | /* |
michael@0 | 1979 | * Must not be used on atoms that are representable as integer jsids. |
michael@0 | 1980 | * Prefer NameToId or AtomToId over this function: |
michael@0 | 1981 | * |
michael@0 | 1982 | * A PropertyName is an atom that does not contain an integer in the range |
michael@0 | 1983 | * [0, UINT32_MAX]. However, jsid can only hold an integer in the range |
michael@0 | 1984 | * [0, JSID_INT_MAX] (where JSID_INT_MAX == 2^31-1). Thus, for the range of |
michael@0 | 1985 | * integers (JSID_INT_MAX, UINT32_MAX], to represent as a jsid 'id', it must be |
michael@0 | 1986 | * the case JSID_IS_ATOM(id) and !JSID_TO_ATOM(id)->isPropertyName(). In most |
michael@0 | 1987 | * cases when creating a jsid, code does not have to care about this corner |
michael@0 | 1988 | * case because: |
michael@0 | 1989 | * |
michael@0 | 1990 | * - When given an arbitrary JSAtom*, AtomToId must be used, which checks for |
michael@0 | 1991 | * integer atoms representable as integer jsids, and does this conversion. |
michael@0 | 1992 | * |
michael@0 | 1993 | * - When given a PropertyName*, NameToId can be used which which does not need |
michael@0 | 1994 | * to do any dynamic checks. |
michael@0 | 1995 | * |
michael@0 | 1996 | * Thus, it is only the rare third case which needs this function, which |
michael@0 | 1997 | * handles any JSAtom* that is known not to be representable with an int jsid. |
michael@0 | 1998 | */ |
michael@0 | 1999 | static MOZ_ALWAYS_INLINE jsid |
michael@0 | 2000 | NON_INTEGER_ATOM_TO_JSID(JSAtom *atom) |
michael@0 | 2001 | { |
michael@0 | 2002 | JS_ASSERT(((size_t)atom & 0x7) == 0); |
michael@0 | 2003 | jsid id = JSID_FROM_BITS((size_t)atom); |
michael@0 | 2004 | JS_ASSERT(js::detail::IdMatchesAtom(id, atom)); |
michael@0 | 2005 | return id; |
michael@0 | 2006 | } |
michael@0 | 2007 | |
michael@0 | 2008 | /* All strings stored in jsids are atomized, but are not necessarily property names. */ |
michael@0 | 2009 | static MOZ_ALWAYS_INLINE bool |
michael@0 | 2010 | JSID_IS_ATOM(jsid id) |
michael@0 | 2011 | { |
michael@0 | 2012 | return JSID_IS_STRING(id); |
michael@0 | 2013 | } |
michael@0 | 2014 | |
michael@0 | 2015 | static MOZ_ALWAYS_INLINE bool |
michael@0 | 2016 | JSID_IS_ATOM(jsid id, JSAtom *atom) |
michael@0 | 2017 | { |
michael@0 | 2018 | return id == JSID_FROM_BITS((size_t)atom); |
michael@0 | 2019 | } |
michael@0 | 2020 | |
michael@0 | 2021 | static MOZ_ALWAYS_INLINE JSAtom * |
michael@0 | 2022 | JSID_TO_ATOM(jsid id) |
michael@0 | 2023 | { |
michael@0 | 2024 | return (JSAtom *)JSID_TO_STRING(id); |
michael@0 | 2025 | } |
michael@0 | 2026 | |
michael@0 | 2027 | JS_STATIC_ASSERT(sizeof(jsid) == sizeof(void*)); |
michael@0 | 2028 | |
michael@0 | 2029 | namespace js { |
michael@0 | 2030 | |
michael@0 | 2031 | static MOZ_ALWAYS_INLINE JS::Value |
michael@0 | 2032 | IdToValue(jsid id) |
michael@0 | 2033 | { |
michael@0 | 2034 | if (JSID_IS_STRING(id)) |
michael@0 | 2035 | return JS::StringValue(JSID_TO_STRING(id)); |
michael@0 | 2036 | if (MOZ_LIKELY(JSID_IS_INT(id))) |
michael@0 | 2037 | return JS::Int32Value(JSID_TO_INT(id)); |
michael@0 | 2038 | if (MOZ_LIKELY(JSID_IS_OBJECT(id))) |
michael@0 | 2039 | return JS::ObjectValue(*JSID_TO_OBJECT(id)); |
michael@0 | 2040 | JS_ASSERT(JSID_IS_VOID(id)); |
michael@0 | 2041 | return JS::UndefinedValue(); |
michael@0 | 2042 | } |
michael@0 | 2043 | |
michael@0 | 2044 | extern JS_FRIEND_API(bool) |
michael@0 | 2045 | IsTypedArrayThisCheck(JS::IsAcceptableThis test); |
michael@0 | 2046 | |
michael@0 | 2047 | /* |
michael@0 | 2048 | * If the embedder has registered a default JSContext callback, returns the |
michael@0 | 2049 | * result of the callback. Otherwise, asserts that |rt| has exactly one |
michael@0 | 2050 | * JSContext associated with it, and returns that context. |
michael@0 | 2051 | */ |
michael@0 | 2052 | extern JS_FRIEND_API(JSContext *) |
michael@0 | 2053 | DefaultJSContext(JSRuntime *rt); |
michael@0 | 2054 | |
michael@0 | 2055 | typedef JSContext* |
michael@0 | 2056 | (* DefaultJSContextCallback)(JSRuntime *rt); |
michael@0 | 2057 | |
michael@0 | 2058 | JS_FRIEND_API(void) |
michael@0 | 2059 | SetDefaultJSContextCallback(JSRuntime *rt, DefaultJSContextCallback cb); |
michael@0 | 2060 | |
michael@0 | 2061 | /* |
michael@0 | 2062 | * To help embedders enforce their invariants, we allow them to specify in |
michael@0 | 2063 | * advance which JSContext should be passed to JSAPI calls. If this is set |
michael@0 | 2064 | * to a non-null value, the assertSameCompartment machinery does double- |
michael@0 | 2065 | * duty (in debug builds) to verify that it matches the cx being used. |
michael@0 | 2066 | */ |
michael@0 | 2067 | #ifdef DEBUG |
michael@0 | 2068 | JS_FRIEND_API(void) |
michael@0 | 2069 | Debug_SetActiveJSContext(JSRuntime *rt, JSContext *cx); |
michael@0 | 2070 | #else |
michael@0 | 2071 | inline void |
michael@0 | 2072 | Debug_SetActiveJSContext(JSRuntime *rt, JSContext *cx) {}; |
michael@0 | 2073 | #endif |
michael@0 | 2074 | |
michael@0 | 2075 | |
michael@0 | 2076 | enum CTypesActivityType { |
michael@0 | 2077 | CTYPES_CALL_BEGIN, |
michael@0 | 2078 | CTYPES_CALL_END, |
michael@0 | 2079 | CTYPES_CALLBACK_BEGIN, |
michael@0 | 2080 | CTYPES_CALLBACK_END |
michael@0 | 2081 | }; |
michael@0 | 2082 | |
michael@0 | 2083 | typedef void |
michael@0 | 2084 | (* CTypesActivityCallback)(JSContext *cx, CTypesActivityType type); |
michael@0 | 2085 | |
michael@0 | 2086 | /* |
michael@0 | 2087 | * Sets a callback that is run whenever js-ctypes is about to be used when |
michael@0 | 2088 | * calling into C. |
michael@0 | 2089 | */ |
michael@0 | 2090 | JS_FRIEND_API(void) |
michael@0 | 2091 | SetCTypesActivityCallback(JSRuntime *rt, CTypesActivityCallback cb); |
michael@0 | 2092 | |
michael@0 | 2093 | class JS_FRIEND_API(AutoCTypesActivityCallback) { |
michael@0 | 2094 | private: |
michael@0 | 2095 | JSContext *cx; |
michael@0 | 2096 | CTypesActivityCallback callback; |
michael@0 | 2097 | CTypesActivityType endType; |
michael@0 | 2098 | MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
michael@0 | 2099 | |
michael@0 | 2100 | public: |
michael@0 | 2101 | AutoCTypesActivityCallback(JSContext *cx, CTypesActivityType beginType, |
michael@0 | 2102 | CTypesActivityType endType |
michael@0 | 2103 | MOZ_GUARD_OBJECT_NOTIFIER_PARAM); |
michael@0 | 2104 | ~AutoCTypesActivityCallback() { |
michael@0 | 2105 | DoEndCallback(); |
michael@0 | 2106 | } |
michael@0 | 2107 | void DoEndCallback() { |
michael@0 | 2108 | if (callback) { |
michael@0 | 2109 | callback(cx, endType); |
michael@0 | 2110 | callback = nullptr; |
michael@0 | 2111 | } |
michael@0 | 2112 | } |
michael@0 | 2113 | }; |
michael@0 | 2114 | |
michael@0 | 2115 | typedef bool |
michael@0 | 2116 | (* ObjectMetadataCallback)(JSContext *cx, JSObject **pmetadata); |
michael@0 | 2117 | |
michael@0 | 2118 | /* |
michael@0 | 2119 | * Specify a callback to invoke when creating each JS object in the current |
michael@0 | 2120 | * compartment, which may return a metadata object to associate with the |
michael@0 | 2121 | * object. Objects with different metadata have different shape hierarchies, |
michael@0 | 2122 | * so for efficiency, objects should generally try to share metadata objects. |
michael@0 | 2123 | */ |
michael@0 | 2124 | JS_FRIEND_API(void) |
michael@0 | 2125 | SetObjectMetadataCallback(JSContext *cx, ObjectMetadataCallback callback); |
michael@0 | 2126 | |
michael@0 | 2127 | /* Manipulate the metadata associated with an object. */ |
michael@0 | 2128 | |
michael@0 | 2129 | JS_FRIEND_API(bool) |
michael@0 | 2130 | SetObjectMetadata(JSContext *cx, JS::HandleObject obj, JS::HandleObject metadata); |
michael@0 | 2131 | |
michael@0 | 2132 | JS_FRIEND_API(JSObject *) |
michael@0 | 2133 | GetObjectMetadata(JSObject *obj); |
michael@0 | 2134 | |
michael@0 | 2135 | JS_FRIEND_API(void) |
michael@0 | 2136 | UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value); |
michael@0 | 2137 | |
michael@0 | 2138 | JS_FRIEND_API(bool) |
michael@0 | 2139 | SliceSlowly(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, |
michael@0 | 2140 | uint32_t begin, uint32_t end, JS::HandleObject result); |
michael@0 | 2141 | |
michael@0 | 2142 | /* ES5 8.12.8. */ |
michael@0 | 2143 | extern JS_FRIEND_API(bool) |
michael@0 | 2144 | DefaultValue(JSContext *cx, JS::HandleObject obj, JSType hint, JS::MutableHandleValue vp); |
michael@0 | 2145 | |
michael@0 | 2146 | /* |
michael@0 | 2147 | * Helper function. To approximate a call to the [[DefineOwnProperty]] internal |
michael@0 | 2148 | * method described in ES5, first call this, then call JS_DefinePropertyById. |
michael@0 | 2149 | * |
michael@0 | 2150 | * JS_DefinePropertyById by itself does not enforce the invariants on |
michael@0 | 2151 | * non-configurable properties when obj->isNative(). This function performs the |
michael@0 | 2152 | * relevant checks (specified in ES5 8.12.9 [[DefineOwnProperty]] steps 1-11), |
michael@0 | 2153 | * but only if obj is native. |
michael@0 | 2154 | * |
michael@0 | 2155 | * The reason for the messiness here is that ES5 uses [[DefineOwnProperty]] as |
michael@0 | 2156 | * a sort of extension point, but there is no hook in js::Class, |
michael@0 | 2157 | * js::ProxyHandler, or the JSAPI with precisely the right semantics for it. |
michael@0 | 2158 | */ |
michael@0 | 2159 | extern JS_FRIEND_API(bool) |
michael@0 | 2160 | CheckDefineProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, |
michael@0 | 2161 | JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); |
michael@0 | 2162 | |
michael@0 | 2163 | /* |
michael@0 | 2164 | * Helper function for HTMLDocument and HTMLFormElement. |
michael@0 | 2165 | * |
michael@0 | 2166 | * These are the only two interfaces that have [OverrideBuiltins], a named |
michael@0 | 2167 | * getter, and no named setter. They're implemented as proxies with a custom |
michael@0 | 2168 | * getOwnPropertyDescriptor() method. Unfortunately, overriding |
michael@0 | 2169 | * getOwnPropertyDescriptor() automatically affects the behavior of set(), |
michael@0 | 2170 | * which normally is just common sense but is *not* desired for these two |
michael@0 | 2171 | * interfaces. |
michael@0 | 2172 | * |
michael@0 | 2173 | * The fix is for these two interfaces to override set() to ignore the |
michael@0 | 2174 | * getOwnPropertyDescriptor() override. |
michael@0 | 2175 | * |
michael@0 | 2176 | * SetPropertyIgnoringNamedGetter is exposed to make it easier to override |
michael@0 | 2177 | * set() in this way. It carries out all the steps of BaseProxyHandler::set() |
michael@0 | 2178 | * except the initial getOwnPropertyDescriptor()/getPropertyDescriptor() calls. |
michael@0 | 2179 | * The caller must supply those results as the 'desc' and 'descIsOwn' |
michael@0 | 2180 | * parameters. |
michael@0 | 2181 | * |
michael@0 | 2182 | * Implemented in jsproxy.cpp. |
michael@0 | 2183 | */ |
michael@0 | 2184 | JS_FRIEND_API(bool) |
michael@0 | 2185 | SetPropertyIgnoringNamedGetter(JSContext *cx, BaseProxyHandler *handler, |
michael@0 | 2186 | JS::HandleObject proxy, JS::HandleObject receiver, |
michael@0 | 2187 | JS::HandleId id, JS::MutableHandle<JSPropertyDescriptor> desc, |
michael@0 | 2188 | bool descIsOwn, bool strict, JS::MutableHandleValue vp); |
michael@0 | 2189 | |
michael@0 | 2190 | } /* namespace js */ |
michael@0 | 2191 | |
michael@0 | 2192 | extern JS_FRIEND_API(bool) |
michael@0 | 2193 | js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg, |
michael@0 | 2194 | JS::Handle<JSPropertyDescriptor> descriptor, bool *bp); |
michael@0 | 2195 | |
michael@0 | 2196 | extern JS_FRIEND_API(bool) |
michael@0 | 2197 | js_ReportIsNotFunction(JSContext *cx, JS::HandleValue v); |
michael@0 | 2198 | |
michael@0 | 2199 | #ifdef JSGC_GENERATIONAL |
michael@0 | 2200 | extern JS_FRIEND_API(void) |
michael@0 | 2201 | JS_StoreObjectPostBarrierCallback(JSContext* cx, |
michael@0 | 2202 | void (*callback)(JSTracer *trc, JSObject *key, void *data), |
michael@0 | 2203 | JSObject *key, void *data); |
michael@0 | 2204 | |
michael@0 | 2205 | extern JS_FRIEND_API(void) |
michael@0 | 2206 | JS_StoreStringPostBarrierCallback(JSContext* cx, |
michael@0 | 2207 | void (*callback)(JSTracer *trc, JSString *key, void *data), |
michael@0 | 2208 | JSString *key, void *data); |
michael@0 | 2209 | #else |
michael@0 | 2210 | inline void |
michael@0 | 2211 | JS_StoreObjectPostBarrierCallback(JSContext* cx, |
michael@0 | 2212 | void (*callback)(JSTracer *trc, JSObject *key, void *data), |
michael@0 | 2213 | JSObject *key, void *data) {} |
michael@0 | 2214 | |
michael@0 | 2215 | inline void |
michael@0 | 2216 | JS_StoreStringPostBarrierCallback(JSContext* cx, |
michael@0 | 2217 | void (*callback)(JSTracer *trc, JSString *key, void *data), |
michael@0 | 2218 | JSString *key, void *data) {} |
michael@0 | 2219 | #endif /* JSGC_GENERATIONAL */ |
michael@0 | 2220 | |
michael@0 | 2221 | #endif /* jsfriendapi_h */ |