summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-10-27 13:40:00 +0100
committerQt by Nokia <qt-info@nokia.com>2012-06-13 09:56:57 +0200
commit6c28d75933a9a56a311573593711a7e73eeab8c3 (patch)
tree7ca910683e52518d150fa5f9621048c354456f81
parentad36f9389077067fc8c990ba3655d7ac4fb6c286 (diff)
downloadqtjsbackend-6c28d75933a9a56a311573593711a7e73eeab8c3.tar.gz
[V8] Add custom object compare callback
A global custom object comparison callback can be set with: V8::SetUserObjectComparisonCallbackFunction() When two JSObjects are compared (== or !=), if either one has the MarkAsUseUserObjectComparison() bit set, the custom comparison callback is invoked to do the actual comparison. This is useful when you have "value" objects that you want to compare as equal, even though they are actually different JS object instances. Change-Id: Id1794ffc17131566c7ee30ab5fcf11445dab2ab2 Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
-rw-r--r--src/3rdparty/v8/include/v8.h13
-rw-r--r--src/3rdparty/v8/src/api.cc22
-rw-r--r--src/3rdparty/v8/src/arm/code-stubs-arm.cc51
-rw-r--r--src/3rdparty/v8/src/factory.cc8
-rw-r--r--src/3rdparty/v8/src/ia32/code-stubs-ia32.cc45
-rw-r--r--src/3rdparty/v8/src/isolate.cc7
-rw-r--r--src/3rdparty/v8/src/isolate.h8
-rw-r--r--src/3rdparty/v8/src/mips/code-stubs-mips.cc68
-rw-r--r--src/3rdparty/v8/src/objects-inl.h22
-rw-r--r--src/3rdparty/v8/src/objects.cc8
-rw-r--r--src/3rdparty/v8/src/objects.h12
-rw-r--r--src/3rdparty/v8/src/runtime.cc23
-rw-r--r--src/3rdparty/v8/src/runtime.h1
-rw-r--r--src/3rdparty/v8/src/x64/code-stubs-x64.cc43
14 files changed, 316 insertions, 15 deletions
diff --git a/src/3rdparty/v8/include/v8.h b/src/3rdparty/v8/include/v8.h
index 98d4e2c..d79b1c3 100644
--- a/src/3rdparty/v8/include/v8.h
+++ b/src/3rdparty/v8/include/v8.h
@@ -2538,6 +2538,12 @@ class V8EXPORT ObjectTemplate : public Template {
bool HasExternalResource();
void SetHasExternalResource(bool value);
+ /**
+ * Mark object instances of the template as using the user object
+ * comparison callback.
+ */
+ void MarkAsUseUserObjectComparison();
+
private:
ObjectTemplate();
static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor);
@@ -2765,6 +2771,10 @@ typedef void (*FailedAccessCheckCallback)(Local<Object> target,
AccessType type,
Local<Value> data);
+// --- User Object Comparisoa nCallback ---
+typedef bool (*UserObjectComparisonCallback)(Local<Object> lhs,
+ Local<Object> rhs);
+
// --- AllowCodeGenerationFromStrings callbacks ---
/**
@@ -3116,6 +3126,9 @@ class V8EXPORT V8 {
/** Callback function for reporting failed access checks.*/
static void SetFailedAccessCheckCallbackFunction(FailedAccessCheckCallback);
+ /** Callback for user object comparisons */
+ static void SetUserObjectComparisonCallbackFunction(UserObjectComparisonCallback);
+
/**
* Enables the host application to receive a notification before a
* garbage collection. Allocations are not allowed in the
diff --git a/src/3rdparty/v8/src/api.cc b/src/3rdparty/v8/src/api.cc
index a33dd3c..d681328 100644
--- a/src/3rdparty/v8/src/api.cc
+++ b/src/3rdparty/v8/src/api.cc
@@ -1493,6 +1493,17 @@ void ObjectTemplate::SetHasExternalResource(bool value)
}
+void ObjectTemplate::MarkAsUseUserObjectComparison()
+{
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::MarkAsUseUserObjectComparison()")) {
+ return;
+ }
+ ENTER_V8(isolate);
+ EnsureConstructor(this);
+ Utils::OpenHandle(this)->set_use_user_object_comparison(i::Smi::FromInt(1));
+}
+
// --- S c r i p t D a t a ---
@@ -5374,6 +5385,17 @@ void V8::SetFailedAccessCheckCallbackFunction(
isolate->SetFailedAccessCheckCallback(callback);
}
+
+void V8::SetUserObjectComparisonCallbackFunction(
+ UserObjectComparisonCallback callback) {
+ i::Isolate* isolate = i::Isolate::Current();
+ if (IsDeadCheck(isolate, "v8::V8::SetUserObjectComparisonCallbackFunction()")) {
+ return;
+ }
+ isolate->SetUserObjectComparisonCallback(callback);
+}
+
+
void V8::AddObjectGroup(Persistent<Value>* objects,
size_t length,
RetainedObjectInfo* info) {
diff --git a/src/3rdparty/v8/src/arm/code-stubs-arm.cc b/src/3rdparty/v8/src/arm/code-stubs-arm.cc
index d06faaa..bea3169 100644
--- a/src/3rdparty/v8/src/arm/code-stubs-arm.cc
+++ b/src/3rdparty/v8/src/arm/code-stubs-arm.cc
@@ -1642,6 +1642,37 @@ void CompareStub::Generate(MacroAssembler* masm) {
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
+ {
+ Label not_user_equal, user_equal;
+ __ and_(r2, r1, Operand(r0));
+ __ tst(r2, Operand(kSmiTagMask));
+ __ b(eq, &not_user_equal);
+
+ __ CompareObjectType(r0, r2, r4, JS_OBJECT_TYPE);
+ __ b(ne, &not_user_equal);
+
+ __ CompareObjectType(r1, r3, r4, JS_OBJECT_TYPE);
+ __ b(ne, &not_user_equal);
+
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(eq, &user_equal);
+
+ __ ldrb(r3, FieldMemOperand(r3, Map::kBitField2Offset));
+ __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(ne, &not_user_equal);
+
+ __ bind(&user_equal);
+
+ __ Push(r0, r1);
+ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
+
+ __ bind(&not_user_equal);
+ }
+
+
// Handle the case where the objects are identical. Either returns the answer
// or goes to slow. Only falls through if the objects were not identical.
EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_);
@@ -6738,10 +6769,18 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ and_(r2, r1, Operand(r0));
__ JumpIfSmi(r2, &miss);
- __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE);
+ __ CompareObjectType(r0, r2, r3, JS_OBJECT_TYPE);
__ b(ne, &miss);
- __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE);
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(eq, &miss);
+ __ CompareObjectType(r1, r2, r3, JS_OBJECT_TYPE);
__ b(ne, &miss);
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(eq, &miss);
ASSERT(GetCondition() == eq);
__ sub(r0, r0, Operand(r1));
@@ -6760,8 +6799,16 @@ void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
__ cmp(r2, Operand(known_map_));
__ b(ne, &miss);
+ __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
+ __ and_(r2, r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r2, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(eq, &miss);
__ cmp(r3, Operand(known_map_));
__ b(ne, &miss);
+ __ ldrb(r3, FieldMemOperand(r3, Map::kBitField2Offset));
+ __ and_(r3, r3, Operand(1 << Map::kUseUserObjectComparison));
+ __ cmp(r3, Operand(1 << Map::kUseUserObjectComparison));
+ __ b(eq, &miss);
__ sub(r0, r0, Operand(r1));
__ Ret();
diff --git a/src/3rdparty/v8/src/factory.cc b/src/3rdparty/v8/src/factory.cc
index 1e8938a..64b26a4 100644
--- a/src/3rdparty/v8/src/factory.cc
+++ b/src/3rdparty/v8/src/factory.cc
@@ -1235,6 +1235,7 @@ Handle<JSFunction> Factory::CreateApiFunction(
int internal_field_count = 0;
bool has_external_resource = false;
+ bool use_user_object_comparison = false;
if (!obj->instance_template()->IsUndefined()) {
Handle<ObjectTemplateInfo> instance_template =
@@ -1244,6 +1245,8 @@ Handle<JSFunction> Factory::CreateApiFunction(
Smi::cast(instance_template->internal_field_count())->value();
has_external_resource =
!instance_template->has_external_resource()->IsUndefined();
+ use_user_object_comparison =
+ !instance_template->use_user_object_comparison()->IsUndefined();
}
int instance_size = kPointerSize * internal_field_count;
@@ -1288,6 +1291,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
map->set_has_external_resource(true);
}
+ // Mark as using user object comparison if needed
+ if (use_user_object_comparison) {
+ map->set_use_user_object_comparison(true);
+ }
+
// Mark as undetectable if needed.
if (obj->undetectable()) {
map->set_is_undetectable();
diff --git a/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc b/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc
index 7224b07..fe9db7b 100644
--- a/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc
@@ -4269,6 +4269,39 @@ void CompareStub::Generate(MacroAssembler* masm) {
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
+ {
+ Label not_user_equal, user_equal;
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(zero, &not_user_equal);
+ __ test(edx, Immediate(kSmiTagMask));
+ __ j(zero, &not_user_equal);
+
+ __ CmpObjectType(eax, JS_OBJECT_TYPE, ebx);
+ __ j(not_equal, &not_user_equal);
+
+ __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
+ __ j(not_equal, &not_user_equal);
+
+ __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
+ 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &user_equal);
+ __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
+ 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &user_equal);
+
+ __ jmp(&not_user_equal);
+
+ __ bind(&user_equal);
+
+ __ pop(ebx); // Return address.
+ __ push(eax);
+ __ push(edx);
+ __ push(ebx);
+ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
+
+ __ bind(&not_user_equal);
+ }
+
// Identical objects can be compared fast, but there are some tricky cases
// for NaN and undefined.
{
@@ -6760,8 +6793,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
__ j(not_equal, &miss, Label::kNear);
+ __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
+ 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &miss, Label::kNear);
__ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
__ j(not_equal, &miss, Label::kNear);
+ __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
+ 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &miss, Label::kNear);
ASSERT(GetCondition() == equal);
__ sub(eax, edx);
@@ -6782,8 +6821,14 @@ void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
__ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
__ cmp(ecx, known_map_);
__ j(not_equal, &miss, Label::kNear);
+ __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
+ 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &miss, Label::kNear);
__ cmp(ebx, known_map_);
__ j(not_equal, &miss, Label::kNear);
+ __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
+ 1 << Map::kUseUserObjectComparison);
+ __ j(not_zero, &miss, Label::kNear);
__ sub(eax, edx);
__ ret(0);
diff --git a/src/3rdparty/v8/src/isolate.cc b/src/3rdparty/v8/src/isolate.cc
index 0c97abd..63029ab 100644
--- a/src/3rdparty/v8/src/isolate.cc
+++ b/src/3rdparty/v8/src/isolate.cc
@@ -97,6 +97,7 @@ void ThreadLocalTop::InitializeInternal() {
thread_id_ = ThreadId::Invalid();
external_caught_exception_ = false;
failed_access_check_callback_ = NULL;
+ user_object_comparison_callback_ = NULL;
save_context_ = NULL;
catcher_ = NULL;
top_lookup_result_ = NULL;
@@ -743,6 +744,12 @@ void Isolate::SetFailedAccessCheckCallback(
thread_local_top()->failed_access_check_callback_ = callback;
}
+
+void Isolate::SetUserObjectComparisonCallback(
+ v8::UserObjectComparisonCallback callback) {
+ thread_local_top()->user_object_comparison_callback_ = callback;
+}
+
void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
if (!thread_local_top()->failed_access_check_callback_) return;
diff --git a/src/3rdparty/v8/src/isolate.h b/src/3rdparty/v8/src/isolate.h
index f1c9b3c..a865d99 100644
--- a/src/3rdparty/v8/src/isolate.h
+++ b/src/3rdparty/v8/src/isolate.h
@@ -273,6 +273,9 @@ class ThreadLocalTop BASE_EMBEDDED {
// Head of the list of live LookupResults.
LookupResult* top_lookup_result_;
+ // Call back function for user object comparisons
+ v8::UserObjectComparisonCallback user_object_comparison_callback_;
+
// Whether out of memory exceptions should be ignored.
bool ignore_out_of_memory_;
@@ -702,6 +705,11 @@ class Isolate {
void SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback);
void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type);
+ void SetUserObjectComparisonCallback(v8::UserObjectComparisonCallback callback);
+ inline v8::UserObjectComparisonCallback UserObjectComparisonCallback() {
+ return thread_local_top()->user_object_comparison_callback_;
+ }
+
// Exception throwing support. The caller should use the result
// of Throw() as its return value.
Failure* Throw(Object* exception, MessageLocation* location = NULL);
diff --git a/src/3rdparty/v8/src/mips/code-stubs-mips.cc b/src/3rdparty/v8/src/mips/code-stubs-mips.cc
index abe9df6..a5b4edd 100644
--- a/src/3rdparty/v8/src/mips/code-stubs-mips.cc
+++ b/src/3rdparty/v8/src/mips/code-stubs-mips.cc
@@ -1716,6 +1716,46 @@ void CompareStub::Generate(MacroAssembler* masm) {
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
+ {
+ // This is optimized for reading the code and not benchmarked for
+ // speed or amount of instructions. The code is not ordered for speed
+ // or anything like this
+ Label miss, user_compare;
+
+ // No global compare if both operands are SMIs
+ __ And(a2, a1, Operand(a0));
+ __ JumpIfSmi(a2, &miss);
+
+
+ // We need to check if lhs and rhs are both objects, if not we are
+ // jumping out of the function. We will keep the 'map' in t0 (lhs) and
+ // t1 (rhs) for later usage.
+ __ GetObjectType(a0, t0, a3);
+ __ Branch(&miss, ne, a3, Operand(JS_OBJECT_TYPE));
+
+ __ GetObjectType(a1, t1, a3);
+ __ Branch(&miss, ne, a3, Operand(JS_OBJECT_TYPE));
+
+ // Check if the UseUserComparison flag is set by using the map of t0 for lhs
+ __ lbu(t0, FieldMemOperand(t0, Map::kBitField2Offset));
+ __ And(t0, t0, Operand(1 << Map::kUseUserObjectComparison));
+ __ Branch(&user_compare, eq, t0, Operand(1 << Map::kUseUserObjectComparison));
+
+
+ // Check if the UseUserComparison flag is _not_ set by using the map of t1 for
+ // rhs and then jump to the miss label.
+ __ lbu(t1, FieldMemOperand(t1, Map::kBitField2Offset));
+ __ And(t1, t1, Operand(1 << Map::kUseUserObjectComparison));
+ __ Branch(&miss, ne, t1, Operand(1 << Map::kUseUserObjectComparison));
+
+ // Invoke the runtime function here
+ __ bind(&user_compare);
+ __ Push(a0, a1);
+ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
+
+ // We exit here without doing anything
+ __ bind(&miss);
+ }
// Handle the case where the objects are identical. Either returns the answer
// or goes to slow. Only falls through if the objects were not identical.
@@ -6977,10 +7017,20 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ And(a2, a1, Operand(a0));
__ JumpIfSmi(a2, &miss);
- __ GetObjectType(a0, a2, a2);
- __ Branch(&miss, ne, a2, Operand(JS_OBJECT_TYPE));
- __ GetObjectType(a1, a2, a2);
- __ Branch(&miss, ne, a2, Operand(JS_OBJECT_TYPE));
+ // Compare lhs, a2 holds the map, a3 holds the type_reg
+ __ GetObjectType(a0, a2, a3);
+ __ Branch(&miss, ne, a3, Operand(JS_OBJECT_TYPE));
+ __ lbu(a2, FieldMemOperand(a2, Map::kBitField2Offset));
+ __ And(a2, a2, Operand(1 << Map::kUseUserObjectComparison));
+ __ Branch(&miss, eq, a2, Operand(1 << Map::kUseUserObjectComparison));
+
+
+ // Compare rhs, a2 holds the map, a3 holds the type_reg
+ __ GetObjectType(a1, a2, a3);
+ __ Branch(&miss, ne, a3, Operand(JS_OBJECT_TYPE));
+ __ lbu(a2, FieldMemOperand(a2, Map::kBitField2Offset));
+ __ And(a2, a2, Operand(1 << Map::kUseUserObjectComparison));
+ __ Branch(&miss, eq, a2, Operand(1 << Map::kUseUserObjectComparison));
ASSERT(GetCondition() == eq);
__ Ret(USE_DELAY_SLOT);
@@ -6997,8 +7047,18 @@ void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
__ JumpIfSmi(a2, &miss);
__ lw(a2, FieldMemOperand(a0, HeapObject::kMapOffset));
__ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
+
+ // Check object in a0
__ Branch(&miss, ne, a2, Operand(known_map_));
+ __ lbu(a2, FieldMemOperand(a2, Map::kBitField2Offset));
+ __ And(a2, a2, Operand(1 << Map::kUseUserObjectComparison));
+ __ Branch(&miss, eq, a2, Operand(1 << Map::kUseUserObjectComparison));
+
+ // Check object in a1
__ Branch(&miss, ne, a3, Operand(known_map_));
+ __ lbu(a3, FieldMemOperand(a3, Map::kBitField2Offset));
+ __ And(a3, a3, Operand(1 << Map::kUseUserObjectComparison));
+ __ Branch(&miss, eq, a3, Operand(1 << Map::kUseUserObjectComparison));
__ Ret(USE_DELAY_SLOT);
__ subu(v0, a0, a1);
diff --git a/src/3rdparty/v8/src/objects-inl.h b/src/3rdparty/v8/src/objects-inl.h
index 194e7ad..74e63f2 100644
--- a/src/3rdparty/v8/src/objects-inl.h
+++ b/src/3rdparty/v8/src/objects-inl.h
@@ -2916,14 +2916,14 @@ bool Map::is_extensible() {
void Map::set_attached_to_shared_function_info(bool value) {
if (value) {
- set_bit_field2(bit_field2() | (1 << kAttachedToSharedFunctionInfo));
+ set_bit_field3(bit_field3() | (1 << kAttachedToSharedFunctionInfo));
} else {
- set_bit_field2(bit_field2() & ~(1 << kAttachedToSharedFunctionInfo));
+ set_bit_field3(bit_field3() & ~(1 << kAttachedToSharedFunctionInfo));
}
}
bool Map::attached_to_shared_function_info() {
- return ((1 << kAttachedToSharedFunctionInfo) & bit_field2()) != 0;
+ return ((1 << kAttachedToSharedFunctionInfo) & bit_field3()) != 0;
}
@@ -2953,6 +2953,20 @@ bool Map::has_external_resource()
}
+void Map::set_use_user_object_comparison(bool value) {
+ if (value) {
+ set_bit_field2(bit_field2() | (1 << kUseUserObjectComparison));
+ } else {
+ set_bit_field2(bit_field2() & ~(1 << kUseUserObjectComparison));
+ }
+}
+
+
+bool Map::use_user_object_comparison() {
+ return ((1 << kUseUserObjectComparison) & bit_field2()) != 0;
+}
+
+
void Map::set_named_interceptor_is_fallback(bool value) {
if (value) {
set_bit_field3(bit_field3() | (1 << kNamedInterceptorIsFallback));
@@ -3592,6 +3606,8 @@ ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
kInternalFieldCountOffset)
ACCESSORS(ObjectTemplateInfo, has_external_resource, Object,
kHasExternalResourceOffset)
+ACCESSORS(ObjectTemplateInfo, use_user_object_comparison, Object,
+ kUseUserObjectComparisonOffset)
ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset)
ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
diff --git a/src/3rdparty/v8/src/objects.cc b/src/3rdparty/v8/src/objects.cc
index 802cb7e..6a7614c 100644
--- a/src/3rdparty/v8/src/objects.cc
+++ b/src/3rdparty/v8/src/objects.cc
@@ -7844,8 +7844,8 @@ void SharedFunctionInfo::DetachInitialMap() {
Map* map = reinterpret_cast<Map*>(initial_map());
// Make the map remember to restore the link if it survives the GC.
- map->set_bit_field2(
- map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
+ map->set_bit_field3(
+ map->bit_field3() | (1 << Map::kAttachedToSharedFunctionInfo));
// Undo state changes made by StartInobjectTracking (except the
// construction_count). This way if the initial map does not survive the GC
@@ -7865,8 +7865,8 @@ void SharedFunctionInfo::DetachInitialMap() {
// Called from GC, hence reinterpret_cast and unchecked accessors.
void SharedFunctionInfo::AttachInitialMap(Map* map) {
- map->set_bit_field2(
- map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
+ map->set_bit_field3(
+ map->bit_field3() & ~(1 << Map::kAttachedToSharedFunctionInfo));
// Resume inobject slack tracking.
set_initial_map(map);
diff --git a/src/3rdparty/v8/src/objects.h b/src/3rdparty/v8/src/objects.h
index 120b24a..3772706 100644
--- a/src/3rdparty/v8/src/objects.h
+++ b/src/3rdparty/v8/src/objects.h
@@ -4713,6 +4713,11 @@ class Map: public HeapObject {
inline void set_has_external_resource(bool value);
inline bool has_external_resource();
+ // Tells whether the user object comparison callback should be used for
+ // comparisons involving this object
+ inline void set_use_user_object_comparison(bool value);
+ inline bool use_user_object_comparison();
+
// [prototype]: implicit prototype object.
DECL_ACCESSORS(prototype, Object)
@@ -4968,7 +4973,7 @@ class Map: public HeapObject {
static const int kIsExtensible = 0;
static const int kFunctionWithPrototype = 1;
static const int kStringWrapperSafeForDefaultValueOf = 2;
- static const int kAttachedToSharedFunctionInfo = 3;
+ static const int kUseUserObjectComparison = 3;
// No bits can be used after kElementsKindFirstBit, they are all reserved for
// storing ElementKind.
static const int kElementsKindShift = 4;
@@ -4987,6 +4992,7 @@ class Map: public HeapObject {
static const int kIsShared = 0;
static const int kNamedInterceptorIsFallback = 1;
static const int kHasInstanceCallHandler = 2;
+ static const int kAttachedToSharedFunctionInfo = 3;
// Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2;
@@ -8374,6 +8380,7 @@ class ObjectTemplateInfo: public TemplateInfo {
DECL_ACCESSORS(constructor, Object)
DECL_ACCESSORS(internal_field_count, Object)
DECL_ACCESSORS(has_external_resource, Object)
+ DECL_ACCESSORS(use_user_object_comparison, Object)
static inline ObjectTemplateInfo* cast(Object* obj);
@@ -8391,7 +8398,8 @@ class ObjectTemplateInfo: public TemplateInfo {
static const int kInternalFieldCountOffset =
kConstructorOffset + kPointerSize;
static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize;
- static const int kSize = kHasExternalResourceOffset + kPointerSize;
+ static const int kUseUserObjectComparisonOffset = kHasExternalResourceOffset + kPointerSize;
+ static const int kSize = kUseUserObjectComparisonOffset + kPointerSize;
};
diff --git a/src/3rdparty/v8/src/runtime.cc b/src/3rdparty/v8/src/runtime.cc
index 63acc4c..f9acdb7 100644
--- a/src/3rdparty/v8/src/runtime.cc
+++ b/src/3rdparty/v8/src/runtime.cc
@@ -7190,6 +7190,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_UserObjectEquals) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 2);
+
+ CONVERT_ARG_CHECKED(JSObject, lhs, 1);
+ CONVERT_ARG_CHECKED(JSObject, rhs, 0);
+
+ bool result;
+
+ v8::UserObjectComparisonCallback callback = isolate->UserObjectComparisonCallback();
+ if (callback) {
+ HandleScope scope(isolate);
+ Handle<JSObject> lhs_handle(lhs);
+ Handle<JSObject> rhs_handle(rhs);
+ result = callback(v8::Utils::ToLocal(lhs_handle), v8::Utils::ToLocal(rhs_handle));
+ } else {
+ result = (lhs == rhs);
+ }
+
+ return Smi::FromInt(result?0:1);
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
NoHandleAllocation ha;
ASSERT(args.length() == 3);
diff --git a/src/3rdparty/v8/src/runtime.h b/src/3rdparty/v8/src/runtime.h
index fed04cf..429102b 100644
--- a/src/3rdparty/v8/src/runtime.h
+++ b/src/3rdparty/v8/src/runtime.h
@@ -160,6 +160,7 @@ namespace internal {
/* Comparisons */ \
F(NumberEquals, 2, 1) \
F(StringEquals, 2, 1) \
+ F(UserObjectEquals, 2, 1) \
\
F(NumberCompare, 3, 1) \
F(SmiLexicographicCompare, 2, 1) \
diff --git a/src/3rdparty/v8/src/x64/code-stubs-x64.cc b/src/3rdparty/v8/src/x64/code-stubs-x64.cc
index 9b9906b..7069829 100644
--- a/src/3rdparty/v8/src/x64/code-stubs-x64.cc
+++ b/src/3rdparty/v8/src/x64/code-stubs-x64.cc
@@ -3328,6 +3328,37 @@ void CompareStub::Generate(MacroAssembler* masm) {
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
+ {
+ Label not_user_equal, user_equal;
+ __ JumpIfSmi(rax, &not_user_equal);
+ __ JumpIfSmi(rdx, &not_user_equal);
+
+ __ CmpObjectType(rax, JS_OBJECT_TYPE, rbx);
+ __ j(not_equal, &not_user_equal);
+
+ __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
+ __ j(not_equal, &not_user_equal);
+
+ __ testb(FieldOperand(rbx, Map::kBitField2Offset),
+ Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &user_equal);
+ __ testb(FieldOperand(rcx, Map::kBitField2Offset),
+ Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &user_equal);
+
+ __ jmp(&not_user_equal);
+
+ __ bind(&user_equal);
+
+ __ pop(rbx); // Return address.
+ __ push(rax);
+ __ push(rdx);
+ __ push(rbx);
+ __ TailCallRuntime(Runtime::kUserObjectEquals, 2, 1);
+
+ __ bind(&not_user_equal);
+ }
+
// Two identical objects are equal unless they are both NaN or undefined.
{
Label not_identical;
@@ -5705,8 +5736,14 @@ void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
__ CmpObjectType(rax, JS_OBJECT_TYPE, rcx);
__ j(not_equal, &miss, Label::kNear);
+ __ testb(FieldOperand(rcx, Map::kBitField2Offset),
+ Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &miss, Label::kNear);
__ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
__ j(not_equal, &miss, Label::kNear);
+ __ testb(FieldOperand(rcx, Map::kBitField2Offset),
+ Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &miss, Label::kNear);
ASSERT(GetCondition() == equal);
__ subq(rax, rdx);
@@ -5726,8 +5763,14 @@ void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
__ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
__ Cmp(rcx, known_map_);
__ j(not_equal, &miss, Label::kNear);
+ __ testb(FieldOperand(rcx, Map::kBitField2Offset),
+ Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &miss, Label::kNear);
__ Cmp(rbx, known_map_);
__ j(not_equal, &miss, Label::kNear);
+ __ testb(FieldOperand(rbx, Map::kBitField2Offset),
+ Immediate(1 << Map::kUseUserObjectComparison));
+ __ j(not_zero, &miss, Label::kNear);
__ subq(rax, rdx);
__ ret(0);