The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / handles.cc @ f230a1cf

History | View | Annotate | Download (30.3 KB)

1
// Copyright 2012 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

    
44
namespace v8 {
45
namespace internal {
46

    
47

    
48
int HandleScope::NumberOfHandles(Isolate* isolate) {
49
  HandleScopeImplementer* impl = isolate->handle_scope_implementer();
50
  int n = impl->blocks()->length();
51
  if (n == 0) return 0;
52
  return ((n - 1) * kHandleBlockSize) + static_cast<int>(
53
      (isolate->handle_scope_data()->next - impl->blocks()->last()));
54
}
55

    
56

    
57
Object** HandleScope::Extend(Isolate* isolate) {
58
  v8::ImplementationUtilities::HandleScopeData* current =
59
      isolate->handle_scope_data();
60

    
61
  Object** result = current->next;
62

    
63
  ASSERT(result == current->limit);
64
  // Make sure there's at least one scope on the stack and that the
65
  // top of the scope stack isn't a barrier.
66
  if (current->level == 0) {
67
    Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
68
                            "Cannot create a handle without a HandleScope");
69
    return NULL;
70
  }
71
  HandleScopeImplementer* impl = isolate->handle_scope_implementer();
72
  // If there's more room in the last block, we use that. This is used
73
  // for fast creation of scopes after scope barriers.
74
  if (!impl->blocks()->is_empty()) {
75
    Object** limit = &impl->blocks()->last()[kHandleBlockSize];
76
    if (current->limit != limit) {
77
      current->limit = limit;
78
      ASSERT(limit - current->next < kHandleBlockSize);
79
    }
80
  }
81

    
82
  // If we still haven't found a slot for the handle, we extend the
83
  // current handle scope by allocating a new handle block.
84
  if (result == current->limit) {
85
    // If there's a spare block, use it for growing the current scope.
86
    result = impl->GetSpareOrNewBlock();
87
    // Add the extension to the global list of blocks, but count the
88
    // extension as part of the current scope.
89
    impl->blocks()->Add(result);
90
    current->limit = &result[kHandleBlockSize];
91
  }
92

    
93
  return result;
94
}
95

    
96

    
97
void HandleScope::DeleteExtensions(Isolate* isolate) {
98
  v8::ImplementationUtilities::HandleScopeData* current =
99
      isolate->handle_scope_data();
100
  isolate->handle_scope_implementer()->DeleteExtensions(current->limit);
101
}
102

    
103

    
104
#ifdef ENABLE_HANDLE_ZAPPING
105
void HandleScope::ZapRange(Object** start, Object** end) {
106
  ASSERT(end - start <= kHandleBlockSize);
107
  for (Object** p = start; p != end; p++) {
108
    *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue;
109
  }
110
}
111
#endif
112

    
113

    
114
Address HandleScope::current_level_address(Isolate* isolate) {
115
  return reinterpret_cast<Address>(&isolate->handle_scope_data()->level);
116
}
117

    
118

    
119
Address HandleScope::current_next_address(Isolate* isolate) {
120
  return reinterpret_cast<Address>(&isolate->handle_scope_data()->next);
121
}
122

    
123

    
124
Address HandleScope::current_limit_address(Isolate* isolate) {
125
  return reinterpret_cast<Address>(&isolate->handle_scope_data()->limit);
126
}
127

    
128

    
129
Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content,
130
                                      Handle<JSArray> array) {
131
  CALL_HEAP_FUNCTION(content->GetIsolate(),
132
                     content->AddKeysFromJSArray(*array), FixedArray);
133
}
134

    
135

    
136
Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first,
137
                               Handle<FixedArray> second) {
138
  CALL_HEAP_FUNCTION(first->GetIsolate(),
139
                     first->UnionOfKeys(*second), FixedArray);
140
}
141

    
142

    
143
Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
144
    Handle<JSFunction> constructor,
