Backed out changeset 45f374858666 (bug 852891) for bad commit message referencing wrong bug. DONTBUILD

This commit is contained in:
Kannan Vijayan 2014-02-13 14:24:37 -05:00
parent 9bd121838b
commit 3d75a41155
17 changed files with 14 additions and 1112 deletions

View File

@ -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 \

View File

@ -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);
}

View File

@ -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 */

View File

@ -13,7 +13,6 @@
#include "builtin/TypeRepresentation.h"
#include "gc/Zone.h"
#include "vm/GlobalObject.h"
#include "vm/PIC.h"
namespace js {

View File

@ -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 **********************************************************************************/

View File

@ -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',

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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") \

View File

@ -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)

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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_ */