blob: 37a5011ce761ca759de780786d9a069312ffae04 [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"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080040#include "string-search.h"
Steve Blockd0582a62009-12-15 09:54:21 +000041#include "stub-cache.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000042
43namespace v8 {
44namespace internal {
45
46
47v8::ImplementationUtilities::HandleScopeData HandleScope::current_ =
John Reck59135872010-11-02 12:39:01 -070048 { NULL, NULL, 0 };
Steve Blocka7e24c12009-10-30 11:49:00 +000049
50
51int HandleScope::NumberOfHandles() {
52 int n = HandleScopeImplementer::instance()->blocks()->length();
53 if (n == 0) return 0;
Steve Blockd0582a62009-12-15 09:54:21 +000054 return ((n - 1) * kHandleBlockSize) + static_cast<int>(
55 (current_.next - HandleScopeImplementer::instance()->blocks()->last()));
Steve Blocka7e24c12009-10-30 11:49:00 +000056}
57
58
59Object** HandleScope::Extend() {
60 Object** result = current_.next;
61
62 ASSERT(result == current_.limit);
63 // Make sure there's at least one scope on the stack and that the
64 // top of the scope stack isn't a barrier.
John Reck59135872010-11-02 12:39:01 -070065 if (current_.level == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +000066 Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
67 "Cannot create a handle without a HandleScope");
68 return NULL;
69 }
70 HandleScopeImplementer* impl = HandleScopeImplementer::instance();
71 // If there's more room in the last block, we use that. This is used
72 // for fast creation of scopes after scope barriers.
73 if (!impl->blocks()->is_empty()) {
74 Object** limit = &impl->blocks()->last()[kHandleBlockSize];
75 if (current_.limit != limit) {
76 current_.limit = limit;
John Reck59135872010-11-02 12:39:01 -070077 ASSERT(limit - current_.next < kHandleBlockSize);
Steve Blocka7e24c12009-10-30 11:49:00 +000078 }
79 }
80
81 // If we still haven't found a slot for the handle, we extend the
82 // current handle scope by allocating a new handle block.
83 if (result == current_.limit) {
84 // If there's a spare block, use it for growing the current scope.
85 result = impl->GetSpareOrNewBlock();
86 // Add the extension to the global list of blocks, but count the
87 // extension as part of the current scope.
88 impl->blocks()->Add(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000089 current_.limit = &result[kHandleBlockSize];
90 }
91
92 return result;
93}
94
95
96void HandleScope::DeleteExtensions() {
John Reck59135872010-11-02 12:39:01 -070097 HandleScopeImplementer::instance()->DeleteExtensions(current_.limit);
Steve Blocka7e24c12009-10-30 11:49:00 +000098}
99
100
101void HandleScope::ZapRange(Object** start, Object** end) {
John Reck59135872010-11-02 12:39:01 -0700102 ASSERT(end - start <= kHandleBlockSize);
103 for (Object** p = start; p != end; p++) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000104 *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue;
105 }
106}
107
108
John Reck59135872010-11-02 12:39:01 -0700109Address HandleScope::current_level_address() {
110 return reinterpret_cast<Address>(&current_.level);
Steve Blockd0582a62009-12-15 09:54:21 +0000111}
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) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100145 // If objects constructed from this function exist then changing
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800146 // 'estimated_nof_properties' is dangerous since the previous value might
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100147 // have been compiled into the fast construct stub. More over, the inobject
148 // slack tracking logic might have adjusted the previous value, so even
149 // passing the same value is risky.
150 if (func->shared()->live_objects_may_exist()) return;
151
Steve Blocka7e24c12009-10-30 11:49:00 +0000152 func->shared()->set_expected_nof_properties(nof);
153 if (func->has_initial_map()) {
154 Handle<Map> new_initial_map =
155 Factory::CopyMapDropTransitions(Handle<Map>(func->initial_map()));
156 new_initial_map->set_unused_property_fields(nof);
157 func->set_initial_map(*new_initial_map);
158 }
159}
160
161
162void SetPrototypeProperty(Handle<JSFunction> func, Handle<JSObject> value) {
163 CALL_HEAP_FUNCTION_VOID(func->SetPrototype(*value));
164}
165
166
167static int ExpectedNofPropertiesFromEstimate(int estimate) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100168 // If no properties are added in the constructor, they are more likely
169 // to be added later.
170 if (estimate == 0) estimate = 2;
171
172 // We do not shrink objects that go into a snapshot (yet), so we adjust
173 // the estimate conservatively.
174 if (Serializer::enabled()) return estimate + 2;
175
176 // Inobject slack tracking will reclaim redundant inobject space later,
177 // so we can afford to adjust the estimate generously.
Ben Murdochf87a2032010-10-22 12:50:53 +0100178 return estimate + 8;
Steve Blocka7e24c12009-10-30 11:49:00 +0000179}
180
181
182void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
183 int estimate) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100184 // See the comment in SetExpectedNofProperties.
185 if (shared->live_objects_may_exist()) return;
186
Steve Blocka7e24c12009-10-30 11:49:00 +0000187 shared->set_expected_nof_properties(
188 ExpectedNofPropertiesFromEstimate(estimate));
189}
190
191
Steve Blocka7e24c12009-10-30 11:49:00 +0000192void NormalizeProperties(Handle<JSObject> object,
193 PropertyNormalizationMode mode,
194 int expected_additional_properties) {
195 CALL_HEAP_FUNCTION_VOID(object->NormalizeProperties(
196 mode,
197 expected_additional_properties));
198}
199
200
201void NormalizeElements(Handle<JSObject> object) {
202 CALL_HEAP_FUNCTION_VOID(object->NormalizeElements());
203}
204
205
206void TransformToFastProperties(Handle<JSObject> object,
207 int unused_property_fields) {
208 CALL_HEAP_FUNCTION_VOID(
209 object->TransformToFastProperties(unused_property_fields));
210}
211
212
John Reck59135872010-11-02 12:39:01 -0700213void NumberDictionarySet(Handle<NumberDictionary> dictionary,
214 uint32_t index,
215 Handle<Object> value,
216 PropertyDetails details) {
217 CALL_HEAP_FUNCTION_VOID(dictionary->Set(index, *value, details));
218}
219
220
Steve Blocka7e24c12009-10-30 11:49:00 +0000221void FlattenString(Handle<String> string) {
Steve Block6ded16b2010-05-10 14:33:55 +0100222 CALL_HEAP_FUNCTION_VOID(string->TryFlatten());
Steve Block8defd9f2010-07-08 12:39:36 +0100223}
224
225
226Handle<String> FlattenGetString(Handle<String> string) {
227 Handle<String> result;
228 CALL_AND_RETRY(string->TryFlatten(),
229 { result = Handle<String>(String::cast(__object__));
230 break; },
231 return Handle<String>());
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 ASSERT(string->IsFlat());
Steve Block8defd9f2010-07-08 12:39:36 +0100233 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000234}
235
236
237Handle<Object> SetPrototype(Handle<JSFunction> function,
238 Handle<Object> prototype) {
Steve Block6ded16b2010-05-10 14:33:55 +0100239 ASSERT(function->should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +0000240 CALL_HEAP_FUNCTION(Accessors::FunctionSetPrototype(*function,
241 *prototype,
242 NULL),
243 Object);
244}
245
246
247Handle<Object> SetProperty(Handle<JSObject> object,
248 Handle<String> key,
249 Handle<Object> value,
250 PropertyAttributes attributes) {
251 CALL_HEAP_FUNCTION(object->SetProperty(*key, *value, attributes), Object);
252}
253
254
255Handle<Object> SetProperty(Handle<Object> object,
256 Handle<Object> key,
257 Handle<Object> value,
258 PropertyAttributes attributes) {
259 CALL_HEAP_FUNCTION(
260 Runtime::SetObjectProperty(object, key, value, attributes), Object);
261}
262
263
264Handle<Object> ForceSetProperty(Handle<JSObject> object,
265 Handle<Object> key,
266 Handle<Object> value,
267 PropertyAttributes attributes) {
268 CALL_HEAP_FUNCTION(
269 Runtime::ForceSetObjectProperty(object, key, value, attributes), Object);
270}
271
272
Andrei Popescu31002712010-02-23 13:46:05 +0000273Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
274 Handle<String> key,
275 Handle<Object> value,
276 PropertyDetails details) {
277 CALL_HEAP_FUNCTION(object->SetNormalizedProperty(*key, *value, details),
278 Object);
279}
280
281
Steve Blocka7e24c12009-10-30 11:49:00 +0000282Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
283 Handle<Object> key) {
284 CALL_HEAP_FUNCTION(Runtime::ForceDeleteObjectProperty(object, key), Object);
285}
286
287
288Handle<Object> IgnoreAttributesAndSetLocalProperty(
289 Handle<JSObject> object,
290 Handle<String> key,
291 Handle<Object> value,
292 PropertyAttributes attributes) {
293 CALL_HEAP_FUNCTION(object->
294 IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object);
295}
296
297
298Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
299 Handle<String> key,
300 Handle<Object> value,
301 PropertyAttributes attributes) {
302 CALL_HEAP_FUNCTION(object->SetPropertyWithInterceptor(*key,
303 *value,
304 attributes),
305 Object);
306}
307
308
309Handle<Object> GetProperty(Handle<JSObject> obj,
310 const char* name) {
311 Handle<String> str = Factory::LookupAsciiSymbol(name);
312 CALL_HEAP_FUNCTION(obj->GetProperty(*str), Object);
313}
314
315
316Handle<Object> GetProperty(Handle<Object> obj,
317 Handle<Object> key) {
318 CALL_HEAP_FUNCTION(Runtime::GetObjectProperty(obj, key), Object);
319}
320
321
Steve Block6ded16b2010-05-10 14:33:55 +0100322Handle<Object> GetElement(Handle<Object> obj,
323 uint32_t index) {
324 CALL_HEAP_FUNCTION(Runtime::GetElement(obj, index), Object);
325}
326
327
Steve Blocka7e24c12009-10-30 11:49:00 +0000328Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
329 Handle<JSObject> holder,
330 Handle<String> name,
331 PropertyAttributes* attributes) {
332 CALL_HEAP_FUNCTION(holder->GetPropertyWithInterceptor(*receiver,
333 *name,
334 attributes),
335 Object);
336}
337
338
339Handle<Object> GetPrototype(Handle<Object> obj) {
340 Handle<Object> result(obj->GetPrototype());
341 return result;
342}
343
344
Andrei Popescu402d9372010-02-26 13:31:12 +0000345Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) {
346 const bool skip_hidden_prototypes = false;
347 CALL_HEAP_FUNCTION(obj->SetPrototype(*value, skip_hidden_prototypes), Object);
348}
349
350
Steve Blocka7e24c12009-10-30 11:49:00 +0000351Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
352 bool create_if_needed) {
Steve Blockd0582a62009-12-15 09:54:21 +0000353 Object* holder = obj->BypassGlobalProxy();
354 if (holder->IsUndefined()) return Factory::undefined_value();
355 obj = Handle<JSObject>(JSObject::cast(holder));
Steve Blocka7e24c12009-10-30 11:49:00 +0000356
357 if (obj->HasFastProperties()) {
358 // If the object has fast properties, check whether the first slot
359 // in the descriptor array matches the hidden symbol. Since the
360 // hidden symbols hash code is zero (and no other string has hash
361 // code zero) it will always occupy the first entry if present.
362 DescriptorArray* descriptors = obj->map()->instance_descriptors();
363 if ((descriptors->number_of_descriptors() > 0) &&
Steve Blockd0582a62009-12-15 09:54:21 +0000364 (descriptors->GetKey(0) == Heap::hidden_symbol()) &&
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 descriptors->IsProperty(0)) {
366 ASSERT(descriptors->GetType(0) == FIELD);
367 return Handle<Object>(obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
368 }
369 }
370
371 // Only attempt to find the hidden properties in the local object and not
372 // in the prototype chain. Note that HasLocalProperty() can cause a GC in
373 // the general case in the presence of interceptors.
Steve Blockd0582a62009-12-15 09:54:21 +0000374 if (!obj->HasHiddenPropertiesObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000375 // Hidden properties object not found. Allocate a new hidden properties
376 // object if requested. Otherwise return the undefined value.
377 if (create_if_needed) {
378 Handle<Object> hidden_obj = Factory::NewJSObject(Top::object_function());
Steve Blockd0582a62009-12-15 09:54:21 +0000379 CALL_HEAP_FUNCTION(obj->SetHiddenPropertiesObject(*hidden_obj), Object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000380 } else {
381 return Factory::undefined_value();
382 }
383 }
Steve Blockd0582a62009-12-15 09:54:21 +0000384 return Handle<Object>(obj->GetHiddenPropertiesObject());
Steve Blocka7e24c12009-10-30 11:49:00 +0000385}
386
387
388Handle<Object> DeleteElement(Handle<JSObject> obj,
389 uint32_t index) {
390 CALL_HEAP_FUNCTION(obj->DeleteElement(index, JSObject::NORMAL_DELETION),
391 Object);
392}
393
394
395Handle<Object> DeleteProperty(Handle<JSObject> obj,
396 Handle<String> prop) {
397 CALL_HEAP_FUNCTION(obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
398 Object);
399}
400
401
402Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) {
403 CALL_HEAP_FUNCTION(Heap::LookupSingleCharacterStringFromCode(index), Object);
404}
405
406
Steve Block6ded16b2010-05-10 14:33:55 +0100407Handle<String> SubString(Handle<String> str,
408 int start,
409 int end,
410 PretenureFlag pretenure) {
411 CALL_HEAP_FUNCTION(str->SubString(start, end, pretenure), String);
Steve Blocka7e24c12009-10-30 11:49:00 +0000412}
413
414
415Handle<Object> SetElement(Handle<JSObject> object,
416 uint32_t index,
417 Handle<Object> value) {
Steve Block3ce2e202009-11-05 08:53:23 +0000418 if (object->HasPixelElements() || object->HasExternalArrayElements()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
420 bool has_exception;
421 Handle<Object> number = Execution::ToNumber(value, &has_exception);
422 if (has_exception) return Handle<Object>();
423 value = number;
424 }
425 }
426 CALL_HEAP_FUNCTION(object->SetElement(index, *value), Object);
427}
428
429
430Handle<JSObject> Copy(Handle<JSObject> obj) {
431 CALL_HEAP_FUNCTION(Heap::CopyJSObject(*obj), JSObject);
432}
433
434
Leon Clarkef7060e22010-06-03 12:02:55 +0100435Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info) {
436 CALL_HEAP_FUNCTION(obj->DefineAccessor(*info), Object);
437}
438
439
Steve Blocka7e24c12009-10-30 11:49:00 +0000440// Wrappers for scripts are kept alive and cached in weak global
441// handles referred from proxy objects held by the scripts as long as
442// they are used. When they are not used anymore, the garbage
443// collector will call the weak callback on the global handle
444// associated with the wrapper and get rid of both the wrapper and the
445// handle.
446static void ClearWrapperCache(Persistent<v8::Value> handle, void*) {
447#ifdef ENABLE_HEAP_PROTECTION
448 // Weak reference callbacks are called as if from outside V8. We
449 // need to reeenter to unprotect the heap.
450 VMState state(OTHER);
451#endif
452 Handle<Object> cache = Utils::OpenHandle(*handle);
453 JSValue* wrapper = JSValue::cast(*cache);
454 Proxy* proxy = Script::cast(wrapper->value())->wrapper();
455 ASSERT(proxy->proxy() == reinterpret_cast<Address>(cache.location()));
456 proxy->set_proxy(0);
457 GlobalHandles::Destroy(cache.location());
458 Counters::script_wrappers.Decrement();
459}
460
461
462Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
463 if (script->wrapper()->proxy() != NULL) {
464 // Return the script wrapper directly from the cache.
465 return Handle<JSValue>(
466 reinterpret_cast<JSValue**>(script->wrapper()->proxy()));
467 }
468
469 // Construct a new script wrapper.
470 Counters::script_wrappers.Increment();
471 Handle<JSFunction> constructor = Top::script_function();
472 Handle<JSValue> result =
473 Handle<JSValue>::cast(Factory::NewJSObject(constructor));
474 result->set_value(*script);
475
476 // Create a new weak global handle and use it to cache the wrapper
477 // for future use. The cache will automatically be cleared by the
478 // garbage collector when it is not used anymore.
479 Handle<Object> handle = GlobalHandles::Create(*result);
480 GlobalHandles::MakeWeak(handle.location(), NULL, &ClearWrapperCache);
481 script->wrapper()->set_proxy(reinterpret_cast<Address>(handle.location()));
482 return result;
483}
484
485
486// Init line_ends array with code positions of line ends inside script
487// source.
488void InitScriptLineEnds(Handle<Script> script) {
489 if (!script->line_ends()->IsUndefined()) return;
490
491 if (!script->source()->IsString()) {
492 ASSERT(script->source()->IsUndefined());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100493 Handle<FixedArray> empty = Factory::NewFixedArray(0);
494 script->set_line_ends(*empty);
Steve Blockd0582a62009-12-15 09:54:21 +0000495 ASSERT(script->line_ends()->IsFixedArray());
Steve Blocka7e24c12009-10-30 11:49:00 +0000496 return;
497 }
498
499 Handle<String> src(String::cast(script->source()));
Steve Block6ded16b2010-05-10 14:33:55 +0100500
501 Handle<FixedArray> array = CalculateLineEnds(src, true);
502
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800503 if (*array != Heap::empty_fixed_array()) {
504 array->set_map(Heap::fixed_cow_array_map());
505 }
506
Steve Block6ded16b2010-05-10 14:33:55 +0100507 script->set_line_ends(*array);
508 ASSERT(script->line_ends()->IsFixedArray());
509}
510
511
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800512template <typename SourceChar>
513static void CalculateLineEnds(List<int>* line_ends,
514 Vector<const SourceChar> src,
515 bool with_last_line) {
516 const int src_len = src.length();
517 StringSearch<char, SourceChar> search(CStrVector("\n"));
Steve Blocka7e24c12009-10-30 11:49:00 +0000518
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800519 // Find and record line ends.
Steve Blocka7e24c12009-10-30 11:49:00 +0000520 int position = 0;
521 while (position != -1 && position < src_len) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800522 position = search.Search(src, position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000523 if (position != -1) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800524 line_ends->Add(position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000525 position++;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800526 } else if (with_last_line) {
Steve Block6ded16b2010-05-10 14:33:55 +0100527 // Even if the last line misses a line end, it is counted.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800528 line_ends->Add(src_len);
529 return;
Steve Block6ded16b2010-05-10 14:33:55 +0100530 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000531 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800532}
Steve Blocka7e24c12009-10-30 11:49:00 +0000533
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800534
535Handle<FixedArray> CalculateLineEnds(Handle<String> src,
536 bool with_last_line) {
537 src = FlattenGetString(src);
538 // Rough estimate of line count based on a roughly estimated average
539 // length of (unpacked) code.
540 int line_count_estimate = src->length() >> 4;
541 List<int> line_ends(line_count_estimate);
542 {
543 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid.
544 // Dispatch on type of strings.
545 if (src->IsAsciiRepresentation()) {
546 CalculateLineEnds(&line_ends, src->ToAsciiVector(), with_last_line);
547 } else {
548 CalculateLineEnds(&line_ends, src->ToUC16Vector(), with_last_line);
549 }
550 }
551 int line_count = line_ends.length();
Steve Blocka7e24c12009-10-30 11:49:00 +0000552 Handle<FixedArray> array = Factory::NewFixedArray(line_count);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800553 for (int i = 0; i < line_count; i++) {
554 array->set(i, Smi::FromInt(line_ends[i]));
Steve Blocka7e24c12009-10-30 11:49:00 +0000555 }
Steve Block6ded16b2010-05-10 14:33:55 +0100556 return array;
Steve Blocka7e24c12009-10-30 11:49:00 +0000557}
558
559
560// Convert code position into line number.
561int GetScriptLineNumber(Handle<Script> script, int code_pos) {
562 InitScriptLineEnds(script);
563 AssertNoAllocation no_allocation;
Andrei Popescu402d9372010-02-26 13:31:12 +0000564 FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
Steve Blockd0582a62009-12-15 09:54:21 +0000565 const int line_ends_len = line_ends_array->length();
Steve Blocka7e24c12009-10-30 11:49:00 +0000566
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800567 if (!line_ends_len) return -1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000568
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800569 if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000570 return script->line_offset()->value();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800571 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000572
573 int left = 0;
574 int right = line_ends_len;
575 while (int half = (right - left) / 2) {
576 if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
577 right -= half;
578 } else {
579 left += half;
Steve Blocka7e24c12009-10-30 11:49:00 +0000580 }
581 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000582 return right + script->line_offset()->value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000583}
584
585
Steve Block6ded16b2010-05-10 14:33:55 +0100586int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) {
587 AssertNoAllocation no_allocation;
588 if (!script->line_ends()->IsUndefined()) {
589 return GetScriptLineNumber(script, code_pos);
590 }
591 // Slow mode: we do not have line_ends. We have to iterate through source.
592 if (!script->source()->IsString()) {
593 return -1;
594 }
595 String* source = String::cast(script->source());
596 int line = 0;
597 int len = source->length();
598 for (int pos = 0; pos < len; pos++) {
599 if (pos == code_pos) {
600 break;
601 }
602 if (source->Get(pos) == '\n') {
603 line++;
604 }
605 }
606 return line;
607}
608
609
Steve Blocka7e24c12009-10-30 11:49:00 +0000610void CustomArguments::IterateInstance(ObjectVisitor* v) {
Steve Block6ded16b2010-05-10 14:33:55 +0100611 v->VisitPointers(values_, values_ + ARRAY_SIZE(values_));
Steve Blocka7e24c12009-10-30 11:49:00 +0000612}
613
614
615// Compute the property keys from the interceptor.
616v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
617 Handle<JSObject> object) {
618 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
619 CustomArguments args(interceptor->data(), *receiver, *object);
620 v8::AccessorInfo info(args.end());
621 v8::Handle<v8::Array> result;
622 if (!interceptor->enumerator()->IsUndefined()) {
623 v8::NamedPropertyEnumerator enum_fun =
624 v8::ToCData<v8::NamedPropertyEnumerator>(interceptor->enumerator());
625 LOG(ApiObjectAccess("interceptor-named-enum", *object));
626 {
627 // Leaving JavaScript.
628 VMState state(EXTERNAL);
629 result = enum_fun(info);
630 }
631 }
632 return result;
633}
634
635
636// Compute the element keys from the interceptor.
637v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
638 Handle<JSObject> object) {
639 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
640 CustomArguments args(interceptor->data(), *receiver, *object);
641 v8::AccessorInfo info(args.end());
642 v8::Handle<v8::Array> result;
643 if (!interceptor->enumerator()->IsUndefined()) {
644 v8::IndexedPropertyEnumerator enum_fun =
645 v8::ToCData<v8::IndexedPropertyEnumerator>(interceptor->enumerator());
646 LOG(ApiObjectAccess("interceptor-indexed-enum", *object));
647 {
648 // Leaving JavaScript.
649 VMState state(EXTERNAL);
650 result = enum_fun(info);
651 }
652 }
653 return result;
654}
655
656
Ben Murdochf87a2032010-10-22 12:50:53 +0100657static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
658 int len = array->length();
659 for (int i = 0; i < len; i++) {
660 Object* e = array->get(i);
661 if (!(e->IsString() || e->IsNumber())) return false;
662 }
663 return true;
664}
665
666
Steve Blocka7e24c12009-10-30 11:49:00 +0000667Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
668 KeyCollectionType type) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100669 USE(ContainsOnlyValidKeys);
Steve Blocka7e24c12009-10-30 11:49:00 +0000670 Handle<FixedArray> content = Factory::empty_fixed_array();
Steve Blockd0582a62009-12-15 09:54:21 +0000671 Handle<JSObject> arguments_boilerplate =
672 Handle<JSObject>(
673 Top::context()->global_context()->arguments_boilerplate());
674 Handle<JSFunction> arguments_function =
675 Handle<JSFunction>(
676 JSFunction::cast(arguments_boilerplate->map()->constructor()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000677
678 // Only collect keys if access is permitted.
679 for (Handle<Object> p = object;
680 *p != Heap::null_value();
681 p = Handle<Object>(p->GetPrototype())) {
682 Handle<JSObject> current(JSObject::cast(*p));
683
684 // Check access rights if required.
685 if (current->IsAccessCheckNeeded() &&
Iain Merrick75681382010-08-19 15:07:18 +0100686 !Top::MayNamedAccess(*current, Heap::undefined_value(),
687 v8::ACCESS_KEYS)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000688 Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
689 break;
690 }
691
692 // Compute the element keys.
693 Handle<FixedArray> element_keys =
694 Factory::NewFixedArray(current->NumberOfEnumElements());
695 current->GetEnumElementKeys(*element_keys);
696 content = UnionOfKeys(content, element_keys);
Ben Murdochf87a2032010-10-22 12:50:53 +0100697 ASSERT(ContainsOnlyValidKeys(content));
Steve Blocka7e24c12009-10-30 11:49:00 +0000698
699 // Add the element keys from the interceptor.
700 if (current->HasIndexedInterceptor()) {
701 v8::Handle<v8::Array> result =
702 GetKeysForIndexedInterceptor(object, current);
703 if (!result.IsEmpty())
704 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
Ben Murdochf87a2032010-10-22 12:50:53 +0100705 ASSERT(ContainsOnlyValidKeys(content));
Steve Blocka7e24c12009-10-30 11:49:00 +0000706 }
707
Steve Blockd0582a62009-12-15 09:54:21 +0000708 // We can cache the computed property keys if access checks are
709 // not needed and no interceptors are involved.
710 //
711 // We do not use the cache if the object has elements and
712 // therefore it does not make sense to cache the property names
713 // for arguments objects. Arguments objects will always have
714 // elements.
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100715 // Wrapped strings have elements, but don't have an elements
716 // array or dictionary. So the fast inline test for whether to
717 // use the cache says yes, so we should not create a cache.
Steve Blockd0582a62009-12-15 09:54:21 +0000718 bool cache_enum_keys =
719 ((current->map()->constructor() != *arguments_function) &&
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100720 !current->IsJSValue() &&
Steve Blockd0582a62009-12-15 09:54:21 +0000721 !current->IsAccessCheckNeeded() &&
722 !current->HasNamedInterceptor() &&
723 !current->HasIndexedInterceptor());
724 // Compute the property keys and cache them if possible.
725 content =
726 UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys));
Ben Murdochf87a2032010-10-22 12:50:53 +0100727 ASSERT(ContainsOnlyValidKeys(content));
Steve Blocka7e24c12009-10-30 11:49:00 +0000728
729 // Add the property keys from the interceptor.
730 if (current->HasNamedInterceptor()) {
731 v8::Handle<v8::Array> result =
732 GetKeysForNamedInterceptor(object, current);
733 if (!result.IsEmpty())
734 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
Ben Murdochf87a2032010-10-22 12:50:53 +0100735 ASSERT(ContainsOnlyValidKeys(content));
Steve Blocka7e24c12009-10-30 11:49:00 +0000736 }
737
738 // If we only want local properties we bail out after the first
739 // iteration.
740 if (type == LOCAL_ONLY)
741 break;
742 }
743 return content;
744}
745
746
747Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
748 Counters::for_in.Increment();
749 Handle<FixedArray> elements = GetKeysInFixedArrayFor(object,
750 INCLUDE_PROTOS);
751 return Factory::NewJSArrayWithElements(elements);
752}
753
754
Steve Blockd0582a62009-12-15 09:54:21 +0000755Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
756 bool cache_result) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000757 int index = 0;
758 if (object->HasFastProperties()) {
759 if (object->map()->instance_descriptors()->HasEnumCache()) {
760 Counters::enum_cache_hits.Increment();
761 DescriptorArray* desc = object->map()->instance_descriptors();
762 return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache()));
763 }
764 Counters::enum_cache_misses.Increment();
765 int num_enum = object->NumberOfEnumProperties();
766 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum);
767 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum);
768 Handle<DescriptorArray> descs =
769 Handle<DescriptorArray>(object->map()->instance_descriptors());
770 for (int i = 0; i < descs->number_of_descriptors(); i++) {
771 if (descs->IsProperty(i) && !descs->IsDontEnum(i)) {
772 (*storage)->set(index, descs->GetKey(i));
773 PropertyDetails details(descs->GetDetails(i));
774 (*sort_array)->set(index, Smi::FromInt(details.index()));
775 index++;
776 }
777 }
778 (*storage)->SortPairs(*sort_array, sort_array->length());
Steve Blockd0582a62009-12-15 09:54:21 +0000779 if (cache_result) {
780 Handle<FixedArray> bridge_storage =
781 Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength);
782 DescriptorArray* desc = object->map()->instance_descriptors();
783 desc->SetEnumCache(*bridge_storage, *storage);
784 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000785 ASSERT(storage->length() == index);
786 return storage;
787 } else {
788 int num_enum = object->NumberOfEnumProperties();
789 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum);
790 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum);
791 object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array);
792 return storage;
793 }
794}
795
796
Leon Clarke4515c472010-02-03 11:58:03 +0000797bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
798 ClearExceptionFlag flag) {
799 return shared->is_compiled() || CompileLazyShared(shared, flag);
800}
801
802
803static bool CompileLazyHelper(CompilationInfo* info,
804 ClearExceptionFlag flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000805 // Compile the source information to a code object.
Leon Clarke4515c472010-02-03 11:58:03 +0000806 ASSERT(!info->shared_info()->is_compiled());
807 bool result = Compiler::CompileLazy(info);
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 ASSERT(result != Top::has_pending_exception());
809 if (!result && flag == CLEAR_EXCEPTION) Top::clear_pending_exception();
810 return result;
811}
812
813
Leon Clarke4515c472010-02-03 11:58:03 +0000814bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
815 ClearExceptionFlag flag) {
Andrei Popescu31002712010-02-23 13:46:05 +0000816 CompilationInfo info(shared);
Leon Clarke4515c472010-02-03 11:58:03 +0000817 return CompileLazyHelper(&info, flag);
818}
819
820
821bool CompileLazy(Handle<JSFunction> function,
Leon Clarke4515c472010-02-03 11:58:03 +0000822 ClearExceptionFlag flag) {
Iain Merrick75681382010-08-19 15:07:18 +0100823 if (function->shared()->is_compiled()) {
824 function->set_code(function->shared()->code());
Ben Murdochf87a2032010-10-22 12:50:53 +0100825 PROFILE(FunctionCreateEvent(*function));
Iain Merrick75681382010-08-19 15:07:18 +0100826 function->shared()->set_code_age(0);
827 return true;
828 } else {
Ben Murdochf87a2032010-10-22 12:50:53 +0100829 CompilationInfo info(function);
Iain Merrick75681382010-08-19 15:07:18 +0100830 bool result = CompileLazyHelper(&info, flag);
Ben Murdochf87a2032010-10-22 12:50:53 +0100831 ASSERT(!result || function->is_compiled());
Iain Merrick75681382010-08-19 15:07:18 +0100832 PROFILE(FunctionCreateEvent(*function));
833 return result;
834 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000835}
836
837
Leon Clarke4515c472010-02-03 11:58:03 +0000838bool CompileLazyInLoop(Handle<JSFunction> function,
Leon Clarke4515c472010-02-03 11:58:03 +0000839 ClearExceptionFlag flag) {
Iain Merrick75681382010-08-19 15:07:18 +0100840 if (function->shared()->is_compiled()) {
841 function->set_code(function->shared()->code());
Ben Murdochf87a2032010-10-22 12:50:53 +0100842 PROFILE(FunctionCreateEvent(*function));
Iain Merrick75681382010-08-19 15:07:18 +0100843 function->shared()->set_code_age(0);
844 return true;
845 } else {
Ben Murdochf87a2032010-10-22 12:50:53 +0100846 CompilationInfo info(function);
847 info.MarkAsInLoop();
Iain Merrick75681382010-08-19 15:07:18 +0100848 bool result = CompileLazyHelper(&info, flag);
Ben Murdochf87a2032010-10-22 12:50:53 +0100849 ASSERT(!result || function->is_compiled());
Iain Merrick75681382010-08-19 15:07:18 +0100850 PROFILE(FunctionCreateEvent(*function));
851 return result;
852 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000853}
854
Leon Clarke4515c472010-02-03 11:58:03 +0000855
Steve Blocka7e24c12009-10-30 11:49:00 +0000856OptimizedObjectForAddingMultipleProperties::
857OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
858 int expected_additional_properties,
859 bool condition) {
860 object_ = object;
861 if (condition && object_->HasFastProperties()) {
862 // Normalize the properties of object to avoid n^2 behavior
863 // when extending the object multiple properties. Indicate the number of
864 // properties to be added.
865 unused_property_fields_ = object->map()->unused_property_fields();
866 NormalizeProperties(object_,
867 KEEP_INOBJECT_PROPERTIES,
868 expected_additional_properties);
869 has_been_transformed_ = true;
870
871 } else {
872 has_been_transformed_ = false;
873 }
874}
875
876
Steve Blocka7e24c12009-10-30 11:49:00 +0000877OptimizedObjectForAddingMultipleProperties::
878~OptimizedObjectForAddingMultipleProperties() {
879 // Reoptimize the object to allow fast property access.
880 if (has_been_transformed_) {
881 TransformToFastProperties(object_, unused_property_fields_);
882 }
883}
884
Steve Blocka7e24c12009-10-30 11:49:00 +0000885} } // namespace v8::internal