145
    Handle<JSGlobalProxy> global) {
146
  CALL_HEAP_FUNCTION(
147
      constructor->GetIsolate(),
148
      constructor->GetHeap()->ReinitializeJSGlobalProxy(*constructor, *global),
149
      JSGlobalProxy);
150
}
151

    
152

    
153
void FlattenString(Handle<String> string) {
154
  CALL_HEAP_FUNCTION_VOID(string->GetIsolate(), string->TryFlatten());
155
}
156

    
157

    
158
Handle<String> FlattenGetString(Handle<String> string) {
159
  CALL_HEAP_FUNCTION(string->GetIsolate(), string->TryFlatten(), String);
160
}
161

    
162

    
163
Handle<Object> SetProperty(Isolate* isolate,
164
                           Handle<Object> object,
165
                           Handle<Object> key,
166
                           Handle<Object> value,
167
                           PropertyAttributes attributes,
168
                           StrictModeFlag strict_mode) {
169
  CALL_HEAP_FUNCTION(
170
      isolate,
171
      Runtime::SetObjectProperty(
172
          isolate, object, key, value, attributes, strict_mode),
173
      Object);
174
}
175

    
176

    
177
Handle<Object> ForceSetProperty(Handle<JSObject> object,
178
                                Handle<Object> key,
179
                                Handle<Object> value,
180
                                PropertyAttributes attributes) {
181
  Isolate* isolate = object->GetIsolate();
182
  CALL_HEAP_FUNCTION(
183
      isolate,
184
      Runtime::ForceSetObjectProperty(
185
          isolate, object, key, value, attributes),
186
      Object);
187
}
188

    
189

    
190
Handle<Object> DeleteProperty(Handle<JSObject> object, Handle<Object> key) {
191
  Isolate* isolate = object->GetIsolate();
192
  CALL_HEAP_FUNCTION(isolate,
193
                     Runtime::DeleteObjectProperty(
194
                         isolate, object, key, JSReceiver::NORMAL_DELETION),
195
                     Object);
196
}
197

    
198

    
199
Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
200
                                   Handle<Object> key) {
201
  Isolate* isolate = object->GetIsolate();
202
  CALL_HEAP_FUNCTION(isolate,
203
                     Runtime::DeleteObjectProperty(
204
                         isolate, object, key, JSReceiver::FORCE_DELETION),
205
                     Object);
206
}
207

    
208

    
209
Handle<Object> HasProperty(Handle<JSReceiver> obj, Handle<Object> key) {
210
  Isolate* isolate = obj->GetIsolate();
211
  CALL_HEAP_FUNCTION(isolate,
212
                     Runtime::HasObjectProperty(isolate, obj, key), Object);
213
}
214

    
215

    
216
Handle<Object> GetProperty(Handle<JSReceiver> obj,
217
                           const char* name) {
218
  Isolate* isolate = obj->GetIsolate();
219
  Handle<String> str = isolate->factory()->InternalizeUtf8String(name);
220
  CALL_HEAP_FUNCTION(isolate, obj->GetProperty(*str), Object);
221
}
222

    
223

    
224
Handle<Object> GetProperty(Isolate* isolate,
225
                           Handle<Object> obj,
226
                           Handle<Object> key) {
227
  CALL_HEAP_FUNCTION(isolate,
228
                     Runtime::GetObjectProperty(isolate, obj, key), Object);
229
}
230

    
231

    
232
Handle<Object> LookupSingleCharacterStringFromCode(Isolate* isolate,
233
                                                   uint32_t index) {
234
  CALL_HEAP_FUNCTION(
235
      isolate,
236
      isolate->heap()->LookupSingleCharacterStringFromCode(index), Object);
237
}
238

    
239

    
240
// Wrappers for scripts are kept alive and cached in weak global
241
// handles referred from foreign objects held by the scripts as long as
242
// they are used. When they are not used anymore, the garbage
243
// collector will call the weak callback on the global handle
244
// associated with the wrapper and get rid of both the wrapper and the
245
// handle.
246
static void ClearWrapperCache(v8::Isolate* v8_isolate,
247
                              Persistent<v8::Value>* handle,
248
                              void*) {
249
  Handle<Object> cache = Utils::OpenPersistent(handle);
250
  JSValue* wrapper = JSValue::cast(*cache);
251
  Foreign* foreign = Script::cast(wrapper->value())->wrapper();
252
  ASSERT(foreign->foreign_address() ==
253
         reinterpret_cast<Address>(cache.location()));
254
  foreign->set_foreign_address(0);
255
  Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
256
  isolate->global_handles()->Destroy(cache.location());
257
  isolate->counters()->script_wrappers()->Decrement();
258
}
259

    
260

    
261
Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
262
  if (script->wrapper()->foreign_address() != NULL) {
263
    // Return the script wrapper directly from the cache.
264
    return Handle<JSValue>(
265
        reinterpret_cast<JSValue**>(script->wrapper()->foreign_address()));
266
  }
