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