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#include "string-search.h"
41#include "stub-cache.h"
42#include "vm-state-inl.h"
43
44namespace v8 {
45namespace internal {
46
47
48int HandleScope::NumberOfHandles() {
49  Isolate* isolate = Isolate::Current();
50  HandleScopeImplementer* impl = isolate->handle_scope_implementer();
51  int n = impl->blocks()->length();
52  if (n == 0) return 0;
53  return ((n - 1) * kHandleBlockSize) + static_cast<int>(
54      (isolate->handle_scope_data()->next - impl->blocks()->last()));
55}
56
57
58Object** HandleScope::Extend() {
59  Isolate* isolate = Isolate::Current();
60  v8::ImplementationUtilities::HandleScopeData* current =
61      isolate->handle_scope_data();
62
63  Object** result = current->next;
64
65  ASSERT(result == current->limit);
66  // Make sure there's at least one scope on the stack and that the
67  // top of the scope stack isn't a barrier.
68  if (current->level == 0) {
69    Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
70                            "Cannot create a handle without a HandleScope");
71    return NULL;
72  }
73  HandleScopeImplementer* impl = isolate->handle_scope_implementer();
74  // If there's more room in the last block, we use that. This is used
75  // for fast creation of scopes after scope barriers.
76  if (!impl->blocks()->is_empty()) {
77    Object** limit = &impl->blocks()->last()[kHandleBlockSize];
78    if (current->limit != limit) {
79      current->limit = limit;
80      ASSERT(limit - current->next < kHandleBlockSize);
81    }
82  }
83
84  // If we still haven't found a slot for the handle, we extend the
85  // current handle scope by allocating a new handle block.
86  if (result == current->limit) {
87    // If there's a spare block, use it for growing the current scope.
88    result = impl->GetSpareOrNewBlock();
89    // Add the extension to the global list of blocks, but count the
90    // extension as part of the current scope.
91    impl->blocks()->Add(result);
92    current->limit = &result[kHandleBlockSize];
93  }
94
95  return result;
96}
97
98
99void HandleScope::DeleteExtensions(Isolate* isolate) {
100  ASSERT(isolate == Isolate::Current());
101  v8::ImplementationUtilities::HandleScopeData* current =
102      isolate->handle_scope_data();
103  isolate->handle_scope_implementer()->DeleteExtensions(current->limit);
104}
105
106
107void HandleScope::ZapRange(Object** start, Object** end) {
108  ASSERT(end - start <= kHandleBlockSize);
109  for (Object** p = start; p != end; p++) {
110    *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue;
111  }
112}
113
114
115Address HandleScope::current_level_address() {
116  return reinterpret_cast<Address>(
117      &Isolate::Current()->handle_scope_data()->level);
118}
119
120
121Address HandleScope::current_next_address() {
122  return reinterpret_cast<Address>(
123      &Isolate::Current()->handle_scope_data()->next);
124}
125
126
127Address HandleScope::current_limit_address() {
128  return reinterpret_cast<Address>(
129      &Isolate::Current()->handle_scope_data()->limit);
130}
131
132
133Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content,
134                                      Handle<JSArray> array) {
135  CALL_HEAP_FUNCTION(content->GetIsolate(),
136                     content->AddKeysFromJSArray(*array), FixedArray);
137}
138
139
140Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first,
141                               Handle<FixedArray> second) {
142  CALL_HEAP_FUNCTION(first->GetIsolate(),
143                     first->UnionOfKeys(*second), FixedArray);
144}
145
146
147Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
148    Handle<JSFunction> constructor,
149    Handle<JSGlobalProxy> global) {
150  CALL_HEAP_FUNCTION(
151      constructor->GetIsolate(),
152      constructor->GetHeap()->ReinitializeJSGlobalProxy(*constructor, *global),
153      JSGlobalProxy);
154}
155
156
157void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
158  // If objects constructed from this function exist then changing
159  // 'estimated_nof_properties' is dangerous since the previous value might
160  // have been compiled into the fast construct stub. More over, the inobject
161  // slack tracking logic might have adjusted the previous value, so even
162  // passing the same value is risky.
163  if (func->shared()->live_objects_may_exist()) return;
164
165  func->shared()->set_expected_nof_properties(nof);
166  if (func->has_initial_map()) {
167    Handle<Map> new_initial_map =
168        func->GetIsolate()->factory()->CopyMapDropTransitions(
169            Handle<Map>(func->initial_map()));
170    new_initial_map->set_unused_property_fields(nof);
171    func->set_initial_map(*new_initial_map);
172  }
173}
174
175
176void SetPrototypeProperty(Handle<JSFunction> func, Handle<JSObject> value) {
177  CALL_HEAP_FUNCTION_VOID(func->GetIsolate(),
178                          func->SetPrototype(*value));
179}
180
181
182static int ExpectedNofPropertiesFromEstimate(int estimate) {
183  // If no properties are added in the constructor, they are more likely
184  // to be added later.
185  if (estimate == 0) estimate = 2;
186
187  // We do not shrink objects that go into a snapshot (yet), so we adjust
188  // the estimate conservatively.
189  if (Serializer::enabled()) return estimate + 2;
190
191  // Inobject slack tracking will reclaim redundant inobject space later,
192  // so we can afford to adjust the estimate generously.
193  return estimate + 8;
194}
195
196
197void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
198                                          int estimate) {
199  // See the comment in SetExpectedNofProperties.
200  if (shared->live_objects_may_exist()) return;
201
202  shared->set_expected_nof_properties(
203      ExpectedNofPropertiesFromEstimate(estimate));
204}
205
206
207void NormalizeProperties(Handle<JSObject> object,
208                         PropertyNormalizationMode mode,
209                         int expected_additional_properties) {
210  CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
211                          object->NormalizeProperties(
212                              mode,
213                              expected_additional_properties));
214}
215
216
217void NormalizeElements(Handle<JSObject> object) {
218  CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
219                          object->NormalizeElements());
220}
221
222
223void TransformToFastProperties(Handle<JSObject> object,
224                               int unused_property_fields) {
225  CALL_HEAP_FUNCTION_VOID(
226      object->GetIsolate(),
227      object->TransformToFastProperties(unused_property_fields));
228}
229
230
231void NumberDictionarySet(Handle<NumberDictionary> dictionary,
232                         uint32_t index,
233                         Handle<Object> value,
234                         PropertyDetails details) {
235  CALL_HEAP_FUNCTION_VOID(dictionary->GetIsolate(),
236                          dictionary->Set(index, *value, details));
237}
238
239
240void FlattenString(Handle<String> string) {
241  CALL_HEAP_FUNCTION_VOID(string->GetIsolate(), string->TryFlatten());
242}
243
244
245Handle<String> FlattenGetString(Handle<String> string) {
246  CALL_HEAP_FUNCTION(string->GetIsolate(), string->TryFlatten(), String);
247}
248
249
250Handle<Object> SetPrototype(Handle<JSFunction> function,
251                            Handle<Object> prototype) {
252  ASSERT(function->should_have_prototype());
253  CALL_HEAP_FUNCTION(function->GetIsolate(),
254                     Accessors::FunctionSetPrototype(*function,
255                                                     *prototype,
256                                                     NULL),
257                     Object);
258}
259
260
261Handle<Object> SetProperty(Handle<JSObject> object,
262                           Handle<String> key,
263                           Handle<Object> value,
264                           PropertyAttributes attributes,
265                           StrictModeFlag strict_mode) {
266  CALL_HEAP_FUNCTION(object->GetIsolate(),
267                     object->SetProperty(*key, *value, attributes, strict_mode),
268                     Object);
269}
270
271
272Handle<Object> SetProperty(Handle<Object> object,
273                           Handle<Object> key,
274                           Handle<Object> value,
275                           PropertyAttributes attributes,
276                           StrictModeFlag strict_mode) {
277  Isolate* isolate = Isolate::Current();
278  CALL_HEAP_FUNCTION(
279      isolate,
280      Runtime::SetObjectProperty(
281          isolate, object, key, value, attributes, strict_mode),
282      Object);
283}
284
285
286Handle<Object> ForceSetProperty(Handle<JSObject> object,
287                                Handle<Object> key,
288                                Handle<Object> value,
289                                PropertyAttributes attributes) {
290  Isolate* isolate = object->GetIsolate();
291  CALL_HEAP_FUNCTION(
292      isolate,
293      Runtime::ForceSetObjectProperty(
294          isolate, object, key, value, attributes),
295      Object);
296}
297
298
299Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
300                                     Handle<String> key,
301                                     Handle<Object> value,
302                                     PropertyDetails details) {
303  CALL_HEAP_FUNCTION(object->GetIsolate(),
304                     object->SetNormalizedProperty(*key, *value, details),
305                     Object);
306}
307
308
309Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
310                                   Handle<Object> key) {
311  Isolate* isolate = object->GetIsolate();
312  CALL_HEAP_FUNCTION(isolate,
313                     Runtime::ForceDeleteObjectProperty(isolate, object, key),
314                     Object);
315}
316
317
318Handle<Object> SetLocalPropertyIgnoreAttributes(
319    Handle<JSObject> object,
320    Handle<String> key,
321    Handle<Object> value,
322    PropertyAttributes attributes) {
323  CALL_HEAP_FUNCTION(
324    object->GetIsolate(),
325    object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
326    Object);
327}
328
329
330void SetLocalPropertyNoThrow(Handle<JSObject> object,
331                             Handle<String> key,
332                             Handle<Object> value,
333                             PropertyAttributes attributes) {
334  Isolate* isolate = object->GetIsolate();
335  ASSERT(!isolate->has_pending_exception());
336  CHECK(!SetLocalPropertyIgnoreAttributes(
337        object, key, value, attributes).is_null());
338  CHECK(!isolate->has_pending_exception());
339}
340
341
342Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
343                                          Handle<String> key,
344                                          Handle<Object> value,
345                                          PropertyAttributes attributes,
346                                          StrictModeFlag strict_mode) {
347  CALL_HEAP_FUNCTION(object->GetIsolate(),
348                     object->SetPropertyWithInterceptor(*key,
349                                                        *value,
350                                                        attributes,
351                                                        strict_mode),
352                     Object);
353}
354
355
356Handle<Object> GetProperty(Handle<JSObject> obj,
357                           const char* name) {
358  Isolate* isolate = obj->GetIsolate();
359  Handle<String> str = isolate->factory()->LookupAsciiSymbol(name);
360  CALL_HEAP_FUNCTION(isolate, obj->GetProperty(*str), Object);
361}
362
363
364Handle<Object> GetProperty(Handle<Object> obj,
365                           Handle<Object> key) {
366  Isolate* isolate = Isolate::Current();
367  CALL_HEAP_FUNCTION(isolate,
368                     Runtime::GetObjectProperty(isolate, obj, key), Object);
369}
370
371
372Handle<Object> GetProperty(Handle<JSObject> obj,
373                           Handle<String> name,
374                           LookupResult* result) {
375  PropertyAttributes attributes;
376  Isolate* isolate = Isolate::Current();
377  CALL_HEAP_FUNCTION(isolate,
378                     obj->GetProperty(*obj, result, *name, &attributes),
379                     Object);
380}
381
382
383Handle<Object> GetElement(Handle<Object> obj,
384                          uint32_t index) {
385  Isolate* isolate = Isolate::Current();
386  CALL_HEAP_FUNCTION(isolate, Runtime::GetElement(obj, index), Object);
387}
388
389
390Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
391                                          Handle<JSObject> holder,
392                                          Handle<String> name,
393                                          PropertyAttributes* attributes) {
394  Isolate* isolate = receiver->GetIsolate();
395  CALL_HEAP_FUNCTION(isolate,
396                     holder->GetPropertyWithInterceptor(*receiver,
397                                                        *name,
398                                                        attributes),
399                     Object);
400}
401
402
403Handle<Object> GetPrototype(Handle<Object> obj) {
404  Handle<Object> result(obj->GetPrototype());
405  return result;
406}
407
408
409Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) {
410  const bool skip_hidden_prototypes = false;
411  CALL_HEAP_FUNCTION(obj->GetIsolate(),
412                     obj->SetPrototype(*value, skip_hidden_prototypes), Object);
413}
414
415
416Handle<Object> PreventExtensions(Handle<JSObject> object) {
417  CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
418}
419
420
421Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
422                                   bool create_if_needed) {
423  Isolate* isolate = obj->GetIsolate();
424  Object* holder = obj->BypassGlobalProxy();
425  if (holder->IsUndefined()) return isolate->factory()->undefined_value();
426  obj = Handle<JSObject>(JSObject::cast(holder), isolate);
427
428  if (obj->HasFastProperties()) {
429    // If the object has fast properties, check whether the first slot
430    // in the descriptor array matches the hidden symbol. Since the
431    // hidden symbols hash code is zero (and no other string has hash
432    // code zero) it will always occupy the first entry if present.
433    DescriptorArray* descriptors = obj->map()->instance_descriptors();
434    if ((descriptors->number_of_descriptors() > 0) &&
435        (descriptors->GetKey(0) == isolate->heap()->hidden_symbol()) &&
436        descriptors->IsProperty(0)) {
437      ASSERT(descriptors->GetType(0) == FIELD);
438      return Handle<Object>(obj->FastPropertyAt(descriptors->GetFieldIndex(0)),
439                            isolate);
440    }
441  }
442
443  // Only attempt to find the hidden properties in the local object and not
444  // in the prototype chain.  Note that HasLocalProperty() can cause a GC in
445  // the general case in the presence of interceptors.
446  if (!obj->HasHiddenPropertiesObject()) {
447    // Hidden properties object not found. Allocate a new hidden properties
448    // object if requested. Otherwise return the undefined value.
449    if (create_if_needed) {
450      Handle<Object> hidden_obj =
451          isolate->factory()->NewJSObject(isolate->object_function());
452      CALL_HEAP_FUNCTION(isolate,
453                         obj->SetHiddenPropertiesObject(*hidden_obj), Object);
454    } else {
455      return isolate->factory()->undefined_value();
456    }
457  }
458  return Handle<Object>(obj->GetHiddenPropertiesObject(), isolate);
459}
460
461
462Handle<Object> DeleteElement(Handle<JSObject> obj,
463                             uint32_t index) {
464  CALL_HEAP_FUNCTION(obj->GetIsolate(),
465                     obj->DeleteElement(index, JSObject::NORMAL_DELETION),
466                     Object);
467}
468
469
470Handle<Object> DeleteProperty(Handle<JSObject> obj,
471                              Handle<String> prop) {
472  CALL_HEAP_FUNCTION(obj->GetIsolate(),
473                     obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
474                     Object);
475}
476
477
478Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) {
479  Isolate* isolate = Isolate::Current();
480  CALL_HEAP_FUNCTION(
481      isolate,
482      isolate->heap()->LookupSingleCharacterStringFromCode(index), Object);
483}
484
485
486Handle<String> SubString(Handle<String> str,
487                         int start,
488                         int end,
489                         PretenureFlag pretenure) {
490  CALL_HEAP_FUNCTION(str->GetIsolate(),
491                     str->SubString(start, end, pretenure), String);
492}
493
494
495Handle<Object> SetElement(Handle<JSObject> object,
496                          uint32_t index,
497                          Handle<Object> value,
498                          StrictModeFlag strict_mode) {
499  if (object->HasExternalArrayElements()) {
500    if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
501      bool has_exception;
502      Handle<Object> number = Execution::ToNumber(value, &has_exception);
503      if (has_exception) return Handle<Object>();
504      value = number;
505    }
506  }
507  CALL_HEAP_FUNCTION(object->GetIsolate(),
508                     object->SetElement(index, *value, strict_mode), Object);
509}
510
511
512Handle<Object> SetOwnElement(Handle<JSObject> object,
513                             uint32_t index,
514                             Handle<Object> value,
515                             StrictModeFlag strict_mode) {
516  ASSERT(!object->HasExternalArrayElements());
517  CALL_HEAP_FUNCTION(object->GetIsolate(),
518                     object->SetElement(index, *value, strict_mode, false),
519                     Object);
520}
521
522
523Handle<JSObject> Copy(Handle<JSObject> obj) {
524  Isolate* isolate = obj->GetIsolate();
525  CALL_HEAP_FUNCTION(isolate,
526                     isolate->heap()->CopyJSObject(*obj), JSObject);
527}
528
529
530Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info) {
531  CALL_HEAP_FUNCTION(obj->GetIsolate(), obj->DefineAccessor(*info), Object);
532}
533
534
535// Wrappers for scripts are kept alive and cached in weak global
536// handles referred from proxy objects held by the scripts as long as
537// they are used. When they are not used anymore, the garbage
538// collector will call the weak callback on the global handle
539// associated with the wrapper and get rid of both the wrapper and the
540// handle.
541static void ClearWrapperCache(Persistent<v8::Value> handle, void*) {
542#ifdef ENABLE_HEAP_PROTECTION
543  // Weak reference callbacks are called as if from outside V8.  We
544  // need to reeenter to unprotect the heap.
545  VMState state(OTHER);
546#endif
547  Handle<Object> cache = Utils::OpenHandle(*handle);
548  JSValue* wrapper = JSValue::cast(*cache);
549  Proxy* proxy = Script::cast(wrapper->value())->wrapper();
550  ASSERT(proxy->proxy() == reinterpret_cast<Address>(cache.location()));
551  proxy->set_proxy(0);
552  Isolate* isolate = Isolate::Current();
553  isolate->global_handles()->Destroy(cache.location());
554  isolate->counters()->script_wrappers()->Decrement();
555}
556
557
558Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
559  if (script->wrapper()->proxy() != NULL) {
560    // Return the script wrapper directly from the cache.
561    return Handle<JSValue>(
562        reinterpret_cast<JSValue**>(script->wrapper()->proxy()));
563  }
564  Isolate* isolate = Isolate::Current();
565  // Construct a new script wrapper.
566  isolate->counters()->script_wrappers()->Increment();
567  Handle<JSFunction> constructor = isolate->script_function();
568  Handle<JSValue> result =
569      Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
570  result->set_value(*script);
571
572  // Create a new weak global handle and use it to cache the wrapper
573  // for future use. The cache will automatically be cleared by the
574  // garbage collector when it is not used anymore.
575  Handle<Object> handle = isolate->global_handles()->Create(*result);
576  isolate->global_handles()->MakeWeak(handle.location(), NULL,
577                                      &ClearWrapperCache);
578  script->wrapper()->set_proxy(reinterpret_cast<Address>(handle.location()));
579  return result;
580}
581
582
583// Init line_ends array with code positions of line ends inside script
584// source.
585void InitScriptLineEnds(Handle<Script> script) {
586  if (!script->line_ends()->IsUndefined()) return;
587
588  Isolate* isolate = script->GetIsolate();
589
590  if (!script->source()->IsString()) {
591    ASSERT(script->source()->IsUndefined());
592    Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
593    script->set_line_ends(*empty);
594    ASSERT(script->line_ends()->IsFixedArray());
595    return;
596  }
597
598  Handle<String> src(String::cast(script->source()), isolate);
599
600  Handle<FixedArray> array = CalculateLineEnds(src, true);
601
602  if (*array != isolate->heap()->empty_fixed_array()) {
603    array->set_map(isolate->heap()->fixed_cow_array_map());
604  }
605
606  script->set_line_ends(*array);
607  ASSERT(script->line_ends()->IsFixedArray());
608}
609
610
611template <typename SourceChar>
612static void CalculateLineEnds(Isolate* isolate,
613                              List<int>* line_ends,
614                              Vector<const SourceChar> src,
615                              bool with_last_line) {
616  const int src_len = src.length();
617  StringSearch<char, SourceChar> search(isolate, CStrVector("\n"));
618
619  // Find and record line ends.
620  int position = 0;
621  while (position != -1 && position < src_len) {
622    position = search.Search(src, position);
623    if (position != -1) {
624      line_ends->Add(position);
625      position++;
626    } else if (with_last_line) {
627      // Even if the last line misses a line end, it is counted.
628      line_ends->Add(src_len);
629      return;
630    }
631  }
632}
633
634
635Handle<FixedArray> CalculateLineEnds(Handle<String> src,
636                                     bool with_last_line) {
637  src = FlattenGetString(src);
638  // Rough estimate of line count based on a roughly estimated average
639  // length of (unpacked) code.
640  int line_count_estimate = src->length() >> 4;
641  List<int> line_ends(line_count_estimate);
642  Isolate* isolate = src->GetIsolate();
643  {
644    AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid.
645    // Dispatch on type of strings.
646    if (src->IsAsciiRepresentation()) {
647      CalculateLineEnds(isolate,
648                        &line_ends,
649                        src->ToAsciiVector(),
650                        with_last_line);
651    } else {
652      CalculateLineEnds(isolate,
653                        &line_ends,
654                        src->ToUC16Vector(),
655                        with_last_line);
656    }
657  }
658  int line_count = line_ends.length();
659  Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
660  for (int i = 0; i < line_count; i++) {
661    array->set(i, Smi::FromInt(line_ends[i]));
662  }
663  return array;
664}
665
666
667// Convert code position into line number.
668int GetScriptLineNumber(Handle<Script> script, int code_pos) {
669  InitScriptLineEnds(script);
670  AssertNoAllocation no_allocation;
671  FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
672  const int line_ends_len = line_ends_array->length();
673
674  if (!line_ends_len) return -1;
675
676  if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
677    return script->line_offset()->value();
678  }
679
680  int left = 0;
681  int right = line_ends_len;
682  while (int half = (right - left) / 2) {
683    if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
684      right -= half;
685    } else {
686      left += half;
687    }
688  }
689  return right + script->line_offset()->value();
690}
691
692
693int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) {
694  AssertNoAllocation no_allocation;
695  if (!script->line_ends()->IsUndefined()) {
696    return GetScriptLineNumber(script, code_pos);
697  }
698  // Slow mode: we do not have line_ends. We have to iterate through source.
699  if (!script->source()->IsString()) {
700    return -1;
701  }
702  String* source = String::cast(script->source());
703  int line = 0;
704  int len = source->length();
705  for (int pos = 0; pos < len; pos++) {
706    if (pos == code_pos) {
707      break;
708    }
709    if (source->Get(pos) == '\n') {
710      line++;
711    }
712  }
713  return line;
714}
715
716
717void CustomArguments::IterateInstance(ObjectVisitor* v) {
718  v->VisitPointers(values_, values_ + ARRAY_SIZE(values_));
719}
720
721
722// Compute the property keys from the interceptor.
723v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
724                                                 Handle<JSObject> object) {
725  Isolate* isolate = receiver->GetIsolate();
726  Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
727  CustomArguments args(isolate, interceptor->data(), *receiver, *object);
728  v8::AccessorInfo info(args.end());
729  v8::Handle<v8::Array> result;
730  if (!interceptor->enumerator()->IsUndefined()) {
731    v8::NamedPropertyEnumerator enum_fun =
732        v8::ToCData<v8::NamedPropertyEnumerator>(interceptor->enumerator());
733    LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object));
734    {
735      // Leaving JavaScript.
736      VMState state(isolate, EXTERNAL);
737      result = enum_fun(info);
738    }
739  }
740  return result;
741}
742
743
744// Compute the element keys from the interceptor.
745v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
746                                                   Handle<JSObject> object) {
747  Isolate* isolate = receiver->GetIsolate();
748  Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
749  CustomArguments args(isolate, interceptor->data(), *receiver, *object);
750  v8::AccessorInfo info(args.end());
751  v8::Handle<v8::Array> result;
752  if (!interceptor->enumerator()->IsUndefined()) {
753    v8::IndexedPropertyEnumerator enum_fun =
754        v8::ToCData<v8::IndexedPropertyEnumerator>(interceptor->enumerator());
755    LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object));
756    {
757      // Leaving JavaScript.
758      VMState state(isolate, EXTERNAL);
759      result = enum_fun(info);
760    }
761  }
762  return result;
763}
764
765
766static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
767  int len = array->length();
768  for (int i = 0; i < len; i++) {
769    Object* e = array->get(i);
770    if (!(e->IsString() || e->IsNumber())) return false;
771  }
772  return true;
773}
774
775
776Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
777                                          KeyCollectionType type) {
778  USE(ContainsOnlyValidKeys);
779  Isolate* isolate = object->GetIsolate();
780  Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
781  Handle<JSObject> arguments_boilerplate = Handle<JSObject>(
782      isolate->context()->global_context()->arguments_boilerplate(),
783      isolate);
784  Handle<JSFunction> arguments_function = Handle<JSFunction>(
785      JSFunction::cast(arguments_boilerplate->map()->constructor()),
786      isolate);
787
788  // Only collect keys if access is permitted.
789  for (Handle<Object> p = object;
790       *p != isolate->heap()->null_value();
791       p = Handle<Object>(p->GetPrototype(), isolate)) {
792    Handle<JSObject> current(JSObject::cast(*p), isolate);
793
794    // Check access rights if required.
795    if (current->IsAccessCheckNeeded() &&
796        !isolate->MayNamedAccess(*current,
797                                 isolate->heap()->undefined_value(),
798                                 v8::ACCESS_KEYS)) {
799      isolate->ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
800      break;
801    }
802
803    // Compute the element keys.
804    Handle<FixedArray> element_keys =
805        isolate->factory()->NewFixedArray(current->NumberOfEnumElements());
806    current->GetEnumElementKeys(*element_keys);
807    content = UnionOfKeys(content, element_keys);
808    ASSERT(ContainsOnlyValidKeys(content));
809
810    // Add the element keys from the interceptor.
811    if (current->HasIndexedInterceptor()) {
812      v8::Handle<v8::Array> result =
813          GetKeysForIndexedInterceptor(object, current);
814      if (!result.IsEmpty())
815        content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
816      ASSERT(ContainsOnlyValidKeys(content));
817    }
818
819    // We can cache the computed property keys if access checks are
820    // not needed and no interceptors are involved.
821    //
822    // We do not use the cache if the object has elements and
823    // therefore it does not make sense to cache the property names
824    // for arguments objects.  Arguments objects will always have
825    // elements.
826    // Wrapped strings have elements, but don't have an elements
827    // array or dictionary.  So the fast inline test for whether to
828    // use the cache says yes, so we should not create a cache.
829    bool cache_enum_keys =
830        ((current->map()->constructor() != *arguments_function) &&
831         !current->IsJSValue() &&
832         !current->IsAccessCheckNeeded() &&
833         !current->HasNamedInterceptor() &&
834         !current->HasIndexedInterceptor());
835    // Compute the property keys and cache them if possible.
836    content =
837        UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys));
838    ASSERT(ContainsOnlyValidKeys(content));
839
840    // Add the property keys from the interceptor.
841    if (current->HasNamedInterceptor()) {
842      v8::Handle<v8::Array> result =
843          GetKeysForNamedInterceptor(object, current);
844      if (!result.IsEmpty())
845        content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
846      ASSERT(ContainsOnlyValidKeys(content));
847    }
848
849    // If we only want local properties we bail out after the first
850    // iteration.
851    if (type == LOCAL_ONLY)
852      break;
853  }
854  return content;
855}
856
857
858Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
859  Isolate* isolate = object->GetIsolate();
860  isolate->counters()->for_in()->Increment();
861  Handle<FixedArray> elements = GetKeysInFixedArrayFor(object,
862                                                       INCLUDE_PROTOS);
863  return isolate->factory()->NewJSArrayWithElements(elements);
864}
865
866
867Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
868                                       bool cache_result) {
869  int index = 0;
870  Isolate* isolate = object->GetIsolate();
871  if (object->HasFastProperties()) {
872    if (object->map()->instance_descriptors()->HasEnumCache()) {
873      isolate->counters()->enum_cache_hits()->Increment();
874      DescriptorArray* desc = object->map()->instance_descriptors();
875      return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache()),
876                                isolate);
877    }
878    isolate->counters()->enum_cache_misses()->Increment();
879    int num_enum = object->NumberOfEnumProperties();
880    Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum);
881    Handle<FixedArray> sort_array = isolate->factory()->NewFixedArray(num_enum);
882    Handle<DescriptorArray> descs =
883        Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
884    for (int i = 0; i < descs->number_of_descriptors(); i++) {
885      if (descs->IsProperty(i) && !descs->IsDontEnum(i)) {
886        (*storage)->set(index, descs->GetKey(i));
887        PropertyDetails details(descs->GetDetails(i));
888        (*sort_array)->set(index, Smi::FromInt(details.index()));
889        index++;
890      }
891    }
892    (*storage)->SortPairs(*sort_array, sort_array->length());
893    if (cache_result) {
894      Handle<FixedArray> bridge_storage =
895          isolate->factory()->NewFixedArray(
896              DescriptorArray::kEnumCacheBridgeLength);
897      DescriptorArray* desc = object->map()->instance_descriptors();
898      desc->SetEnumCache(*bridge_storage, *storage);
899    }
900    ASSERT(storage->length() == index);
901    return storage;
902  } else {
903    int num_enum = object->NumberOfEnumProperties();
904    Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum);
905    Handle<FixedArray> sort_array = isolate->factory()->NewFixedArray(num_enum);
906    object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array);
907    return storage;
908  }
909}
910
911
912bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
913                    ClearExceptionFlag flag) {
914  return shared->is_compiled() || CompileLazyShared(shared, flag);
915}
916
917
918static bool CompileLazyHelper(CompilationInfo* info,
919                              ClearExceptionFlag flag) {
920  // Compile the source information to a code object.
921  ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
922  ASSERT(!info->isolate()->has_pending_exception());
923  bool result = Compiler::CompileLazy(info);
924  ASSERT(result != Isolate::Current()->has_pending_exception());
925  if (!result && flag == CLEAR_EXCEPTION) {
926    info->isolate()->clear_pending_exception();
927  }
928  return result;
929}
930
931
932bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
933                       ClearExceptionFlag flag) {
934  CompilationInfo info(shared);
935  return CompileLazyHelper(&info, flag);
936}
937
938
939static bool CompileLazyFunction(Handle<JSFunction> function,
940                                ClearExceptionFlag flag,
941                                InLoopFlag in_loop_flag) {
942  bool result = true;
943  if (function->shared()->is_compiled()) {
944    function->ReplaceCode(function->shared()->code());
945    function->shared()->set_code_age(0);
946  } else {
947    CompilationInfo info(function);
948    if (in_loop_flag == IN_LOOP) info.MarkAsInLoop();
949    result = CompileLazyHelper(&info, flag);
950    ASSERT(!result || function->is_compiled());
951  }
952  return result;
953}
954
955
956bool CompileLazy(Handle<JSFunction> function,
957                 ClearExceptionFlag flag) {
958  return CompileLazyFunction(function, flag, NOT_IN_LOOP);
959}
960
961
962bool CompileLazyInLoop(Handle<JSFunction> function,
963                       ClearExceptionFlag flag) {
964  return CompileLazyFunction(function, flag, IN_LOOP);
965}
966
967
968bool CompileOptimized(Handle<JSFunction> function,
969                      int osr_ast_id,
970                      ClearExceptionFlag flag) {
971  CompilationInfo info(function);
972  info.SetOptimizing(osr_ast_id);
973  return CompileLazyHelper(&info, flag);
974}
975
976} }  // namespace v8::internal
977