267
  Isolate* isolate = script->GetIsolate();
268
  // Construct a new script wrapper.
269
  isolate->counters()->script_wrappers()->Increment();
270
  Handle<JSFunction> constructor = isolate->script_function();
271
  Handle<JSValue> result =
272
      Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
273

    
274
  // The allocation might have triggered a GC, which could have called this
275
  // function recursively, and a wrapper has already been created and cached.
276
  // In that case, simply return the cached wrapper.
277
  if (script->wrapper()->foreign_address() != NULL) {
278
    return Handle<JSValue>(
279
        reinterpret_cast<JSValue**>(script->wrapper()->foreign_address()));
280
  }
281

    
282
  result->set_value(*script);
283

    
284
  // Create a new weak global handle and use it to cache the wrapper
285
  // for future use. The cache will automatically be cleared by the
286
  // garbage collector when it is not used anymore.
287
  Handle<Object> handle = isolate->global_handles()->Create(*result);
288
  isolate->global_handles()->MakeWeak(handle.location(),
289
                                      NULL,
290
                                      &ClearWrapperCache);
291
  script->wrapper()->set_foreign_address(
292
      reinterpret_cast<Address>(handle.location()));
293
  return result;
294
}
295

    
296

    
297
// Init line_ends array with code positions of line ends inside script
298
// source.
299
void InitScriptLineEnds(Handle<Script> script) {
300
  if (!script->line_ends()->IsUndefined()) return;
301

    
302
  Isolate* isolate = script->GetIsolate();
303

    
304
  if (!script->source()->IsString()) {
305
    ASSERT(script->source()->IsUndefined());
306
    Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
307
    script->set_line_ends(*empty);
308
    ASSERT(script->line_ends()->IsFixedArray());
309
    return;
310
  }
311

    
312
  Handle<String> src(String::cast(script->source()), isolate);
313

    
314
  Handle<FixedArray> array = CalculateLineEnds(src, true);
315

    
316
  if (*array != isolate->heap()->empty_fixed_array()) {
317
    array->set_map(isolate->heap()->fixed_cow_array_map());
318
  }
319

    
320
  script->set_line_ends(*array);
321
  ASSERT(script->line_ends()->IsFixedArray());
322
}
323

    
324

    
325
template <typename SourceChar>
326
static void CalculateLineEnds(Isolate* isolate,
327
                              List<int>* line_ends,
328
                              Vector<const SourceChar> src,
329
                              bool with_last_line) {
330
  const int src_len = src.length();
331
  StringSearch<uint8_t, SourceChar> search(isolate, STATIC_ASCII_VECTOR("\n"));
332

    
333
  // Find and record line ends.
334
  int position = 0;
335
  while (position != -1 && position < src_len) {
336
    position = search.Search(src, position);
337
    if (position != -1) {
338
      line_ends->Add(position);
339
      position++;
340
    } else if (with_last_line) {
341
      // Even if the last line misses a line end, it is counted.
342
      line_ends->Add(src_len);
343
      return;
344
    }
345
  }
346
}
347

    
348

    
349
Handle<FixedArray> CalculateLineEnds(Handle<String> src,
350
                                     bool with_last_line) {
351
  src = FlattenGetString(src);
352
  // Rough estimate of line count based on a roughly estimated average
353
  // length of (unpacked) code.
354
  int line_count_estimate = src->length() >> 4;
355
  List<int> line_ends(line_count_estimate);
356
  Isolate* isolate = src->GetIsolate();
357
  {
358
    DisallowHeapAllocation no_allocation;  // ensure vectors stay valid.
359
    // Dispatch on type of strings.
360
    String::FlatContent content = src->GetFlatContent();
361
    ASSERT(content.IsFlat());
362
    if (content.IsAscii()) {
363
      CalculateLineEnds(isolate,
364
                        &line_ends,
365
                        content.ToOneByteVector(),
366
                        with_last_line);
367
    } else {
368
      CalculateLineEnds(isolate,
369
                        &line_ends,
370
                        content.ToUC16Vector(),
371
                        with_last_line);
372
    }
373
  }
374
  int line_count = line_ends.length();
375
  Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
376
  for (int i = 0; i < line_count; i++) {
377
    array->set(i, Smi::FromInt(line_ends[i]));
378
  }
379
  return array;
380
}
381

    
382

    
383
// Convert code position into line number.
384
int GetScriptLineNumber(Handle<Script> script, int code_pos) {
385
  InitScriptLineEnds(script);
386
  DisallowHeapAllocation no_allocation;
387
  FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
388
  const int line_ends_len = line_ends_array->length();
389

    
390
  if (!line_ends_len) return -1;
391

    
392
  if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
393
    return script->line_offset()->value();
394
  }
