summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-10-27 13:40:00 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-04-12 16:57:17 +0200
commit41ad1ef234caf1c359ff85b13cd24f2de8e501e8 (patch)
treee74f5d509363c062233085d2890f6d7f040b83c0
parentb592f2d76a93c3ee70be8965a6a2c5e1ebe108b0 (diff)
[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: I1ecf0c563fe1162c8f875ec26dacc8f1d10e9b8d Reviewed-by: Simon Hausmann <simon.hausmann@nokia.com> Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/3rdparty/v8/include/v8.h14
-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.h9
-rw-r--r--src/3rdparty/v8/src/mips/code-stubs-mips.cc71
-rw-r--r--src/3rdparty/v8/src/objects-inl.h24
-rw-r--r--src/3rdparty/v8/src/objects.cc6
-rw-r--r--src/3rdparty/v8/src/objects.h31
-rw-r--r--src/3rdparty/v8/src/runtime.cc25
-rw-r--r--src/3rdparty/v8/src/runtime.h1
-rw-r--r--src/3rdparty/v8/src/x64/code-stubs-x64.cc43
14 files changed, 330 insertions, 27 deletions
diff --git a/src/3rdparty/v8/include/v8.h b/src/3rdparty/v8/include/v8.h
index 5026a01..5af2016 100644
--- a/src/3rdparty/v8/include/v8.h
+++ b/src/3rdparty/v8/include/v8.h
@@ -2629,6 +2629,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);
@@ -2869,6 +2875,10 @@ typedef void (*FailedAccessCheckCallback)(Local<Object> target,
AccessType type,
Local<Value> data);
+// --- User Object Comparison Callback ---
+typedef bool (*UserObjectComparisonCallback)(Local<Object> lhs,
+ Local<Object> rhs);
+
// --- AllowCodeGenerationFromStrings callbacks ---
/**
@@ -3328,6 +3338,10 @@ 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 8fbd64e..f5eecb2 100644
--- a/src/3rdparty/v8/src/api.cc
+++ b/src/3rdparty/v8/src/api.cc
@@ -1560,6 +1560,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 ---
@@ -5579,6 +5590,17 @@ void V8::SetFailedAccessCheckCallbackFunction(
}
+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 4cf9d01..e7a8489 100644
--- a/src/3rdparty/v8/src/arm/code-stubs-arm.cc
+++ b/src/3rdparty/v8/src/arm/code-stubs-arm.cc
@@ -1797,6 +1797,37 @@ void ICCompareStub::GenerateGeneric(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);
@@ -7343,10 +7374,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));
@@ -7365,8 +7404,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 44aa429..4c6af40 100644
--- a/src/3rdparty/v8/src/factory.cc
+++ b/src/3rdparty/v8/src/factory.cc
@@ -1245,6 +1245,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 =
@@ -1254,6 +1255,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;
@@ -1302,6 +1305,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 a334c8b..44df82a 100644
--- a/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc
+++ b/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc
@@ -4535,6 +4535,39 @@ void ICCompareStub::GenerateGeneric(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.
{
@@ -7184,8 +7217,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);
@@ -7206,8 +7245,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 4970ec7..eba1982 100644
--- a/src/3rdparty/v8/src/isolate.cc
+++ b/src/3rdparty/v8/src/isolate.cc
@@ -99,6 +99,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;
@@ -870,6 +871,12 @@ void Isolate::SetFailedAccessCheckCallback(
}
+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 33e4d3e..53fece7 100644
--- a/src/3rdparty/v8/src/isolate.h
+++ b/src/3rdparty/v8/src/isolate.h
@@ -277,6 +277,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_;
@@ -749,6 +752,12 @@ 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 09611fb..8f2484b 100644
--- a/src/3rdparty/v8/src/mips/code-stubs-mips.cc
+++ b/src/3rdparty/v8/src/mips/code-stubs-mips.cc
@@ -1832,6 +1832,49 @@ void ICCompareStub::GenerateGeneric(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.
@@ -7242,10 +7285,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);
@@ -7262,8 +7315,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 f11582c..8e7d4cd 100644
--- a/src/3rdparty/v8/src/objects-inl.h
+++ b/src/3rdparty/v8/src/objects-inl.h
@@ -3395,15 +3395,11 @@ bool Map::is_extensible() {
void Map::set_attached_to_shared_function_info(bool value) {
- if (value) {
- set_bit_field2(bit_field2() | (1 << kAttachedToSharedFunctionInfo));
- } else {
- set_bit_field2(bit_field2() & ~(1 << kAttachedToSharedFunctionInfo));
- }
+ set_bit_field3(AttachedToSharedFunctionInfo::update(bit_field3(), value));
}
bool Map::attached_to_shared_function_info() {
- return ((1 << kAttachedToSharedFunctionInfo) & bit_field2()) != 0;
+ return AttachedToSharedFunctionInfo::decode(bit_field3());
}
@@ -3429,6 +3425,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) {
set_bit_field3(NamedInterceptorIsFallback::update(bit_field3(), value));
}
@@ -4242,6 +4252,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 6f166cb..5221f1a 100644
--- a/src/3rdparty/v8/src/objects.cc
+++ b/src/3rdparty/v8/src/objects.cc
@@ -8448,8 +8448,7 @@ 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_attached_to_shared_function_info(true);
// Undo state changes made by StartInobjectTracking (except the
// construction_count). This way if the initial map does not survive the GC
@@ -8469,8 +8468,7 @@ 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_attached_to_shared_function_info(false);
// 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 e9e8a35..07bb288 100644
--- a/src/3rdparty/v8/src/objects.h
+++ b/src/3rdparty/v8/src/objects.h
@@ -4865,15 +4865,16 @@ class Map: public HeapObject {
inline int bit_field3();
inline void set_bit_field3(int value);
- class EnumLengthBits: public BitField<int, 0, 11> {};
- class NumberOfOwnDescriptorsBits: public BitField<int, 11, 11> {};
- class IsShared: public BitField<bool, 22, 1> {};
- class FunctionWithPrototype: public BitField<bool, 23, 1> {};
- class DictionaryMap: public BitField<bool, 24, 1> {};
- class OwnsDescriptors: public BitField<bool, 25, 1> {};
- class IsObserved: public BitField<bool, 26, 1> {};
- class NamedInterceptorIsFallback: public BitField<bool, 27, 1> {};
- class HasInstanceCallHandler: public BitField<bool, 28, 1> {};
+ class EnumLengthBits: public BitField<int, 0, 11> {};
+ class NumberOfOwnDescriptorsBits: public BitField<int, 11, 11> {};
+ class IsShared: public BitField<bool, 22, 1> {};
+ class FunctionWithPrototype: public BitField<bool, 23, 1> {};
+ class DictionaryMap: public BitField<bool, 24, 1> {};
+ class OwnsDescriptors: public BitField<bool, 25, 1> {};
+ class IsObserved: public BitField<bool, 26, 1> {};
+ class NamedInterceptorIsFallback: public BitField<bool, 27, 1> {};
+ class HasInstanceCallHandler: public BitField<bool, 28, 1> {};
+ class AttachedToSharedFunctionInfo: public BitField<bool, 29, 1> {};
// Tells whether the object in the prototype property will be used
// for instances created from this function. If the prototype
@@ -5049,6 +5050,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)
@@ -5382,7 +5388,7 @@ class Map: public HeapObject {
// Bit positions for bit field 2
static const int kIsExtensible = 0;
static const int kStringWrapperSafeForDefaultValueOf = 1;
- static const int kAttachedToSharedFunctionInfo = 2;
+ static const int kUseUserObjectComparison = 2;
// No bits can be used after kElementsKindFirstBit, they are all reserved for
// storing ElementKind.
static const int kElementsKindShift = 3;
@@ -8845,6 +8851,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);
@@ -8857,7 +8864,9 @@ class ObjectTemplateInfo: public TemplateInfo {
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 dd490ce..c465a5b 100644
--- a/src/3rdparty/v8/src/runtime.cc
+++ b/src/3rdparty/v8/src/runtime.cc
@@ -6775,6 +6775,31 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_UserObjectEquals) {
+ NoHandleAllocation ha(isolate);
+ 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(isolate);
ASSERT(args.length() == 3);
diff --git a/src/3rdparty/v8/src/runtime.h b/src/3rdparty/v8/src/runtime.h
index bbe06a3..036264e 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 a90683b..c4dd865 100644
--- a/src/3rdparty/v8/src/x64/code-stubs-x64.cc
+++ b/src/3rdparty/v8/src/x64/code-stubs-x64.cc
@@ -3658,6 +3658,37 @@ void ICCompareStub::GenerateGeneric(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;
@@ -6163,8 +6194,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);
@@ -6184,8 +6221,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);