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