395

    
396
  int left = 0;
397
  int right = line_ends_len;
398
  while (int half = (right - left) / 2) {
399
    if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
400
      right -= half;
401
    } else {
402
      left += half;
403
    }
404
  }
405
  return right + script->line_offset()->value();
406
}
407

    
408

    
409
// Convert code position into column number.
410
int GetScriptColumnNumber(Handle<Script> script, int code_pos) {
411
  int line_number = GetScriptLineNumber(script, code_pos);
412
  if (line_number == -1) return -1;
413

    
414
  DisallowHeapAllocation no_allocation;
415
  FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
416
  line_number = line_number - script->line_offset()->value();
417
  if (line_number == 0) return code_pos + script->column_offset()->value();
418
  int prev_line_end_pos =
419
      Smi::cast(line_ends_array->get(line_number - 1))->value();
420
  return code_pos - (prev_line_end_pos + 1);
421
}
422

    
423

    
424
int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) {
425
  DisallowHeapAllocation no_allocation;
426
  if (!script->line_ends()->IsUndefined()) {
427
    return GetScriptLineNumber(script, code_pos);
428
  }
429
  // Slow mode: we do not have line_ends. We have to iterate through source.
430
  if (!script->source()->IsString()) {
431
    return -1;
432
  }
433
  String* source = String::cast(script->source());
434
  int line = 0;
435
  int len = source->length();
436
  for (int pos = 0; pos < len; pos++) {
437
    if (pos == code_pos) {
438
      break;
439
    }
440
    if (source->Get(pos) == '\n') {
441
      line++;
442
    }
443
  }
444
  return line;
445
}
446

    
447

    
448
// Compute the property keys from the interceptor.
449
// TODO(rossberg): support symbols in API, and filter here if needed.
450
v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSReceiver> receiver,
451
                                                 Handle<JSObject> object) {
452
  Isolate* isolate = receiver->GetIsolate();
453
  Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
454
  PropertyCallbackArguments
455
      args(isolate, interceptor->data(), *receiver, *object);
456
  v8::Handle<v8::Array> result;
457
  if (!interceptor->enumerator()->IsUndefined()) {
458
    v8::NamedPropertyEnumeratorCallback enum_fun =
459
        v8::ToCData<v8::NamedPropertyEnumeratorCallback>(
460
            interceptor->enumerator());
461
    LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object));
462
    result = args.Call(enum_fun);
463
  }
