Use a walking visitor to traverse JSObject structure. The purpose is to...

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
parent a01e0298
...@@ -5583,7 +5583,53 @@ Handle<JSObject> JSObject::Copy(Handle<JSObject> object) { ...@@ -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(); Isolate* isolate = object->GetIsolate();
StackLimitCheck check(isolate); StackLimitCheck check(isolate);
if (check.HasOverflowed()) { if (check.HasOverflowed()) {
...@@ -5592,10 +5638,11 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) { ...@@ -5592,10 +5638,11 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
} }
if (object->map()->is_deprecated()) { 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); HandleScope scope(isolate);
...@@ -5609,13 +5656,15 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) { ...@@ -5609,13 +5656,15 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
int index = descriptors->GetFieldIndex(i); int index = descriptors->GetFieldIndex(i);
Handle<Object> value(object->RawFastPropertyAt(index), isolate); Handle<Object> value(object->RawFastPropertyAt(index), isolate);
if (value->IsJSObject()) { 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>()); RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<JSObject>());
} else { } else {
Representation representation = details.representation(); Representation representation = details.representation();
value = NewStorageFor(isolate, value, representation); value = NewStorageFor(isolate, value, representation);
} }
copy->FastPropertyAtPut(index, *value); if (copying) {
copy->FastPropertyAtPut(index, *value);
}
} }
} else { } else {
Handle<FixedArray> names = Handle<FixedArray> names =
...@@ -5634,11 +5683,14 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) { ...@@ -5634,11 +5683,14 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
copy->GetProperty(*key_string, &attributes)->ToObjectUnchecked(), copy->GetProperty(*key_string, &attributes)->ToObjectUnchecked(),
isolate); isolate);
if (value->IsJSObject()) { 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>()); RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
// Creating object copy for literals. No strict mode needed. if (copying) {
CHECK_NOT_EMPTY_HANDLE(isolate, SetProperty( // Creating object copy for literals. No strict mode needed.
copy, key_string, result, NONE, kNonStrictMode)); CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetProperty(
copy, key_string, result, NONE, kNonStrictMode));
}
} }
} }
} }
...@@ -5666,9 +5718,12 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) { ...@@ -5666,9 +5718,12 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
value->IsTheHole() || value->IsTheHole() ||
(IsFastObjectElementsKind(copy->GetElementsKind()))); (IsFastObjectElementsKind(copy->GetElementsKind())));
if (value->IsJSObject()) { 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>()); 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) { ...@@ -5683,9 +5738,12 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
if (element_dictionary->IsKey(k)) { if (element_dictionary->IsKey(k)) {
Handle<Object> value(element_dictionary->ValueAt(i), isolate); Handle<Object> value(element_dictionary->ValueAt(i), isolate);
if (value->IsJSObject()) { 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>()); 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) { ...@@ -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: // Tests for the fast common case for property enumeration:
// - This object and all prototypes has an enum cache (which means that // - This object and all prototypes has an enum cache (which means that
// it is no proxy, has no interceptors and needs no access checks). // it is no proxy, has no interceptors and needs no access checks).
......
...@@ -92,16 +92,25 @@ for (var i = 0; i < sizes.length; i++) { ...@@ -92,16 +92,25 @@ for (var i = 0; i < sizes.length; i++) {
testLiteral(sizes[i], true); testLiteral(sizes[i], true);
} }
function checkExpectedException(e) {
assertInstanceof(e, RangeError);
assertTrue(e.message.indexOf("Maximum call stack size exceeded") >= 0);
}
function testLiteralAndCatch(size) { function testLiteralAndCatch(size) {
var big_enough = false; var big_enough = false;
try { try {
testLiteral(size, false); testLiteral(size, false);
} catch (e) { } catch (e) {
checkExpectedException(e);
big_enough = true; big_enough = true;
} }
try { try {
testLiteral(size, true); testLiteral(size, true);
} catch (e) { } catch (e) {
checkExpectedException(e);
big_enough = true; big_enough = true;
} }
return big_enough; return big_enough;
......
...@@ -92,16 +92,25 @@ for (var i = 0; i < sizes.length; i++) { ...@@ -92,16 +92,25 @@ for (var i = 0; i < sizes.length; i++) {
testLiteral(sizes[i], true); testLiteral(sizes[i], true);
} }
function checkExpectedException(e) {
assertInstanceof(e, RangeError);
assertTrue(e.message.indexOf("Maximum call stack size exceeded") >= 0);
}
function testLiteralAndCatch(size) { function testLiteralAndCatch(size) {
var big_enough = false; var big_enough = false;
try { try {
testLiteral(size, false); testLiteral(size, false);
} catch (e) { } catch (e) {
checkExpectedException(e);
big_enough = true; big_enough = true;
} }
try { try {
testLiteral(size, true); testLiteral(size, true);
} catch (e) { } catch (e) {
checkExpectedException(e);
big_enough = true; big_enough = true;
} }
return big_enough; return big_enough;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment