handles.cc revision 85b71799222b55eb5dd74ea26efe0c64ab655c8c
1// Copyright 2011 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
217Handle<SeededNumberDictionary> NormalizeElements(Handle<JSObject> object) {
218  CALL_HEAP_FUNCTION(object->GetIsolate(),
219                     object->NormalizeElements(),
220                     SeededNumberDictionary);
221}
222
223
224void TransformToFastProperties(Handle<JSObject> object,
225                               int unused_property_fields) {
226  CALL_HEAP_FUNCTION_VOID(
227      object->GetIsolate(),
228      object->TransformToFastProperties(unused_property_fields));
229}
230
231
232Handle<SeededNumberDictionary> SeededNumberDictionarySet(
233    Handle<SeededNumberDictionary> dictionary,
234    uint32_t index,
235    Handle<Object> value,
236    PropertyDetails details) {
237  CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
238                     dictionary->Set(index, *value, details),
239                     SeededNumberDictionary);
240}
241
242
243void FlattenString(Handle<String> string) {
244  CALL_HEAP_FUNCTION_VOID(string->GetIsolate(), string->TryFlatten());
245}
246
247
248Handle<String> FlattenGetString(Handle<String> string) {
249  CALL_HEAP_FUNCTION(string->GetIsolate(), string->TryFlatten(), String);
250}
251
252
253Handle<Object> SetPrototype(Handle<JSFunction> function,
254                            Handle<Object> prototype) {
255  ASSERT(function->should_have_prototype());
256  CALL_HEAP_FUNCTION(function->GetIsolate(),
257                     Accessors::FunctionSetPrototype(*function,
258                                                     *prototype,
259                                                     NULL),
260                     Object);
261}
262
263
264Handle<Object> SetProperty(Handle<JSReceiver> object,
265                           Handle<String> key,
266                           Handle<Object> value,
267                           PropertyAttributes attributes,
268                           StrictModeFlag strict_mode) {
269  CALL_HEAP_FUNCTION(object->GetIsolate(),
270                     object->SetProperty(*key, *value, attributes, strict_mode),
271                     Object);
272}
273
274
275Handle<Object> SetProperty(Handle<Object> object,
276                           Handle<Object> key,
277                           Handle<Object> value,
278                           PropertyAttributes attributes,
279                           StrictModeFlag strict_mode) {
280  Isolate* isolate = Isolate::Current();
281  CALL_HEAP_FUNCTION(
282      isolate,
283      Runtime::SetObjectProperty(
284          isolate, object, key, value, attributes, strict_mode),
285      Object);
286}
287
288
289Handle<Object> ForceSetProperty(Handle<JSObject> object,
290                                Handle<Object> key,
291                                Handle<Object> value,
292                                PropertyAttributes attributes) {
293  Isolate* isolate = object->GetIsolate();
294  CALL_HEAP_FUNCTION(
295      isolate,
296      Runtime::ForceSetObjectProperty(
297          isolate, object, key, value, attributes),
298      Object);
299}
300
301
302Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
303                                     Handle<String> key,
304                                     Handle<Object> value,
305                                     PropertyDetails details) {
306  CALL_HEAP_FUNCTION(object->GetIsolate(),
307                     object->SetNormalizedProperty(*key, *value, details),
308                     Object);
309}
310
311
312Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
313                                   Handle<Object> key) {
314  Isolate* isolate = object->GetIsolate();
315  CALL_HEAP_FUNCTION(isolate,
316                     Runtime::ForceDeleteObjectProperty(isolate, object, key),
317                     Object);
318}
319
320
321Handle<Object> SetLocalPropertyIgnoreAttributes(
322    Handle<JSObject> object,
323    Handle<String> key,
324    Handle<Object> value,
325    PropertyAttributes attributes) {
326  CALL_HEAP_FUNCTION(
327    object->GetIsolate(),
328    object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
329    Object);
330}
331
332
333void SetLocalPropertyNoThrow(Handle<JSObject> object,
334                             Handle<String> key,
335                             Handle<Object> value,
336                             PropertyAttributes attributes) {
337  Isolate* isolate = object->GetIsolate();
338  ASSERT(!isolate->has_pending_exception());
339  CHECK(!SetLocalPropertyIgnoreAttributes(
340        object, key, value, attributes).is_null());
341  CHECK(!isolate->has_pending_exception());
342}
343
344
345Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
346                                          Handle<String> key,
347                                          Handle<Object> value,
348                                          PropertyAttributes attributes,
349                                          StrictModeFlag strict_mode) {
350  CALL_HEAP_FUNCTION(object->GetIsolate(),
351                     object->SetPropertyWithInterceptor(*key,
352                                                        *value,
353                                                        attributes,
354                                                        strict_mode),
355                     Object);
356}
357
358
359Handle<Object> GetProperty(Handle<JSReceiver> obj,
360                           const char* name) {
361  Isolate* isolate = obj->GetIsolate();
362  Handle<String> str = isolate->factory()->LookupAsciiSymbol(name);
363  CALL_HEAP_FUNCTION(isolate, obj->GetProperty(*str), Object);
364}
365
366
367Handle<Object> GetProperty(Handle<Object> obj,
368                           Handle<Object> key) {
369  Isolate* isolate = Isolate::Current();
370  CALL_HEAP_FUNCTION(isolate,
371                     Runtime::GetObjectProperty(isolate, obj, key), Object);
372}
373
374
375Handle<Object> GetProperty(Handle<JSReceiver> obj,
376                           Handle<String> name,
377                           LookupResult* result) {
378  PropertyAttributes attributes;
379  Isolate* isolate = Isolate::Current();
380  CALL_HEAP_FUNCTION(isolate,
381                     obj->GetProperty(*obj, result, *name, &attributes),
382                     Object);
383}
384
385
386Handle<Object> GetElement(Handle<Object> obj,
387                          uint32_t index) {
388  Isolate* isolate = Isolate::Current();
389  CALL_HEAP_FUNCTION(isolate, Runtime::GetElement(obj, index), Object);
390}
391
392
393Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
394                                          Handle<JSObject> holder,
395                                          Handle<String> name,
396                                          PropertyAttributes* attributes) {
397  Isolate* isolate = receiver->GetIsolate();
398  CALL_HEAP_FUNCTION(isolate,
399                     holder->GetPropertyWithInterceptor(*receiver,
400                                                        *name,
401                                                        attributes),
402                     Object);
403}
404
405
406Handle<Object> GetPrototype(Handle<Object> obj) {
407  Handle<Object> result(obj->GetPrototype());
408  return result;
409}
410
411
412Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) {
413  const bool skip_hidden_prototypes = false;
414  CALL_HEAP_FUNCTION(obj->GetIsolate(),
415                     obj->SetPrototype(*value, skip_hidden_prototypes), Object);
416}
417
418
419Handle<Object> PreventExtensions(Handle<JSObject> object) {
420  CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
421}
422
423
424Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
425                                   JSObject::HiddenPropertiesFlag flag) {
426  CALL_HEAP_FUNCTION(obj->GetIsolate(),
427                     obj->GetHiddenProperties(flag),
428                     Object);
429}
430
431
432int GetIdentityHash(Handle<JSObject> obj) {
433  CALL_AND_RETRY(obj->GetIsolate(),
434                 obj->GetIdentityHash(JSObject::ALLOW_CREATION),
435                 return Smi::cast(__object__)->value(),
436                 return 0);
437}
438
439
440Handle<Object> DeleteElement(Handle<JSObject> obj,
441                             uint32_t index) {
442  CALL_HEAP_FUNCTION(obj->GetIsolate(),
443                     obj->DeleteElement(index, JSObject::NORMAL_DELETION),
444                     Object);
445}
446
447
448Handle<Object> DeleteProperty(Handle<JSObject> obj,
449                              Handle<String> prop) {
450  CALL_HEAP_FUNCTION(obj->GetIsolate(),
451                     obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
452                     Object);
453}
454
455
456Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) {
457  Isolate* isolate = Isolate::Current();
458  CALL_HEAP_FUNCTION(
459      isolate,
460      isolate->heap()->LookupSingleCharacterStringFromCode(index), Object);
461}
462
463
464Handle<String> SubString(Handle<String> str,
465                         int start,
466                         int end,
467                         PretenureFlag pretenure) {
468  CALL_HEAP_FUNCTION(str->GetIsolate(),
469                     str->SubString(start, end, pretenure), String);
470}
471
472
473Handle<Object> SetElement(Handle<JSObject> object,
474                          uint32_t index,
475                          Handle<Object> value,
476                          StrictModeFlag strict_mode) {
477  if (object->HasExternalArrayElements()) {
478    if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
479      bool has_exception;
480      Handle<Object> number = Execution::ToNumber(value, &has_exception);
481      if (has_exception) return Handle<Object>();
482      value = number;
483    }
484  }
485  CALL_HEAP_FUNCTION(object->GetIsolate(),
486                     object->SetElement(index, *value, strict_mode, true),
487                     Object);
488}
489
490
491Handle<Object> SetOwnElement(Handle<JSObject> object,
492                             uint32_t index,
493                             Handle<Object> value,
494                             StrictModeFlag strict_mode) {
495  ASSERT(!object->HasExternalArrayElements());
496  CALL_HEAP_FUNCTION(object->GetIsolate(),
497                     object->SetElement(index, *value, strict_mode, false),
498                     Object);
499}
500
501
502Handle<JSObject> Copy(Handle<JSObject> obj) {
503  Isolate* isolate = obj->GetIsolate();
504  CALL_HEAP_FUNCTION(isolate,
505                     isolate->heap()->CopyJSObject(*obj), JSObject);
506}
507
508
509Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info) {
510  CALL_HEAP_FUNCTION(obj->GetIsolate(), obj->DefineAccessor(*info), Object);
511}
512
513
514// Wrappers for scripts are kept alive and cached in weak global
515// handles referred from foreign objects held by the scripts as long as
516// they are used. When they are not used anymore, the garbage
517// collector will call the weak callback on the global handle
518// associated with the wrapper and get rid of both the wrapper and the
519// handle.
520static void ClearWrapperCache(Persistent<v8::Value> handle, void*) {
521  Handle<Object> cache = Utils::OpenHandle(*handle);
522  JSValue* wrapper = JSValue::cast(*cache);
523  Foreign* foreign = Script::cast(wrapper->value())->wrapper();
524  ASSERT(foreign->address() == reinterpret_cast<Address>(cache.location()));
525  foreign->set_address(0);
526  Isolate* isolate = Isolate::Current();
527  isolate->global_handles()->Destroy(cache.location());
528  isolate->counters()->script_wrappers()->Decrement();
529}
530
531
532Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
533  if (script->wrapper()->address() != NULL) {
534    // Return the script wrapper directly from the cache.
535    return Handle<JSValue>(
536        reinterpret_cast<JSValue**>(script->wrapper()->address()));
537  }
538  Isolate* isolate = Isolate::Current();
539  // Construct a new script wrapper.
540  isolate->counters()->script_wrappers()->Increment();
541  Handle<JSFunction> constructor = isolate->script_function();
542  Handle<JSValue> result =
543      Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
544  result->set_value(*script);
545
546  // Create a new weak global handle and use it to cache the wrapper
547  // for future use. The cache will automatically be cleared by the
548  // garbage collector when it is not used anymore.
549  Handle<Object> handle = isolate->global_handles()->Create(*result);
550  isolate->global_handles()->MakeWeak(handle.location(), NULL,
551                                      &ClearWrapperCache);
552  script->wrapper()->set_address(reinterpret_cast<Address>(handle.location()));
553  return result;
554}
555
556
557// Init line_ends array with code positions of line ends inside script
558// source.
559void InitScriptLineEnds(Handle<Script> script) {
560  if (!script->line_ends()->IsUndefined()) return;
561
562  Isolate* isolate = script->GetIsolate();
563
564  if (!script->source()->IsString()) {
565    ASSERT(script->source()->IsUndefined());
566    Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
567    script->set_line_ends(*empty);
568    ASSERT(script->line_ends()->IsFixedArray());
569    return;
570  }
571
572  Handle<String> src(String::cast(script->source()), isolate);
573
574  Handle<FixedArray> array = CalculateLineEnds(src, true);
575
576  if (*array != isolate->heap()->empty_fixed_array()) {
577    array->set_map(isolate->heap()->fixed_cow_array_map());
578  }
579
580  script->set_line_ends(*array);
581  ASSERT(script->line_ends()->IsFixedArray());
582}
583
584
585template <typename SourceChar>
586static void CalculateLineEnds(Isolate* isolate,
587                              List<int>* line_ends,
588                              Vector<const SourceChar> src,
589                              bool with_last_line) {
590  const int src_len = src.length();
591  StringSearch<char, SourceChar> search(isolate, CStrVector("\n"));
592
593  // Find and record line ends.
594  int position = 0;
595  while (position != -1 && position < src_len) {
596    position = search.Search(src, position);
597    if (position != -1) {
598      line_ends->Add(position);
599      position++;
600    } else if (with_last_line) {
601      // Even if the last line misses a line end, it is counted.
602      line_ends->Add(src_len);
603      return;
604    }
605  }
606}
607
608
609Handle<FixedArray> CalculateLineEnds(Handle<String> src,
610                                     bool with_last_line) {
611  src = FlattenGetString(src);
612  // Rough estimate of line count based on a roughly estimated average
613  // length of (unpacked) code.
614  int line_count_estimate = src->length() >> 4;
615  List<int> line_ends(line_count_estimate);
616  Isolate* isolate = src->GetIsolate();
617  {
618    AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid.
619    // Dispatch on type of strings.
620    String::FlatContent content = src->GetFlatContent();
621    ASSERT(content.IsFlat());
622    if (content.IsAscii()) {
623      CalculateLineEnds(isolate,
624                        &line_ends,
625                        content.ToAsciiVector(),
626                        with_last_line);
627    } else {
628      CalculateLineEnds(isolate,
629                        &line_ends,
630                        content.ToUC16Vector(),
631                        with_last_line);
632    }
633  }
634  int line_count = line_ends.length();
635  Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
636  for (int i = 0; i < line_count; i++) {
637    array->set(i, Smi::FromInt(line_ends[i]));
638  }
639  return array;
640}
641
642
643// Convert code position into line number.
644int GetScriptLineNumber(Handle<Script> script, int code_pos) {
645  InitScriptLineEnds(script);
646  AssertNoAllocation no_allocation;
647  FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
648  const int line_ends_len = line_ends_array->length();
649
650  if (!line_ends_len) return -1;
651
652  if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
653    return script->line_offset()->value();
654  }
655
656  int left = 0;
657  int right = line_ends_len;
658  while (int half = (right - left) / 2) {
659    if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
660      right -= half;
661    } else {
662      left += half;
663    }
664  }
665  return right + script->line_offset()->value();
666}
667
668
669int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) {
670  AssertNoAllocation no_allocation;
671  if (!script->line_ends()->IsUndefined()) {
672    return GetScriptLineNumber(script, code_pos);
673  }
674  // Slow mode: we do not have line_ends. We have to iterate through source.
675  if (!script->source()->IsString()) {
676    return -1;
677  }
678  String* source = String::cast(script->source());
679  int line = 0;
680  int len = source->length();
681  for (int pos = 0; pos < len; pos++) {
682    if (pos == code_pos) {
683      break;
684    }
685    if (source->Get(pos) == '\n') {
686      line++;
687    }
688  }
689  return line;
690}
691
692
693void CustomArguments::IterateInstance(ObjectVisitor* v) {
694  v->VisitPointers(values_, values_ + ARRAY_SIZE(values_));
695}
696
697
698// Compute the property keys from the interceptor.
699v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
700                                                 Handle<JSObject> object) {
701  Isolate* isolate = receiver->GetIsolate();
702  Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
703  CustomArguments args(isolate, interceptor->data(), *receiver, *object);
704  v8::AccessorInfo info(args.end());
705  v8::Handle<v8::Array> result;
706  if (!interceptor->enumerator()->IsUndefined()) {
707    v8::NamedPropertyEnumerator enum_fun =
708        v8::ToCData<v8::NamedPropertyEnumerator>(interceptor->enumerator());
709    LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object));
710    {
711      // Leaving JavaScript.
712      VMState state(isolate, EXTERNAL);
713      result = enum_fun(info);
714    }
715  }
716  return result;
717}
718
719
720// Compute the element keys from the interceptor.
721v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
722                                                   Handle<JSObject> object) {
723  Isolate* isolate = receiver->GetIsolate();
724  Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
725  CustomArguments args(isolate, interceptor->data(), *receiver, *object);
726  v8::AccessorInfo info(args.end());
727  v8::Handle<v8::Array> result;
728  if (!interceptor->enumerator()->IsUndefined()) {
729    v8::IndexedPropertyEnumerator enum_fun =
730        v8::ToCData<v8::IndexedPropertyEnumerator>(interceptor->enumerator());
731    LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object));
732    {
733      // Leaving JavaScript.
734      VMState state(isolate, EXTERNAL);
735      result = enum_fun(info);
736    }
737  }
738  return result;
739}
740
741
742static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
743  int len = array->length();
744  for (int i = 0; i < len; i++) {
745    Object* e = array->get(i);
746    if (!(e->IsString() || e->IsNumber())) return false;
747  }
748  return true;
749}
750
751
752Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
753                                          KeyCollectionType type) {
754  USE(ContainsOnlyValidKeys);
755  Isolate* isolate = object->GetIsolate();
756  Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
757  Handle<JSObject> arguments_boilerplate = Handle<JSObject>(
758      isolate->context()->global_context()->arguments_boilerplate(),
759      isolate);
760  Handle<JSFunction> arguments_function = Handle<JSFunction>(
761      JSFunction::cast(arguments_boilerplate->map()->constructor()),
762      isolate);
763
764  // Only collect keys if access is permitted.
765  for (Handle<Object> p = object;
766       *p != isolate->heap()->null_value();
767       p = Handle<Object>(p->GetPrototype(), isolate)) {
768    Handle<JSObject> current(JSObject::cast(*p), isolate);
769
770    // Check access rights if required.
771    if (current->IsAccessCheckNeeded() &&
772        !isolate->MayNamedAccess(*current,
773                                 isolate->heap()->undefined_value(),
774                                 v8::ACCESS_KEYS)) {
775      isolate->ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
776      break;
777    }
778
779    // Compute the element keys.
780    Handle<FixedArray> element_keys =
781        isolate->factory()->NewFixedArray(current->NumberOfEnumElements());
782    current->GetEnumElementKeys(*element_keys);
783    content = UnionOfKeys(content, element_keys);
784    ASSERT(ContainsOnlyValidKeys(content));
785
786    // Add the element keys from the interceptor.
787    if (current->HasIndexedInterceptor()) {
788      v8::Handle<v8::Array> result =
789          GetKeysForIndexedInterceptor(object, current);
790      if (!result.IsEmpty())
791        content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
792      ASSERT(ContainsOnlyValidKeys(content));
793    }
794
795    // We can cache the computed property keys if access checks are
796    // not needed and no interceptors are involved.
797    //
798    // We do not use the cache if the object has elements and
799    // therefore it does not make sense to cache the property names
800    // for arguments objects.  Arguments objects will always have
801    // elements.
802    // Wrapped strings have elements, but don't have an elements
803    // array or dictionary.  So the fast inline test for whether to
804    // use the cache says yes, so we should not create a cache.
805    bool cache_enum_keys =
806        ((current->map()->constructor() != *arguments_function) &&
807         !current->IsJSValue() &&
808         !current->IsAccessCheckNeeded() &&
809         !current->HasNamedInterceptor() &&
810         !current->HasIndexedInterceptor());
811    // Compute the property keys and cache them if possible.
812    content =
813        UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys));
814    ASSERT(ContainsOnlyValidKeys(content));
815
816    // Add the property keys from the interceptor.
817    if (current->HasNamedInterceptor()) {
818      v8::Handle<v8::Array> result =
819          GetKeysForNamedInterceptor(object, current);
820      if (!result.IsEmpty())
821        content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
822      ASSERT(ContainsOnlyValidKeys(content));
823    }
824
825    // If we only want local properties we bail out after the first
826    // iteration.
827    if (type == LOCAL_ONLY)
828      break;
829  }
830  return content;
831}
832
833
834Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
835  Isolate* isolate = object->GetIsolate();
836  isolate->counters()->for_in()->Increment();
837  Handle<FixedArray> elements = GetKeysInFixedArrayFor(object,
838                                                       INCLUDE_PROTOS);
839  return isolate->factory()->NewJSArrayWithElements(elements);
840}
841
842
843Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
844                                       bool cache_result) {
845  int index = 0;
846  Isolate* isolate = object->GetIsolate();
847  if (object->HasFastProperties()) {
848    if (object->map()->instance_descriptors()->HasEnumCache()) {
849      isolate->counters()->enum_cache_hits()->Increment();
850      DescriptorArray* desc = object->map()->instance_descriptors();
851      return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache()),
852                                isolate);
853    }
854    isolate->counters()->enum_cache_misses()->Increment();
855    int num_enum = object->NumberOfEnumProperties();
856    Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum);
857    Handle<FixedArray> sort_array = isolate->factory()->NewFixedArray(num_enum);
858    Handle<DescriptorArray> descs =
859        Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
860    for (int i = 0; i < descs->number_of_descriptors(); i++) {
861      if (descs->IsProperty(i) && !descs->IsDontEnum(i)) {
862        (*storage)->set(index, descs->GetKey(i));
863        PropertyDetails details(descs->GetDetails(i));
864        (*sort_array)->set(index, Smi::FromInt(details.index()));
865        index++;
866      }
867    }
868    (*storage)->SortPairs(*sort_array, sort_array->length());
869    if (cache_result) {
870      Handle<FixedArray> bridge_storage =
871          isolate->factory()->NewFixedArray(
872              DescriptorArray::kEnumCacheBridgeLength);
873      DescriptorArray* desc = object->map()->instance_descriptors();
874      desc->SetEnumCache(*bridge_storage, *storage);
875    }
876    ASSERT(storage->length() == index);
877    return storage;
878  } else {
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    object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array);
883    return storage;
884  }
885}
886
887
888Handle<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
889                                               Handle<JSObject> key,
890                                               Handle<Object> value) {
891  CALL_HEAP_FUNCTION(table->GetIsolate(),
892                     table->Put(*key, *value),
893                     ObjectHashTable);
894}
895
896
897bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
898                    ClearExceptionFlag flag) {
899  return shared->is_compiled() || CompileLazyShared(shared, flag);
900}
901
902
903static bool CompileLazyHelper(CompilationInfo* info,
904                              ClearExceptionFlag flag) {
905  // Compile the source information to a code object.
906  ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
907  ASSERT(!info->isolate()->has_pending_exception());
908  bool result = Compiler::CompileLazy(info);
909  ASSERT(result != Isolate::Current()->has_pending_exception());
910  if (!result && flag == CLEAR_EXCEPTION) {
911    info->isolate()->clear_pending_exception();
912  }
913  return result;
914}
915
916
917bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
918                       ClearExceptionFlag flag) {
919  CompilationInfo info(shared);
920  return CompileLazyHelper(&info, flag);
921}
922
923
924bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag) {
925  bool result = true;
926  if (function->shared()->is_compiled()) {
927    function->ReplaceCode(function->shared()->code());
928    function->shared()->set_code_age(0);
929  } else {
930    CompilationInfo info(function);
931    result = CompileLazyHelper(&info, flag);
932    ASSERT(!result || function->is_compiled());
933  }
934  return result;
935}
936
937
938bool CompileOptimized(Handle<JSFunction> function,
939                      int osr_ast_id,
940                      ClearExceptionFlag flag) {
941  CompilationInfo info(function);
942  info.SetOptimizing(osr_ast_id);
943  return CompileLazyHelper(&info, flag);
944}
945
946} }  // namespace v8::internal
947