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 |
11 // with the distribution. | 11 // with the distribution. |
12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
15 // | 15 // |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #include "accessors.h" | 30 #include "handles.h" |
31 #include "api.h" | |
32 #include "arguments.h" | |
33 #include "bootstrapper.h" | |
34 #include "compiler.h" | |
35 #include "debug.h" | |
36 #include "execution.h" | |
37 #include "global-handles.h" | |
38 #include "natives.h" | |
39 #include "runtime.h" | |
40 #include "string-search.h" | |
41 #include "stub-cache.h" | |
42 #include "vm-state-inl.h" | |
43 | 31 |
44 namespace v8 { | 32 namespace v8 { |
45 namespace internal { | 33 namespace internal { |
46 | 34 |
47 | 35 |
48 int HandleScope::NumberOfHandles(Isolate* isolate) { | 36 int HandleScope::NumberOfHandles(Isolate* isolate) { |
49 HandleScopeImplementer* impl = isolate->handle_scope_implementer(); | 37 HandleScopeImplementer* impl = isolate->handle_scope_implementer(); |
50 int n = impl->blocks()->length(); | 38 int n = impl->blocks()->length(); |
51 if (n == 0) return 0; | 39 if (n == 0) return 0; |
52 return ((n - 1) * kHandleBlockSize) + static_cast<int>( | 40 return ((n - 1) * kHandleBlockSize) + static_cast<int>( |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 Address HandleScope::current_next_address(Isolate* isolate) { | 105 Address HandleScope::current_next_address(Isolate* isolate) { |
118 return reinterpret_cast<Address>(&isolate->handle_scope_data()->next); | 106 return reinterpret_cast<Address>(&isolate->handle_scope_data()->next); |
119 } | 107 } |
120 | 108 |
121 | 109 |
122 Address HandleScope::current_limit_address(Isolate* isolate) { | 110 Address HandleScope::current_limit_address(Isolate* isolate) { |
123 return reinterpret_cast<Address>(&isolate->handle_scope_data()->limit); | 111 return reinterpret_cast<Address>(&isolate->handle_scope_data()->limit); |
124 } | 112 } |
125 | 113 |
126 | 114 |
127 MaybeHandle<Object> GetProperty(Handle<JSReceiver> obj, | |
128 const char* name) { | |
129 Isolate* isolate = obj->GetIsolate(); | |
130 Handle<String> str = isolate->factory()->InternalizeUtf8String(name); | |
131 ASSERT(!str.is_null()); | |
132 return Object::GetPropertyOrElement(obj, str); | |
133 } | |
134 | |
135 | |
136 // Wrappers for scripts are kept alive and cached in weak global | |
137 // handles referred from foreign objects held by the scripts as long as | |
138 // they are used. When they are not used anymore, the garbage | |
139 // collector will call the weak callback on the global handle | |
140 // associated with the wrapper and get rid of both the wrapper and the | |
141 // handle. | |
142 static void ClearWrapperCache( | |
143 const v8::WeakCallbackData<v8::Value, void>& data) { | |
144 Object** location = reinterpret_cast<Object**>(data.GetParameter()); | |
145 JSValue* wrapper = JSValue::cast(*location); | |
146 Foreign* foreign = Script::cast(wrapper->value())->wrapper(); | |
147 ASSERT_EQ(foreign->foreign_address(), reinterpret_cast<Address>(location)); | |
148 foreign->set_foreign_address(0); | |
149 GlobalHandles::Destroy(location); | |
150 Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate()); | |
151 isolate->counters()->script_wrappers()->Decrement(); | |
152 } | |
153 | |
154 | |
155 Handle<JSValue> GetScriptWrapper(Handle<Script> script) { | |
156 if (script->wrapper()->foreign_address() != NULL) { | |
157 // Return a handle for the existing script wrapper from the cache. | |
158 return Handle<JSValue>( | |
159 *reinterpret_cast<JSValue**>(script->wrapper()->foreign_address())); | |
160 } | |
161 Isolate* isolate = script->GetIsolate(); | |
162 // Construct a new script wrapper. | |
163 isolate->counters()->script_wrappers()->Increment(); | |
164 Handle<JSFunction> constructor = isolate->script_function(); | |
165 Handle<JSValue> result = | |
166 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor)); | |
167 | |
168 result->set_value(*script); | |
169 | |
170 // Create a new weak global handle and use it to cache the wrapper | |
171 // for future use. The cache will automatically be cleared by the | |
172 // garbage collector when it is not used anymore. | |
173 Handle<Object> handle = isolate->global_handles()->Create(*result); | |
174 GlobalHandles::MakeWeak(handle.location(), | |
175 reinterpret_cast<void*>(handle.location()), | |
176 &ClearWrapperCache); | |
177 script->wrapper()->set_foreign_address( | |
178 reinterpret_cast<Address>(handle.location())); | |
179 return result; | |
180 } | |
181 | |
182 | |
183 // Init line_ends array with code positions of line ends inside script | |
184 // source. | |
185 void InitScriptLineEnds(Handle<Script> script) { | |
186 if (!script->line_ends()->IsUndefined()) return; | |
187 | |
188 Isolate* isolate = script->GetIsolate(); | |
189 | |
190 if (!script->source()->IsString()) { | |
191 ASSERT(script->source()->IsUndefined()); | |
192 Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0); | |
193 script->set_line_ends(*empty); | |
194 ASSERT(script->line_ends()->IsFixedArray()); | |
195 return; | |
196 } | |
197 | |
198 Handle<String> src(String::cast(script->source()), isolate); | |
199 | |
200 Handle<FixedArray> array = CalculateLineEnds(src, true); | |
201 | |
202 if (*array != isolate->heap()->empty_fixed_array()) { | |
203 array->set_map(isolate->heap()->fixed_cow_array_map()); | |
204 } | |
205 | |
206 script->set_line_ends(*array); | |
207 ASSERT(script->line_ends()->IsFixedArray()); | |
208 } | |
209 | |
210 | |
211 template <typename SourceChar> | |
212 static void CalculateLineEnds(Isolate* isolate, | |
213 List<int>* line_ends, | |
214 Vector<const SourceChar> src, | |
215 bool with_last_line) { | |
216 const int src_len = src.length(); | |
217 StringSearch<uint8_t, SourceChar> search(isolate, STATIC_ASCII_VECTOR("\n")); | |
218 | |
219 // Find and record line ends. | |
220 int position = 0; | |
221 while (position != -1 && position < src_len) { | |
222 position = search.Search(src, position); | |
223 if (position != -1) { | |
224 line_ends->Add(position); | |
225 position++; | |
226 } else if (with_last_line) { | |
227 // Even if the last line misses a line end, it is counted. | |
228 line_ends->Add(src_len); | |
229 return; | |
230 } | |
231 } | |
232 } | |
233 | |
234 | |
235 Handle<FixedArray> CalculateLineEnds(Handle<String> src, | |
236 bool with_last_line) { | |
237 src = String::Flatten(src); | |
238 // Rough estimate of line count based on a roughly estimated average | |
239 // length of (unpacked) code. | |
240 int line_count_estimate = src->length() >> 4; | |
241 List<int> line_ends(line_count_estimate); | |
242 Isolate* isolate = src->GetIsolate(); | |
243 { | |
244 DisallowHeapAllocation no_allocation; // ensure vectors stay valid. | |
245 // Dispatch on type of strings. | |
246 String::FlatContent content = src->GetFlatContent(); | |
247 ASSERT(content.IsFlat()); | |
248 if (content.IsAscii()) { | |
249 CalculateLineEnds(isolate, | |
250 &line_ends, | |
251 content.ToOneByteVector(), | |
252 with_last_line); | |
253 } else { | |
254 CalculateLineEnds(isolate, | |
255 &line_ends, | |
256 content.ToUC16Vector(), | |
257 with_last_line); | |
258 } | |
259 } | |
260 int line_count = line_ends.length(); | |
261 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count); | |
262 for (int i = 0; i < line_count; i++) { | |
263 array->set(i, Smi::FromInt(line_ends[i])); | |
264 } | |
265 return array; | |
266 } | |
267 | |
268 | |
269 // Convert code position into line number. | |
270 int GetScriptLineNumber(Handle<Script> script, int code_pos) { | |
271 InitScriptLineEnds(script); | |
272 DisallowHeapAllocation no_allocation; | |
273 FixedArray* line_ends_array = FixedArray::cast(script->line_ends()); | |
274 const int line_ends_len = line_ends_array->length(); | |
275 | |
276 if (!line_ends_len) return -1; | |
277 | |
278 if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) { | |
279 return script->line_offset()->value(); | |
280 } | |
281 | |
282 int left = 0; | |
283 int right = line_ends_len; | |
284 while (int half = (right - left) / 2) { | |
285 if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) { | |
286 right -= half; | |
287 } else { | |
288 left += half; | |
289 } | |
290 } | |
291 return right + script->line_offset()->value(); | |
292 } | |
293 | |
294 | |
295 // Convert code position into column number. | |
296 int GetScriptColumnNumber(Handle<Script> script, int code_pos) { | |
297 int line_number = GetScriptLineNumber(script, code_pos); | |
298 if (line_number == -1) return -1; | |
299 | |
300 DisallowHeapAllocation no_allocation; | |
301 FixedArray* line_ends_array = FixedArray::cast(script->line_ends()); | |
302 line_number = line_number - script->line_offset()->value(); | |
303 if (line_number == 0) return code_pos + script->column_offset()->value(); | |
304 int prev_line_end_pos = | |
305 Smi::cast(line_ends_array->get(line_number - 1))->value(); | |
306 return code_pos - (prev_line_end_pos + 1); | |
307 } | |
308 | |
309 | |
310 int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) { | |
311 DisallowHeapAllocation no_allocation; | |
312 if (!script->line_ends()->IsUndefined()) { | |
313 return GetScriptLineNumber(script, code_pos); | |
314 } | |
315 // Slow mode: we do not have line_ends. We have to iterate through source. | |
316 if (!script->source()->IsString()) { | |
317 return -1; | |
318 } | |
319 String* source = String::cast(script->source()); | |
320 int line = 0; | |
321 int len = source->length(); | |
322 for (int pos = 0; pos < len; pos++) { | |
323 if (pos == code_pos) { | |
324 break; | |
325 } | |
326 if (source->Get(pos) == '\n') { | |
327 line++; | |
328 } | |
329 } | |
330 return line; | |
331 } | |
332 | |
333 | |
334 // Compute the property keys from the interceptor. | |
335 // TODO(rossberg): support symbols in API, and filter here if needed. | |
336 v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSReceiver> receiver, | |
337 Handle<JSObject> object) { | |
338 Isolate* isolate = receiver->GetIsolate(); | |
339 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor()); | |
340 PropertyCallbackArguments | |
341 args(isolate, interceptor->data(), *receiver, *object); | |
342 v8::Handle<v8::Array> result; | |
343 if (!interceptor->enumerator()->IsUndefined()) { | |
344 v8::NamedPropertyEnumeratorCallback enum_fun = | |
345 v8::ToCData<v8::NamedPropertyEnumeratorCallback>( | |
346 interceptor->enumerator()); | |
347 LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object)); | |
348 result = args.Call(enum_fun); | |
349 } | |
350 #if ENABLE_EXTRA_CHECKS | |
351 CHECK(result.IsEmpty() || v8::Utils::OpenHandle(*result)->IsJSObject()); | |
352 #endif | |
353 return v8::Local<v8::Array>::New(reinterpret_cast<v8::Isolate*>(isolate), | |
354 result); | |
355 } | |
356 | |
357 | |
358 // Compute the element keys from the interceptor. | |
359 v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSReceiver> receiver, | |
360 Handle<JSObject> object) { | |
361 Isolate* isolate = receiver->GetIsolate(); | |
362 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor()); | |
363 PropertyCallbackArguments | |
364 args(isolate, interceptor->data(), *receiver, *object); | |
365 v8::Handle<v8::Array> result; | |
366 if (!interceptor->enumerator()->IsUndefined()) { | |
367 v8::IndexedPropertyEnumeratorCallback enum_fun = | |
368 v8::ToCData<v8::IndexedPropertyEnumeratorCallback>( | |
369 interceptor->enumerator()); | |
370 LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object)); | |
371 result = args.Call(enum_fun); | |
372 #if ENABLE_EXTRA_CHECKS | |
373 CHECK(result.IsEmpty() || v8::Utils::OpenHandle(*result)->IsJSObject()); | |
374 #endif | |
375 } | |
376 return v8::Local<v8::Array>::New(reinterpret_cast<v8::Isolate*>(isolate), | |
377 result); | |
378 } | |
379 | |
380 | |
381 Handle<Object> GetScriptNameOrSourceURL(Handle<Script> script) { | |
382 Isolate* isolate = script->GetIsolate(); | |
383 Handle<String> name_or_source_url_key = | |
384 isolate->factory()->InternalizeOneByteString( | |
385 STATIC_ASCII_VECTOR("nameOrSourceURL")); | |
386 Handle<JSValue> script_wrapper = GetScriptWrapper(script); | |
387 Handle<Object> property = Object::GetProperty( | |
388 script_wrapper, name_or_source_url_key).ToHandleChecked(); | |
389 ASSERT(property->IsJSFunction()); | |
390 Handle<JSFunction> method = Handle<JSFunction>::cast(property); | |
391 Handle<Object> result; | |
392 // Do not check against pending exception, since this function may be called | |
393 // when an exception has already been pending. | |
394 if (!Execution::TryCall(method, script_wrapper, 0, NULL).ToHandle(&result)) { | |
395 return isolate->factory()->undefined_value(); | |
396 } | |
397 return result; | |
398 } | |
399 | |
400 | |
401 static bool ContainsOnlyValidKeys(Handle<FixedArray> array) { | |
402 int len = array->length(); | |
403 for (int i = 0; i < len; i++) { | |
404 Object* e = array->get(i); | |
405 if (!(e->IsString() || e->IsNumber())) return false; | |
406 } | |
407 return true; | |
408 } | |
409 | |
410 | |
411 MaybeHandle<FixedArray> GetKeysInFixedArrayFor(Handle<JSReceiver> object, | |
412 KeyCollectionType type) { | |
413 USE(ContainsOnlyValidKeys); | |
414 Isolate* isolate = object->GetIsolate(); | |
415 Handle<FixedArray> content = isolate->factory()->empty_fixed_array(); | |
416 Handle<JSObject> arguments_boilerplate = Handle<JSObject>( | |
417 isolate->context()->native_context()->sloppy_arguments_boilerplate(), | |
418 isolate); | |
419 Handle<JSFunction> arguments_function = Handle<JSFunction>( | |
420 JSFunction::cast(arguments_boilerplate->map()->constructor()), | |
421 isolate); | |
422 | |
423 // Only collect keys if access is permitted. | |
424 for (Handle<Object> p = object; | |
425 *p != isolate->heap()->null_value(); | |
426 p = Handle<Object>(p->GetPrototype(isolate), isolate)) { | |
427 if (p->IsJSProxy()) { | |
428 Handle<JSProxy> proxy(JSProxy::cast(*p), isolate); | |
429 Handle<Object> args[] = { proxy }; | |
430 Handle<Object> names; | |
431 ASSIGN_RETURN_ON_EXCEPTION( | |
432 isolate, names, | |
433 Execution::Call(isolate, | |
434 isolate->proxy_enumerate(), | |
435 object, | |
436 ARRAY_SIZE(args), | |
437 args), | |
438 FixedArray); | |
439 ASSIGN_RETURN_ON_EXCEPTION( | |
440 isolate, content, | |
441 FixedArray::AddKeysFromJSArray( | |
442 content, Handle<JSArray>::cast(names)), | |
443 FixedArray); | |
444 break; | |
445 } | |
446 | |
447 Handle<JSObject> current(JSObject::cast(*p), isolate); | |
448 | |
449 // Check access rights if required. | |
450 if (current->IsAccessCheckNeeded() && | |
451 !isolate->MayNamedAccess( | |
452 current, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) { | |
453 isolate->ReportFailedAccessCheck(current, v8::ACCESS_KEYS); | |
454 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray); | |
455 break; | |
456 } | |
457 | |
458 // Compute the element keys. | |
459 Handle<FixedArray> element_keys = | |
460 isolate->factory()->NewFixedArray(current->NumberOfEnumElements()); | |
461 current->GetEnumElementKeys(*element_keys); | |
462 ASSIGN_RETURN_ON_EXCEPTION( | |
463 isolate, content, | |
464 FixedArray::UnionOfKeys(content, element_keys), | |
465 FixedArray); | |
466 ASSERT(ContainsOnlyValidKeys(content)); | |
467 | |
468 // Add the element keys from the interceptor. | |
469 if (current->HasIndexedInterceptor()) { | |
470 v8::Handle<v8::Array> result = | |
471 GetKeysForIndexedInterceptor(object, current); | |
472 if (!result.IsEmpty()) { | |
473 ASSIGN_RETURN_ON_EXCEPTION( | |
474 isolate, content, | |
475 FixedArray::AddKeysFromJSArray( | |
476 content, v8::Utils::OpenHandle(*result)), | |
477 FixedArray); | |
478 } | |
479 ASSERT(ContainsOnlyValidKeys(content)); | |
480 } | |
481 | |
482 // We can cache the computed property keys if access checks are | |
483 // not needed and no interceptors are involved. | |
484 // | |
485 // We do not use the cache if the object has elements and | |
486 // therefore it does not make sense to cache the property names | |
487 // for arguments objects. Arguments objects will always have | |
488 // elements. | |
489 // Wrapped strings have elements, but don't have an elements | |
490 // array or dictionary. So the fast inline test for whether to | |
491 // use the cache says yes, so we should not create a cache. | |
492 bool cache_enum_keys = | |
493 ((current->map()->constructor() != *arguments_function) && | |
494 !current->IsJSValue() && | |
495 !current->IsAccessCheckNeeded() && | |
496 !current->HasNamedInterceptor() && | |
497 !current->HasIndexedInterceptor()); | |
498 // Compute the property keys and cache them if possible. | |
499 ASSIGN_RETURN_ON_EXCEPTION( | |
500 isolate, content, | |
501 FixedArray::UnionOfKeys( | |
502 content, GetEnumPropertyKeys(current, cache_enum_keys)), | |
503 FixedArray); | |
504 ASSERT(ContainsOnlyValidKeys(content)); | |
505 | |
506 // Add the property keys from the interceptor. | |
507 if (current->HasNamedInterceptor()) { | |
508 v8::Handle<v8::Array> result = | |
509 GetKeysForNamedInterceptor(object, current); | |
510 if (!result.IsEmpty()) { | |
511 ASSIGN_RETURN_ON_EXCEPTION( | |
512 isolate, content, | |
513 FixedArray::AddKeysFromJSArray( | |
514 content, v8::Utils::OpenHandle(*result)), | |
515 FixedArray); | |
516 } | |
517 ASSERT(ContainsOnlyValidKeys(content)); | |
518 } | |
519 | |
520 // If we only want local properties we bail out after the first | |
521 // iteration. | |
522 if (type == LOCAL_ONLY) break; | |
523 } | |
524 return content; | |
525 } | |
526 | |
527 | |
528 Handle<FixedArray> ReduceFixedArrayTo(Handle<FixedArray> array, int length) { | |
529 ASSERT(array->length() >= length); | |
530 if (array->length() == length) return array; | |
531 | |
532 Handle<FixedArray> new_array = | |
533 array->GetIsolate()->factory()->NewFixedArray(length); | |
534 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); | |
535 return new_array; | |
536 } | |
537 | |
538 | |
539 Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, | |
540 bool cache_result) { | |
541 Isolate* isolate = object->GetIsolate(); | |
542 if (object->HasFastProperties()) { | |
543 int own_property_count = object->map()->EnumLength(); | |
544 // If the enum length of the given map is set to kInvalidEnumCache, this | |
545 // means that the map itself has never used the present enum cache. The | |
546 // first step to using the cache is to set the enum length of the map by | |
547 // counting the number of own descriptors that are not DONT_ENUM or | |
548 // SYMBOLIC. | |
549 if (own_property_count == kInvalidEnumCacheSentinel) { | |
550 own_property_count = object->map()->NumberOfDescribedProperties( | |
551 OWN_DESCRIPTORS, DONT_SHOW); | |
552 } else { | |
553 ASSERT(own_property_count == object->map()->NumberOfDescribedProperties( | |
554 OWN_DESCRIPTORS, DONT_SHOW)); | |
555 } | |
556 | |
557 if (object->map()->instance_descriptors()->HasEnumCache()) { | |
558 DescriptorArray* desc = object->map()->instance_descriptors(); | |
559 Handle<FixedArray> keys(desc->GetEnumCache(), isolate); | |
560 | |
561 // In case the number of properties required in the enum are actually | |
562 // present, we can reuse the enum cache. Otherwise, this means that the | |
563 // enum cache was generated for a previous (smaller) version of the | |
564 // Descriptor Array. In that case we regenerate the enum cache. | |
565 if (own_property_count <= keys->length()) { | |
566 if (cache_result) object->map()->SetEnumLength(own_property_count); | |
567 isolate->counters()->enum_cache_hits()->Increment(); | |
568 return ReduceFixedArrayTo(keys, own_property_count); | |
569 } | |
570 } | |
571 | |
572 Handle<Map> map(object->map()); | |
573 | |
574 if (map->instance_descriptors()->IsEmpty()) { | |
575 isolate->counters()->enum_cache_hits()->Increment(); | |
576 if (cache_result) map->SetEnumLength(0); | |
577 return isolate->factory()->empty_fixed_array(); | |
578 } | |
579 | |
580 isolate->counters()->enum_cache_misses()->Increment(); | |
581 | |
582 Handle<FixedArray> storage = isolate->factory()->NewFixedArray( | |
583 own_property_count); | |
584 Handle<FixedArray> indices = isolate->factory()->NewFixedArray( | |
585 own_property_count); | |
586 | |
587 Handle<DescriptorArray> descs = | |
588 Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate); | |
589 | |
590 int size = map->NumberOfOwnDescriptors(); | |
591 int index = 0; | |
592 | |
593 for (int i = 0; i < size; i++) { | |
594 PropertyDetails details = descs->GetDetails(i); | |
595 Object* key = descs->GetKey(i); | |
596 if (!(details.IsDontEnum() || key->IsSymbol())) { | |
597 storage->set(index, key); | |
598 if (!indices.is_null()) { | |
599 if (details.type() != FIELD) { | |
600 indices = Handle<FixedArray>(); | |
601 } else { | |
602 int field_index = descs->GetFieldIndex(i); | |
603 if (field_index >= map->inobject_properties()) { | |
604 field_index = -(field_index - map->inobject_properties() + 1); | |
605 } | |
606 field_index = field_index << 1; | |
607 if (details.representation().IsDouble()) { | |
608 field_index |= 1; | |
609 } | |
610 indices->set(index, Smi::FromInt(field_index)); | |
611 } | |
612 } | |
613 index++; | |
614 } | |
615 } | |
616 ASSERT(index == storage->length()); | |
617 | |
618 Handle<FixedArray> bridge_storage = | |
619 isolate->factory()->NewFixedArray( | |
620 DescriptorArray::kEnumCacheBridgeLength); | |
621 DescriptorArray* desc = object->map()->instance_descriptors(); | |
622 desc->SetEnumCache(*bridge_storage, | |
623 *storage, | |
624 indices.is_null() ? Object::cast(Smi::FromInt(0)) | |
625 : Object::cast(*indices)); | |
626 if (cache_result) { | |
627 object->map()->SetEnumLength(own_property_count); | |
628 } | |
629 return storage; | |
630 } else { | |
631 Handle<NameDictionary> dictionary(object->property_dictionary()); | |
632 int length = dictionary->NumberOfEnumElements(); | |
633 if (length == 0) { | |
634 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); | |
635 } | |
636 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); | |
637 dictionary->CopyEnumKeysTo(*storage); | |
638 return storage; | |
639 } | |
640 } | |
641 | |
642 | |
643 DeferredHandleScope::DeferredHandleScope(Isolate* isolate) | 115 DeferredHandleScope::DeferredHandleScope(Isolate* isolate) |
644 : impl_(isolate->handle_scope_implementer()) { | 116 : impl_(isolate->handle_scope_implementer()) { |
645 impl_->BeginDeferredScope(); | 117 impl_->BeginDeferredScope(); |
646 HandleScopeData* data = impl_->isolate()->handle_scope_data(); | 118 HandleScopeData* data = impl_->isolate()->handle_scope_data(); |
647 Object** new_next = impl_->GetSpareOrNewBlock(); | 119 Object** new_next = impl_->GetSpareOrNewBlock(); |
648 Object** new_limit = &new_next[kHandleBlockSize]; | 120 Object** new_limit = &new_next[kHandleBlockSize]; |
649 ASSERT(data->limit == &impl_->blocks()->last()[kHandleBlockSize]); | 121 ASSERT(data->limit == &impl_->blocks()->last()[kHandleBlockSize]); |
650 impl_->blocks()->Add(new_next); | 122 impl_->blocks()->Add(new_next); |
651 | 123 |
652 #ifdef DEBUG | 124 #ifdef DEBUG |
(...skipping 18 matching lines...) Expand all Loading... |
671 DeferredHandles* deferred = impl_->Detach(prev_limit_); | 143 DeferredHandles* deferred = impl_->Detach(prev_limit_); |
672 HandleScopeData* data = impl_->isolate()->handle_scope_data(); | 144 HandleScopeData* data = impl_->isolate()->handle_scope_data(); |
673 data->next = prev_next_; | 145 data->next = prev_next_; |
674 data->limit = prev_limit_; | 146 data->limit = prev_limit_; |
675 #ifdef DEBUG | 147 #ifdef DEBUG |
676 handles_detached_ = true; | 148 handles_detached_ = true; |
677 #endif | 149 #endif |
678 return deferred; | 150 return deferred; |
679 } | 151 } |
680 | 152 |
681 | |
682 void AddWeakObjectToCodeDependency(Heap* heap, | |
683 Handle<Object> object, | |
684 Handle<Code> code) { | |
685 heap->EnsureWeakObjectToCodeTable(); | |
686 Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(*object)); | |
687 dep = DependentCode::Insert(dep, DependentCode::kWeakCodeGroup, code); | |
688 CALL_HEAP_FUNCTION_VOID(heap->isolate(), | |
689 heap->AddWeakObjectToCodeDependency(*object, *dep)); | |
690 } | |
691 | |
692 | |
693 } } // namespace v8::internal | 153 } } // namespace v8::internal |
OLD | NEW |