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