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