• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
27 
28 #include "v8.h"
29 
30 #include "accessors.h"
31 #include "api.h"
32 #include "arguments.h"
33 #include "bootstrapper.h"
34 #include "codegen.h"
35 #include "compiler.h"
36 #include "debug.h"
37 #include "execution.h"
38 #include "global-handles.h"
39 #include "natives.h"
40 #include "runtime.h"
41 #include "stub-cache.h"
42 
43 namespace v8 {
44 namespace internal {
45 
46 
47 v8::ImplementationUtilities::HandleScopeData HandleScope::current_ =
48     { -1, NULL, NULL };
49 
50 
NumberOfHandles()51 int HandleScope::NumberOfHandles() {
52   int n = HandleScopeImplementer::instance()->blocks()->length();
53   if (n == 0) return 0;
54   return ((n - 1) * kHandleBlockSize) + static_cast<int>(
55       (current_.next - HandleScopeImplementer::instance()->blocks()->last()));
56 }
57 
58 
Extend()59 Object** HandleScope::Extend() {
60   Object** result = current_.next;
61 
62   ASSERT(result == current_.limit);
63   // Make sure there's at least one scope on the stack and that the
64   // top of the scope stack isn't a barrier.
65   if (current_.extensions < 0) {
66     Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
67                             "Cannot create a handle without a HandleScope");
68     return NULL;
69   }
70   HandleScopeImplementer* impl = HandleScopeImplementer::instance();
71   // If there's more room in the last block, we use that. This is used
72   // for fast creation of scopes after scope barriers.
73   if (!impl->blocks()->is_empty()) {
74     Object** limit = &impl->blocks()->last()[kHandleBlockSize];
75     if (current_.limit != limit) {
76       current_.limit = limit;
77     }
78   }
79 
80   // If we still haven't found a slot for the handle, we extend the
81   // current handle scope by allocating a new handle block.
82   if (result == current_.limit) {
83     // If there's a spare block, use it for growing the current scope.
84     result = impl->GetSpareOrNewBlock();
85     // Add the extension to the global list of blocks, but count the
86     // extension as part of the current scope.
87     impl->blocks()->Add(result);
88     current_.extensions++;
89     current_.limit = &result[kHandleBlockSize];
90   }
91 
92   return result;
93 }
94 
95 
DeleteExtensions()96 void HandleScope::DeleteExtensions() {
97   ASSERT(current_.extensions != 0);
98   HandleScopeImplementer::instance()->DeleteExtensions(current_.extensions);
99 }
100 
101 
ZapRange(Object ** start,Object ** end)102 void HandleScope::ZapRange(Object** start, Object** end) {
103   if (start == NULL) return;
104   for (Object** p = start; p < end; p++) {
105     *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue;
106   }
107 }
108 
109 
current_extensions_address()110 Address HandleScope::current_extensions_address() {
111   return reinterpret_cast<Address>(&current_.extensions);
112 }
113 
114 
current_next_address()115 Address HandleScope::current_next_address() {
116   return reinterpret_cast<Address>(&current_.next);
117 }
118 
119 
current_limit_address()120 Address HandleScope::current_limit_address() {
121   return reinterpret_cast<Address>(&current_.limit);
122 }
123 
124 
AddKeysFromJSArray(Handle<FixedArray> content,Handle<JSArray> array)125 Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content,
126                                       Handle<JSArray> array) {
127   CALL_HEAP_FUNCTION(content->AddKeysFromJSArray(*array), FixedArray);
128 }
129 
130 
UnionOfKeys(Handle<FixedArray> first,Handle<FixedArray> second)131 Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first,
132                                Handle<FixedArray> second) {
133   CALL_HEAP_FUNCTION(first->UnionOfKeys(*second), FixedArray);
134 }
135 
136 
ReinitializeJSGlobalProxy(Handle<JSFunction> constructor,Handle<JSGlobalProxy> global)137 Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
138     Handle<JSFunction> constructor,
139     Handle<JSGlobalProxy> global) {
140   CALL_HEAP_FUNCTION(Heap::ReinitializeJSGlobalProxy(*constructor, *global),
141                      JSGlobalProxy);
142 }
143 
144 
SetExpectedNofProperties(Handle<JSFunction> func,int nof)145 void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
146   func->shared()->set_expected_nof_properties(nof);
147   if (func->has_initial_map()) {
148     Handle<Map> new_initial_map =
149         Factory::CopyMapDropTransitions(Handle<Map>(func->initial_map()));
150     new_initial_map->set_unused_property_fields(nof);
151     func->set_initial_map(*new_initial_map);
152   }
153 }
154 
155 
SetPrototypeProperty(Handle<JSFunction> func,Handle<JSObject> value)156 void SetPrototypeProperty(Handle<JSFunction> func, Handle<JSObject> value) {
157   CALL_HEAP_FUNCTION_VOID(func->SetPrototype(*value));
158 }
159 
160 
ExpectedNofPropertiesFromEstimate(int estimate)161 static int ExpectedNofPropertiesFromEstimate(int estimate) {
162   // TODO(1231235): We need dynamic feedback to estimate the number
163   // of expected properties in an object. The static hack below
164   // is barely a solution.
165   if (estimate == 0) return 4;
166   return estimate + 2;
167 }
168 
169 
SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,int estimate)170 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
171                                           int estimate) {
172   shared->set_expected_nof_properties(
173       ExpectedNofPropertiesFromEstimate(estimate));
174 }
175 
176 
SetExpectedNofPropertiesFromEstimate(Handle<JSFunction> func,int estimate)177 void SetExpectedNofPropertiesFromEstimate(Handle<JSFunction> func,
178                                           int estimate) {
179   SetExpectedNofProperties(
180       func, ExpectedNofPropertiesFromEstimate(estimate));
181 }
182 
183 
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties)184 void NormalizeProperties(Handle<JSObject> object,
185                          PropertyNormalizationMode mode,
186                          int expected_additional_properties) {
187   CALL_HEAP_FUNCTION_VOID(object->NormalizeProperties(
188       mode,
189       expected_additional_properties));
190 }
191 
192 
NormalizeElements(Handle<JSObject> object)193 void NormalizeElements(Handle<JSObject> object) {
194   CALL_HEAP_FUNCTION_VOID(object->NormalizeElements());
195 }
196 
197 
TransformToFastProperties(Handle<JSObject> object,int unused_property_fields)198 void TransformToFastProperties(Handle<JSObject> object,
199                                int unused_property_fields) {
200   CALL_HEAP_FUNCTION_VOID(
201       object->TransformToFastProperties(unused_property_fields));
202 }
203 
204 
FlattenString(Handle<String> string)205 void FlattenString(Handle<String> string) {
206   CALL_HEAP_FUNCTION_VOID(string->TryFlattenIfNotFlat());
207   ASSERT(string->IsFlat());
208 }
209 
210 
SetPrototype(Handle<JSFunction> function,Handle<Object> prototype)211 Handle<Object> SetPrototype(Handle<JSFunction> function,
212                             Handle<Object> prototype) {
213   CALL_HEAP_FUNCTION(Accessors::FunctionSetPrototype(*function,
214                                                      *prototype,
215                                                      NULL),
216                      Object);
217 }
218 
219 
SetProperty(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyAttributes attributes)220 Handle<Object> SetProperty(Handle<JSObject> object,
221                            Handle<String> key,
222                            Handle<Object> value,
223                            PropertyAttributes attributes) {
224   CALL_HEAP_FUNCTION(object->SetProperty(*key, *value, attributes), Object);
225 }
226 
227 
SetProperty(Handle<Object> object,Handle<Object> key,Handle<Object> value,PropertyAttributes attributes)228 Handle<Object> SetProperty(Handle<Object> object,
229                            Handle<Object> key,
230                            Handle<Object> value,
231                            PropertyAttributes attributes) {
232   CALL_HEAP_FUNCTION(
233       Runtime::SetObjectProperty(object, key, value, attributes), Object);
234 }
235 
236 
ForceSetProperty(Handle<JSObject> object,Handle<Object> key,Handle<Object> value,PropertyAttributes attributes)237 Handle<Object> ForceSetProperty(Handle<JSObject> object,
238                                 Handle<Object> key,
239                                 Handle<Object> value,
240                                 PropertyAttributes attributes) {
241   CALL_HEAP_FUNCTION(
242       Runtime::ForceSetObjectProperty(object, key, value, attributes), Object);
243 }
244 
245 
SetNormalizedProperty(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyDetails details)246 Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
247                                      Handle<String> key,
248                                      Handle<Object> value,
249                                      PropertyDetails details) {
250   CALL_HEAP_FUNCTION(object->SetNormalizedProperty(*key, *value, details),
251                      Object);
252 }
253 
254 
ForceDeleteProperty(Handle<JSObject> object,Handle<Object> key)255 Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
256                                    Handle<Object> key) {
257   CALL_HEAP_FUNCTION(Runtime::ForceDeleteObjectProperty(object, key), Object);
258 }
259 
260 
IgnoreAttributesAndSetLocalProperty(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyAttributes attributes)261 Handle<Object> IgnoreAttributesAndSetLocalProperty(
262     Handle<JSObject> object,
263     Handle<String> key,
264     Handle<Object> value,
265     PropertyAttributes attributes) {
266   CALL_HEAP_FUNCTION(object->
267       IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object);
268 }
269 
270 
SetPropertyWithInterceptor(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyAttributes attributes)271 Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
272                                           Handle<String> key,
273                                           Handle<Object> value,
274                                           PropertyAttributes attributes) {
275   CALL_HEAP_FUNCTION(object->SetPropertyWithInterceptor(*key,
276                                                         *value,
277                                                         attributes),
278                      Object);
279 }
280 
281 
GetProperty(Handle<JSObject> obj,const char * name)282 Handle<Object> GetProperty(Handle<JSObject> obj,
283                            const char* name) {
284   Handle<String> str = Factory::LookupAsciiSymbol(name);
285   CALL_HEAP_FUNCTION(obj->GetProperty(*str), Object);
286 }
287 
288 
GetProperty(Handle<Object> obj,Handle<Object> key)289 Handle<Object> GetProperty(Handle<Object> obj,
290                            Handle<Object> key) {
291   CALL_HEAP_FUNCTION(Runtime::GetObjectProperty(obj, key), Object);
292 }
293 
294 
GetPropertyWithInterceptor(Handle<JSObject> receiver,Handle<JSObject> holder,Handle<String> name,PropertyAttributes * attributes)295 Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
296                                           Handle<JSObject> holder,
297                                           Handle<String> name,
298                                           PropertyAttributes* attributes) {
299   CALL_HEAP_FUNCTION(holder->GetPropertyWithInterceptor(*receiver,
300                                                         *name,
301                                                         attributes),
302                      Object);
303 }
304 
305 
GetPrototype(Handle<Object> obj)306 Handle<Object> GetPrototype(Handle<Object> obj) {
307   Handle<Object> result(obj->GetPrototype());
308   return result;
309 }
310 
311 
SetPrototype(Handle<JSObject> obj,Handle<Object> value)312 Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) {
313   const bool skip_hidden_prototypes = false;
314   CALL_HEAP_FUNCTION(obj->SetPrototype(*value, skip_hidden_prototypes), Object);
315 }
316 
317 
GetHiddenProperties(Handle<JSObject> obj,bool create_if_needed)318 Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
319                                    bool create_if_needed) {
320   Object* holder = obj->BypassGlobalProxy();
321   if (holder->IsUndefined()) return Factory::undefined_value();
322   obj = Handle<JSObject>(JSObject::cast(holder));
323 
324   if (obj->HasFastProperties()) {
325     // If the object has fast properties, check whether the first slot
326     // in the descriptor array matches the hidden symbol. Since the
327     // hidden symbols hash code is zero (and no other string has hash
328     // code zero) it will always occupy the first entry if present.
329     DescriptorArray* descriptors = obj->map()->instance_descriptors();
330     if ((descriptors->number_of_descriptors() > 0) &&
331         (descriptors->GetKey(0) == Heap::hidden_symbol()) &&
332         descriptors->IsProperty(0)) {
333       ASSERT(descriptors->GetType(0) == FIELD);
334       return Handle<Object>(obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
335     }
336   }
337 
338   // Only attempt to find the hidden properties in the local object and not
339   // in the prototype chain.  Note that HasLocalProperty() can cause a GC in
340   // the general case in the presence of interceptors.
341   if (!obj->HasHiddenPropertiesObject()) {
342     // Hidden properties object not found. Allocate a new hidden properties
343     // object if requested. Otherwise return the undefined value.
344     if (create_if_needed) {
345       Handle<Object> hidden_obj = Factory::NewJSObject(Top::object_function());
346       CALL_HEAP_FUNCTION(obj->SetHiddenPropertiesObject(*hidden_obj), Object);
347     } else {
348       return Factory::undefined_value();
349     }
350   }
351   return Handle<Object>(obj->GetHiddenPropertiesObject());
352 }
353 
354 
DeleteElement(Handle<JSObject> obj,uint32_t index)355 Handle<Object> DeleteElement(Handle<JSObject> obj,
356                              uint32_t index) {
357   CALL_HEAP_FUNCTION(obj->DeleteElement(index, JSObject::NORMAL_DELETION),
358                      Object);
359 }
360 
361 
DeleteProperty(Handle<JSObject> obj,Handle<String> prop)362 Handle<Object> DeleteProperty(Handle<JSObject> obj,
363                               Handle<String> prop) {
364   CALL_HEAP_FUNCTION(obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
365                      Object);
366 }
367 
368 
LookupSingleCharacterStringFromCode(uint32_t index)369 Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) {
370   CALL_HEAP_FUNCTION(Heap::LookupSingleCharacterStringFromCode(index), Object);
371 }
372 
373 
SubString(Handle<String> str,int start,int end)374 Handle<String> SubString(Handle<String> str, int start, int end) {
375   CALL_HEAP_FUNCTION(str->SubString(start, end), String);
376 }
377 
378 
SetElement(Handle<JSObject> object,uint32_t index,Handle<Object> value)379 Handle<Object> SetElement(Handle<JSObject> object,
380                           uint32_t index,
381                           Handle<Object> value) {
382   if (object->HasPixelElements() || object->HasExternalArrayElements()) {
383     if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
384       bool has_exception;
385       Handle<Object> number = Execution::ToNumber(value, &has_exception);
386       if (has_exception) return Handle<Object>();
387       value = number;
388     }
389   }
390   CALL_HEAP_FUNCTION(object->SetElement(index, *value), Object);
391 }
392 
393 
Copy(Handle<JSObject> obj)394 Handle<JSObject> Copy(Handle<JSObject> obj) {
395   CALL_HEAP_FUNCTION(Heap::CopyJSObject(*obj), JSObject);
396 }
397 
398 
399 // Wrappers for scripts are kept alive and cached in weak global
400 // handles referred from proxy objects held by the scripts as long as
401 // they are used. When they are not used anymore, the garbage
402 // collector will call the weak callback on the global handle
403 // associated with the wrapper and get rid of both the wrapper and the
404 // handle.
ClearWrapperCache(Persistent<v8::Value> handle,void *)405 static void ClearWrapperCache(Persistent<v8::Value> handle, void*) {
406 #ifdef ENABLE_HEAP_PROTECTION
407   // Weak reference callbacks are called as if from outside V8.  We
408   // need to reeenter to unprotect the heap.
409   VMState state(OTHER);
410 #endif
411   Handle<Object> cache = Utils::OpenHandle(*handle);
412   JSValue* wrapper = JSValue::cast(*cache);
413   Proxy* proxy = Script::cast(wrapper->value())->wrapper();
414   ASSERT(proxy->proxy() == reinterpret_cast<Address>(cache.location()));
415   proxy->set_proxy(0);
416   GlobalHandles::Destroy(cache.location());
417   Counters::script_wrappers.Decrement();
418 }
419 
420 
GetScriptWrapper(Handle<Script> script)421 Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
422   if (script->wrapper()->proxy() != NULL) {
423     // Return the script wrapper directly from the cache.
424     return Handle<JSValue>(
425         reinterpret_cast<JSValue**>(script->wrapper()->proxy()));
426   }
427 
428   // Construct a new script wrapper.
429   Counters::script_wrappers.Increment();
430   Handle<JSFunction> constructor = Top::script_function();
431   Handle<JSValue> result =
432       Handle<JSValue>::cast(Factory::NewJSObject(constructor));
433   result->set_value(*script);
434 
435   // Create a new weak global handle and use it to cache the wrapper
436   // for future use. The cache will automatically be cleared by the
437   // garbage collector when it is not used anymore.
438   Handle<Object> handle = GlobalHandles::Create(*result);
439   GlobalHandles::MakeWeak(handle.location(), NULL, &ClearWrapperCache);
440   script->wrapper()->set_proxy(reinterpret_cast<Address>(handle.location()));
441   return result;
442 }
443 
444 
445 // Init line_ends array with code positions of line ends inside script
446 // source.
InitScriptLineEnds(Handle<Script> script)447 void InitScriptLineEnds(Handle<Script> script) {
448   if (!script->line_ends()->IsUndefined()) return;
449 
450   if (!script->source()->IsString()) {
451     ASSERT(script->source()->IsUndefined());
452     script->set_line_ends(*(Factory::NewFixedArray(0)));
453     ASSERT(script->line_ends()->IsFixedArray());
454     return;
455   }
456 
457   Handle<String> src(String::cast(script->source()));
458   const int src_len = src->length();
459   Handle<String> new_line = Factory::NewStringFromAscii(CStrVector("\n"));
460 
461   // Pass 1: Identify line count.
462   int line_count = 0;
463   int position = 0;
464   while (position != -1 && position < src_len) {
465     position = Runtime::StringMatch(src, new_line, position);
466     if (position != -1) {
467       position++;
468     }
469     // Even if the last line misses a line end, it is counted.
470     line_count++;
471   }
472 
473   // Pass 2: Fill in line ends positions
474   Handle<FixedArray> array = Factory::NewFixedArray(line_count);
475   int array_index = 0;
476   position = 0;
477   while (position != -1 && position < src_len) {
478     position = Runtime::StringMatch(src, new_line, position);
479     // If the script does not end with a line ending add the final end
480     // position as just past the last line ending.
481     array->set(array_index++,
482                Smi::FromInt(position != -1 ? position++ : src_len));
483   }
484   ASSERT(array_index == line_count);
485 
486   script->set_line_ends(*array);
487   ASSERT(script->line_ends()->IsFixedArray());
488 }
489 
490 
491 // Convert code position into line number.
GetScriptLineNumber(Handle<Script> script,int code_pos)492 int GetScriptLineNumber(Handle<Script> script, int code_pos) {
493   InitScriptLineEnds(script);
494   AssertNoAllocation no_allocation;
495   FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
496   const int line_ends_len = line_ends_array->length();
497 
498   if (!line_ends_len)
499     return -1;
500 
501   if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos)
502     return script->line_offset()->value();
503 
504   int left = 0;
505   int right = line_ends_len;
506   while (int half = (right - left) / 2) {
507     if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
508       right -= half;
509     } else {
510       left += half;
511     }
512   }
513   return right + script->line_offset()->value();
514 }
515 
516 
IterateInstance(ObjectVisitor * v)517 void CustomArguments::IterateInstance(ObjectVisitor* v) {
518   v->VisitPointers(values_, values_ + 4);
519 }
520 
521 
522 // Compute the property keys from the interceptor.
GetKeysForNamedInterceptor(Handle<JSObject> receiver,Handle<JSObject> object)523 v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
524                                                  Handle<JSObject> object) {
525   Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
526   CustomArguments args(interceptor->data(), *receiver, *object);
527   v8::AccessorInfo info(args.end());
528   v8::Handle<v8::Array> result;
529   if (!interceptor->enumerator()->IsUndefined()) {
530     v8::NamedPropertyEnumerator enum_fun =
531         v8::ToCData<v8::NamedPropertyEnumerator>(interceptor->enumerator());
532     LOG(ApiObjectAccess("interceptor-named-enum", *object));
533     {
534       // Leaving JavaScript.
535       VMState state(EXTERNAL);
536       result = enum_fun(info);
537     }
538   }
539   return result;
540 }
541 
542 
543 // Compute the element keys from the interceptor.
GetKeysForIndexedInterceptor(Handle<JSObject> receiver,Handle<JSObject> object)544 v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
545                                                    Handle<JSObject> object) {
546   Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
547   CustomArguments args(interceptor->data(), *receiver, *object);
548   v8::AccessorInfo info(args.end());
549   v8::Handle<v8::Array> result;
550   if (!interceptor->enumerator()->IsUndefined()) {
551     v8::IndexedPropertyEnumerator enum_fun =
552         v8::ToCData<v8::IndexedPropertyEnumerator>(interceptor->enumerator());
553     LOG(ApiObjectAccess("interceptor-indexed-enum", *object));
554     {
555       // Leaving JavaScript.
556       VMState state(EXTERNAL);
557       result = enum_fun(info);
558     }
559   }
560   return result;
561 }
562 
563 
GetKeysInFixedArrayFor(Handle<JSObject> object,KeyCollectionType type)564 Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
565                                           KeyCollectionType type) {
566   Handle<FixedArray> content = Factory::empty_fixed_array();
567   Handle<JSObject> arguments_boilerplate =
568       Handle<JSObject>(
569           Top::context()->global_context()->arguments_boilerplate());
570   Handle<JSFunction> arguments_function =
571       Handle<JSFunction>(
572           JSFunction::cast(arguments_boilerplate->map()->constructor()));
573 
574   // Only collect keys if access is permitted.
575   for (Handle<Object> p = object;
576        *p != Heap::null_value();
577        p = Handle<Object>(p->GetPrototype())) {
578     Handle<JSObject> current(JSObject::cast(*p));
579 
580     // Check access rights if required.
581     if (current->IsAccessCheckNeeded() &&
582       !Top::MayNamedAccess(*current, Heap::undefined_value(),
583                            v8::ACCESS_KEYS)) {
584       Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
585       break;
586     }
587 
588     // Compute the element keys.
589     Handle<FixedArray> element_keys =
590         Factory::NewFixedArray(current->NumberOfEnumElements());
591     current->GetEnumElementKeys(*element_keys);
592     content = UnionOfKeys(content, element_keys);
593 
594     // Add the element keys from the interceptor.
595     if (current->HasIndexedInterceptor()) {
596       v8::Handle<v8::Array> result =
597           GetKeysForIndexedInterceptor(object, current);
598       if (!result.IsEmpty())
599         content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
600     }
601 
602     // We can cache the computed property keys if access checks are
603     // not needed and no interceptors are involved.
604     //
605     // We do not use the cache if the object has elements and
606     // therefore it does not make sense to cache the property names
607     // for arguments objects.  Arguments objects will always have
608     // elements.
609     bool cache_enum_keys =
610         ((current->map()->constructor() != *arguments_function) &&
611          !current->IsAccessCheckNeeded() &&
612          !current->HasNamedInterceptor() &&
613          !current->HasIndexedInterceptor());
614     // Compute the property keys and cache them if possible.
615     content =
616         UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys));
617 
618     // Add the property keys from the interceptor.
619     if (current->HasNamedInterceptor()) {
620       v8::Handle<v8::Array> result =
621           GetKeysForNamedInterceptor(object, current);
622       if (!result.IsEmpty())
623         content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
624     }
625 
626     // If we only want local properties we bail out after the first
627     // iteration.
628     if (type == LOCAL_ONLY)
629       break;
630   }
631   return content;
632 }
633 
634 
GetKeysFor(Handle<JSObject> object)635 Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
636   Counters::for_in.Increment();
637   Handle<FixedArray> elements = GetKeysInFixedArrayFor(object,
638                                                        INCLUDE_PROTOS);
639   return Factory::NewJSArrayWithElements(elements);
640 }
641 
642 
GetEnumPropertyKeys(Handle<JSObject> object,bool cache_result)643 Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
644                                        bool cache_result) {
645   int index = 0;
646   if (object->HasFastProperties()) {
647     if (object->map()->instance_descriptors()->HasEnumCache()) {
648       Counters::enum_cache_hits.Increment();
649       DescriptorArray* desc = object->map()->instance_descriptors();
650       return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache()));
651     }
652     Counters::enum_cache_misses.Increment();
653     int num_enum = object->NumberOfEnumProperties();
654     Handle<FixedArray> storage = Factory::NewFixedArray(num_enum);
655     Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum);
656     Handle<DescriptorArray> descs =
657         Handle<DescriptorArray>(object->map()->instance_descriptors());
658     for (int i = 0; i < descs->number_of_descriptors(); i++) {
659       if (descs->IsProperty(i) && !descs->IsDontEnum(i)) {
660         (*storage)->set(index, descs->GetKey(i));
661         PropertyDetails details(descs->GetDetails(i));
662         (*sort_array)->set(index, Smi::FromInt(details.index()));
663         index++;
664       }
665     }
666     (*storage)->SortPairs(*sort_array, sort_array->length());
667     if (cache_result) {
668       Handle<FixedArray> bridge_storage =
669           Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength);
670       DescriptorArray* desc = object->map()->instance_descriptors();
671       desc->SetEnumCache(*bridge_storage, *storage);
672     }
673     ASSERT(storage->length() == index);
674     return storage;
675   } else {
676     int num_enum = object->NumberOfEnumProperties();
677     Handle<FixedArray> storage = Factory::NewFixedArray(num_enum);
678     Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum);
679     object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array);
680     return storage;
681   }
682 }
683 
684 
EnsureCompiled(Handle<SharedFunctionInfo> shared,ClearExceptionFlag flag)685 bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
686                     ClearExceptionFlag flag) {
687   return shared->is_compiled() || CompileLazyShared(shared, flag);
688 }
689 
690 
CompileLazyHelper(CompilationInfo * info,ClearExceptionFlag flag)691 static bool CompileLazyHelper(CompilationInfo* info,
692                               ClearExceptionFlag flag) {
693   // Compile the source information to a code object.
694   ASSERT(!info->shared_info()->is_compiled());
695   bool result = Compiler::CompileLazy(info);
696   ASSERT(result != Top::has_pending_exception());
697   if (!result && flag == CLEAR_EXCEPTION) Top::clear_pending_exception();
698   return result;
699 }
700 
701 
CompileLazyShared(Handle<SharedFunctionInfo> shared,ClearExceptionFlag flag)702 bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
703                        ClearExceptionFlag flag) {
704   CompilationInfo info(shared);
705   return CompileLazyHelper(&info, flag);
706 }
707 
708 
CompileLazy(Handle<JSFunction> function,Handle<Object> receiver,ClearExceptionFlag flag)709 bool CompileLazy(Handle<JSFunction> function,
710                  Handle<Object> receiver,
711                  ClearExceptionFlag flag) {
712   CompilationInfo info(function, 0, receiver);
713   bool result = CompileLazyHelper(&info, flag);
714   LOG(FunctionCreateEvent(*function));
715   return result;
716 }
717 
718 
CompileLazyInLoop(Handle<JSFunction> function,Handle<Object> receiver,ClearExceptionFlag flag)719 bool CompileLazyInLoop(Handle<JSFunction> function,
720                        Handle<Object> receiver,
721                        ClearExceptionFlag flag) {
722   CompilationInfo info(function, 1, receiver);
723   bool result = CompileLazyHelper(&info, flag);
724   LOG(FunctionCreateEvent(*function));
725   return result;
726 }
727 
728 
729 OptimizedObjectForAddingMultipleProperties::
OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,int expected_additional_properties,bool condition)730 OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
731                                            int expected_additional_properties,
732                                            bool condition) {
733   object_ = object;
734   if (condition && object_->HasFastProperties()) {
735     // Normalize the properties of object to avoid n^2 behavior
736     // when extending the object multiple properties. Indicate the number of
737     // properties to be added.
738     unused_property_fields_ = object->map()->unused_property_fields();
739     NormalizeProperties(object_,
740                         KEEP_INOBJECT_PROPERTIES,
741                         expected_additional_properties);
742     has_been_transformed_ = true;
743 
744   } else {
745     has_been_transformed_ = false;
746   }
747 }
748 
749 
ComputeLazyCompile(int argc)750 Handle<Code> ComputeLazyCompile(int argc) {
751   CALL_HEAP_FUNCTION(StubCache::ComputeLazyCompile(argc), Code);
752 }
753 
754 
755 OptimizedObjectForAddingMultipleProperties::
~OptimizedObjectForAddingMultipleProperties()756 ~OptimizedObjectForAddingMultipleProperties() {
757   // Reoptimize the object to allow fast property access.
758   if (has_been_transformed_) {
759     TransformToFastProperties(object_, unused_property_fields_);
760   }
761 }
762 
763 } }  // namespace v8::internal
764