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