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 jit_VMFunctions_h |
michael@0 | 8 | #define jit_VMFunctions_h |
michael@0 | 9 | |
michael@0 | 10 | #include "jspubtd.h" |
michael@0 | 11 | |
michael@0 | 12 | #include "jit/CompileInfo.h" |
michael@0 | 13 | #include "jit/IonFrames.h" |
michael@0 | 14 | |
michael@0 | 15 | namespace js { |
michael@0 | 16 | |
michael@0 | 17 | class DeclEnvObject; |
michael@0 | 18 | class ForkJoinContext; |
michael@0 | 19 | class StaticWithObject; |
michael@0 | 20 | |
michael@0 | 21 | namespace jit { |
michael@0 | 22 | |
michael@0 | 23 | enum DataType { |
michael@0 | 24 | Type_Void, |
michael@0 | 25 | Type_Bool, |
michael@0 | 26 | Type_Int32, |
michael@0 | 27 | Type_Double, |
michael@0 | 28 | Type_Pointer, |
michael@0 | 29 | Type_Object, |
michael@0 | 30 | Type_Value, |
michael@0 | 31 | Type_Handle |
michael@0 | 32 | }; |
michael@0 | 33 | |
michael@0 | 34 | struct PopValues |
michael@0 | 35 | { |
michael@0 | 36 | uint32_t numValues; |
michael@0 | 37 | |
michael@0 | 38 | explicit PopValues(uint32_t numValues) |
michael@0 | 39 | : numValues(numValues) |
michael@0 | 40 | { } |
michael@0 | 41 | }; |
michael@0 | 42 | |
michael@0 | 43 | // Contains information about a virtual machine function that can be called |
michael@0 | 44 | // from JIT code. Functions described in this manner must conform to a simple |
michael@0 | 45 | // protocol: the return type must have a special "failure" value (for example, |
michael@0 | 46 | // false for bool, or nullptr for Objects). If the function is designed to |
michael@0 | 47 | // return a value that does not meet this requirement - such as |
michael@0 | 48 | // object-or-nullptr, or an integer, an optional, final outParam can be |
michael@0 | 49 | // specified. In this case, the return type must be boolean to indicate |
michael@0 | 50 | // failure. |
michael@0 | 51 | // |
michael@0 | 52 | // All functions described by VMFunction take a JSContext * as a first |
michael@0 | 53 | // argument, and are treated as re-entrant into the VM and therefore fallible. |
michael@0 | 54 | struct VMFunction |
michael@0 | 55 | { |
michael@0 | 56 | // Global linked list of all VMFunctions. |
michael@0 | 57 | static VMFunction *functions; |
michael@0 | 58 | VMFunction *next; |
michael@0 | 59 | |
michael@0 | 60 | // Address of the C function. |
michael@0 | 61 | void *wrapped; |
michael@0 | 62 | |
michael@0 | 63 | // Number of arguments expected, excluding JSContext * as an implicit |
michael@0 | 64 | // first argument and an outparam as a possible implicit final argument. |
michael@0 | 65 | uint32_t explicitArgs; |
michael@0 | 66 | |
michael@0 | 67 | enum ArgProperties { |
michael@0 | 68 | WordByValue = 0, |
michael@0 | 69 | DoubleByValue = 1, |
michael@0 | 70 | WordByRef = 2, |
michael@0 | 71 | DoubleByRef = 3, |
michael@0 | 72 | // BitMask version. |
michael@0 | 73 | Word = 0, |
michael@0 | 74 | Double = 1, |
michael@0 | 75 | ByRef = 2 |
michael@0 | 76 | }; |
michael@0 | 77 | |
michael@0 | 78 | // Contains properties about the first 16 arguments. |
michael@0 | 79 | uint32_t argumentProperties; |
michael@0 | 80 | |
michael@0 | 81 | // Which arguments should be passed in float register on platforms that |
michael@0 | 82 | // have them. |
michael@0 | 83 | uint32_t argumentPassedInFloatRegs; |
michael@0 | 84 | |
michael@0 | 85 | // The outparam may be any Type_*, and must be the final argument to the |
michael@0 | 86 | // function, if not Void. outParam != Void implies that the return type |
michael@0 | 87 | // has a boolean failure mode. |
michael@0 | 88 | DataType outParam; |
michael@0 | 89 | |
michael@0 | 90 | // Type returned by the C function and used by the VMFunction wrapper to |
michael@0 | 91 | // check for failures of the C function. Valid failure/return types are |
michael@0 | 92 | // boolean and object pointers which are asserted inside the VMFunction |
michael@0 | 93 | // constructor. If the C function use an outparam (!= Type_Void), then |
michael@0 | 94 | // the only valid failure/return type is boolean -- object pointers are |
michael@0 | 95 | // pointless because the wrapper will only use it to compare it against |
michael@0 | 96 | // nullptr before discarding its value. |
michael@0 | 97 | DataType returnType; |
michael@0 | 98 | |
michael@0 | 99 | // Note: a maximum of seven root types is supported. |
michael@0 | 100 | enum RootType { |
michael@0 | 101 | RootNone = 0, |
michael@0 | 102 | RootObject, |
michael@0 | 103 | RootString, |
michael@0 | 104 | RootPropertyName, |
michael@0 | 105 | RootFunction, |
michael@0 | 106 | RootValue, |
michael@0 | 107 | RootCell |
michael@0 | 108 | }; |
michael@0 | 109 | |
michael@0 | 110 | // Contains an combination of enumerated types used by the gc for marking |
michael@0 | 111 | // arguments of the VM wrapper. |
michael@0 | 112 | uint64_t argumentRootTypes; |
michael@0 | 113 | |
michael@0 | 114 | // The root type of the out param if outParam == Type_Handle. |
michael@0 | 115 | RootType outParamRootType; |
michael@0 | 116 | |
michael@0 | 117 | // Does this function take a ForkJoinContext * or a JSContext *? |
michael@0 | 118 | ExecutionMode executionMode; |
michael@0 | 119 | |
michael@0 | 120 | // Number of Values the VM wrapper should pop from the stack when it returns. |
michael@0 | 121 | // Used by baseline IC stubs so that they can use tail calls to call the VM |
michael@0 | 122 | // wrapper. |
michael@0 | 123 | uint32_t extraValuesToPop; |
michael@0 | 124 | |
michael@0 | 125 | uint32_t argc() const { |
michael@0 | 126 | // JSContext * + args + (OutParam? *) |
michael@0 | 127 | return 1 + explicitArgc() + ((outParam == Type_Void) ? 0 : 1); |
michael@0 | 128 | } |
michael@0 | 129 | |
michael@0 | 130 | DataType failType() const { |
michael@0 | 131 | return returnType; |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | ArgProperties argProperties(uint32_t explicitArg) const { |
michael@0 | 135 | return ArgProperties((argumentProperties >> (2 * explicitArg)) & 3); |
michael@0 | 136 | } |
michael@0 | 137 | |
michael@0 | 138 | RootType argRootType(uint32_t explicitArg) const { |
michael@0 | 139 | return RootType((argumentRootTypes >> (3 * explicitArg)) & 7); |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | bool argPassedInFloatReg(uint32_t explicitArg) const { |
michael@0 | 143 | return ((argumentPassedInFloatRegs >> explicitArg) & 1) == 1; |
michael@0 | 144 | } |
michael@0 | 145 | |
michael@0 | 146 | // Return the stack size consumed by explicit arguments. |
michael@0 | 147 | size_t explicitStackSlots() const { |
michael@0 | 148 | size_t stackSlots = explicitArgs; |
michael@0 | 149 | |
michael@0 | 150 | // Fetch all double-word flags of explicit arguments. |
michael@0 | 151 | uint32_t n = |
michael@0 | 152 | ((1 << (explicitArgs * 2)) - 1) // = Explicit argument mask. |
michael@0 | 153 | & 0x55555555 // = Mask double-size args. |
michael@0 | 154 | & argumentProperties; |
michael@0 | 155 | |
michael@0 | 156 | // Add the number of double-word flags. (expect a few loop |
michael@0 | 157 | // iteration) |
michael@0 | 158 | while (n) { |
michael@0 | 159 | stackSlots++; |
michael@0 | 160 | n &= n - 1; |
michael@0 | 161 | } |
michael@0 | 162 | return stackSlots; |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | // Double-size argument which are passed by value are taking the space |
michael@0 | 166 | // of 2 C arguments. This function is used to compute the number of |
michael@0 | 167 | // argument expected by the C function. This is not the same as |
michael@0 | 168 | // explicitStackSlots because reference to stack slots may take one less |
michael@0 | 169 | // register in the total count. |
michael@0 | 170 | size_t explicitArgc() const { |
michael@0 | 171 | size_t stackSlots = explicitArgs; |
michael@0 | 172 | |
michael@0 | 173 | // Fetch all explicit arguments. |
michael@0 | 174 | uint32_t n = |
michael@0 | 175 | ((1 << (explicitArgs * 2)) - 1) // = Explicit argument mask. |
michael@0 | 176 | & argumentProperties; |
michael@0 | 177 | |
michael@0 | 178 | // Filter double-size arguments (0x5 = 0b0101) and remove (& ~) |
michael@0 | 179 | // arguments passed by reference (0b1010 >> 1 == 0b0101). |
michael@0 | 180 | n = (n & 0x55555555) & ~(n >> 1); |
michael@0 | 181 | |
michael@0 | 182 | // Add the number of double-word transfered by value. (expect a few |
michael@0 | 183 | // loop iteration) |
michael@0 | 184 | while (n) { |
michael@0 | 185 | stackSlots++; |
michael@0 | 186 | n &= n - 1; |
michael@0 | 187 | } |
michael@0 | 188 | return stackSlots; |
michael@0 | 189 | } |
michael@0 | 190 | |
michael@0 | 191 | VMFunction() |
michael@0 | 192 | : wrapped(nullptr), |
michael@0 | 193 | explicitArgs(0), |
michael@0 | 194 | argumentProperties(0), |
michael@0 | 195 | argumentPassedInFloatRegs(0), |
michael@0 | 196 | outParam(Type_Void), |
michael@0 | 197 | returnType(Type_Void), |
michael@0 | 198 | outParamRootType(RootNone), |
michael@0 | 199 | executionMode(SequentialExecution), |
michael@0 | 200 | extraValuesToPop(0) |
michael@0 | 201 | { |
michael@0 | 202 | } |
michael@0 | 203 | |
michael@0 | 204 | |
michael@0 | 205 | VMFunction(void *wrapped, uint32_t explicitArgs, uint32_t argumentProperties, |
michael@0 | 206 | uint32_t argumentPassedInFloatRegs, uint64_t argRootTypes, |
michael@0 | 207 | DataType outParam, RootType outParamRootType, DataType returnType, |
michael@0 | 208 | ExecutionMode executionMode, uint32_t extraValuesToPop = 0) |
michael@0 | 209 | : wrapped(wrapped), |
michael@0 | 210 | explicitArgs(explicitArgs), |
michael@0 | 211 | argumentProperties(argumentProperties), |
michael@0 | 212 | argumentPassedInFloatRegs(argumentPassedInFloatRegs), |
michael@0 | 213 | outParam(outParam), |
michael@0 | 214 | returnType(returnType), |
michael@0 | 215 | argumentRootTypes(argRootTypes), |
michael@0 | 216 | outParamRootType(outParamRootType), |
michael@0 | 217 | executionMode(executionMode), |
michael@0 | 218 | extraValuesToPop(extraValuesToPop) |
michael@0 | 219 | { |
michael@0 | 220 | // Check for valid failure/return type. |
michael@0 | 221 | JS_ASSERT_IF(outParam != Type_Void && executionMode == SequentialExecution, |
michael@0 | 222 | returnType == Type_Bool); |
michael@0 | 223 | JS_ASSERT(returnType == Type_Bool || |
michael@0 | 224 | returnType == Type_Object); |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | VMFunction(const VMFunction &o) { |
michael@0 | 228 | init(o); |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | void init(const VMFunction &o) { |
michael@0 | 232 | JS_ASSERT(!wrapped); |
michael@0 | 233 | *this = o; |
michael@0 | 234 | addToFunctions(); |
michael@0 | 235 | } |
michael@0 | 236 | |
michael@0 | 237 | private: |
michael@0 | 238 | // Add this to the global list of VMFunctions. |
michael@0 | 239 | void addToFunctions(); |
michael@0 | 240 | }; |
michael@0 | 241 | |
michael@0 | 242 | // A collection of VM functions for each execution mode. |
michael@0 | 243 | struct VMFunctionsModal |
michael@0 | 244 | { |
michael@0 | 245 | VMFunctionsModal(const VMFunction &info) { |
michael@0 | 246 | add(info); |
michael@0 | 247 | } |
michael@0 | 248 | VMFunctionsModal(const VMFunction &info1, const VMFunction &info2) { |
michael@0 | 249 | add(info1); |
michael@0 | 250 | add(info2); |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | inline const VMFunction &operator[](ExecutionMode mode) const { |
michael@0 | 254 | JS_ASSERT((unsigned)mode < NumExecutionModes); |
michael@0 | 255 | return funs_[mode]; |
michael@0 | 256 | } |
michael@0 | 257 | |
michael@0 | 258 | private: |
michael@0 | 259 | void add(const VMFunction &info) { |
michael@0 | 260 | JS_ASSERT((unsigned)info.executionMode < NumExecutionModes); |
michael@0 | 261 | funs_[info.executionMode].init(info); |
michael@0 | 262 | } |
michael@0 | 263 | |
michael@0 | 264 | mozilla::Array<VMFunction, NumExecutionModes> funs_; |
michael@0 | 265 | }; |
michael@0 | 266 | |
michael@0 | 267 | template <class> struct TypeToDataType { /* Unexpected return type for a VMFunction. */ }; |
michael@0 | 268 | template <> struct TypeToDataType<bool> { static const DataType result = Type_Bool; }; |
michael@0 | 269 | template <> struct TypeToDataType<JSObject *> { static const DataType result = Type_Object; }; |
michael@0 | 270 | template <> struct TypeToDataType<DeclEnvObject *> { static const DataType result = Type_Object; }; |
michael@0 | 271 | template <> struct TypeToDataType<JSString *> { static const DataType result = Type_Object; }; |
michael@0 | 272 | template <> struct TypeToDataType<JSFlatString *> { static const DataType result = Type_Object; }; |
michael@0 | 273 | template <> struct TypeToDataType<HandleObject> { static const DataType result = Type_Handle; }; |
michael@0 | 274 | template <> struct TypeToDataType<HandleString> { static const DataType result = Type_Handle; }; |
michael@0 | 275 | template <> struct TypeToDataType<HandlePropertyName> { static const DataType result = Type_Handle; }; |
michael@0 | 276 | template <> struct TypeToDataType<HandleFunction> { static const DataType result = Type_Handle; }; |
michael@0 | 277 | template <> struct TypeToDataType<Handle<StaticWithObject *> > { static const DataType result = Type_Handle; }; |
michael@0 | 278 | template <> struct TypeToDataType<Handle<StaticBlockObject *> > { static const DataType result = Type_Handle; }; |
michael@0 | 279 | template <> struct TypeToDataType<HandleScript> { static const DataType result = Type_Handle; }; |
michael@0 | 280 | template <> struct TypeToDataType<HandleValue> { static const DataType result = Type_Handle; }; |
michael@0 | 281 | template <> struct TypeToDataType<MutableHandleValue> { static const DataType result = Type_Handle; }; |
michael@0 | 282 | |
michael@0 | 283 | // Convert argument types to properties of the argument known by the jit. |
michael@0 | 284 | template <class T> struct TypeToArgProperties { |
michael@0 | 285 | static const uint32_t result = |
michael@0 | 286 | (sizeof(T) <= sizeof(void *) ? VMFunction::Word : VMFunction::Double); |
michael@0 | 287 | }; |
michael@0 | 288 | template <> struct TypeToArgProperties<const Value &> { |
michael@0 | 289 | static const uint32_t result = TypeToArgProperties<Value>::result | VMFunction::ByRef; |
michael@0 | 290 | }; |
michael@0 | 291 | template <> struct TypeToArgProperties<HandleObject> { |
michael@0 | 292 | static const uint32_t result = TypeToArgProperties<JSObject *>::result | VMFunction::ByRef; |
michael@0 | 293 | }; |
michael@0 | 294 | template <> struct TypeToArgProperties<HandleString> { |
michael@0 | 295 | static const uint32_t result = TypeToArgProperties<JSString *>::result | VMFunction::ByRef; |
michael@0 | 296 | }; |
michael@0 | 297 | template <> struct TypeToArgProperties<HandlePropertyName> { |
michael@0 | 298 | static const uint32_t result = TypeToArgProperties<PropertyName *>::result | VMFunction::ByRef; |
michael@0 | 299 | }; |
michael@0 | 300 | template <> struct TypeToArgProperties<HandleFunction> { |
michael@0 | 301 | static const uint32_t result = TypeToArgProperties<JSFunction *>::result | VMFunction::ByRef; |
michael@0 | 302 | }; |
michael@0 | 303 | template <> struct TypeToArgProperties<Handle<StaticWithObject *> > { |
michael@0 | 304 | static const uint32_t result = TypeToArgProperties<StaticWithObject *>::result | VMFunction::ByRef; |
michael@0 | 305 | }; |
michael@0 | 306 | template <> struct TypeToArgProperties<Handle<StaticBlockObject *> > { |
michael@0 | 307 | static const uint32_t result = TypeToArgProperties<StaticBlockObject *>::result | VMFunction::ByRef; |
michael@0 | 308 | }; |
michael@0 | 309 | template <> struct TypeToArgProperties<HandleScript> { |
michael@0 | 310 | static const uint32_t result = TypeToArgProperties<JSScript *>::result | VMFunction::ByRef; |
michael@0 | 311 | }; |
michael@0 | 312 | template <> struct TypeToArgProperties<HandleValue> { |
michael@0 | 313 | static const uint32_t result = TypeToArgProperties<Value>::result | VMFunction::ByRef; |
michael@0 | 314 | }; |
michael@0 | 315 | template <> struct TypeToArgProperties<MutableHandleValue> { |
michael@0 | 316 | static const uint32_t result = TypeToArgProperties<Value>::result | VMFunction::ByRef; |
michael@0 | 317 | }; |
michael@0 | 318 | template <> struct TypeToArgProperties<HandleShape> { |
michael@0 | 319 | static const uint32_t result = TypeToArgProperties<Shape *>::result | VMFunction::ByRef; |
michael@0 | 320 | }; |
michael@0 | 321 | template <> struct TypeToArgProperties<HandleTypeObject> { |
michael@0 | 322 | static const uint32_t result = TypeToArgProperties<types::TypeObject *>::result | VMFunction::ByRef; |
michael@0 | 323 | }; |
michael@0 | 324 | |
michael@0 | 325 | // Convert argument type to whether or not it should be passed in a float |
michael@0 | 326 | // register on platforms that have them, like x64. |
michael@0 | 327 | template <class T> struct TypeToPassInFloatReg { |
michael@0 | 328 | static const uint32_t result = 0; |
michael@0 | 329 | }; |
michael@0 | 330 | template <> struct TypeToPassInFloatReg<double> { |
michael@0 | 331 | static const uint32_t result = 1; |
michael@0 | 332 | }; |
michael@0 | 333 | |
michael@0 | 334 | // Convert argument types to root types used by the gc, see MarkJitExitFrame. |
michael@0 | 335 | template <class T> struct TypeToRootType { |
michael@0 | 336 | static const uint32_t result = VMFunction::RootNone; |
michael@0 | 337 | }; |
michael@0 | 338 | template <> struct TypeToRootType<HandleObject> { |
michael@0 | 339 | static const uint32_t result = VMFunction::RootObject; |
michael@0 | 340 | }; |
michael@0 | 341 | template <> struct TypeToRootType<HandleString> { |
michael@0 | 342 | static const uint32_t result = VMFunction::RootString; |
michael@0 | 343 | }; |
michael@0 | 344 | template <> struct TypeToRootType<HandlePropertyName> { |
michael@0 | 345 | static const uint32_t result = VMFunction::RootPropertyName; |
michael@0 | 346 | }; |
michael@0 | 347 | template <> struct TypeToRootType<HandleFunction> { |
michael@0 | 348 | static const uint32_t result = VMFunction::RootFunction; |
michael@0 | 349 | }; |
michael@0 | 350 | template <> struct TypeToRootType<HandleValue> { |
michael@0 | 351 | static const uint32_t result = VMFunction::RootValue; |
michael@0 | 352 | }; |
michael@0 | 353 | template <> struct TypeToRootType<MutableHandleValue> { |
michael@0 | 354 | static const uint32_t result = VMFunction::RootValue; |
michael@0 | 355 | }; |
michael@0 | 356 | template <> struct TypeToRootType<HandleShape> { |
michael@0 | 357 | static const uint32_t result = VMFunction::RootCell; |
michael@0 | 358 | }; |
michael@0 | 359 | template <> struct TypeToRootType<HandleTypeObject> { |
michael@0 | 360 | static const uint32_t result = VMFunction::RootCell; |
michael@0 | 361 | }; |
michael@0 | 362 | template <> struct TypeToRootType<HandleScript> { |
michael@0 | 363 | static const uint32_t result = VMFunction::RootCell; |
michael@0 | 364 | }; |
michael@0 | 365 | template <> struct TypeToRootType<Handle<StaticBlockObject *> > { |
michael@0 | 366 | static const uint32_t result = VMFunction::RootObject; |
michael@0 | 367 | }; |
michael@0 | 368 | template <> struct TypeToRootType<Handle<StaticWithObject *> > { |
michael@0 | 369 | static const uint32_t result = VMFunction::RootCell; |
michael@0 | 370 | }; |
michael@0 | 371 | template <class T> struct TypeToRootType<Handle<T> > { |
michael@0 | 372 | // Fail for Handle types that aren't specialized above. |
michael@0 | 373 | }; |
michael@0 | 374 | |
michael@0 | 375 | template <class> struct OutParamToDataType { static const DataType result = Type_Void; }; |
michael@0 | 376 | template <> struct OutParamToDataType<Value *> { static const DataType result = Type_Value; }; |
michael@0 | 377 | template <> struct OutParamToDataType<int *> { static const DataType result = Type_Int32; }; |
michael@0 | 378 | template <> struct OutParamToDataType<uint32_t *> { static const DataType result = Type_Int32; }; |
michael@0 | 379 | template <> struct OutParamToDataType<uint8_t **> { static const DataType result = Type_Pointer; }; |
michael@0 | 380 | template <> struct OutParamToDataType<bool *> { static const DataType result = Type_Bool; }; |
michael@0 | 381 | template <> struct OutParamToDataType<double *> { static const DataType result = Type_Double; }; |
michael@0 | 382 | template <> struct OutParamToDataType<MutableHandleValue> { static const DataType result = Type_Handle; }; |
michael@0 | 383 | template <> struct OutParamToDataType<MutableHandleObject> { static const DataType result = Type_Handle; }; |
michael@0 | 384 | template <> struct OutParamToDataType<MutableHandleString> { static const DataType result = Type_Handle; }; |
michael@0 | 385 | |
michael@0 | 386 | template <class> struct OutParamToRootType { |
michael@0 | 387 | static const VMFunction::RootType result = VMFunction::RootNone; |
michael@0 | 388 | }; |
michael@0 | 389 | template <> struct OutParamToRootType<MutableHandleValue> { |
michael@0 | 390 | static const VMFunction::RootType result = VMFunction::RootValue; |
michael@0 | 391 | }; |
michael@0 | 392 | template <> struct OutParamToRootType<MutableHandleObject> { |
michael@0 | 393 | static const VMFunction::RootType result = VMFunction::RootObject; |
michael@0 | 394 | }; |
michael@0 | 395 | template <> struct OutParamToRootType<MutableHandleString> { |
michael@0 | 396 | static const VMFunction::RootType result = VMFunction::RootString; |
michael@0 | 397 | }; |
michael@0 | 398 | |
michael@0 | 399 | template <class> struct MatchContext { }; |
michael@0 | 400 | template <> struct MatchContext<JSContext *> { |
michael@0 | 401 | static const ExecutionMode execMode = SequentialExecution; |
michael@0 | 402 | }; |
michael@0 | 403 | template <> struct MatchContext<ExclusiveContext *> { |
michael@0 | 404 | static const ExecutionMode execMode = SequentialExecution; |
michael@0 | 405 | }; |
michael@0 | 406 | template <> struct MatchContext<ForkJoinContext *> { |
michael@0 | 407 | static const ExecutionMode execMode = ParallelExecution; |
michael@0 | 408 | }; |
michael@0 | 409 | template <> struct MatchContext<ThreadSafeContext *> { |
michael@0 | 410 | // ThreadSafeContext functions can be called from either mode, but for |
michael@0 | 411 | // calling from parallel they should be wrapped first, so we default to |
michael@0 | 412 | // SequentialExecution here. |
michael@0 | 413 | static const ExecutionMode execMode = SequentialExecution; |
michael@0 | 414 | }; |
michael@0 | 415 | |
michael@0 | 416 | #define FOR_EACH_ARGS_1(Macro, Sep, Last) Macro(1) Last(1) |
michael@0 | 417 | #define FOR_EACH_ARGS_2(Macro, Sep, Last) FOR_EACH_ARGS_1(Macro, Sep, Sep) Macro(2) Last(2) |
michael@0 | 418 | #define FOR_EACH_ARGS_3(Macro, Sep, Last) FOR_EACH_ARGS_2(Macro, Sep, Sep) Macro(3) Last(3) |
michael@0 | 419 | #define FOR_EACH_ARGS_4(Macro, Sep, Last) FOR_EACH_ARGS_3(Macro, Sep, Sep) Macro(4) Last(4) |
michael@0 | 420 | #define FOR_EACH_ARGS_5(Macro, Sep, Last) FOR_EACH_ARGS_4(Macro, Sep, Sep) Macro(5) Last(5) |
michael@0 | 421 | #define FOR_EACH_ARGS_6(Macro, Sep, Last) FOR_EACH_ARGS_5(Macro, Sep, Sep) Macro(6) Last(6) |
michael@0 | 422 | |
michael@0 | 423 | #define COMPUTE_INDEX(NbArg) NbArg |
michael@0 | 424 | #define COMPUTE_OUTPARAM_RESULT(NbArg) OutParamToDataType<A ## NbArg>::result |
michael@0 | 425 | #define COMPUTE_OUTPARAM_ROOT(NbArg) OutParamToRootType<A ## NbArg>::result |
michael@0 | 426 | #define COMPUTE_ARG_PROP(NbArg) (TypeToArgProperties<A ## NbArg>::result << (2 * (NbArg - 1))) |
michael@0 | 427 | #define COMPUTE_ARG_ROOT(NbArg) (uint64_t(TypeToRootType<A ## NbArg>::result) << (3 * (NbArg - 1))) |
michael@0 | 428 | #define COMPUTE_ARG_FLOAT(NbArg) (TypeToPassInFloatReg<A ## NbArg>::result) << (NbArg - 1) |
michael@0 | 429 | #define SEP_OR(_) | |
michael@0 | 430 | #define NOTHING(_) |
michael@0 | 431 | |
michael@0 | 432 | #define FUNCTION_INFO_STRUCT_BODY(ForEachNb) \ |
michael@0 | 433 | static inline ExecutionMode executionMode() { \ |
michael@0 | 434 | return MatchContext<Context>::execMode; \ |
michael@0 | 435 | } \ |
michael@0 | 436 | static inline DataType returnType() { \ |
michael@0 | 437 | return TypeToDataType<R>::result; \ |
michael@0 | 438 | } \ |
michael@0 | 439 | static inline DataType outParam() { \ |
michael@0 | 440 | return ForEachNb(NOTHING, NOTHING, COMPUTE_OUTPARAM_RESULT); \ |
michael@0 | 441 | } \ |
michael@0 | 442 | static inline RootType outParamRootType() { \ |
michael@0 | 443 | return ForEachNb(NOTHING, NOTHING, COMPUTE_OUTPARAM_ROOT); \ |
michael@0 | 444 | } \ |
michael@0 | 445 | static inline size_t NbArgs() { \ |
michael@0 | 446 | return ForEachNb(NOTHING, NOTHING, COMPUTE_INDEX); \ |
michael@0 | 447 | } \ |
michael@0 | 448 | static inline size_t explicitArgs() { \ |
michael@0 | 449 | return NbArgs() - (outParam() != Type_Void ? 1 : 0); \ |
michael@0 | 450 | } \ |
michael@0 | 451 | static inline uint32_t argumentProperties() { \ |
michael@0 | 452 | return ForEachNb(COMPUTE_ARG_PROP, SEP_OR, NOTHING); \ |
michael@0 | 453 | } \ |
michael@0 | 454 | static inline uint32_t argumentPassedInFloatRegs() { \ |
michael@0 | 455 | return ForEachNb(COMPUTE_ARG_FLOAT, SEP_OR, NOTHING); \ |
michael@0 | 456 | } \ |
michael@0 | 457 | static inline uint64_t argumentRootTypes() { \ |
michael@0 | 458 | return ForEachNb(COMPUTE_ARG_ROOT, SEP_OR, NOTHING); \ |
michael@0 | 459 | } \ |
michael@0 | 460 | FunctionInfo(pf fun, PopValues extraValuesToPop = PopValues(0)) \ |
michael@0 | 461 | : VMFunction(JS_FUNC_TO_DATA_PTR(void *, fun), explicitArgs(), \ |
michael@0 | 462 | argumentProperties(), argumentPassedInFloatRegs(), \ |
michael@0 | 463 | argumentRootTypes(), outParam(), outParamRootType(), \ |
michael@0 | 464 | returnType(), executionMode(), \ |
michael@0 | 465 | extraValuesToPop.numValues) \ |
michael@0 | 466 | { } |
michael@0 | 467 | |
michael@0 | 468 | template <typename Fun> |
michael@0 | 469 | struct FunctionInfo { |
michael@0 | 470 | }; |
michael@0 | 471 | |
michael@0 | 472 | // VMFunction wrapper with no explicit arguments. |
michael@0 | 473 | template <class R, class Context> |
michael@0 | 474 | struct FunctionInfo<R (*)(Context)> : public VMFunction { |
michael@0 | 475 | typedef R (*pf)(Context); |
michael@0 | 476 | |
michael@0 | 477 | static inline ExecutionMode executionMode() { |
michael@0 | 478 | return MatchContext<Context>::execMode; |
michael@0 | 479 | } |
michael@0 | 480 | static inline DataType returnType() { |
michael@0 | 481 | return TypeToDataType<R>::result; |
michael@0 | 482 | } |
michael@0 | 483 | static inline DataType outParam() { |
michael@0 | 484 | return Type_Void; |
michael@0 | 485 | } |
michael@0 | 486 | static inline RootType outParamRootType() { |
michael@0 | 487 | return RootNone; |
michael@0 | 488 | } |
michael@0 | 489 | static inline size_t explicitArgs() { |
michael@0 | 490 | return 0; |
michael@0 | 491 | } |
michael@0 | 492 | static inline uint32_t argumentProperties() { |
michael@0 | 493 | return 0; |
michael@0 | 494 | } |
michael@0 | 495 | static inline uint32_t argumentPassedInFloatRegs() { |
michael@0 | 496 | return 0; |
michael@0 | 497 | } |
michael@0 | 498 | static inline uint64_t argumentRootTypes() { |
michael@0 | 499 | return 0; |
michael@0 | 500 | } |
michael@0 | 501 | FunctionInfo(pf fun) |
michael@0 | 502 | : VMFunction(JS_FUNC_TO_DATA_PTR(void *, fun), explicitArgs(), |
michael@0 | 503 | argumentProperties(), argumentPassedInFloatRegs(), |
michael@0 | 504 | argumentRootTypes(), outParam(), outParamRootType(), |
michael@0 | 505 | returnType(), executionMode()) |
michael@0 | 506 | { } |
michael@0 | 507 | }; |
michael@0 | 508 | |
michael@0 | 509 | // Specialize the class for each number of argument used by VMFunction. |
michael@0 | 510 | // Keep it verbose unless you find a readable macro for it. |
michael@0 | 511 | template <class R, class Context, class A1> |
michael@0 | 512 | struct FunctionInfo<R (*)(Context, A1)> : public VMFunction { |
michael@0 | 513 | typedef R (*pf)(Context, A1); |
michael@0 | 514 | FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_1) |
michael@0 | 515 | }; |
michael@0 | 516 | |
michael@0 | 517 | template <class R, class Context, class A1, class A2> |
michael@0 | 518 | struct FunctionInfo<R (*)(Context, A1, A2)> : public VMFunction { |
michael@0 | 519 | typedef R (*pf)(Context, A1, A2); |
michael@0 | 520 | FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_2) |
michael@0 | 521 | }; |
michael@0 | 522 | |
michael@0 | 523 | template <class R, class Context, class A1, class A2, class A3> |
michael@0 | 524 | struct FunctionInfo<R (*)(Context, A1, A2, A3)> : public VMFunction { |
michael@0 | 525 | typedef R (*pf)(Context, A1, A2, A3); |
michael@0 | 526 | FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_3) |
michael@0 | 527 | }; |
michael@0 | 528 | |
michael@0 | 529 | template <class R, class Context, class A1, class A2, class A3, class A4> |
michael@0 | 530 | struct FunctionInfo<R (*)(Context, A1, A2, A3, A4)> : public VMFunction { |
michael@0 | 531 | typedef R (*pf)(Context, A1, A2, A3, A4); |
michael@0 | 532 | FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_4) |
michael@0 | 533 | }; |
michael@0 | 534 | |
michael@0 | 535 | template <class R, class Context, class A1, class A2, class A3, class A4, class A5> |
michael@0 | 536 | struct FunctionInfo<R (*)(Context, A1, A2, A3, A4, A5)> : public VMFunction { |
michael@0 | 537 | typedef R (*pf)(Context, A1, A2, A3, A4, A5); |
michael@0 | 538 | FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_5) |
michael@0 | 539 | }; |
michael@0 | 540 | |
michael@0 | 541 | template <class R, class Context, class A1, class A2, class A3, class A4, class A5, class A6> |
michael@0 | 542 | struct FunctionInfo<R (*)(Context, A1, A2, A3, A4, A5, A6)> : public VMFunction { |
michael@0 | 543 | typedef R (*pf)(Context, A1, A2, A3, A4, A5, A6); |
michael@0 | 544 | FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_6) |
michael@0 | 545 | }; |
michael@0 | 546 | |
michael@0 | 547 | #undef FUNCTION_INFO_STRUCT_BODY |
michael@0 | 548 | |
michael@0 | 549 | #undef FOR_EACH_ARGS_6 |
michael@0 | 550 | #undef FOR_EACH_ARGS_5 |
michael@0 | 551 | #undef FOR_EACH_ARGS_4 |
michael@0 | 552 | #undef FOR_EACH_ARGS_3 |
michael@0 | 553 | #undef FOR_EACH_ARGS_2 |
michael@0 | 554 | #undef FOR_EACH_ARGS_1 |
michael@0 | 555 | |
michael@0 | 556 | #undef COMPUTE_INDEX |
michael@0 | 557 | #undef COMPUTE_OUTPARAM_RESULT |
michael@0 | 558 | #undef COMPUTE_OUTPARAM_ROOT |
michael@0 | 559 | #undef COMPUTE_ARG_PROP |
michael@0 | 560 | #undef COMPUTE_ARG_FLOAT |
michael@0 | 561 | #undef SEP_OR |
michael@0 | 562 | #undef NOTHING |
michael@0 | 563 | |
michael@0 | 564 | class AutoDetectInvalidation |
michael@0 | 565 | { |
michael@0 | 566 | JSContext *cx_; |
michael@0 | 567 | IonScript *ionScript_; |
michael@0 | 568 | Value *rval_; |
michael@0 | 569 | bool disabled_; |
michael@0 | 570 | |
michael@0 | 571 | public: |
michael@0 | 572 | AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript = nullptr); |
michael@0 | 573 | |
michael@0 | 574 | void disable() { |
michael@0 | 575 | JS_ASSERT(!disabled_); |
michael@0 | 576 | disabled_ = true; |
michael@0 | 577 | } |
michael@0 | 578 | |
michael@0 | 579 | ~AutoDetectInvalidation() { |
michael@0 | 580 | if (!disabled_ && ionScript_->invalidated()) |
michael@0 | 581 | cx_->runtime()->setIonReturnOverride(*rval_); |
michael@0 | 582 | } |
michael@0 | 583 | }; |
michael@0 | 584 | |
michael@0 | 585 | bool InvokeFunction(JSContext *cx, HandleObject obj0, uint32_t argc, Value *argv, Value *rval); |
michael@0 | 586 | JSObject *NewGCObject(JSContext *cx, gc::AllocKind allocKind, gc::InitialHeap initialHeap); |
michael@0 | 587 | |
michael@0 | 588 | bool CheckOverRecursed(JSContext *cx); |
michael@0 | 589 | bool CheckOverRecursedWithExtra(JSContext *cx, BaselineFrame *frame, |
michael@0 | 590 | uint32_t extra, uint32_t earlyCheck); |
michael@0 | 591 | |
michael@0 | 592 | bool DefVarOrConst(JSContext *cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain); |
michael@0 | 593 | bool SetConst(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, HandleValue rval); |
michael@0 | 594 | bool MutatePrototype(JSContext *cx, HandleObject obj, HandleValue value); |
michael@0 | 595 | bool InitProp(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value); |
michael@0 | 596 | |
michael@0 | 597 | template<bool Equal> |
michael@0 | 598 | bool LooselyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res); |
michael@0 | 599 | |
michael@0 | 600 | template<bool Equal> |
michael@0 | 601 | bool StrictlyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res); |
michael@0 | 602 | |
michael@0 | 603 | bool LessThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res); |
michael@0 | 604 | bool LessThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res); |
michael@0 | 605 | bool GreaterThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res); |
michael@0 | 606 | bool GreaterThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res); |
michael@0 | 607 | |
michael@0 | 608 | template<bool Equal> |
michael@0 | 609 | bool StringsEqual(JSContext *cx, HandleString left, HandleString right, bool *res); |
michael@0 | 610 | |
michael@0 | 611 | bool IteratorMore(JSContext *cx, HandleObject obj, bool *res); |
michael@0 | 612 | |
michael@0 | 613 | // Allocation functions for JSOP_NEWARRAY and JSOP_NEWOBJECT and parallel array inlining |
michael@0 | 614 | JSObject *NewInitParallelArray(JSContext *cx, HandleObject templateObj); |
michael@0 | 615 | JSObject *NewInitArray(JSContext *cx, uint32_t count, types::TypeObject *type); |
michael@0 | 616 | JSObject *NewInitObject(JSContext *cx, HandleObject templateObject); |
michael@0 | 617 | JSObject *NewInitObjectWithClassPrototype(JSContext *cx, HandleObject templateObject); |
michael@0 | 618 | |
michael@0 | 619 | bool ArrayPopDense(JSContext *cx, HandleObject obj, MutableHandleValue rval); |
michael@0 | 620 | bool ArrayPushDense(JSContext *cx, HandleObject obj, HandleValue v, uint32_t *length); |
michael@0 | 621 | bool ArrayShiftDense(JSContext *cx, HandleObject obj, MutableHandleValue rval); |
michael@0 | 622 | JSObject *ArrayConcatDense(JSContext *cx, HandleObject obj1, HandleObject obj2, HandleObject res); |
michael@0 | 623 | |
michael@0 | 624 | bool CharCodeAt(JSContext *cx, HandleString str, int32_t index, uint32_t *code); |
michael@0 | 625 | JSFlatString *StringFromCharCode(JSContext *cx, int32_t code); |
michael@0 | 626 | |
michael@0 | 627 | bool SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value, |
michael@0 | 628 | bool strict, jsbytecode *pc); |
michael@0 | 629 | |
michael@0 | 630 | bool InterruptCheck(JSContext *cx); |
michael@0 | 631 | |
michael@0 | 632 | HeapSlot *NewSlots(JSRuntime *rt, unsigned nslots); |
michael@0 | 633 | JSObject *NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots); |
michael@0 | 634 | JSObject *NewSingletonCallObject(JSContext *cx, HandleShape shape, HeapSlot *slots); |
michael@0 | 635 | JSObject *NewStringObject(JSContext *cx, HandleString str); |
michael@0 | 636 | |
michael@0 | 637 | bool SPSEnter(JSContext *cx, HandleScript script); |
michael@0 | 638 | bool SPSExit(JSContext *cx, HandleScript script); |
michael@0 | 639 | |
michael@0 | 640 | bool OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, bool *out); |
michael@0 | 641 | bool OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, bool *out); |
michael@0 | 642 | |
michael@0 | 643 | bool GetIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue rval); |
michael@0 | 644 | |
michael@0 | 645 | bool CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval); |
michael@0 | 646 | |
michael@0 | 647 | void GetDynamicName(JSContext *cx, JSObject *scopeChain, JSString *str, Value *vp); |
michael@0 | 648 | |
michael@0 | 649 | bool FilterArgumentsOrEval(JSContext *cx, JSString *str); |
michael@0 | 650 | |
michael@0 | 651 | #ifdef JSGC_GENERATIONAL |
michael@0 | 652 | void PostWriteBarrier(JSRuntime *rt, JSObject *obj); |
michael@0 | 653 | void PostGlobalWriteBarrier(JSRuntime *rt, JSObject *obj); |
michael@0 | 654 | #endif |
michael@0 | 655 | |
michael@0 | 656 | uint32_t GetIndexFromString(JSString *str); |
michael@0 | 657 | |
michael@0 | 658 | bool DebugPrologue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn); |
michael@0 | 659 | bool DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok); |
michael@0 | 660 | |
michael@0 | 661 | bool StrictEvalPrologue(JSContext *cx, BaselineFrame *frame); |
michael@0 | 662 | bool HeavyweightFunPrologue(JSContext *cx, BaselineFrame *frame); |
michael@0 | 663 | |
michael@0 | 664 | bool NewArgumentsObject(JSContext *cx, BaselineFrame *frame, MutableHandleValue res); |
michael@0 | 665 | |
michael@0 | 666 | JSObject *InitRestParameter(JSContext *cx, uint32_t length, Value *rest, HandleObject templateObj, |
michael@0 | 667 | HandleObject res); |
michael@0 | 668 | |
michael@0 | 669 | bool HandleDebugTrap(JSContext *cx, BaselineFrame *frame, uint8_t *retAddr, bool *mustReturn); |
michael@0 | 670 | bool OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn); |
michael@0 | 671 | |
michael@0 | 672 | bool EnterWith(JSContext *cx, BaselineFrame *frame, HandleValue val, |
michael@0 | 673 | Handle<StaticWithObject *> templ); |
michael@0 | 674 | bool LeaveWith(JSContext *cx, BaselineFrame *frame); |
michael@0 | 675 | |
michael@0 | 676 | bool PushBlockScope(JSContext *cx, BaselineFrame *frame, Handle<StaticBlockObject *> block); |
michael@0 | 677 | bool PopBlockScope(JSContext *cx, BaselineFrame *frame); |
michael@0 | 678 | bool DebugLeaveBlock(JSContext *cx, BaselineFrame *frame, jsbytecode *pc); |
michael@0 | 679 | |
michael@0 | 680 | bool InitBaselineFrameForOsr(BaselineFrame *frame, InterpreterFrame *interpFrame, |
michael@0 | 681 | uint32_t numStackValues); |
michael@0 | 682 | |
michael@0 | 683 | JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject descr, |
michael@0 | 684 | HandleObject owner, int32_t offset); |
michael@0 | 685 | |
michael@0 | 686 | bool ArraySpliceDense(JSContext *cx, HandleObject obj, uint32_t start, uint32_t deleteCount); |
michael@0 | 687 | |
michael@0 | 688 | bool Recompile(JSContext *cx); |
michael@0 | 689 | JSString *RegExpReplace(JSContext *cx, HandleString string, HandleObject regexp, |
michael@0 | 690 | HandleString repl); |
michael@0 | 691 | JSString *StringReplace(JSContext *cx, HandleString string, HandleString pattern, |
michael@0 | 692 | HandleString repl); |
michael@0 | 693 | |
michael@0 | 694 | bool SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value, |
michael@0 | 695 | bool strict); |
michael@0 | 696 | |
michael@0 | 697 | #ifdef DEBUG |
michael@0 | 698 | void AssertValidObjectPtr(JSContext *cx, JSObject *obj); |
michael@0 | 699 | void AssertValidStringPtr(JSContext *cx, JSString *str); |
michael@0 | 700 | void AssertValidValue(JSContext *cx, Value *v); |
michael@0 | 701 | #endif |
michael@0 | 702 | |
michael@0 | 703 | } // namespace jit |
michael@0 | 704 | } // namespace js |
michael@0 | 705 | |
michael@0 | 706 | #endif /* jit_VMFunctions_h */ |