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:
parent
a01e029882
commit
81557f21fc
@ -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).
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user