464
#if ENABLE_EXTRA_CHECKS
465
  CHECK(result.IsEmpty() || v8::Utils::OpenHandle(*result)->IsJSObject());
466
#endif
467
  return v8::Local<v8::Array>::New(reinterpret_cast<v8::Isolate*>(isolate),
468
                                   result);
469
}
470

    
471

    
472
// Compute the element keys from the interceptor.
473
v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSReceiver> receiver,
474
                                                   Handle<JSObject> object) {
475
  Isolate* isolate = receiver->GetIsolate();
476
  Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
477
  PropertyCallbackArguments
478
      args(isolate, interceptor->data(), *receiver, *object);
479
  v8::Handle<v8::Array> result;
480
  if (!interceptor->enumerator()->IsUndefined()) {
481
    v8::IndexedPropertyEnumeratorCallback enum_fun =
482
        v8::ToCData<v8::IndexedPropertyEnumeratorCallback>(
483
            interceptor->enumerator());
484
    LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object));
485
    result = args.Call(enum_fun);
486
#if ENABLE_EXTRA_CHECKS
487
    CHECK(result.IsEmpty() || v8::Utils::OpenHandle(*result)->IsJSObject());
488
#endif
489
  }
490
  return v8::Local<v8::Array>::New(reinterpret_cast<v8::Isolate*>(isolate),
491
                                   result);
492
}
493

    
494

    
495
Handle<Object> GetScriptNameOrSourceURL(Handle<Script> script) {
496
  Isolate* isolate = script->GetIsolate();
497
  Handle<String> name_or_source_url_key =
498
      isolate->factory()->InternalizeOneByteString(
499
          STATIC_ASCII_VECTOR("nameOrSourceURL"));
500
  Handle<JSValue> script_wrapper = GetScriptWrapper(script);
501
  Handle<Object> property = GetProperty(isolate,
502
                                        script_wrapper,
503
                                        name_or_source_url_key);
504
  ASSERT(property->IsJSFunction());
505
  Handle<JSFunction> method = Handle<JSFunction>::cast(property);
506
  bool caught_exception;
507
  Handle<Object> result = Execution::TryCall(method, script_wrapper, 0,
508
                                             NULL, &caught_exception);
509
  if (caught_exception) {
510
    result = isolate->factory()->undefined_value();
511
  }
512
  return result;
513
}
514

    
515

    
516
static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
517
  int len = array->length();
518
  for (int i = 0; i < len; i++) {
519
    Object* e = array->get(i);
520
    if (!(e->IsString() || e->IsNumber())) return false;
521
  }
522
  return true;
523
}
524

    
525

    
526
Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSReceiver> object,
527
                                          KeyCollectionType type,
