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();
|
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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++) {
|
|||||||
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++) {
|
|||||||
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;
|
||||||
|
Loading…
Reference in New Issue
Block a user