Use a walking visitor to traverse JSObject structure. The purpose is to prepare for more complex context-dependent walks of the structure, needed for allocation site and pretenuring work. Different visitors can be created that annotate the object in various ways.

BUG=
R=yangguo@chromium.org

Review URL: https://codereview.chromium.org/25025002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17001 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mvstanton@chromium.org 2013-09-30 11:36:50 +00:00
parent a01e029882
commit 81557f21fc
3 changed files with 97 additions and 13 deletions

View File

@ -5583,7 +5583,53 @@ Handle<JSObject> JSObject::Copy(Handle<JSObject> object) {
}
Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
class JSObjectWalkVisitor {
public:
explicit JSObjectWalkVisitor() {}
virtual ~JSObjectWalkVisitor() {}
Handle<JSObject> Visit(Handle<JSObject> object) {
return StructureWalk(object);
}
// Returns true if the visitor is a copying visitor.
virtual bool is_copying() = 0;
protected:
Handle<JSObject> StructureWalk(Handle<JSObject> object);
// The returned handle should point to a new object if the visitor is a
// copying visitor, otherwise it should be the same as the input object.
virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0;
// The returned handle should point to a new value if the visitor is a
// copying visitor, otherwise it should be the same as the input value.
virtual Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object,
Handle<JSObject> value) = 0;
};
class JSObjectCopyVisitor: public JSObjectWalkVisitor {
public:
explicit JSObjectCopyVisitor() {}
virtual bool is_copying() V8_OVERRIDE { return true; }
protected:
virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
return JSObject::Copy(object);
}
virtual Handle<JSObject> VisitElementOrProperty(
Handle<JSObject> object,
Handle<JSObject> value) V8_OVERRIDE {
return StructureWalk(value);
}
};
Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) {
bool copying = is_copying();
Isolate* isolate = object->GetIsolate();
StackLimitCheck check(isolate);
if (check.HasOverflowed()) {
@ -5592,10 +5638,11 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
}
if (object->map()->is_deprecated()) {
MigrateInstance(object);
JSObject::MigrateInstance(object);
}
Handle<JSObject> copy = Copy(object);
Handle<JSObject> copy = VisitObject(object);
ASSERT(copying || copy.is_identical_to(object));
HandleScope scope(isolate);
@ -5609,13 +5656,15 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
int index = descriptors->GetFieldIndex(i);
Handle<Object> value(object->RawFastPropertyAt(index), isolate);
if (value->IsJSObject()) {
value = DeepCopy(Handle<JSObject>::cast(value));
value = VisitElementOrProperty(copy, Handle<JSObject>::cast(value));
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<JSObject>());
} else {
Representation representation = details.representation();
value = NewStorageFor(isolate, value, representation);
}
copy->FastPropertyAtPut(index, *value);
if (copying) {
copy->FastPropertyAtPut(index, *value);
}
}
} else {
Handle<FixedArray> names =
@ -5634,11 +5683,14 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
copy->GetProperty(*key_string, &attributes)->ToObjectUnchecked(),
isolate);
if (value->IsJSObject()) {
Handle<Object> result = DeepCopy(Handle<JSObject>::cast(value));
Handle<JSObject> result = VisitElementOrProperty(
copy, Handle<JSObject>::cast(value));
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
// Creating object copy for literals. No strict mode needed.
CHECK_NOT_EMPTY_HANDLE(isolate, SetProperty(
copy, key_string, result, NONE, kNonStrictMode));
if (copying) {
// Creating object copy for literals. No strict mode needed.
CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetProperty(
copy, key_string, result, NONE, kNonStrictMode));
}
}
}
}
@ -5666,9 +5718,12 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
value->IsTheHole() ||
(IsFastObjectElementsKind(copy->GetElementsKind())));
if (value->IsJSObject()) {
Handle<Object> result = DeepCopy(Handle<JSObject>::cast(value));
Handle<JSObject> result = VisitElementOrProperty(
copy, Handle<JSObject>::cast(value));
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
elements->set(i, *result);
if (copying) {
elements->set(i, *result);
}
}
}
}
@ -5683,9 +5738,12 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
if (element_dictionary->IsKey(k)) {
Handle<Object> value(element_dictionary->ValueAt(i), isolate);
if (value->IsJSObject()) {
Handle<Object> result = DeepCopy(Handle<JSObject>::cast(value));
Handle<JSObject> result = VisitElementOrProperty(
copy, Handle<JSObject>::cast(value));
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
element_dictionary->ValueAtPut(i, *result);
if (copying) {
element_dictionary->ValueAtPut(i, *result);
}
}
}
}
@ -5712,6 +5770,14 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
}
Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
JSObjectCopyVisitor v;
Handle<JSObject> copy = v.Visit(object);
ASSERT(v.is_copying() && !copy.is_identical_to(object));
return copy;
}
// Tests for the fast common case for property enumeration:
// - This object and all prototypes has an enum cache (which means that
// it is no proxy, has no interceptors and needs no access checks).

View File

@ -92,16 +92,25 @@ for (var i = 0; i < sizes.length; i++) {
testLiteral(sizes[i], true);
}
function checkExpectedException(e) {
assertInstanceof(e, RangeError);
assertTrue(e.message.indexOf("Maximum call stack size exceeded") >= 0);
}
function testLiteralAndCatch(size) {
var big_enough = false;
try {
testLiteral(size, false);
} catch (e) {
checkExpectedException(e);
big_enough = true;
}
try {
testLiteral(size, true);
} catch (e) {
checkExpectedException(e);
big_enough = true;
}
return big_enough;

View File

@ -92,16 +92,25 @@ for (var i = 0; i < sizes.length; i++) {
testLiteral(sizes[i], true);
}
function checkExpectedException(e) {
assertInstanceof(e, RangeError);
assertTrue(e.message.indexOf("Maximum call stack size exceeded") >= 0);
}
function testLiteralAndCatch(size) {
var big_enough = false;
try {
testLiteral(size, false);
} catch (e) {
checkExpectedException(e);
big_enough = true;
}
try {
testLiteral(size, true);
} catch (e) {
checkExpectedException(e);
big_enough = true;
}
return big_enough;