528
                                          bool* threw) {
529
  USE(ContainsOnlyValidKeys);
530
  Isolate* isolate = object->GetIsolate();
531
  Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
532
  Handle<JSObject> arguments_boilerplate = Handle<JSObject>(
533
      isolate->context()->native_context()->arguments_boilerplate(),
534
      isolate);
535
  Handle<JSFunction> arguments_function = Handle<JSFunction>(
536
      JSFunction::cast(arguments_boilerplate->map()->constructor()),
537
      isolate);
538

    
539
  // Only collect keys if access is permitted.
540
  for (Handle<Object> p = object;
541
       *p != isolate->heap()->null_value();
542
       p = Handle<Object>(p->GetPrototype(isolate), isolate)) {
543
    if (p->IsJSProxy()) {
544
      Handle<JSProxy> proxy(JSProxy::cast(*p), isolate);
545
      Handle<Object> args[] = { proxy };
546
      Handle<Object> names = Execution::Call(isolate,
547
                                             isolate->proxy_enumerate(),
548
                                             object,
549
                                             ARRAY_SIZE(args),
550
                                             args,
551
                                             threw);
552
      if (*threw) return content;
553
      content = AddKeysFromJSArray(content, Handle<JSArray>::cast(names));
554
      break;
555
    }
556

    
557
    Handle<JSObject> current(JSObject::cast(*p), isolate);
558

    
559
    // Check access rights if required.
560
    if (current->IsAccessCheckNeeded() &&
561
        !isolate->MayNamedAccess(*current,
562
                                 isolate->heap()->undefined_value(),
563
                                 v8::ACCESS_KEYS)) {
564
      isolate->ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
565
      if (isolate->has_scheduled_exception()) {
566
        isolate->PromoteScheduledException();
567
        *threw = true;
568
      }
569
      break;
570
    }
571

    
572
    // Compute the element keys.
573
    Handle<FixedArray> element_keys =
574
        isolate->factory()->NewFixedArray(current->NumberOfEnumElements());
575
    current->GetEnumElementKeys(*element_keys);
576
    content = UnionOfKeys(content, element_keys);
577
    ASSERT(ContainsOnlyValidKeys(content));
578

    
579
    // Add the element keys from the interceptor.
580
    if (current->HasIndexedInterceptor()) {
581
      v8::Handle<v8::Array> result =
582
          GetKeysForIndexedInterceptor(object, current);
583
      if (!result.IsEmpty())
584
        content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
585
      ASSERT(ContainsOnlyValidKeys(content));
586
    }
587

    
588
    // We can cache the computed property keys if access checks are
589
    // not needed and no interceptors are involved.
590
    //
591
    // We do not use the cache if the object has elements and
592
    // therefore it does not make sense to cache the property names
593
    // for arguments objects.  Arguments objects will always have
594
    // elements.
595
    // Wrapped strings have elements, but don't have an elements
596
    // array or dictionary.  So the fast inline test for whether to
597
    // use the cache says yes, so we should not create a cache.
598
    bool cache_enum_keys =
599
        ((current->map()->constructor() != *arguments_function) &&
600
         !current->IsJSValue() &&
601
         !current->IsAccessCheckNeeded() &&
602
         !current->HasNamedInterceptor() &&
603
         !current->HasIndexedInterceptor());
604
    // Compute the property keys and cache them if possible.
605
    content =
606
        UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys));
607
    ASSERT(ContainsOnlyValidKeys(content));
608

    
609
    // Add the property keys from the interceptor.
610
    if (current->HasNamedInterceptor()) {
611
      v8::Handle<v8::Array> result =
612
          GetKeysForNamedInterceptor(object, current);
613
      if (!result.IsEmpty())
614
        content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
615
      ASSERT(ContainsOnlyValidKeys(content));
616
    }
617

    
618
    // If we only want local properties we bail out after the first
619
    // iteration.
620
    if (type == LOCAL_ONLY)
621
      break;
622
  }
623
  return content;
624
}
625

    
626

    
627
Handle<JSArray> GetKeysFor(Handle<JSReceiver> object, bool* threw) {
628
  Isolate* isolate = object->GetIsolate();
629
  isolate->counters()->for_in()->Increment();
630
  Handle<FixedArray> elements =
631
      GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, threw);
632
  return isolate->factory()->NewJSArrayWithElements(elements);
