blob: 7a46bc3ea251fc6232b769ee0c4232c279306ae2 [file] [log] [blame]
ager@chromium.org71daaf62009-04-01 07:22:49 +00001// Copyright 2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000032#include "arguments.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#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"
ager@chromium.orgc4c92722009-11-18 14:12:51 +000040#include "stub-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041
kasperl@chromium.org71affb52009-05-26 05:44:31 +000042namespace v8 {
43namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
ager@chromium.orgddb913d2009-01-27 10:01:48 +000046v8::ImplementationUtilities::HandleScopeData HandleScope::current_ =
lrn@chromium.org303ada72010-10-27 09:33:13 +000047 { NULL, NULL, 0 };
ager@chromium.orgddb913d2009-01-27 10:01:48 +000048
49
50int HandleScope::NumberOfHandles() {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000051 int n = HandleScopeImplementer::instance()->blocks()->length();
ager@chromium.orgddb913d2009-01-27 10:01:48 +000052 if (n == 0) return 0;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000053 return ((n - 1) * kHandleBlockSize) + static_cast<int>(
54 (current_.next - HandleScopeImplementer::instance()->blocks()->last()));
ager@chromium.orgddb913d2009-01-27 10:01:48 +000055}
56
57
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058Object** HandleScope::Extend() {
59 Object** result = current_.next;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000060
ager@chromium.org3b45ab52009-03-19 22:21:34 +000061 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.
lrn@chromium.org303ada72010-10-27 09:33:13 +000064 if (current_.level == 0) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000065 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.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000072 if (!impl->blocks()->is_empty()) {
73 Object** limit = &impl->blocks()->last()[kHandleBlockSize];
ager@chromium.org3b45ab52009-03-19 22:21:34 +000074 if (current_.limit != limit) {
75 current_.limit = limit;
lrn@chromium.org303ada72010-10-27 09:33:13 +000076 ASSERT(limit - current_.next < kHandleBlockSize);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000077 }
78 }
79
ager@chromium.org3b45ab52009-03-19 22:21:34 +000080 // If we still haven't found a slot for the handle, we extend the
81 // current handle scope by allocating a new handle block.
82 if (result == current_.limit) {
83 // If there's a spare block, use it for growing the current scope.
84 result = impl->GetSpareOrNewBlock();
85 // Add the extension to the global list of blocks, but count the
86 // extension as part of the current scope.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000087 impl->blocks()->Add(result);
ager@chromium.org3b45ab52009-03-19 22:21:34 +000088 current_.limit = &result[kHandleBlockSize];
89 }
90
ager@chromium.orgddb913d2009-01-27 10:01:48 +000091 return result;
92}
93
94
95void HandleScope::DeleteExtensions() {
lrn@chromium.org303ada72010-10-27 09:33:13 +000096 HandleScopeImplementer::instance()->DeleteExtensions(current_.limit);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000097}
98
99
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000100void HandleScope::ZapRange(Object** start, Object** end) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000101 ASSERT(end - start <= kHandleBlockSize);
102 for (Object** p = start; p != end; p++) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000103 *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000104 }
105}
106
107
lrn@chromium.org303ada72010-10-27 09:33:13 +0000108Address HandleScope::current_level_address() {
109 return reinterpret_cast<Address>(&current_.level);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000110}
111
112
113Address HandleScope::current_next_address() {
114 return reinterpret_cast<Address>(&current_.next);
115}
116
117
118Address HandleScope::current_limit_address() {
119 return reinterpret_cast<Address>(&current_.limit);
120}
121
122
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content,
124 Handle<JSArray> array) {
125 CALL_HEAP_FUNCTION(content->AddKeysFromJSArray(*array), FixedArray);
126}
127
128
129Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first,
130 Handle<FixedArray> second) {
131 CALL_HEAP_FUNCTION(first->UnionOfKeys(*second), FixedArray);
132}
133
134
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000135Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136 Handle<JSFunction> constructor,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000137 Handle<JSGlobalProxy> global) {
138 CALL_HEAP_FUNCTION(Heap::ReinitializeJSGlobalProxy(*constructor, *global),
139 JSGlobalProxy);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000140}
141
142
143void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000144 // If objects constructed from this function exist then changing
145 // 'estimated_nof_properties' is dangerous since the previois value might
146 // have been compiled into the fast construct stub. More over, the inobject
147 // slack tracking logic might have adjusted the previous value, so even
148 // passing the same value is risky.
149 if (func->shared()->live_objects_may_exist()) return;
150
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151 func->shared()->set_expected_nof_properties(nof);
152 if (func->has_initial_map()) {
153 Handle<Map> new_initial_map =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000154 Factory::CopyMapDropTransitions(Handle<Map>(func->initial_map()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155 new_initial_map->set_unused_property_fields(nof);
156 func->set_initial_map(*new_initial_map);
157 }
158}
159
160
161void SetPrototypeProperty(Handle<JSFunction> func, Handle<JSObject> value) {
162 CALL_HEAP_FUNCTION_VOID(func->SetPrototype(*value));
163}
164
165
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000166static int ExpectedNofPropertiesFromEstimate(int estimate) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000167 // If no properties are added in the constructor, they are more likely
168 // to be added later.
169 if (estimate == 0) estimate = 2;
170
171 // We do not shrink objects that go into a snapshot (yet), so we adjust
172 // the estimate conservatively.
173 if (Serializer::enabled()) return estimate + 2;
174
175 // Inobject slack tracking will reclaim redundant inobject space later,
176 // so we can afford to adjust the estimate generously.
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000177 return estimate + 8;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000178}
179
180
181void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
182 int estimate) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000183 // See the comment in SetExpectedNofProperties.
184 if (shared->live_objects_may_exist()) return;
185
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000186 shared->set_expected_nof_properties(
187 ExpectedNofPropertiesFromEstimate(estimate));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000188}
189
190
ager@chromium.org32912102009-01-16 10:38:43 +0000191void NormalizeProperties(Handle<JSObject> object,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000192 PropertyNormalizationMode mode,
193 int expected_additional_properties) {
194 CALL_HEAP_FUNCTION_VOID(object->NormalizeProperties(
195 mode,
196 expected_additional_properties));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000197}
198
199
200void NormalizeElements(Handle<JSObject> object) {
201 CALL_HEAP_FUNCTION_VOID(object->NormalizeElements());
202}
203
204
205void TransformToFastProperties(Handle<JSObject> object,
206 int unused_property_fields) {
207 CALL_HEAP_FUNCTION_VOID(
208 object->TransformToFastProperties(unused_property_fields));
209}
210
211
lrn@chromium.org303ada72010-10-27 09:33:13 +0000212void NumberDictionarySet(Handle<NumberDictionary> dictionary,
213 uint32_t index,
214 Handle<Object> value,
215 PropertyDetails details) {
216 CALL_HEAP_FUNCTION_VOID(dictionary->Set(index, *value, details));
217}
218
219
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220void FlattenString(Handle<String> string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000221 CALL_HEAP_FUNCTION_VOID(string->TryFlatten());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000222}
223
224
225Handle<String> FlattenGetString(Handle<String> string) {
226 Handle<String> result;
227 CALL_AND_RETRY(string->TryFlatten(),
228 { result = Handle<String>(String::cast(__object__));
229 break; },
230 return Handle<String>());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000231 ASSERT(string->IsFlat());
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000232 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233}
234
235
236Handle<Object> SetPrototype(Handle<JSFunction> function,
237 Handle<Object> prototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000238 ASSERT(function->should_have_prototype());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239 CALL_HEAP_FUNCTION(Accessors::FunctionSetPrototype(*function,
240 *prototype,
241 NULL),
242 Object);
243}
244
245
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000246Handle<Object> SetProperty(Handle<JSObject> object,
247 Handle<String> key,
248 Handle<Object> value,
249 PropertyAttributes attributes) {
250 CALL_HEAP_FUNCTION(object->SetProperty(*key, *value, attributes), Object);
251}
252
253
254Handle<Object> SetProperty(Handle<Object> object,
255 Handle<Object> key,
256 Handle<Object> value,
257 PropertyAttributes attributes) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000258 CALL_HEAP_FUNCTION(
259 Runtime::SetObjectProperty(object, key, value, attributes), Object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000260}
261
262
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000263Handle<Object> ForceSetProperty(Handle<JSObject> object,
264 Handle<Object> key,
265 Handle<Object> value,
266 PropertyAttributes attributes) {
267 CALL_HEAP_FUNCTION(
268 Runtime::ForceSetObjectProperty(object, key, value, attributes), Object);
269}
270
271
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000272Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
273 Handle<String> key,
274 Handle<Object> value,
275 PropertyDetails details) {
276 CALL_HEAP_FUNCTION(object->SetNormalizedProperty(*key, *value, details),
277 Object);
278}
279
280
ager@chromium.orge2902be2009-06-08 12:21:35 +0000281Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
282 Handle<Object> key) {
283 CALL_HEAP_FUNCTION(Runtime::ForceDeleteObjectProperty(object, key), Object);
284}
285
286
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000287Handle<Object> IgnoreAttributesAndSetLocalProperty(
288 Handle<JSObject> object,
289 Handle<String> key,
290 Handle<Object> value,
291 PropertyAttributes attributes) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000292 CALL_HEAP_FUNCTION(object->
293 IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object);
294}
295
ager@chromium.orge2902be2009-06-08 12:21:35 +0000296
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
298 Handle<String> key,
299 Handle<Object> value,
300 PropertyAttributes attributes) {
301 CALL_HEAP_FUNCTION(object->SetPropertyWithInterceptor(*key,
302 *value,
303 attributes),
304 Object);
305}
306
307
308Handle<Object> GetProperty(Handle<JSObject> obj,
309 const char* name) {
310 Handle<String> str = Factory::LookupAsciiSymbol(name);
311 CALL_HEAP_FUNCTION(obj->GetProperty(*str), Object);
312}
313
314
315Handle<Object> GetProperty(Handle<Object> obj,
316 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000317 CALL_HEAP_FUNCTION(Runtime::GetObjectProperty(obj, key), Object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318}
319
320
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000321Handle<Object> GetElement(Handle<Object> obj,
322 uint32_t index) {
323 CALL_HEAP_FUNCTION(Runtime::GetElement(obj, index), Object);
324}
325
326
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
328 Handle<JSObject> holder,
329 Handle<String> name,
330 PropertyAttributes* attributes) {
331 CALL_HEAP_FUNCTION(holder->GetPropertyWithInterceptor(*receiver,
332 *name,
333 attributes),
334 Object);
335}
336
337
338Handle<Object> GetPrototype(Handle<Object> obj) {
339 Handle<Object> result(obj->GetPrototype());
340 return result;
341}
342
343
ager@chromium.org5c838252010-02-19 08:53:10 +0000344Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) {
345 const bool skip_hidden_prototypes = false;
346 CALL_HEAP_FUNCTION(obj->SetPrototype(*value, skip_hidden_prototypes), Object);
347}
348
349
ager@chromium.org3b45ab52009-03-19 22:21:34 +0000350Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
351 bool create_if_needed) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000352 Object* holder = obj->BypassGlobalProxy();
353 if (holder->IsUndefined()) return Factory::undefined_value();
354 obj = Handle<JSObject>(JSObject::cast(holder));
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000355
356 if (obj->HasFastProperties()) {
357 // If the object has fast properties, check whether the first slot
358 // in the descriptor array matches the hidden symbol. Since the
359 // hidden symbols hash code is zero (and no other string has hash
360 // code zero) it will always occupy the first entry if present.
361 DescriptorArray* descriptors = obj->map()->instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000362 if ((descriptors->number_of_descriptors() > 0) &&
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000363 (descriptors->GetKey(0) == Heap::hidden_symbol()) &&
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000364 descriptors->IsProperty(0)) {
365 ASSERT(descriptors->GetType(0) == FIELD);
366 return Handle<Object>(obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000367 }
368 }
369
370 // Only attempt to find the hidden properties in the local object and not
371 // in the prototype chain. Note that HasLocalProperty() can cause a GC in
372 // the general case in the presence of interceptors.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000373 if (!obj->HasHiddenPropertiesObject()) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000374 // Hidden properties object not found. Allocate a new hidden properties
375 // object if requested. Otherwise return the undefined value.
376 if (create_if_needed) {
377 Handle<Object> hidden_obj = Factory::NewJSObject(Top::object_function());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000378 CALL_HEAP_FUNCTION(obj->SetHiddenPropertiesObject(*hidden_obj), Object);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000379 } else {
380 return Factory::undefined_value();
381 }
382 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000383 return Handle<Object>(obj->GetHiddenPropertiesObject());
ager@chromium.org3b45ab52009-03-19 22:21:34 +0000384}
385
386
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387Handle<Object> DeleteElement(Handle<JSObject> obj,
388 uint32_t index) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000389 CALL_HEAP_FUNCTION(obj->DeleteElement(index, JSObject::NORMAL_DELETION),
390 Object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391}
392
393
394Handle<Object> DeleteProperty(Handle<JSObject> obj,
395 Handle<String> prop) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000396 CALL_HEAP_FUNCTION(obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
397 Object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398}
399
400
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000401Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) {
402 CALL_HEAP_FUNCTION(Heap::LookupSingleCharacterStringFromCode(index), Object);
403}
404
405
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000406Handle<String> SubString(Handle<String> str,
407 int start,
408 int end,
409 PretenureFlag pretenure) {
410 CALL_HEAP_FUNCTION(str->SubString(start, end, pretenure), String);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000411}
412
413
414Handle<Object> SetElement(Handle<JSObject> object,
415 uint32_t index,
416 Handle<Object> value) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000417 if (object->HasPixelElements() || object->HasExternalArrayElements()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000418 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
419 bool has_exception;
420 Handle<Object> number = Execution::ToNumber(value, &has_exception);
421 if (has_exception) return Handle<Object>();
422 value = number;
423 }
424 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000425 CALL_HEAP_FUNCTION(object->SetElement(index, *value), Object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000426}
427
428
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000429Handle<JSObject> Copy(Handle<JSObject> obj) {
430 CALL_HEAP_FUNCTION(Heap::CopyJSObject(*obj), JSObject);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431}
432
433
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000434Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info) {
435 CALL_HEAP_FUNCTION(obj->DefineAccessor(*info), Object);
436}
437
438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439// Wrappers for scripts are kept alive and cached in weak global
440// handles referred from proxy objects held by the scripts as long as
441// they are used. When they are not used anymore, the garbage
442// collector will call the weak callback on the global handle
443// associated with the wrapper and get rid of both the wrapper and the
444// handle.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000445static void ClearWrapperCache(Persistent<v8::Value> handle, void*) {
ager@chromium.org71daaf62009-04-01 07:22:49 +0000446#ifdef ENABLE_HEAP_PROTECTION
447 // Weak reference callbacks are called as if from outside V8. We
448 // need to reeenter to unprotect the heap.
449 VMState state(OTHER);
450#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000451 Handle<Object> cache = Utils::OpenHandle(*handle);
452 JSValue* wrapper = JSValue::cast(*cache);
453 Proxy* proxy = Script::cast(wrapper->value())->wrapper();
454 ASSERT(proxy->proxy() == reinterpret_cast<Address>(cache.location()));
455 proxy->set_proxy(0);
456 GlobalHandles::Destroy(cache.location());
457 Counters::script_wrappers.Decrement();
458}
459
460
461Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000462 if (script->wrapper()->proxy() != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000463 // Return the script wrapper directly from the cache.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000464 return Handle<JSValue>(
465 reinterpret_cast<JSValue**>(script->wrapper()->proxy()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000466 }
467
468 // Construct a new script wrapper.
469 Counters::script_wrappers.Increment();
470 Handle<JSFunction> constructor = Top::script_function();
471 Handle<JSValue> result =
472 Handle<JSValue>::cast(Factory::NewJSObject(constructor));
473 result->set_value(*script);
474
475 // Create a new weak global handle and use it to cache the wrapper
476 // for future use. The cache will automatically be cleared by the
477 // garbage collector when it is not used anymore.
478 Handle<Object> handle = GlobalHandles::Create(*result);
479 GlobalHandles::MakeWeak(handle.location(), NULL, &ClearWrapperCache);
480 script->wrapper()->set_proxy(reinterpret_cast<Address>(handle.location()));
481 return result;
482}
483
484
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000485// Init line_ends array with code positions of line ends inside script
486// source.
487void InitScriptLineEnds(Handle<Script> script) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000488 if (!script->line_ends()->IsUndefined()) return;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000489
490 if (!script->source()->IsString()) {
491 ASSERT(script->source()->IsUndefined());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000492 Handle<FixedArray> empty = Factory::NewFixedArray(0);
493 script->set_line_ends(*empty);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000494 ASSERT(script->line_ends()->IsFixedArray());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000495 return;
496 }
497
498 Handle<String> src(String::cast(script->source()));
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000499
500 Handle<FixedArray> array = CalculateLineEnds(src, true);
501
502 script->set_line_ends(*array);
503 ASSERT(script->line_ends()->IsFixedArray());
504}
505
506
507Handle<FixedArray> CalculateLineEnds(Handle<String> src,
508 bool with_imaginary_last_new_line) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000509 const int src_len = src->length();
510 Handle<String> new_line = Factory::NewStringFromAscii(CStrVector("\n"));
511
512 // Pass 1: Identify line count.
513 int line_count = 0;
514 int position = 0;
515 while (position != -1 && position < src_len) {
516 position = Runtime::StringMatch(src, new_line, position);
517 if (position != -1) {
518 position++;
519 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000520 if (position != -1) {
521 line_count++;
522 } else if (with_imaginary_last_new_line) {
523 // Even if the last line misses a line end, it is counted.
524 line_count++;
525 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000526 }
527
528 // Pass 2: Fill in line ends positions
529 Handle<FixedArray> array = Factory::NewFixedArray(line_count);
530 int array_index = 0;
531 position = 0;
532 while (position != -1 && position < src_len) {
533 position = Runtime::StringMatch(src, new_line, position);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000534 if (position != -1) {
535 array->set(array_index++, Smi::FromInt(position++));
536 } else if (with_imaginary_last_new_line) {
537 // If the script does not end with a line ending add the final end
538 // position as just past the last line ending.
539 array->set(array_index++, Smi::FromInt(src_len));
540 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000541 }
542 ASSERT(array_index == line_count);
543
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000544 return array;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000545}
546
547
548// Convert code position into line number.
549int GetScriptLineNumber(Handle<Script> script, int code_pos) {
550 InitScriptLineEnds(script);
551 AssertNoAllocation no_allocation;
ager@chromium.org5c838252010-02-19 08:53:10 +0000552 FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000553 const int line_ends_len = line_ends_array->length();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000554
ager@chromium.org5c838252010-02-19 08:53:10 +0000555 if (!line_ends_len)
556 return -1;
557
558 if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos)
559 return script->line_offset()->value();
560
561 int left = 0;
562 int right = line_ends_len;
563 while (int half = (right - left) / 2) {
564 if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
565 right -= half;
566 } else {
567 left += half;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000568 }
569 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000570 return right + script->line_offset()->value();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000571}
572
573
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000574int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) {
575 AssertNoAllocation no_allocation;
576 if (!script->line_ends()->IsUndefined()) {
577 return GetScriptLineNumber(script, code_pos);
578 }
579 // Slow mode: we do not have line_ends. We have to iterate through source.
580 if (!script->source()->IsString()) {
581 return -1;
582 }
583 String* source = String::cast(script->source());
584 int line = 0;
585 int len = source->length();
586 for (int pos = 0; pos < len; pos++) {
587 if (pos == code_pos) {
588 break;
589 }
590 if (source->Get(pos) == '\n') {
591 line++;
592 }
593 }
594 return line;
595}
596
597
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000598void CustomArguments::IterateInstance(ObjectVisitor* v) {
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000599 v->VisitPointers(values_, values_ + ARRAY_SIZE(values_));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000600}
601
602
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603// Compute the property keys from the interceptor.
604v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
605 Handle<JSObject> object) {
606 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000607 CustomArguments args(interceptor->data(), *receiver, *object);
608 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000609 v8::Handle<v8::Array> result;
610 if (!interceptor->enumerator()->IsUndefined()) {
611 v8::NamedPropertyEnumerator enum_fun =
612 v8::ToCData<v8::NamedPropertyEnumerator>(interceptor->enumerator());
613 LOG(ApiObjectAccess("interceptor-named-enum", *object));
614 {
615 // Leaving JavaScript.
ager@chromium.org41826e72009-03-30 13:30:57 +0000616 VMState state(EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617 result = enum_fun(info);
618 }
619 }
620 return result;
621}
622
623
624// Compute the element keys from the interceptor.
625v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
626 Handle<JSObject> object) {
627 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000628 CustomArguments args(interceptor->data(), *receiver, *object);
629 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630 v8::Handle<v8::Array> result;
631 if (!interceptor->enumerator()->IsUndefined()) {
632 v8::IndexedPropertyEnumerator enum_fun =
633 v8::ToCData<v8::IndexedPropertyEnumerator>(interceptor->enumerator());
634 LOG(ApiObjectAccess("interceptor-indexed-enum", *object));
635 {
636 // Leaving JavaScript.
ager@chromium.org41826e72009-03-30 13:30:57 +0000637 VMState state(EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638 result = enum_fun(info);
639 }
640 }
641 return result;
642}
643
644
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000645static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
646 int len = array->length();
647 for (int i = 0; i < len; i++) {
648 Object* e = array->get(i);
649 if (!(e->IsString() || e->IsNumber())) return false;
650 }
651 return true;
652}
653
654
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000655Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
656 KeyCollectionType type) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000657 USE(ContainsOnlyValidKeys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000658 Handle<FixedArray> content = Factory::empty_fixed_array();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000659 Handle<JSObject> arguments_boilerplate =
660 Handle<JSObject>(
661 Top::context()->global_context()->arguments_boilerplate());
662 Handle<JSFunction> arguments_function =
663 Handle<JSFunction>(
664 JSFunction::cast(arguments_boilerplate->map()->constructor()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000666 // Only collect keys if access is permitted.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000667 for (Handle<Object> p = object;
668 *p != Heap::null_value();
669 p = Handle<Object>(p->GetPrototype())) {
670 Handle<JSObject> current(JSObject::cast(*p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000672 // Check access rights if required.
673 if (current->IsAccessCheckNeeded() &&
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000674 !Top::MayNamedAccess(*current, Heap::undefined_value(),
675 v8::ACCESS_KEYS)) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000676 Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
677 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000678 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000679
680 // Compute the element keys.
681 Handle<FixedArray> element_keys =
682 Factory::NewFixedArray(current->NumberOfEnumElements());
683 current->GetEnumElementKeys(*element_keys);
684 content = UnionOfKeys(content, element_keys);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000685 ASSERT(ContainsOnlyValidKeys(content));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000686
687 // Add the element keys from the interceptor.
688 if (current->HasIndexedInterceptor()) {
689 v8::Handle<v8::Array> result =
690 GetKeysForIndexedInterceptor(object, current);
691 if (!result.IsEmpty())
692 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000693 ASSERT(ContainsOnlyValidKeys(content));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000694 }
695
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000696 // We can cache the computed property keys if access checks are
697 // not needed and no interceptors are involved.
698 //
699 // We do not use the cache if the object has elements and
700 // therefore it does not make sense to cache the property names
701 // for arguments objects. Arguments objects will always have
702 // elements.
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000703 // Wrapped strings have elements, but don't have an elements
704 // array or dictionary. So the fast inline test for whether to
705 // use the cache says yes, so we should not create a cache.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000706 bool cache_enum_keys =
707 ((current->map()->constructor() != *arguments_function) &&
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000708 !current->IsJSValue() &&
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000709 !current->IsAccessCheckNeeded() &&
710 !current->HasNamedInterceptor() &&
711 !current->HasIndexedInterceptor());
712 // Compute the property keys and cache them if possible.
713 content =
714 UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000715 ASSERT(ContainsOnlyValidKeys(content));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000716
717 // Add the property keys from the interceptor.
718 if (current->HasNamedInterceptor()) {
719 v8::Handle<v8::Array> result =
720 GetKeysForNamedInterceptor(object, current);
721 if (!result.IsEmpty())
722 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000723 ASSERT(ContainsOnlyValidKeys(content));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000724 }
725
726 // If we only want local properties we bail out after the first
727 // iteration.
728 if (type == LOCAL_ONLY)
729 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000730 }
731 return content;
732}
733
734
735Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
736 Counters::for_in.Increment();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000737 Handle<FixedArray> elements = GetKeysInFixedArrayFor(object,
738 INCLUDE_PROTOS);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000739 return Factory::NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000740}
741
742
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000743Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
744 bool cache_result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745 int index = 0;
746 if (object->HasFastProperties()) {
747 if (object->map()->instance_descriptors()->HasEnumCache()) {
748 Counters::enum_cache_hits.Increment();
749 DescriptorArray* desc = object->map()->instance_descriptors();
750 return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache()));
751 }
752 Counters::enum_cache_misses.Increment();
753 int num_enum = object->NumberOfEnumProperties();
754 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum);
755 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000756 Handle<DescriptorArray> descs =
757 Handle<DescriptorArray>(object->map()->instance_descriptors());
758 for (int i = 0; i < descs->number_of_descriptors(); i++) {
759 if (descs->IsProperty(i) && !descs->IsDontEnum(i)) {
760 (*storage)->set(index, descs->GetKey(i));
761 PropertyDetails details(descs->GetDetails(i));
762 (*sort_array)->set(index, Smi::FromInt(details.index()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000763 index++;
764 }
765 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000766 (*storage)->SortPairs(*sort_array, sort_array->length());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000767 if (cache_result) {
768 Handle<FixedArray> bridge_storage =
769 Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength);
770 DescriptorArray* desc = object->map()->instance_descriptors();
771 desc->SetEnumCache(*bridge_storage, *storage);
772 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773 ASSERT(storage->length() == index);
774 return storage;
775 } else {
776 int num_enum = object->NumberOfEnumProperties();
777 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum);
778 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum);
779 object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array);
780 return storage;
781 }
782}
783
784
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000785bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
786 ClearExceptionFlag flag) {
787 return shared->is_compiled() || CompileLazyShared(shared, flag);
788}
789
790
791static bool CompileLazyHelper(CompilationInfo* info,
792 ClearExceptionFlag flag) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793 // Compile the source information to a code object.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000794 ASSERT(!info->shared_info()->is_compiled());
795 bool result = Compiler::CompileLazy(info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000796 ASSERT(result != Top::has_pending_exception());
797 if (!result && flag == CLEAR_EXCEPTION) Top::clear_pending_exception();
798 return result;
799}
800
801
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000802bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
803 ClearExceptionFlag flag) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000804 CompilationInfo info(shared);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000805 return CompileLazyHelper(&info, flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806}
807
808
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000809bool CompileLazy(Handle<JSFunction> function,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000810 ClearExceptionFlag flag) {
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000811 if (function->shared()->is_compiled()) {
812 function->set_code(function->shared()->code());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000813 PROFILE(FunctionCreateEvent(*function));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000814 function->shared()->set_code_age(0);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000815 return true;
816 } else {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000817 CompilationInfo info(function);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000818 bool result = CompileLazyHelper(&info, flag);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000819 ASSERT(!result || function->is_compiled());
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000820 PROFILE(FunctionCreateEvent(*function));
821 return result;
822 }
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000823}
824
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000825
826bool CompileLazyInLoop(Handle<JSFunction> function,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000827 ClearExceptionFlag flag) {
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000828 if (function->shared()->is_compiled()) {
829 function->set_code(function->shared()->code());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000830 PROFILE(FunctionCreateEvent(*function));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000831 function->shared()->set_code_age(0);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000832 return true;
833 } else {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000834 CompilationInfo info(function);
835 info.MarkAsInLoop();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000836 bool result = CompileLazyHelper(&info, flag);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000837 ASSERT(!result || function->is_compiled());
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000838 PROFILE(FunctionCreateEvent(*function));
839 return result;
840 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000841}
842
843
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000844OptimizedObjectForAddingMultipleProperties::
845OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000846 int expected_additional_properties,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847 bool condition) {
848 object_ = object;
849 if (condition && object_->HasFastProperties()) {
850 // Normalize the properties of object to avoid n^2 behavior
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000851 // when extending the object multiple properties. Indicate the number of
852 // properties to be added.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000853 unused_property_fields_ = object->map()->unused_property_fields();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000854 NormalizeProperties(object_,
855 KEEP_INOBJECT_PROPERTIES,
856 expected_additional_properties);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000857 has_been_transformed_ = true;
858
859 } else {
860 has_been_transformed_ = false;
861 }
862}
863
864
865OptimizedObjectForAddingMultipleProperties::
866~OptimizedObjectForAddingMultipleProperties() {
867 // Reoptimize the object to allow fast property access.
868 if (has_been_transformed_) {
869 TransformToFastProperties(object_, unused_property_fields_);
870 }
871}
872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873} } // namespace v8::internal