mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changeset 45f374858666 (bug 852891) for bad commit message referencing wrong bug. DONTBUILD
This commit is contained in:
parent
9bd121838b
commit
3d75a41155
@ -583,7 +583,7 @@ struct JSClass {
|
||||
// with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
|
||||
// previously allowed, but is now an ES5 violation and thus unsupported.
|
||||
//
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT (3 + JSProto_LIMIT * 3 + 31)
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT (3 + JSProto_LIMIT * 3 + 30)
|
||||
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
|
||||
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
|
||||
#define JSCLASS_GLOBAL_FLAGS \
|
||||
|
@ -498,17 +498,14 @@ function ArrayFindIndex(predicate/*, thisArg*/) {
|
||||
#define ITEM_KIND_KEY 2
|
||||
|
||||
// ES6 draft specification, section 22.1.5.1, version 2013-09-05.
|
||||
function CreateArrayIteratorAt(obj, kind, n) {
|
||||
function CreateArrayIterator(obj, kind) {
|
||||
var iteratedObject = ToObject(obj);
|
||||
var iterator = NewArrayIterator();
|
||||
UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITERATED_OBJECT, iteratedObject);
|
||||
UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_NEXT_INDEX, n);
|
||||
UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_NEXT_INDEX, 0);
|
||||
UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITEM_KIND, kind);
|
||||
return iterator;
|
||||
}
|
||||
function CreateArrayIterator(obj, kind) {
|
||||
return CreateArrayIteratorAt(obj, kind, 0);
|
||||
}
|
||||
|
||||
function ArrayIteratorIdentity() {
|
||||
return this;
|
||||
@ -547,10 +544,6 @@ function ArrayIteratorNext() {
|
||||
return { value: index, done: false };
|
||||
}
|
||||
|
||||
function ArrayValuesAt(n) {
|
||||
return CreateArrayIteratorAt(this, ITEM_KIND_VALUE, n);
|
||||
}
|
||||
|
||||
function ArrayValues() {
|
||||
return CreateArrayIterator(this, ITEM_KIND_VALUE);
|
||||
}
|
||||
|
@ -4861,30 +4861,13 @@ SetAsmJSCacheOps(JSRuntime *rt, const AsmJSCacheOps *callbacks);
|
||||
class MOZ_STACK_CLASS JS_PUBLIC_API(ForOfIterator) {
|
||||
protected:
|
||||
JSContext *cx_;
|
||||
/*
|
||||
* Use the ForOfPIC on the global object (see vm/GlobalObject.h) to try
|
||||
* to optimize iteration across arrays.
|
||||
*
|
||||
* Case 1: Regular Iteration
|
||||
* iterator - pointer to the iterator object.
|
||||
* index - fixed to NOT_ARRAY (== UINT32_MAX)
|
||||
*
|
||||
* Case 2: Optimized Array Iteration
|
||||
* iterator - pointer to the array object.
|
||||
* index - current position in array.
|
||||
*
|
||||
* The cases are distinguished by whether or not |index| is equal to NOT_ARRAY.
|
||||
*/
|
||||
JS::RootedObject iterator;
|
||||
uint32_t index;
|
||||
|
||||
static const uint32_t NOT_ARRAY = UINT32_MAX;
|
||||
|
||||
ForOfIterator(const ForOfIterator &) MOZ_DELETE;
|
||||
ForOfIterator &operator=(const ForOfIterator &) MOZ_DELETE;
|
||||
|
||||
public:
|
||||
ForOfIterator(JSContext *cx) : cx_(cx), iterator(cx_), index(NOT_ARRAY) { }
|
||||
ForOfIterator(JSContext *cx) : cx_(cx), iterator(cx) { }
|
||||
|
||||
enum NonIterableBehavior {
|
||||
ThrowOnNonIterable,
|
||||
@ -4913,10 +4896,6 @@ class MOZ_STACK_CLASS JS_PUBLIC_API(ForOfIterator) {
|
||||
bool valueIsIterable() const {
|
||||
return iterator;
|
||||
}
|
||||
|
||||
private:
|
||||
inline bool nextFromOptimizedArray(MutableHandleValue val, bool *done);
|
||||
bool materializeArrayIterator();
|
||||
};
|
||||
|
||||
} /* namespace JS */
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "builtin/TypeRepresentation.h"
|
||||
#include "gc/Zone.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/PIC.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -1278,28 +1278,6 @@ ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavio
|
||||
if (!iterableObj)
|
||||
return false;
|
||||
|
||||
JS_ASSERT(index == NOT_ARRAY);
|
||||
|
||||
// Check the PIC first for a match.
|
||||
if (iterableObj->is<ArrayObject>()) {
|
||||
ForOfPIC::Chain *stubChain = ForOfPIC::getOrCreate(cx);
|
||||
if (!stubChain)
|
||||
return false;
|
||||
|
||||
bool optimized;
|
||||
if (!stubChain->tryOptimizeArray(cx, iterableObj, &optimized))
|
||||
return false;
|
||||
|
||||
if (optimized) {
|
||||
// Got optimized stub. Array is optimizable.
|
||||
index = 0;
|
||||
iterator = iterableObj;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
JS_ASSERT(index == NOT_ARRAY);
|
||||
|
||||
// The iterator is the result of calling obj[@@iterator]().
|
||||
InvokeArgs args(cx);
|
||||
if (!args.init(0))
|
||||
@ -1336,110 +1314,37 @@ ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavio
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
ForOfIterator::nextFromOptimizedArray(MutableHandleValue vp, bool *done)
|
||||
{
|
||||
JS_ASSERT(index != NOT_ARRAY);
|
||||
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx_))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(iterator->isNative());
|
||||
JS_ASSERT(iterator->is<ArrayObject>());
|
||||
|
||||
if (index >= iterator->as<ArrayObject>().length()) {
|
||||
vp.setUndefined();
|
||||
*done = true;
|
||||
return true;
|
||||
}
|
||||
*done = false;
|
||||
|
||||
// Try to get array element via direct access.
|
||||
if (index < iterator->getDenseInitializedLength()) {
|
||||
vp.set(iterator->getDenseElement(index));
|
||||
if (!vp.isMagic(JS_ELEMENTS_HOLE)) {
|
||||
++index;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return JSObject::getElement(cx_, iterator, iterator, index++, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
ForOfIterator::next(MutableHandleValue vp, bool *done)
|
||||
{
|
||||
JS_ASSERT(iterator);
|
||||
|
||||
if (index != NOT_ARRAY) {
|
||||
ForOfPIC::Chain *stubChain = ForOfPIC::getOrCreate(cx_);
|
||||
if (!stubChain)
|
||||
return false;
|
||||
|
||||
if (stubChain->isArrayNextStillSane())
|
||||
return nextFromOptimizedArray(vp, done);
|
||||
|
||||
// ArrayIterator.prototype.next changed, materialize a proper
|
||||
// ArrayIterator instance and fall through to slowpath case.
|
||||
if (!materializeArrayIterator())
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue method(cx_);
|
||||
if (!JSObject::getProperty(cx_, iterator, iterator, cx_->names().next, &method))
|
||||
JSContext *cx = cx_;
|
||||
RootedValue method(cx);
|
||||
if (!JSObject::getProperty(cx, iterator, iterator, cx->names().next, &method))
|
||||
return false;
|
||||
|
||||
InvokeArgs args(cx_);
|
||||
InvokeArgs args(cx);
|
||||
if (!args.init(1))
|
||||
return false;
|
||||
args.setCallee(method);
|
||||
args.setThis(ObjectValue(*iterator));
|
||||
args[0].setUndefined();
|
||||
if (!Invoke(cx_, args))
|
||||
if (!Invoke(cx, args))
|
||||
return false;
|
||||
|
||||
RootedObject resultObj(cx_, ToObject(cx_, args.rval()));
|
||||
RootedObject resultObj(cx, ToObject(cx, args.rval()));
|
||||
if (!resultObj)
|
||||
return false;
|
||||
RootedValue doneVal(cx_);
|
||||
if (!JSObject::getProperty(cx_, resultObj, resultObj, cx_->names().done, &doneVal))
|
||||
RootedValue doneVal(cx);
|
||||
if (!JSObject::getProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
|
||||
return false;
|
||||
*done = ToBoolean(doneVal);
|
||||
if (*done) {
|
||||
vp.setUndefined();
|
||||
return true;
|
||||
}
|
||||
return JSObject::getProperty(cx_, resultObj, resultObj, cx_->names().value, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
ForOfIterator::materializeArrayIterator()
|
||||
{
|
||||
JS_ASSERT(index != NOT_ARRAY);
|
||||
|
||||
const char *nameString = "ArrayValuesAt";
|
||||
|
||||
RootedAtom name(cx_, Atomize(cx_, nameString, strlen(nameString)));
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
RootedValue val(cx_);
|
||||
if (!cx_->global()->getSelfHostedFunction(cx_, name, name, 1, &val))
|
||||
return false;
|
||||
|
||||
InvokeArgs args(cx_);
|
||||
if (!args.init(1))
|
||||
return false;
|
||||
args.setCallee(val);
|
||||
args.setThis(ObjectValue(*iterator));
|
||||
args[0].set(Int32Value(index));
|
||||
if (!Invoke(cx_, args))
|
||||
return false;
|
||||
|
||||
index = NOT_ARRAY;
|
||||
// Result of call to ArrayValuesAt must be an object.
|
||||
iterator = &args.rval().toObject();
|
||||
return true;
|
||||
return JSObject::getProperty(cx, resultObj, resultObj, cx->names().value, vp);
|
||||
}
|
||||
|
||||
/*** Generators **********************************************************************************/
|
||||
|
@ -169,7 +169,6 @@ UNIFIED_SOURCES += [
|
||||
'vm/Monitor.cpp',
|
||||
'vm/ObjectImpl.cpp',
|
||||
'vm/OldDebugAPI.cpp',
|
||||
'vm/PIC.cpp',
|
||||
'vm/Probes.cpp',
|
||||
'vm/PropertyKey.cpp',
|
||||
'vm/ProxyObject.cpp',
|
||||
|
@ -1,140 +0,0 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonky JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
|
||||
// Test the properties and prototype of a generator object.
|
||||
function TestManySmallArrays() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
result += arguments[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
var TRUE_SUM = 0;
|
||||
var N = 100;
|
||||
var M = 3;
|
||||
var sum = 0;
|
||||
for (var i = 0; i < N; i++) {
|
||||
var arr = new Array(M);
|
||||
for (var j = 0; j < M; j++) {
|
||||
arr[j] = j;
|
||||
TRUE_SUM += j;
|
||||
}
|
||||
sum += doIter(fun, arr);
|
||||
}
|
||||
assertEq(sum, TRUE_SUM);
|
||||
}
|
||||
TestManySmallArrays();
|
||||
|
||||
// Test the properties and prototype of a generator object.
|
||||
function TestSingleSmallArray() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
result += arguments[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
var TRUE_SUM = 0;
|
||||
var N = 100;
|
||||
var M = 3;
|
||||
var arr = new Array(M);
|
||||
for (var j = 0; j < M; j++) {
|
||||
arr[j] = j;
|
||||
TRUE_SUM += j;
|
||||
}
|
||||
TRUE_SUM *= N;
|
||||
|
||||
var sum = 0;
|
||||
for (var i = 0; i < N; i++) {
|
||||
sum += doIter(fun, arr);
|
||||
}
|
||||
assertEq(sum, TRUE_SUM);
|
||||
}
|
||||
TestSingleSmallArray();
|
||||
|
||||
|
||||
function TestChangeArrayPrototype() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
result += arguments[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
var Proto1 = Object.create(Array.prototype);
|
||||
|
||||
var TRUE_SUM = 0;
|
||||
var N = 100;
|
||||
var MID = N/2;
|
||||
var M = 3;
|
||||
var arr = new Array(M);
|
||||
var ARR_SUM = 0;
|
||||
for (var j = 0; j < M; j++) {
|
||||
arr[j] = j;
|
||||
ARR_SUM += j;
|
||||
}
|
||||
|
||||
var sum = 0;
|
||||
for (var i = 0; i < N; i++) {
|
||||
sum += doIter(fun, arr);
|
||||
if (i == MID)
|
||||
arr.__proto__ = Proto1;
|
||||
TRUE_SUM += ARR_SUM;
|
||||
}
|
||||
assertEq(sum, TRUE_SUM);
|
||||
}
|
||||
TestChangeArrayPrototype();
|
||||
|
||||
|
||||
function TestChangeManyArrayShape() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
result += arguments[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
var TRUE_SUM = 0;
|
||||
var N = 100;
|
||||
var MID = N/2;
|
||||
var M = 3;
|
||||
var sum = 0;
|
||||
for (var i = 0; i < N; i++) {
|
||||
var arr = new Array(M);
|
||||
var ARR_SUM = 0;
|
||||
for (var j = 0; j < M; j++) {
|
||||
arr[j] = j;
|
||||
ARR_SUM += j;
|
||||
}
|
||||
arr['v_' + i] = i;
|
||||
sum += doIter(fun, arr);
|
||||
TRUE_SUM += ARR_SUM;
|
||||
}
|
||||
assertEq(sum, TRUE_SUM);
|
||||
}
|
||||
TestChangeManyArrayShape();
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
@ -1,59 +0,0 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonky JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
//
|
||||
// Check case where ArrayIterator.prototype.next changes in the middle of iteration.
|
||||
//
|
||||
function TestChangeArrayIteratorNext() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
result += arguments[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
var GET_COUNT = 0;
|
||||
function getter() {
|
||||
GET_COUNT++;
|
||||
if (GET_COUNT == MID)
|
||||
iterProto.next = NewNext;
|
||||
return M2;
|
||||
}
|
||||
|
||||
var iter = ([])['@@iterator']();
|
||||
var iterProto = Object.getPrototypeOf(iter);
|
||||
var OldNext = iterProto.next;
|
||||
var NewNext = function () {
|
||||
return OldNext.apply(this, arguments);
|
||||
};
|
||||
|
||||
var TRUE_SUM = 0;
|
||||
var N = 100;
|
||||
var MID = N/2;
|
||||
var M = 3;
|
||||
var arr = new Array(M);
|
||||
var ARR_SUM = 0;
|
||||
for (var j = 0; j < M; j++) {
|
||||
arr[j] = j;
|
||||
ARR_SUM += j;
|
||||
}
|
||||
var M2 = (M/2)|0;
|
||||
Object.defineProperty(arr, M2, {'get':getter});
|
||||
|
||||
var sum = 0;
|
||||
for (var i = 0; i < N; i++) {
|
||||
sum += doIter(fun, arr);
|
||||
TRUE_SUM += ARR_SUM;
|
||||
}
|
||||
assertEq(sum, TRUE_SUM);
|
||||
}
|
||||
TestChangeArrayIteratorNext();
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
@ -1,61 +0,0 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonkey JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
//
|
||||
// Check array length increases changes during iteration.
|
||||
//
|
||||
function TestIncreaseArrayLength() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
result += arguments[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
var GET_COUNT = 0;
|
||||
function getter() {
|
||||
GET_COUNT++;
|
||||
if (GET_COUNT == MID) {
|
||||
ARR_SUM += arr.length;
|
||||
arr.push(arr.length);
|
||||
}
|
||||
return M2;
|
||||
}
|
||||
|
||||
var iter = ([])['@@iterator']();
|
||||
var iterProto = Object.getPrototypeOf(iter);
|
||||
var OldNext = iterProto.next;
|
||||
var NewNext = function () {
|
||||
return OldNext.apply(this, arguments);
|
||||
};
|
||||
|
||||
var TRUE_SUM = 0;
|
||||
var N = 100;
|
||||
var MID = N/2;
|
||||
var M = 3;
|
||||
var arr = new Array(M);
|
||||
var ARR_SUM = 0;
|
||||
for (var j = 0; j < M; j++) {
|
||||
arr[j] = j;
|
||||
ARR_SUM += j;
|
||||
}
|
||||
var M2 = (M/2)|0;
|
||||
Object.defineProperty(arr, M2, {'get':getter});
|
||||
|
||||
var sum = 0;
|
||||
for (var i = 0; i < N; i++) {
|
||||
sum += doIter(fun, arr);
|
||||
TRUE_SUM += ARR_SUM;
|
||||
}
|
||||
assertEq(sum, TRUE_SUM);
|
||||
}
|
||||
TestIncreaseArrayLength();
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
@ -1,65 +0,0 @@
|
||||
// Test corner cases of for-of iteration over Arrays.
|
||||
// The current spidermonkey JSOP_SPREAD implementation for function calls
|
||||
// with '...rest' arguments uses a ForOfIterator to extract values from
|
||||
// the array, so we use that mechanism to test ForOfIterator here.
|
||||
|
||||
//
|
||||
// Check array length decreases changes during iteration.
|
||||
//
|
||||
function TestDecreaseArrayLength() {
|
||||
function doIter(f, arr) {
|
||||
return f(...arr)
|
||||
}
|
||||
|
||||
function fun(a, b, c) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
result += arguments[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
var GET_COUNT = 0;
|
||||
function getter() {
|
||||
GET_COUNT++;
|
||||
if (GET_COUNT == MID) {
|
||||
arr.length = 0;
|
||||
}
|
||||
return M2;
|
||||
}
|
||||
|
||||
var iter = ([])['@@iterator']();
|
||||
var iterProto = Object.getPrototypeOf(iter);
|
||||
var OldNext = iterProto.next;
|
||||
var NewNext = function () {
|
||||
return OldNext.apply(this, arguments);
|
||||
};
|
||||
|
||||
var TRUE_SUM = 0;
|
||||
var N = 100;
|
||||
var MID = N/2;
|
||||
var M = 3;
|
||||
var arr = new Array(M);
|
||||
var ARR_SUM = 0;
|
||||
for (var j = 0; j < M; j++) {
|
||||
arr[j] = j;
|
||||
ARR_SUM += j;
|
||||
}
|
||||
var M2 = (M/2)|0;
|
||||
Object.defineProperty(arr, M2, {'get':getter});
|
||||
|
||||
var sum = 0;
|
||||
for (var i = 0; i < N; i++) {
|
||||
var oldLen = arr.length;
|
||||
sum += doIter(fun, arr);
|
||||
var newLen = arr.length;
|
||||
if (oldLen == newLen)
|
||||
TRUE_SUM += arr.length > 0 ? ARR_SUM : 0;
|
||||
else
|
||||
TRUE_SUM += 1
|
||||
}
|
||||
assertEq(sum, TRUE_SUM);
|
||||
}
|
||||
TestDecreaseArrayLength();
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
@ -17,9 +17,7 @@
|
||||
macro(apply, apply, "apply") \
|
||||
macro(arguments, arguments, "arguments") \
|
||||
macro(as, as, "as") \
|
||||
macro(ArrayIteratorNext, ArrayIteratorNext, "ArrayIteratorNext") \
|
||||
macro(ArrayType, ArrayType, "ArrayType") \
|
||||
macro(ArrayValues, ArrayValues, "ArrayValues") \
|
||||
macro(buffer, buffer, "buffer") \
|
||||
macro(builder, builder, "builder") \
|
||||
macro(byteLength, byteLength, "byteLength") \
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "builtin/RegExp.h"
|
||||
#include "builtin/SIMD.h"
|
||||
#include "builtin/TypedObject.h"
|
||||
#include "vm/PIC.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/StopIterationObject.h"
|
||||
#include "vm/WeakMapObject.h"
|
||||
@ -742,21 +741,6 @@ GlobalObject::addDebugger(JSContext *cx, Handle<GlobalObject*> global, Debugger
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ JSObject *
|
||||
GlobalObject::getOrCreateForOfPICObject(JSContext *cx, Handle<GlobalObject *> global)
|
||||
{
|
||||
assertSameCompartment(cx, global);
|
||||
JSObject *forOfPIC = global->getForOfPICObject();
|
||||
if (forOfPIC)
|
||||
return forOfPIC;
|
||||
|
||||
forOfPIC = ForOfPIC::createForOfPICObject(cx, global);
|
||||
if (!forOfPIC)
|
||||
return nullptr;
|
||||
global->setReservedSlot(FOR_OF_PIC_CHAIN, ObjectValue(*forOfPIC));
|
||||
return forOfPIC;
|
||||
}
|
||||
|
||||
bool
|
||||
GlobalObject::getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, HandleAtom name,
|
||||
unsigned nargs, MutableHandleValue funVal)
|
||||
|
@ -111,10 +111,9 @@ class GlobalObject : public JSObject
|
||||
static const unsigned INTRINSICS = DEBUGGERS + 1;
|
||||
static const unsigned FLOAT32X4_TYPE_DESCR = INTRINSICS + 1;
|
||||
static const unsigned INT32X4_TYPE_DESCR = FLOAT32X4_TYPE_DESCR + 1;
|
||||
static const unsigned FOR_OF_PIC_CHAIN = INT32X4_TYPE_DESCR + 1;
|
||||
|
||||
/* Total reserved-slot count for global objects. */
|
||||
static const unsigned RESERVED_SLOTS = FOR_OF_PIC_CHAIN + 1;
|
||||
static const unsigned RESERVED_SLOTS = INT32X4_TYPE_DESCR + 1;
|
||||
|
||||
/*
|
||||
* The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, and
|
||||
@ -676,14 +675,6 @@ class GlobalObject : public JSObject
|
||||
*/
|
||||
static DebuggerVector *getOrCreateDebuggers(JSContext *cx, Handle<GlobalObject*> global);
|
||||
|
||||
inline JSObject *getForOfPICObject() {
|
||||
Value forOfPIC = getReservedSlot(FOR_OF_PIC_CHAIN);
|
||||
if (forOfPIC.isUndefined())
|
||||
return nullptr;
|
||||
return &forOfPIC.toObject();
|
||||
}
|
||||
static JSObject *getOrCreateForOfPICObject(JSContext *cx, Handle<GlobalObject*> global);
|
||||
|
||||
static bool addDebugger(JSContext *cx, Handle<GlobalObject*> global, Debugger *dbg);
|
||||
};
|
||||
|
||||
|
@ -1,330 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "vm/PIC.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsobj.h"
|
||||
#include "gc/Marking.h"
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/ObjectImpl.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "vm/ObjectImpl-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
bool
|
||||
js::ForOfPIC::Chain::initialize(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(!initialized_);
|
||||
|
||||
// Get the canonical Array.prototype
|
||||
RootedObject arrayProto(cx, GlobalObject::getOrCreateArrayPrototype(cx, cx->global()));
|
||||
if (!arrayProto)
|
||||
return false;
|
||||
|
||||
// Get the canonical ArrayIterator.prototype
|
||||
RootedObject arrayIteratorProto(cx,
|
||||
GlobalObject::getOrCreateArrayIteratorPrototype(cx, cx->global()));
|
||||
if (!arrayIteratorProto)
|
||||
return false;
|
||||
|
||||
// From this point on, we can't fail. Set initialized and fill the fields
|
||||
// for the canonical Array.prototype and ArrayIterator.prototype objects.
|
||||
initialized_ = true;
|
||||
arrayProto_ = arrayProto;
|
||||
arrayIteratorProto_ = arrayIteratorProto;
|
||||
|
||||
// Shortcut returns below means Array for-of will never be optimizable,
|
||||
// do set disabled_ now, and clear it later when we succeed.
|
||||
disabled_ = true;
|
||||
|
||||
// Look up '@@iterator' on Array.prototype, ensure it's a slotful shape.
|
||||
Shape *iterShape = arrayProto->nativeLookup(cx, cx->names().std_iterator);
|
||||
if (!iterShape || !iterShape->hasSlot() || !iterShape->hasDefaultGetter())
|
||||
return true;
|
||||
|
||||
// Get the referred value, and ensure it holds the canonical ArrayValues function.
|
||||
Value iterator = arrayProto->getSlot(iterShape->slot());
|
||||
JSFunction *iterFun;
|
||||
if (!IsFunctionObject(iterator, &iterFun))
|
||||
return true;
|
||||
if (!IsSelfHostedFunctionWithName(iterFun, cx->names().ArrayValues))
|
||||
return true;
|
||||
|
||||
// Look up the 'next' value on ArrayIterator.prototype
|
||||
Shape *nextShape = arrayIteratorProto->nativeLookup(cx, cx->names().next);
|
||||
if (!nextShape || !nextShape->hasSlot())
|
||||
return true;
|
||||
|
||||
// Get the referred value, ensure it holds the canonical ArrayIteratorNext function.
|
||||
Value next = arrayIteratorProto->getSlot(nextShape->slot());
|
||||
JSFunction *nextFun;
|
||||
if (!IsFunctionObject(next, &nextFun))
|
||||
return true;
|
||||
if (!IsSelfHostedFunctionWithName(nextFun, cx->names().ArrayIteratorNext))
|
||||
return true;
|
||||
|
||||
disabled_ = false;
|
||||
arrayProtoShape_ = arrayProto->lastProperty();
|
||||
arrayProtoIteratorSlot_ = iterShape->slot();
|
||||
canonicalIteratorFunc_ = iterator;
|
||||
arrayIteratorProtoShape_ = arrayIteratorProto->lastProperty();
|
||||
arrayIteratorProtoNextSlot_ = nextShape->slot();
|
||||
canonicalNextFunc_ = next;
|
||||
return true;
|
||||
}
|
||||
|
||||
js::ForOfPIC::Stub *
|
||||
js::ForOfPIC::Chain::isArrayOptimized(ArrayObject *obj)
|
||||
{
|
||||
Stub *stub = getMatchingStub(obj);
|
||||
if (!stub)
|
||||
return nullptr;
|
||||
|
||||
// Ensure that this is an otherwise optimizable array.
|
||||
if (!isOptimizableArray(obj))
|
||||
return nullptr;
|
||||
|
||||
// Not yet enough! Ensure that the world as we know it remains sane.
|
||||
if (!isArrayStateStillSane())
|
||||
return nullptr;
|
||||
|
||||
return stub;
|
||||
}
|
||||
|
||||
bool
|
||||
js::ForOfPIC::Chain::tryOptimizeArray(JSContext *cx, HandleObject array, bool *optimized)
|
||||
{
|
||||
JS_ASSERT(array->is<ArrayObject>());
|
||||
JS_ASSERT(optimized);
|
||||
|
||||
*optimized = false;
|
||||
|
||||
if (!initialized_) {
|
||||
// If PIC is not initialized, initialize it.
|
||||
if (!initialize(cx))
|
||||
return false;
|
||||
|
||||
} else if (!disabled_ && !isArrayStateStillSane()) {
|
||||
// Otherwise, if array state is no longer sane, reinitialize.
|
||||
reset(cx);
|
||||
|
||||
if (!initialize(cx))
|
||||
return false;
|
||||
}
|
||||
JS_ASSERT(initialized_);
|
||||
|
||||
// If PIC is disabled, don't bother trying to optimize.
|
||||
if (disabled_)
|
||||
return true;
|
||||
|
||||
// By the time we get here, we should have a sane array state to work with.
|
||||
JS_ASSERT(isArrayStateStillSane());
|
||||
|
||||
// Check if stub already exists.
|
||||
ForOfPIC::Stub *stub = isArrayOptimized(&array->as<ArrayObject>());
|
||||
if (stub) {
|
||||
*optimized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the number of stubs is about to exceed the limit, throw away entire
|
||||
// existing cache before adding new stubs. We shouldn't really have heavy
|
||||
// churn on these.
|
||||
if (numStubs() >= MAX_STUBS)
|
||||
eraseChain();
|
||||
|
||||
// Ensure array's prototype is the actual Array.prototype
|
||||
if (!isOptimizableArray(array))
|
||||
return true;
|
||||
|
||||
// Ensure array doesn't define '@@iterator' directly.
|
||||
if (array->nativeLookup(cx, cx->names().std_iterator))
|
||||
return true;
|
||||
|
||||
// Good to optimize now, create stub to add.
|
||||
RootedShape shape(cx, array->lastProperty());
|
||||
stub = cx->new_<Stub>(shape);
|
||||
if (!stub)
|
||||
return false;
|
||||
|
||||
// Add the stub.
|
||||
addStub(stub);
|
||||
|
||||
*optimized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
js::ForOfPIC::Stub *
|
||||
js::ForOfPIC::Chain::getMatchingStub(JSObject *obj)
|
||||
{
|
||||
// Ensure PIC is initialized and not disabled.
|
||||
if (!initialized_ || disabled_)
|
||||
return nullptr;
|
||||
|
||||
// Check if there is a matching stub.
|
||||
for (Stub *stub = stubs(); stub != nullptr; stub = stub->next()) {
|
||||
if (stub->shape() == obj->lastProperty())
|
||||
return stub;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
js::ForOfPIC::Chain::isOptimizableArray(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->is<ArrayObject>());
|
||||
|
||||
// Ensure object's prototype is the actual Array.prototype
|
||||
if (!obj->getTaggedProto().isObject())
|
||||
return false;
|
||||
if (obj->getTaggedProto().toObject() != arrayProto_)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::ForOfPIC::Chain::isArrayStateStillSane()
|
||||
{
|
||||
// Ensure that canonical Array.prototype has matching shape.
|
||||
if (arrayProto_->lastProperty() != arrayProtoShape_)
|
||||
return false;
|
||||
|
||||
// Ensure that Array.prototype['@@iterator'] contains the
|
||||
// canonical iterator function.
|
||||
if (arrayProto_->getSlot(arrayProtoIteratorSlot_) != canonicalIteratorFunc_)
|
||||
return false;
|
||||
|
||||
// Chain to isArrayNextStillSane.
|
||||
return isArrayNextStillSane();
|
||||
}
|
||||
|
||||
void
|
||||
js::ForOfPIC::Chain::reset(JSContext *cx)
|
||||
{
|
||||
// Should never reset a disabled_ stub.
|
||||
JS_ASSERT(!disabled_);
|
||||
|
||||
// Erase the chain.
|
||||
eraseChain();
|
||||
|
||||
arrayProto_ = nullptr;
|
||||
arrayIteratorProto_ = nullptr;
|
||||
|
||||
arrayProtoShape_ = nullptr;
|
||||
arrayProtoIteratorSlot_ = -1;
|
||||
canonicalIteratorFunc_ = UndefinedValue();
|
||||
|
||||
arrayIteratorProtoShape_ = nullptr;
|
||||
arrayIteratorProtoNextSlot_ = -1;
|
||||
canonicalNextFunc_ = UndefinedValue();
|
||||
|
||||
initialized_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
js::ForOfPIC::Chain::eraseChain()
|
||||
{
|
||||
// Should never need to clear the chain of a disabled stub.
|
||||
JS_ASSERT(!disabled_);
|
||||
|
||||
// Free all stubs.
|
||||
Stub *stub = stubs_;
|
||||
while (stub) {
|
||||
Stub *next = stub->next();
|
||||
js_delete(stub);
|
||||
stub = next;
|
||||
}
|
||||
stubs_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
// Trace the pointers stored directly on the stub.
|
||||
void
|
||||
js::ForOfPIC::Chain::mark(JSTracer *trc)
|
||||
{
|
||||
if (!initialized_ || disabled_)
|
||||
return;
|
||||
|
||||
gc::MarkObject(trc, &arrayProto_, "ForOfPIC Array.prototype.");
|
||||
gc::MarkObject(trc, &arrayIteratorProto_, "ForOfPIC ArrayIterator.prototype.");
|
||||
|
||||
gc::MarkShape(trc, &arrayProtoShape_, "ForOfPIC Array.prototype shape.");
|
||||
gc::MarkShape(trc, &arrayIteratorProtoShape_, "ForOfPIC ArrayIterator.prototype shape.");
|
||||
|
||||
gc::MarkValue(trc, &canonicalIteratorFunc_, "ForOfPIC ArrayValues builtin.");
|
||||
gc::MarkValue(trc, &canonicalNextFunc_, "ForOfPIC ArrayIterator.prototype.next builtin.");
|
||||
|
||||
// Free all the stubs in the chain.
|
||||
while (stubs_)
|
||||
removeStub(stubs_, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
js::ForOfPIC::Chain::sweep(FreeOp *fop)
|
||||
{
|
||||
// Free all the stubs in the chain.
|
||||
while (stubs_) {
|
||||
Stub *next = stubs_->next();
|
||||
fop->delete_(stubs_);
|
||||
stubs_ = next;
|
||||
}
|
||||
fop->delete_(this);
|
||||
}
|
||||
|
||||
static void
|
||||
ForOfPIC_finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
if (ForOfPIC::Chain *chain = ForOfPIC::fromJSObject(obj))
|
||||
chain->sweep(fop);
|
||||
}
|
||||
|
||||
static void
|
||||
ForOfPIC_traceObject(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
if (ForOfPIC::Chain *chain = ForOfPIC::fromJSObject(obj))
|
||||
chain->mark(trc);
|
||||
}
|
||||
|
||||
const Class ForOfPIC::jsclass = {
|
||||
"ForOfPIC", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
|
||||
JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ForOfPIC_finalize,
|
||||
nullptr, /* call */
|
||||
nullptr, /* hasInstance */
|
||||
nullptr, /* construct */
|
||||
ForOfPIC_traceObject
|
||||
};
|
||||
|
||||
/* static */ JSObject *
|
||||
js::ForOfPIC::createForOfPICObject(JSContext *cx, Handle<GlobalObject*> global)
|
||||
{
|
||||
assertSameCompartment(cx, global);
|
||||
JSObject *obj = NewObjectWithGivenProto(cx, &ForOfPIC::jsclass, nullptr, global);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
ForOfPIC::Chain *chain = cx->new_<ForOfPIC::Chain>();
|
||||
if (!chain)
|
||||
return nullptr;
|
||||
obj->setPrivate(chain);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* static */ js::ForOfPIC::Chain *
|
||||
js::ForOfPIC::create(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(!cx->global()->getForOfPICObject());
|
||||
Rooted<GlobalObject *> global(cx, cx->global());
|
||||
JSObject *obj = GlobalObject::getOrCreateForOfPICObject(cx, global);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
return fromJSObject(obj);
|
||||
}
|
276
js/src/vm/PIC.h
276
js/src/vm/PIC.h
@ -1,276 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef vm_PIC_h
|
||||
#define vm_PIC_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "gc/Barrier.h"
|
||||
#include "gc/Heap.h"
|
||||
#include "gc/Marking.h"
|
||||
|
||||
#include "js/Value.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class Shape;
|
||||
|
||||
template <typename Category> class PICChain;
|
||||
|
||||
/*
|
||||
* The basic PICStub just has a pointer to the next stub.
|
||||
*/
|
||||
template <typename Category>
|
||||
class PICStub
|
||||
{
|
||||
friend class PICChain<Category>;
|
||||
private:
|
||||
typedef typename Category::Stub CatStub;
|
||||
typedef typename Category::Chain CatChain;
|
||||
|
||||
protected:
|
||||
CatStub *next_;
|
||||
|
||||
PICStub() : next_(nullptr) {}
|
||||
PICStub(const CatStub *next) : next_(next) {
|
||||
JS_ASSERT(next_);
|
||||
}
|
||||
PICStub(const CatStub &other) : next_(other.next_) {}
|
||||
|
||||
public:
|
||||
CatStub *next() const {
|
||||
return next_;
|
||||
}
|
||||
|
||||
protected:
|
||||
void append(CatStub *stub) {
|
||||
JS_ASSERT(!next_);
|
||||
JS_ASSERT(!stub->next_);
|
||||
next_ = stub;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* The basic PIC just has a pointer to the list of stubs.
|
||||
*/
|
||||
template <typename Category>
|
||||
class PICChain
|
||||
{
|
||||
private:
|
||||
typedef typename Category::Stub CatStub;
|
||||
typedef typename Category::Chain CatChain;
|
||||
|
||||
protected:
|
||||
CatStub *stubs_;
|
||||
|
||||
PICChain() : stubs_(nullptr) {}
|
||||
// PICs should never be copy constructed.
|
||||
PICChain(const PICChain<Category> &other) MOZ_DELETE;
|
||||
|
||||
public:
|
||||
CatStub *stubs() const {
|
||||
return stubs_;
|
||||
}
|
||||
|
||||
void addStub(CatStub *stub) {
|
||||
JS_ASSERT(stub);
|
||||
JS_ASSERT(!stub->next());
|
||||
if (!stubs_) {
|
||||
stubs_ = stub;
|
||||
return;
|
||||
}
|
||||
|
||||
CatStub *cur = stubs_;
|
||||
while (cur->next())
|
||||
cur = cur->next();
|
||||
cur->append(stub);
|
||||
}
|
||||
|
||||
unsigned numStubs() const {
|
||||
unsigned count = 0;
|
||||
for (CatStub *stub = stubs_; stub; stub = stub->next())
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
void removeStub(CatStub *stub, CatStub *previous) {
|
||||
if (previous) {
|
||||
JS_ASSERT(previous->next() == stub);
|
||||
previous->next_ = stub->next();
|
||||
} else {
|
||||
JS_ASSERT(stub == stubs_);
|
||||
stubs_ = stub->next();
|
||||
}
|
||||
js_delete(stub);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* ForOfPIC defines a PIC category for optimizing for-of operations.
|
||||
*/
|
||||
struct ForOfPIC
|
||||
{
|
||||
/* Forward declarations so template-substitution works. */
|
||||
class Stub;
|
||||
class Chain;
|
||||
|
||||
ForOfPIC() MOZ_DELETE;
|
||||
ForOfPIC(const ForOfPIC &other) MOZ_DELETE;
|
||||
|
||||
typedef PICStub<ForOfPIC> BaseStub;
|
||||
typedef PICChain<ForOfPIC> BaseChain;
|
||||
|
||||
/*
|
||||
* A ForOfPIC has only one kind of stub for now: one that holds the shape
|
||||
* of an array object that does not override its '@@iterator' property.
|
||||
*/
|
||||
class Stub : public BaseStub
|
||||
{
|
||||
private:
|
||||
// Shape of matching array object.
|
||||
Shape *shape_;
|
||||
|
||||
public:
|
||||
Stub(Shape *shape)
|
||||
: BaseStub(),
|
||||
shape_(shape)
|
||||
{
|
||||
JS_ASSERT(shape_);
|
||||
}
|
||||
|
||||
Shape *shape() {
|
||||
return shape_;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* A ForOfPIC chain holds the following:
|
||||
*
|
||||
* Array.prototype (arrayProto_)
|
||||
* To ensure that the incoming array has the standard proto.
|
||||
*
|
||||
* Array.prototype's shape (arrayProtoShape_)
|
||||
* To ensure that Array.prototype has not been modified.
|
||||
*
|
||||
* ArrayIterator.prototype (arrayIteratorProto_)
|
||||
* ArrayIterator.prototype's shape (arrayIteratorProtoShape_)
|
||||
* To ensure that an ArrayIterator.prototype has not been modified.
|
||||
*
|
||||
* Array.prototype's slot number for '@@iterator' (arrayProtoIteratorSlot_)
|
||||
* Array.prototype's canonical value for '@@iterator' (canonicalIteratorFunc_)
|
||||
* To quickly retreive and ensure that the iterator constructor
|
||||
* stored in the slot has not changed.
|
||||
*
|
||||
* ArrayIterator.prototype's slot number for 'next' (arrayIteratorProtoNextSlot_)
|
||||
* ArrayIterator.prototype's canonical value for 'next' (canonicalNextFunc_)
|
||||
* To quickly retreive and ensure that the 'next' method for ArrayIterator
|
||||
* objects has not changed.
|
||||
*/
|
||||
class Chain : public BaseChain
|
||||
{
|
||||
private:
|
||||
// Pointer to canonical Array.prototype and ArrayIterator.prototype
|
||||
HeapPtrObject arrayProto_;
|
||||
HeapPtrObject arrayIteratorProto_;
|
||||
|
||||
// Shape of matching Array.prototype object, and slot containing
|
||||
// the '@@iterator' for it, and the canonical value.
|
||||
HeapPtrShape arrayProtoShape_;
|
||||
uint32_t arrayProtoIteratorSlot_;
|
||||
HeapValue canonicalIteratorFunc_;
|
||||
|
||||
// Shape of matching ArrayIteratorProto, and slot containing
|
||||
// the 'next' property, and the canonical value.
|
||||
HeapPtrShape arrayIteratorProtoShape_;
|
||||
uint32_t arrayIteratorProtoNextSlot_;
|
||||
HeapValue canonicalNextFunc_;
|
||||
|
||||
// Initialization flag marking lazy initialization of above fields.
|
||||
bool initialized_;
|
||||
|
||||
// Disabled flag is set when we don't want to try optimizing anymore
|
||||
// because core objects were changed.
|
||||
bool disabled_;
|
||||
|
||||
static const unsigned MAX_STUBS = 10;
|
||||
|
||||
public:
|
||||
Chain()
|
||||
: BaseChain(),
|
||||
arrayProto_(nullptr),
|
||||
arrayIteratorProto_(nullptr),
|
||||
arrayProtoShape_(nullptr),
|
||||
arrayProtoIteratorSlot_(-1),
|
||||
canonicalIteratorFunc_(UndefinedValue()),
|
||||
arrayIteratorProtoShape_(nullptr),
|
||||
arrayIteratorProtoNextSlot_(-1),
|
||||
initialized_(false),
|
||||
disabled_(false)
|
||||
{}
|
||||
|
||||
// Initialize the canonical iterator function.
|
||||
bool initialize(JSContext *cx);
|
||||
|
||||
// Check if a given array object is optimized by this PIC.
|
||||
Stub *isArrayOptimized(ArrayObject *obj);
|
||||
|
||||
// Try to optimize this chain for an object.
|
||||
bool tryOptimizeArray(JSContext *cx, HandleObject array, bool *optimized);
|
||||
|
||||
// Check if the global array-related objects have not been messed with
|
||||
// in a way that would disable this PIC.
|
||||
bool isArrayStateStillSane();
|
||||
|
||||
// Check if ArrayIterator.next is still optimizable.
|
||||
inline bool isArrayNextStillSane() {
|
||||
return (arrayIteratorProto_->lastProperty() == arrayIteratorProtoShape_) &&
|
||||
(arrayIteratorProto_->getSlot(arrayIteratorProtoNextSlot_) == canonicalNextFunc_);
|
||||
}
|
||||
|
||||
void mark(JSTracer *trc);
|
||||
void sweep(FreeOp *fop);
|
||||
|
||||
private:
|
||||
// Get a matching optimized stub for the given object.
|
||||
Stub *getMatchingStub(JSObject *obj);
|
||||
|
||||
// Check if the given object is for-of optimizable with this PIC.
|
||||
bool isOptimizableArray(JSObject *obj);
|
||||
|
||||
// Reset the PIC and all info associated with it.
|
||||
void reset(JSContext *cx);
|
||||
|
||||
// Erase the stub chain.
|
||||
void eraseChain();
|
||||
};
|
||||
|
||||
// Class for object that holds ForOfPIC chain.
|
||||
static const Class jsclass;
|
||||
|
||||
static JSObject *createForOfPICObject(JSContext *cx, Handle<GlobalObject *> global);
|
||||
|
||||
static inline Chain *fromJSObject(JSObject *obj) {
|
||||
JS_ASSERT(js::GetObjectClass(obj) == &ForOfPIC::jsclass);
|
||||
return (ForOfPIC::Chain *) obj->getPrivate();
|
||||
}
|
||||
static inline Chain *getOrCreate(JSContext *cx) {
|
||||
JSObject *obj = cx->global()->getForOfPICObject();
|
||||
if (obj)
|
||||
return fromJSObject(obj);
|
||||
return create(cx);
|
||||
}
|
||||
static Chain *create(JSContext *cx);
|
||||
};
|
||||
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* vm_PIC_h */
|
@ -20,7 +20,6 @@
|
||||
#include "vm/Compression.h"
|
||||
#include "vm/ForkJoin.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/String.h"
|
||||
|
||||
#include "jsfuninlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
@ -1167,9 +1166,3 @@ js::SelfHostedFunction(JSContext *cx, HandlePropertyName propName)
|
||||
JS_ASSERT(func.toObject().is<JSFunction>());
|
||||
return &func.toObject().as<JSFunction>();
|
||||
}
|
||||
|
||||
bool
|
||||
js::IsSelfHostedFunctionWithName(JSFunction *fun, JSAtom *name)
|
||||
{
|
||||
return fun->isSelfHostedBuiltin() && fun->getExtendedSlot(0).toString() == name;
|
||||
}
|
||||
|
@ -9,8 +9,6 @@
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
class JSAtom;
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
@ -22,12 +20,6 @@ namespace js {
|
||||
*/
|
||||
extern const JSWrapObjectCallbacks SelfHostingWrapObjectCallbacks;
|
||||
|
||||
/*
|
||||
* Check whether the given JSFunction is a self-hosted function whose
|
||||
* self-hosted name is the given name.
|
||||
*/
|
||||
bool IsSelfHostedFunctionWithName(JSFunction *fun, JSAtom *name);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_SelfHosting_h_ */
|
||||
|
Loading…
Reference in New Issue
Block a user