633
}
634

    
635

    
636
Handle<FixedArray> ReduceFixedArrayTo(Handle<FixedArray> array, int length) {
637
  ASSERT(array->length() >= length);
638
  if (array->length() == length) return array;
639

    
640
  Handle<FixedArray> new_array =
641
      array->GetIsolate()->factory()->NewFixedArray(length);
642
  for (int i = 0; i < length; ++i) new_array->set(i, array->get(i));
643
  return new_array;
644
}
645

    
646

    
647
Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
648
                                       bool cache_result) {
649
  Isolate* isolate = object->GetIsolate();
650
  if (object->HasFastProperties()) {
651
    if (object->map()->instance_descriptors()->HasEnumCache()) {
652
      int own_property_count = object->map()->EnumLength();
653
      // If we have an enum cache, but the enum length of the given map is set
654
      // to kInvalidEnumCache, this means that the map itself has never used the
655
      // present enum cache. The first step to using the cache is to set the
656
      // enum length of the map by counting the number of own descriptors that
657
      // are not DONT_ENUM or SYMBOLIC.
658
      if (own_property_count == Map::kInvalidEnumCache) {
659
        own_property_count = object->map()->NumberOfDescribedProperties(
660
            OWN_DESCRIPTORS, DONT_SHOW);
661

    
662
        if (cache_result) object->map()->SetEnumLength(own_property_count);
663
      }
664

    
665
      DescriptorArray* desc = object->map()->instance_descriptors();
666
      Handle<FixedArray> keys(desc->GetEnumCache(), isolate);
667

    
668
      // In case the number of properties required in the enum are actually
669
      // present, we can reuse the enum cache. Otherwise, this means that the
670
      // enum cache was generated for a previous (smaller) version of the
671
      // Descriptor Array. In that case we regenerate the enum cache.
672
      if (own_property_count <= keys->length()) {
673
        isolate->counters()->enum_cache_hits()->Increment();
674
        return ReduceFixedArrayTo(keys, own_property_count);
675
      }
676
    }
677

    
678
    Handle<Map> map(object->map());
679

    
680
    if (map->instance_descriptors()->IsEmpty()) {
681
      isolate->counters()->enum_cache_hits()->Increment();
682
      if (cache_result) map->SetEnumLength(0);
683
      return isolate->factory()->empty_fixed_array();
684
    }
685

    
686
    isolate->counters()->enum_cache_misses()->Increment();
687
    int num_enum = map->NumberOfDescribedProperties(ALL_DESCRIPTORS, DONT_SHOW);
688

    
689
    Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum);
690
    Handle<FixedArray> indices = isolate->factory()->NewFixedArray(num_enum);
691

    
692
    Handle<DescriptorArray> descs =
693
        Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
694

    
695
    int real_size = map->NumberOfOwnDescriptors();
696
    int enum_size = 0;
697
    int index = 0;
698

    
699
    for (int i = 0; i < descs->number_of_descriptors(); i++) {
700
      PropertyDetails details = descs->GetDetails(i);
701
      Object* key = descs->GetKey(i);
702
      if (!(details.IsDontEnum() || key->IsSymbol())) {
703
        if (i < real_size) ++enum_size;
704
        storage->set(index, key);
705
        if (!indices.is_null()) {
706
          if (details.type() != FIELD) {
707
            indices = Handle<FixedArray>();
708
          } else {
709
            int field_index = descs->GetFieldIndex(i);
710
            if (field_index >= map->inobject_properties()) {
711
              field_index = -(field_index - map->inobject_properties() + 1);
712
            }
713
            indices->set(index, Smi::FromInt(field_index));
714
          }
715
        }
716
        index++;
717
      }
718
    }
719
    ASSERT(index == storage->length());
720

    
721
    Handle<FixedArray> bridge_storage =
722
        isolate->factory()->NewFixedArray(
723
            DescriptorArray::kEnumCacheBridgeLength);
724
    DescriptorArray* desc = object->map()->instance_descriptors();
725
    desc->SetEnumCache(*bridge_storage,
726
                       *storage,
727
                       indices.is_null() ? Object::cast(Smi::FromInt(0))
728
                                         : Object::cast(*indices));
729
    if (cache_result) {
730
      object->map()->SetEnumLength(enum_size);
731
    }
732

    
733
    return ReduceFixedArrayTo(storage, enum_size);
734
  } else {
735
    Handle<NameDictionary> dictionary(object->property_dictionary());
736

    
737
    int length = dictionary->NumberOfElements();
738
    if (length == 0) {
739
      return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
740
    }
741

    
742
    // The enumeration array is generated by allocating an array big enough to
743
    // hold all properties that have been seen, whether they are are deleted or
744
    // not. Subsequently all visible properties are added to the array. If some
745
    // properties were not visible, the array is trimmed so it only contains
746
    // visible properties. This improves over adding elements and sorting by
747
    // index by having linear complexity rather than n*log(n).
748

    
749
    // By comparing the monotonous NextEnumerationIndex to the NumberOfElements,
750
    // we can predict the number of holes in the final array. If there will be
751
    // more than 50% holes, regenerate the enumeration indices to reduce the
752
    // number of holes to a minimum. This avoids allocating a large array if
753
    // many properties were added but subsequently deleted.
754
    int next_enumeration = dictionary->NextEnumerationIndex();
755
    if (!object->IsGlobalObject() && next_enumeration > (length * 3) / 2) {
756
      NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
757
      next_enumeration = dictionary->NextEnumerationIndex();
758
    }
759

    
760
    Handle<FixedArray> storage =
761
        isolate->factory()->NewFixedArray(next_enumeration);
762

    
763
    storage = Handle<FixedArray>(dictionary->CopyEnumKeysTo(*storage));
764
    ASSERT(storage->length() == object->NumberOfLocalProperties(DONT_SHOW));
765
    return storage;
766
  }
