| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 isolate_->Dispose(); | 47 isolate_->Dispose(); |
| 48 } | 48 } |
| 49 | 49 |
| 50 Isolate* GetIsolate() const { return isolate_; } | 50 Isolate* GetIsolate() const { return isolate_; } |
| 51 | 51 |
| 52 private: | 52 private: |
| 53 Isolate* isolate_; | 53 Isolate* isolate_; |
| 54 }; | 54 }; |
| 55 } | 55 } |
| 56 | 56 |
| 57 |
| 57 TEST(PerIsolateState) { | 58 TEST(PerIsolateState) { |
| 58 HarmonyIsolate isolate; | 59 HarmonyIsolate isolate; |
| 59 HandleScope scope(isolate.GetIsolate()); | 60 HandleScope scope(isolate.GetIsolate()); |
| 60 LocalContext context1; | 61 LocalContext context1; |
| 61 CompileRun( | 62 CompileRun( |
| 62 "var count = 0;" | 63 "var count = 0;" |
| 63 "var calls = 0;" | 64 "var calls = 0;" |
| 64 "var observer = function(records) { count = records.length; calls++ };" | 65 "var observer = function(records) { count = records.length; calls++ };" |
| 65 "var obj = {};" | 66 "var obj = {};" |
| 66 "Object.observe(obj, observer);"); | 67 "Object.observe(obj, observer);"); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 87 context4->Global()->Set(String::New("observer"), observer); | 88 context4->Global()->Set(String::New("observer"), observer); |
| 88 context4->Global()->Set(String::New("fun1"), notify_fun1); | 89 context4->Global()->Set(String::New("fun1"), notify_fun1); |
| 89 context4->Global()->Set(String::New("fun2"), notify_fun2); | 90 context4->Global()->Set(String::New("fun2"), notify_fun2); |
| 90 context4->Global()->Set(String::New("fun3"), notify_fun3); | 91 context4->Global()->Set(String::New("fun3"), notify_fun3); |
| 91 CompileRun("fun1(); fun2(); fun3(); Object.deliverChangeRecords(observer)"); | 92 CompileRun("fun1(); fun2(); fun3(); Object.deliverChangeRecords(observer)"); |
| 92 } | 93 } |
| 93 CHECK_EQ(1, CompileRun("calls")->Int32Value()); | 94 CHECK_EQ(1, CompileRun("calls")->Int32Value()); |
| 94 CHECK_EQ(3, CompileRun("count")->Int32Value()); | 95 CHECK_EQ(3, CompileRun("count")->Int32Value()); |
| 95 } | 96 } |
| 96 | 97 |
| 98 |
| 97 TEST(EndOfMicrotaskDelivery) { | 99 TEST(EndOfMicrotaskDelivery) { |
| 98 HarmonyIsolate isolate; | 100 HarmonyIsolate isolate; |
| 99 HandleScope scope(isolate.GetIsolate()); | 101 HandleScope scope(isolate.GetIsolate()); |
| 100 LocalContext context; | 102 LocalContext context; |
| 101 CompileRun( | 103 CompileRun( |
| 102 "var obj = {};" | 104 "var obj = {};" |
| 103 "var count = 0;" | 105 "var count = 0;" |
| 104 "var observer = function(records) { count = records.length };" | 106 "var observer = function(records) { count = records.length };" |
| 105 "Object.observe(obj, observer);" | 107 "Object.observe(obj, observer);" |
| 106 "obj.foo = 'bar';"); | 108 "obj.foo = 'bar';"); |
| 107 CHECK_EQ(1, CompileRun("count")->Int32Value()); | 109 CHECK_EQ(1, CompileRun("count")->Int32Value()); |
| 108 } | 110 } |
| 109 | 111 |
| 112 |
| 110 TEST(DeliveryOrdering) { | 113 TEST(DeliveryOrdering) { |
| 111 HarmonyIsolate isolate; | 114 HarmonyIsolate isolate; |
| 112 HandleScope scope(isolate.GetIsolate()); | 115 HandleScope scope(isolate.GetIsolate()); |
| 113 LocalContext context; | 116 LocalContext context; |
| 114 CompileRun( | 117 CompileRun( |
| 115 "var obj1 = {};" | 118 "var obj1 = {};" |
| 116 "var obj2 = {};" | 119 "var obj2 = {};" |
| 117 "var ordering = [];" | 120 "var ordering = [];" |
| 118 "function observer2() { ordering.push(2); };" | 121 "function observer2() { ordering.push(2); };" |
| 119 "function observer1() { ordering.push(1); };" | 122 "function observer1() { ordering.push(1); };" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 131 "Object.observe(obj2, observer3);" | 134 "Object.observe(obj2, observer3);" |
| 132 "Object.observe(obj2, observer2);" | 135 "Object.observe(obj2, observer2);" |
| 133 "Object.observe(obj2, observer1);" | 136 "Object.observe(obj2, observer1);" |
| 134 "obj2.foo = 'baz'"); | 137 "obj2.foo = 'baz'"); |
| 135 CHECK_EQ(3, CompileRun("ordering.length")->Int32Value()); | 138 CHECK_EQ(3, CompileRun("ordering.length")->Int32Value()); |
| 136 CHECK_EQ(1, CompileRun("ordering[0]")->Int32Value()); | 139 CHECK_EQ(1, CompileRun("ordering[0]")->Int32Value()); |
| 137 CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value()); | 140 CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value()); |
| 138 CHECK_EQ(3, CompileRun("ordering[2]")->Int32Value()); | 141 CHECK_EQ(3, CompileRun("ordering[2]")->Int32Value()); |
| 139 } | 142 } |
| 140 | 143 |
| 144 |
| 141 TEST(DeliveryOrderingReentrant) { | 145 TEST(DeliveryOrderingReentrant) { |
| 142 HarmonyIsolate isolate; | 146 HarmonyIsolate isolate; |
| 143 HandleScope scope(isolate.GetIsolate()); | 147 HandleScope scope(isolate.GetIsolate()); |
| 144 LocalContext context; | 148 LocalContext context; |
| 145 CompileRun( | 149 CompileRun( |
| 146 "var obj = {};" | 150 "var obj = {};" |
| 147 "var reentered = false;" | 151 "var reentered = false;" |
| 148 "var ordering = [];" | 152 "var ordering = [];" |
| 149 "function observer1() { ordering.push(1); };" | 153 "function observer1() { ordering.push(1); };" |
| 150 "function observer2() {" | 154 "function observer2() {" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 162 CHECK_EQ(5, CompileRun("ordering.length")->Int32Value()); | 166 CHECK_EQ(5, CompileRun("ordering.length")->Int32Value()); |
| 163 CHECK_EQ(1, CompileRun("ordering[0]")->Int32Value()); | 167 CHECK_EQ(1, CompileRun("ordering[0]")->Int32Value()); |
| 164 CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value()); | 168 CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value()); |
| 165 CHECK_EQ(3, CompileRun("ordering[2]")->Int32Value()); | 169 CHECK_EQ(3, CompileRun("ordering[2]")->Int32Value()); |
| 166 // Note that we re-deliver to observers 1 and 2, while observer3 | 170 // Note that we re-deliver to observers 1 and 2, while observer3 |
| 167 // already received the second record during the first round. | 171 // already received the second record during the first round. |
| 168 CHECK_EQ(1, CompileRun("ordering[3]")->Int32Value()); | 172 CHECK_EQ(1, CompileRun("ordering[3]")->Int32Value()); |
| 169 CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value()); | 173 CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value()); |
| 170 } | 174 } |
| 171 | 175 |
| 176 |
| 172 TEST(DeliveryOrderingDeliverChangeRecords) { | 177 TEST(DeliveryOrderingDeliverChangeRecords) { |
| 173 HarmonyIsolate isolate; | 178 HarmonyIsolate isolate; |
| 174 HandleScope scope(isolate.GetIsolate()); | 179 HandleScope scope(isolate.GetIsolate()); |
| 175 LocalContext context; | 180 LocalContext context; |
| 176 CompileRun( | 181 CompileRun( |
| 177 "var obj = {};" | 182 "var obj = {};" |
| 178 "var ordering = [];" | 183 "var ordering = [];" |
| 179 "function observer1() { ordering.push(1); if (!obj.b) obj.b = true };" | 184 "function observer1() { ordering.push(1); if (!obj.b) obj.b = true };" |
| 180 "function observer2() { ordering.push(2); };" | 185 "function observer2() { ordering.push(2); };" |
| 181 "Object.observe(obj, observer1);" | 186 "Object.observe(obj, observer1);" |
| 182 "Object.observe(obj, observer2);" | 187 "Object.observe(obj, observer2);" |
| 183 "obj.a = 1;" | 188 "obj.a = 1;" |
| 184 "Object.deliverChangeRecords(observer2);"); | 189 "Object.deliverChangeRecords(observer2);"); |
| 185 CHECK_EQ(4, CompileRun("ordering.length")->Int32Value()); | 190 CHECK_EQ(4, CompileRun("ordering.length")->Int32Value()); |
| 186 // First, observer2 is called due to deliverChangeRecords | 191 // First, observer2 is called due to deliverChangeRecords |
| 187 CHECK_EQ(2, CompileRun("ordering[0]")->Int32Value()); | 192 CHECK_EQ(2, CompileRun("ordering[0]")->Int32Value()); |
| 188 // Then, observer1 is called when the stack unwinds | 193 // Then, observer1 is called when the stack unwinds |
| 189 CHECK_EQ(1, CompileRun("ordering[1]")->Int32Value()); | 194 CHECK_EQ(1, CompileRun("ordering[1]")->Int32Value()); |
| 190 // observer1's mutation causes both 1 and 2 to be reactivated, | 195 // observer1's mutation causes both 1 and 2 to be reactivated, |
| 191 // with 1 having priority. | 196 // with 1 having priority. |
| 192 CHECK_EQ(1, CompileRun("ordering[2]")->Int32Value()); | 197 CHECK_EQ(1, CompileRun("ordering[2]")->Int32Value()); |
| 193 CHECK_EQ(2, CompileRun("ordering[3]")->Int32Value()); | 198 CHECK_EQ(2, CompileRun("ordering[3]")->Int32Value()); |
| 194 } | 199 } |
| 195 | 200 |
| 201 |
| 196 TEST(ObjectHashTableGrowth) { | 202 TEST(ObjectHashTableGrowth) { |
| 197 HarmonyIsolate isolate; | 203 HarmonyIsolate isolate; |
| 198 HandleScope scope(isolate.GetIsolate()); | 204 HandleScope scope(isolate.GetIsolate()); |
| 199 // Initializing this context sets up initial hash tables. | 205 // Initializing this context sets up initial hash tables. |
| 200 LocalContext context; | 206 LocalContext context; |
| 201 Handle<Value> obj = CompileRun("obj = {};"); | 207 Handle<Value> obj = CompileRun("obj = {};"); |
| 202 Handle<Value> observer = CompileRun( | 208 Handle<Value> observer = CompileRun( |
| 203 "var ran = false;" | 209 "var ran = false;" |
| 204 "(function() { ran = true })"); | 210 "(function() { ran = true })"); |
| 205 { | 211 { |
| 206 // As does initializing this context. | 212 // As does initializing this context. |
| 207 LocalContext context2; | 213 LocalContext context2; |
| 208 context2->Global()->Set(String::New("obj"), obj); | 214 context2->Global()->Set(String::New("obj"), obj); |
| 209 context2->Global()->Set(String::New("observer"), observer); | 215 context2->Global()->Set(String::New("observer"), observer); |
| 210 CompileRun( | 216 CompileRun( |
| 211 "var objArr = [];" | 217 "var objArr = [];" |
| 212 // 100 objects should be enough to make the hash table grow | 218 // 100 objects should be enough to make the hash table grow |
| 213 // (and thus relocate). | 219 // (and thus relocate). |
| 214 "for (var i = 0; i < 100; ++i) {" | 220 "for (var i = 0; i < 100; ++i) {" |
| 215 " objArr.push({});" | 221 " objArr.push({});" |
| 216 " Object.observe(objArr[objArr.length-1], function(){});" | 222 " Object.observe(objArr[objArr.length-1], function(){});" |
| 217 "}" | 223 "}" |
| 218 "Object.observe(obj, observer);"); | 224 "Object.observe(obj, observer);"); |
| 219 } | 225 } |
| 220 // obj is now marked "is_observed", but our map has moved. | 226 // obj is now marked "is_observed", but our map has moved. |
| 221 CompileRun("obj.foo = 'bar'"); | 227 CompileRun("obj.foo = 'bar'"); |
| 222 CHECK(CompileRun("ran")->BooleanValue()); | 228 CHECK(CompileRun("ran")->BooleanValue()); |
| 223 } | 229 } |
| 224 | 230 |
| 231 |
| 225 TEST(GlobalObjectObservation) { | 232 TEST(GlobalObjectObservation) { |
| 226 HarmonyIsolate isolate; | 233 HarmonyIsolate isolate; |
| 227 LocalContext context; | 234 LocalContext context; |
| 228 HandleScope scope(isolate.GetIsolate()); | 235 HandleScope scope(isolate.GetIsolate()); |
| 229 Handle<Object> global_proxy = context->Global(); | 236 Handle<Object> global_proxy = context->Global(); |
| 230 Handle<Object> inner_global = global_proxy->GetPrototype().As<Object>(); | 237 Handle<Object> inner_global = global_proxy->GetPrototype().As<Object>(); |
| 231 CompileRun( | 238 CompileRun( |
| 232 "var records = [];" | 239 "var records = [];" |
| 233 "var global = this;" | 240 "var global = this;" |
| 234 "Object.observe(global, function(r) { [].push.apply(records, r) });" | 241 "Object.observe(global, function(r) { [].push.apply(records, r) });" |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 } | 290 } |
| 284 | 291 |
| 285 | 292 |
| 286 struct RecordExpectation { | 293 struct RecordExpectation { |
| 287 Handle<Value> object; | 294 Handle<Value> object; |
| 288 const char* type; | 295 const char* type; |
| 289 const char* name; | 296 const char* name; |
| 290 Handle<Value> old_value; | 297 Handle<Value> old_value; |
| 291 }; | 298 }; |
| 292 | 299 |
| 300 |
| 293 // TODO(adamk): Use this helper elsewhere in this file. | 301 // TODO(adamk): Use this helper elsewhere in this file. |
| 294 static void ExpectRecords(Handle<Value> records, | 302 static void ExpectRecords(Handle<Value> records, |
| 295 const RecordExpectation expectations[], | 303 const RecordExpectation expectations[], |
| 296 int num) { | 304 int num) { |
| 297 CHECK(records->IsArray()); | 305 CHECK(records->IsArray()); |
| 298 Handle<Array> recordArray = records.As<Array>(); | 306 Handle<Array> recordArray = records.As<Array>(); |
| 299 CHECK_EQ(num, static_cast<int>(recordArray->Length())); | 307 CHECK_EQ(num, static_cast<int>(recordArray->Length())); |
| 300 for (int i = 0; i < num; ++i) { | 308 for (int i = 0; i < num; ++i) { |
| 301 Handle<Value> record = recordArray->Get(i); | 309 Handle<Value> record = recordArray->Get(i); |
| 302 CHECK(record->IsObject()); | 310 CHECK(record->IsObject()); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 { obj, "updated", "1", Number::New(2) }, | 361 { obj, "updated", "1", Number::New(2) }, |
| 354 { obj, "updated", "1", Number::New(4) }, | 362 { obj, "updated", "1", Number::New(4) }, |
| 355 { obj, "new", "1.1", Handle<Value>() }, | 363 { obj, "new", "1.1", Handle<Value>() }, |
| 356 { obj, "deleted", "foo", Number::New(3) }, | 364 { obj, "deleted", "foo", Number::New(3) }, |
| 357 { obj, "deleted", "1", Number::New(5) }, | 365 { obj, "deleted", "1", Number::New(5) }, |
| 358 { obj, "deleted", "1.1", Number::New(6) } | 366 { obj, "deleted", "1.1", Number::New(6) } |
| 359 }; | 367 }; |
| 360 EXPECT_RECORDS(CompileRun("records"), expected_records); | 368 EXPECT_RECORDS(CompileRun("records"), expected_records); |
| 361 } | 369 } |
| 362 | 370 |
| 371 |
| 363 TEST(HiddenPrototypeObservation) { | 372 TEST(HiddenPrototypeObservation) { |
| 364 HarmonyIsolate isolate; | 373 HarmonyIsolate isolate; |
| 365 HandleScope scope(isolate.GetIsolate()); | 374 HandleScope scope(isolate.GetIsolate()); |
| 366 LocalContext context; | 375 LocalContext context; |
| 367 Handle<FunctionTemplate> tmpl = FunctionTemplate::New(); | 376 Handle<FunctionTemplate> tmpl = FunctionTemplate::New(); |
| 368 tmpl->SetHiddenPrototype(true); | 377 tmpl->SetHiddenPrototype(true); |
| 369 tmpl->InstanceTemplate()->Set(String::New("foo"), Number::New(75)); | 378 tmpl->InstanceTemplate()->Set(String::New("foo"), Number::New(75)); |
| 370 Handle<Object> proto = tmpl->GetFunction()->NewInstance(); | 379 Handle<Object> proto = tmpl->GetFunction()->NewInstance(); |
| 371 Handle<Object> obj = Object::New(); | 380 Handle<Object> obj = Object::New(); |
| 372 obj->SetPrototype(proto); | 381 obj->SetPrototype(proto); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 i::Handle<i::JSWeakMap>::cast( | 439 i::Handle<i::JSWeakMap>::cast( |
| 431 i::GetProperty(observation_state, "notifierTargetMap")); | 440 i::GetProperty(observation_state, "notifierTargetMap")); |
| 432 CHECK_EQ(1, NumberOfElements(observerInfoMap)); | 441 CHECK_EQ(1, NumberOfElements(observerInfoMap)); |
| 433 CHECK_EQ(1, NumberOfElements(objectInfoMap)); | 442 CHECK_EQ(1, NumberOfElements(objectInfoMap)); |
| 434 CHECK_EQ(1, NumberOfElements(notifierTargetMap)); | 443 CHECK_EQ(1, NumberOfElements(notifierTargetMap)); |
| 435 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 444 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
| 436 CHECK_EQ(0, NumberOfElements(observerInfoMap)); | 445 CHECK_EQ(0, NumberOfElements(observerInfoMap)); |
| 437 CHECK_EQ(0, NumberOfElements(objectInfoMap)); | 446 CHECK_EQ(0, NumberOfElements(objectInfoMap)); |
| 438 CHECK_EQ(0, NumberOfElements(notifierTargetMap)); | 447 CHECK_EQ(0, NumberOfElements(notifierTargetMap)); |
| 439 } | 448 } |
| OLD | NEW |