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 |