767
}
768

    
769

    
770
Handle<ObjectHashSet> ObjectHashSetAdd(Handle<ObjectHashSet> table,
771
                                       Handle<Object> key) {
772
  CALL_HEAP_FUNCTION(table->GetIsolate(),
773
                     table->Add(*key),
774
                     ObjectHashSet);
775
}
776

    
777

    
778
Handle<ObjectHashSet> ObjectHashSetRemove(Handle<ObjectHashSet> table,
779
                                          Handle<Object> key) {
780
  CALL_HEAP_FUNCTION(table->GetIsolate(),
781
                     table->Remove(*key),
782
                     ObjectHashSet);
783
}
784

    
785

    
786
Handle<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
787
                                               Handle<Object> key,
788
                                               Handle<Object> value) {
789
  CALL_HEAP_FUNCTION(table->GetIsolate(),
790
                     table->Put(*key, *value),
791
                     ObjectHashTable);
792
}
793

    
794

    
795
DeferredHandleScope::DeferredHandleScope(Isolate* isolate)
796
    : impl_(isolate->handle_scope_implementer()) {
797
  impl_->BeginDeferredScope();
798
  v8::ImplementationUtilities::HandleScopeData* data =
799
      impl_->isolate()->handle_scope_data();
800
  Object** new_next = impl_->GetSpareOrNewBlock();
801
  Object** new_limit = &new_next[kHandleBlockSize];
802
  ASSERT(data->limit == &impl_->blocks()->last()[kHandleBlockSize]);
803
  impl_->blocks()->Add(new_next);
804

    
805
#ifdef DEBUG
806
  prev_level_ = data->level;
807
#endif
808
  data->level++;
809
  prev_limit_ = data->limit;
810
  prev_next_ = data->next;
811
  data->next = new_next;
812
  data->limit = new_limit;
813
}
814

    
815

    
816
DeferredHandleScope::~DeferredHandleScope() {
817
  impl_->isolate()->handle_scope_data()->level--;
818
  ASSERT(handles_detached_);
819
  ASSERT(impl_->isolate()->handle_scope_data()->level == prev_level_);
820
}
821

    
822

    
823
DeferredHandles* DeferredHandleScope::Detach() {
824
  DeferredHandles* deferred = impl_->Detach(prev_limit_);
825
  v8::ImplementationUtilities::HandleScopeData* data =
826
      impl_->isolate()->handle_scope_data();
827
  data->next = prev_next_;
828
  data->limit = prev_limit_;
829
#ifdef DEBUG
830
  handles_detached_ = true;
831
#endif
832
  return deferred;
833
}
834

    
835

    
836
void AddWeakObjectToCodeDependency(Heap* heap,
837
                                   Handle<Object> object,
838
                                   Handle<Code> code) {
839
  heap->EnsureWeakObjectToCodeTable();
840
  Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(*object));
841
  dep = DependentCode::Insert(dep, DependentCode::kWeaklyEmbeddedGroup, code);
842
  CALL_HEAP_FUNCTION_VOID(heap->isolate(),
843
                          heap->AddWeakObjectToCodeDependency(*object, *dep));
844
}
845

    
846

    
847
} }  // namespace v8::internal