| 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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 throw MakeTypeError("observe_callback_frozen"); | 75 throw MakeTypeError("observe_callback_frozen"); |
| 76 | 76 |
| 77 if (!observerInfoMap.has(callback)) { | 77 if (!observerInfoMap.has(callback)) { |
| 78 observerInfoMap.set(callback, { | 78 observerInfoMap.set(callback, { |
| 79 pendingChangeRecords: null, | 79 pendingChangeRecords: null, |
| 80 priority: observationState.observerPriority++, | 80 priority: observationState.observerPriority++, |
| 81 }); | 81 }); |
| 82 } | 82 } |
| 83 | 83 |
| 84 var objectInfo = objectInfoMap.get(object); | 84 var objectInfo = objectInfoMap.get(object); |
| 85 if (IS_UNDEFINED(objectInfo)) { | 85 if (IS_UNDEFINED(objectInfo)) objectInfo = CreateObjectInfo(object); |
| 86 objectInfo = CreateObjectInfo(object); | |
| 87 } | |
| 88 %SetIsObserved(object, true); | 86 %SetIsObserved(object, true); |
| 89 | 87 |
| 90 var changeObservers = objectInfo.changeObservers; | 88 var changeObservers = objectInfo.changeObservers; |
| 91 if (changeObservers.indexOf(callback) < 0) | 89 if (changeObservers.indexOf(callback) < 0) changeObservers.push(callback); |
| 92 changeObservers.push(callback); | |
| 93 | 90 |
| 94 return object; | 91 return object; |
| 95 } | 92 } |
| 96 | 93 |
| 97 function ObjectUnobserve(object, callback) { | 94 function ObjectUnobserve(object, callback) { |
| 98 if (!IS_SPEC_OBJECT(object)) | 95 if (!IS_SPEC_OBJECT(object)) |
| 99 throw MakeTypeError("observe_non_object", ["unobserve"]); | 96 throw MakeTypeError("observe_non_object", ["unobserve"]); |
| 100 if (!IS_SPEC_FUNCTION(callback)) | 97 if (!IS_SPEC_FUNCTION(callback)) |
| 101 throw MakeTypeError("observe_non_function", ["unobserve"]); | 98 throw MakeTypeError("observe_non_function", ["unobserve"]); |
| 102 | 99 |
| 103 var objectInfo = objectInfoMap.get(object); | 100 var objectInfo = objectInfoMap.get(object); |
| 104 if (IS_UNDEFINED(objectInfo)) | 101 if (IS_UNDEFINED(objectInfo)) |
| 105 return object; | 102 return object; |
| 106 | 103 |
| 107 var changeObservers = objectInfo.changeObservers; | 104 var changeObservers = objectInfo.changeObservers; |
| 108 var index = changeObservers.indexOf(callback); | 105 var index = changeObservers.indexOf(callback); |
| 109 if (index >= 0) { | 106 if (index >= 0) { |
| 110 changeObservers.splice(index, 1); | 107 changeObservers.splice(index, 1); |
| 111 if (changeObservers.length === 0) | 108 if (changeObservers.length === 0) %SetIsObserved(object, false); |
| 112 %SetIsObserved(object, false); | |
| 113 } | 109 } |
| 114 | 110 |
| 115 return object; | 111 return object; |
| 116 } | 112 } |
| 117 | 113 |
| 118 function EnqueueChangeRecord(changeRecord, observers) { | 114 function EnqueueChangeRecord(changeRecord, observers) { |
| 119 for (var i = 0; i < observers.length; i++) { | 115 for (var i = 0; i < observers.length; i++) { |
| 120 var observer = observers[i]; | 116 var observer = observers[i]; |
| 121 var observerInfo = observerInfoMap.get(observer); | 117 var observerInfo = observerInfoMap.get(observer); |
| 122 observationState.pendingObservers[observerInfo.priority] = observer; | 118 observationState.pendingObservers[observerInfo.priority] = observer; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 134 var changeRecord = (arguments.length < 4) ? | 130 var changeRecord = (arguments.length < 4) ? |
| 135 { type: type, object: object, name: name } : | 131 { type: type, object: object, name: name } : |
| 136 { type: type, object: object, name: name, oldValue: oldValue }; | 132 { type: type, object: object, name: name, oldValue: oldValue }; |
| 137 ObjectFreeze(changeRecord); | 133 ObjectFreeze(changeRecord); |
| 138 EnqueueChangeRecord(changeRecord, objectInfo.changeObservers); | 134 EnqueueChangeRecord(changeRecord, objectInfo.changeObservers); |
| 139 } | 135 } |
| 140 | 136 |
| 141 var notifierPrototype = {}; | 137 var notifierPrototype = {}; |
| 142 | 138 |
| 143 function ObjectNotifierNotify(changeRecord) { | 139 function ObjectNotifierNotify(changeRecord) { |
| 140 var target = notifierTargetMap.get(this); |
| 144 if (!IS_SPEC_OBJECT(this)) | 141 if (!IS_SPEC_OBJECT(this)) |
| 145 throw MakeTypeError("called_on_non_object", ["notify"]); | 142 throw MakeTypeError("called_on_non_object", ["notify"]); |
| 146 | |
| 147 var target = notifierTargetMap.get(this); | |
| 148 if (IS_UNDEFINED(target)) | 143 if (IS_UNDEFINED(target)) |
| 149 throw MakeTypeError("observe_notify_non_notifier"); | 144 throw MakeTypeError("observe_notify_non_notifier"); |
| 150 | |
| 151 if (!IS_STRING(changeRecord.type)) | 145 if (!IS_STRING(changeRecord.type)) |
| 152 throw MakeTypeError("observe_type_non_string"); | 146 throw MakeTypeError("observe_type_non_string"); |
| 153 | 147 |
| 154 var objectInfo = objectInfoMap.get(target); | 148 var objectInfo = objectInfoMap.get(target); |
| 155 if (IS_UNDEFINED(objectInfo)) | 149 if (IS_UNDEFINED(objectInfo) || objectInfo.changeObservers.length === 0) |
| 156 return; | 150 return; |
| 157 | 151 |
| 158 if (!objectInfo.changeObservers.length) | 152 var newRecord = { object: target }; |
| 159 return; | |
| 160 | |
| 161 var newRecord = { | |
| 162 object: target | |
| 163 }; | |
| 164 for (var prop in changeRecord) { | 153 for (var prop in changeRecord) { |
| 165 if (prop === 'object') | 154 if (prop === 'object') continue; |
| 166 continue; | |
| 167 | |
| 168 %DefineOrRedefineDataProperty(newRecord, prop, changeRecord[prop], | 155 %DefineOrRedefineDataProperty(newRecord, prop, changeRecord[prop], |
| 169 READ_ONLY + DONT_DELETE); | 156 READ_ONLY + DONT_DELETE); |
| 170 } | 157 } |
| 171 ObjectFreeze(newRecord); | 158 ObjectFreeze(newRecord); |
| 172 | 159 |
| 173 EnqueueChangeRecord(newRecord, objectInfo.changeObservers); | 160 EnqueueChangeRecord(newRecord, objectInfo.changeObservers); |
| 174 } | 161 } |
| 175 | 162 |
| 176 function ObjectGetNotifier(object) { | 163 function ObjectGetNotifier(object) { |
| 177 if (!IS_SPEC_OBJECT(object)) | 164 if (!IS_SPEC_OBJECT(object)) |
| 178 throw MakeTypeError("observe_non_object", ["getNotifier"]); | 165 throw MakeTypeError("observe_non_object", ["getNotifier"]); |
| 179 | 166 |
| 180 if (ObjectIsFrozen(object)) | 167 if (ObjectIsFrozen(object)) return null; |
| 181 return null; | |
| 182 | 168 |
| 183 var objectInfo = objectInfoMap.get(object); | 169 var objectInfo = objectInfoMap.get(object); |
| 184 if (IS_UNDEFINED(objectInfo)) | 170 if (IS_UNDEFINED(objectInfo)) objectInfo = CreateObjectInfo(object); |
| 185 objectInfo = CreateObjectInfo(object); | |
| 186 | 171 |
| 187 if (IS_NULL(objectInfo.notifier)) { | 172 if (IS_NULL(objectInfo.notifier)) { |
| 188 objectInfo.notifier = { | 173 objectInfo.notifier = { __proto__: notifierPrototype }; |
| 189 __proto__: notifierPrototype | |
| 190 }; | |
| 191 notifierTargetMap.set(objectInfo.notifier, object); | 174 notifierTargetMap.set(objectInfo.notifier, object); |
| 192 } | 175 } |
| 193 | 176 |
| 194 return objectInfo.notifier; | 177 return objectInfo.notifier; |
| 195 } | 178 } |
| 196 | 179 |
| 197 function DeliverChangeRecordsForObserver(observer) { | 180 function DeliverChangeRecordsForObserver(observer) { |
| 198 var observerInfo = observerInfoMap.get(observer); | 181 var observerInfo = observerInfoMap.get(observer); |
| 199 if (IS_UNDEFINED(observerInfo)) | 182 if (IS_UNDEFINED(observerInfo)) |
| 200 return; | 183 return false; |
| 201 | 184 |
| 202 var pendingChangeRecords = observerInfo.pendingChangeRecords; | 185 var pendingChangeRecords = observerInfo.pendingChangeRecords; |
| 203 if (IS_NULL(pendingChangeRecords)) | 186 if (IS_NULL(pendingChangeRecords)) |
| 204 return; | 187 return false; |
| 205 | 188 |
| 206 observerInfo.pendingChangeRecords = null; | 189 observerInfo.pendingChangeRecords = null; |
| 207 delete observationState.pendingObservers[observerInfo.priority]; | 190 delete observationState.pendingObservers[observerInfo.priority]; |
| 208 var delivered = []; | 191 var delivered = []; |
| 209 %MoveArrayContents(pendingChangeRecords, delivered); | 192 %MoveArrayContents(pendingChangeRecords, delivered); |
| 210 try { | 193 try { |
| 211 %Call(void 0, delivered, observer); | 194 %Call(void 0, delivered, observer); |
| 212 } catch (ex) {} | 195 } catch (ex) {} |
| 196 return true; |
| 213 } | 197 } |
| 214 | 198 |
| 215 function ObjectDeliverChangeRecords(callback) { | 199 function ObjectDeliverChangeRecords(callback) { |
| 216 if (!IS_SPEC_FUNCTION(callback)) | 200 if (!IS_SPEC_FUNCTION(callback)) |
| 217 throw MakeTypeError("observe_non_function", ["deliverChangeRecords"]); | 201 throw MakeTypeError("observe_non_function", ["deliverChangeRecords"]); |
| 218 | 202 |
| 219 DeliverChangeRecordsForObserver(callback); | 203 while (DeliverChangeRecordsForObserver(callback)) {} |
| 220 } | 204 } |
| 221 | 205 |
| 222 function DeliverChangeRecords() { | 206 function DeliverChangeRecords() { |
| 223 while (observationState.pendingObservers.length) { | 207 while (observationState.pendingObservers.length) { |
| 224 var pendingObservers = observationState.pendingObservers; | 208 var pendingObservers = observationState.pendingObservers; |
| 225 observationState.pendingObservers = new InternalArray; | 209 observationState.pendingObservers = new InternalArray; |
| 226 for (var i in pendingObservers) { | 210 for (var i in pendingObservers) { |
| 227 DeliverChangeRecordsForObserver(pendingObservers[i]); | 211 DeliverChangeRecordsForObserver(pendingObservers[i]); |
| 228 } | 212 } |
| 229 } | 213 } |
| 230 } | 214 } |
| 231 | 215 |
| 232 function SetupObjectObserve() { | 216 function SetupObjectObserve() { |
| 233 %CheckIsBootstrapping(); | 217 %CheckIsBootstrapping(); |
| 234 InstallFunctions($Object, DONT_ENUM, $Array( | 218 InstallFunctions($Object, DONT_ENUM, $Array( |
| 235 "deliverChangeRecords", ObjectDeliverChangeRecords, | 219 "deliverChangeRecords", ObjectDeliverChangeRecords, |
| 236 "getNotifier", ObjectGetNotifier, | 220 "getNotifier", ObjectGetNotifier, |
| 237 "observe", ObjectObserve, | 221 "observe", ObjectObserve, |
| 238 "unobserve", ObjectUnobserve | 222 "unobserve", ObjectUnobserve |
| 239 )); | 223 )); |
| 240 InstallFunctions(notifierPrototype, DONT_ENUM, $Array( | 224 InstallFunctions(notifierPrototype, DONT_ENUM, $Array( |
| 241 "notify", ObjectNotifierNotify | 225 "notify", ObjectNotifierNotify |
| 242 )); | 226 )); |
| 243 } | 227 } |
| 244 | 228 |
| 245 SetupObjectObserve(); | 229 SetupObjectObserve(); |
| OLD | NEW |