• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #include "accessors.h"
31 #include "api.h"
32 #include "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 #include "string-search.h"
41 #include "stub-cache.h"
42 #include "vm-state-inl.h"
43 
44 namespace v8 {
45 namespace internal {
46 
47 
NumberOfHandles()48 int HandleScope::NumberOfHandles() {
49   Isolate* isolate = Isolate::Current();
50   HandleScopeImplementer* impl = isolate->handle_scope_implementer();
51   int n = impl->blocks()->length();
52   if (n == 0) return 0;
53   return ((n - 1) * kHandleBlockSize) + static_cast<int>(
54       (isolate->handle_scope_data()->next - impl->blocks()->last()));
55 }
56 
57 
Extend()58 Object** HandleScope::Extend() {
59   Isolate* isolate = Isolate::Current();
60   v8::ImplementationUtilities::HandleScopeData* current =
61       isolate->handle_scope_data();
62 
63   Object** result = current->next;
64 
65   ASSERT(result == current->limit);
66   // Make sure there's at least one scope on the stack and that the
67   // top of the scope stack isn't a barrier.
68   if (current->level == 0) {
69     Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
70                             "Cannot create a handle without a HandleScope");
71     return NULL;
72   }
73   HandleScopeImplementer* impl = isolate->handle_scope_implementer();
74   // If there's more room in the last block, we use that. This is used
75   // for fast creation of scopes after scope barriers.
76   if (!impl->blocks()->is_empty()) {
77     Object** limit = &impl->blocks()->last()[kHandleBlockSize];
78     if (current->limit != limit) {
79       current->limit = limit;
80       ASSERT(limit - current->next < kHandleBlockSize);
81     }
82   }
83 
84   // If we still haven't found a slot for the handle, we extend the
85   // current handle scope by allocating a new handle block.
86   if (result == current->limit) {
87     // If there's a spare block, use it for growing the current scope.
88     result = impl->GetSpareOrNewBlock();
89     // Add the extension to the global list of blocks, but count the
90     // extension as part of the current scope.
91     impl->blocks()->Add(result);
92     current->limit = &result[kHandleBlockSize];
93   }
94 
95   return result;
96 }
97 
98 
DeleteExtensions(Isolate * isolate)99 void HandleScope::DeleteExtensions(Isolate* isolate) {
100   ASSERT(isolate == Isolate::Current());
101   v8::ImplementationUtilities::HandleScopeData* current =
102       isolate->handle_scope_data();
103   isolate->handle_scope_implementer()->DeleteExtensions(current->limit);
104 }
105 
106 
ZapRange(Object ** start,Object ** end)107 void HandleScope::ZapRange(Object** start, Object** end) {
108   ASSERT(end - start <= kHandleBlockSize);
109   for (Object** p = start; p != end; p++) {
110     *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue;
111   }
112 }
113 
114 
current_level_address()115 Address HandleScope::current_level_address() {
116   return reinterpret_cast<Address>(
117       &Isolate::Current()->handle_scope_data()->level);
118 }
119 
120 
current_next_address()121 Address HandleScope::current_next_address() {
122   return reinterpret_cast<Address>(
123       &Isolate::Current()->handle_scope_data()->next);
124 }
125 
126 
current_limit_address()127 Address HandleScope::current_limit_address() {
128   return reinterpret_cast<Address>(
129       &Isolate::Current()->handle_scope_data()->limit);
130 }
131 
132 
AddKeysFromJSArray(Handle<FixedArray> content,Handle<JSArray> array)133 Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content,
134                                       Handle<JSArray> array) {
135   CALL_HEAP_FUNCTION(content->GetIsolate(),
136                      content->AddKeysFromJSArray(*array), FixedArray);
137 }
138 
139 
UnionOfKeys(Handle<FixedArray> first,Handle<FixedArray> second)140 Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first,
141                                Handle<FixedArray> second) {
142   CALL_HEAP_FUNCTION(first->GetIsolate(),
143                      first->UnionOfKeys(*second), FixedArray);
144 }
145 
146 
ReinitializeJSGlobalProxy(Handle<JSFunction> constructor,Handle<JSGlobalProxy> global)147 Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
148     Handle<JSFunction> constructor,
149     Handle<JSGlobalProxy> global) {
150   CALL_HEAP_FUNCTION(
151       constructor->GetIsolate(),
152       constructor->GetHeap()->ReinitializeJSGlobalProxy(*constructor, *global),
153       JSGlobalProxy);
154 }
155 
156 
SetExpectedNofProperties(Handle<JSFunction> func,int nof)157 void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
158   // If objects constructed from this function exist then changing
159   // 'estimated_nof_properties' is dangerous since the previous value might
160   // have been compiled into the fast construct stub. More over, the inobject
161   // slack tracking logic might have adjusted the previous value, so even
162   // passing the same value is risky.
163   if (func->shared()->live_objects_may_exist()) return;
164 
165   func->shared()->set_expected_nof_properties(nof);
166   if (func->has_initial_map()) {
167     Handle<Map> new_initial_map =
168         func->GetIsolate()->factory()->CopyMapDropTransitions(
169             Handle<Map>(func->initial_map()));
170     new_initial_map->set_unused_property_fields(nof);
171     func->set_initial_map(*new_initial_map);
172   }
173 }
174 
175 
SetPrototypeProperty(Handle<JSFunction> func,Handle<JSObject> value)176 void SetPrototypeProperty(Handle<JSFunction> func, Handle<JSObject> value) {
177   CALL_HEAP_FUNCTION_VOID(func->GetIsolate(),
178                           func->SetPrototype(*value));
179 }
180 
181 
ExpectedNofPropertiesFromEstimate(int estimate)182 static int ExpectedNofPropertiesFromEstimate(int estimate) {
183   // If no properties are added in the constructor, they are more likely
184   // to be added later.
185   if (estimate == 0) estimate = 2;
186 
187   // We do not shrink objects that go into a snapshot (yet), so we adjust
188   // the estimate conservatively.
189   if (Serializer::enabled()) return estimate + 2;
190 
191   // Inobject slack tracking will reclaim redundant inobject space later,
192   // so we can afford to adjust the estimate generously.
193   return estimate + 8;
194 }
195 
196 
SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,int estimate)197 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
198                                           int estimate) {
199   // See the comment in SetExpectedNofProperties.
200   if (shared->live_objects_may_exist()) return;
201 
202   shared->set_expected_nof_properties(
203       ExpectedNofPropertiesFromEstimate(estimate));
204 }
205 
206 
NormalizeProperties(Handle<JSObject> object,PropertyNormalizationMode mode,int expected_additional_properties)207 void NormalizeProperties(Handle<JSObject> object,
208                          PropertyNormalizationMode mode,
209                          int expected_additional_properties) {
210   CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
211                           object->NormalizeProperties(
212                               mode,
213                               expected_additional_properties));
214 }
215 
216 
NormalizeElements(Handle<JSObject> object)217 void NormalizeElements(Handle<JSObject> object) {
218   CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
219                           object->NormalizeElements());
220 }
221 
222 
TransformToFastProperties(Handle<JSObject> object,int unused_property_fields)223 void TransformToFastProperties(Handle<JSObject> object,
224                                int unused_property_fields) {
225   CALL_HEAP_FUNCTION_VOID(
226       object->GetIsolate(),
227       object->TransformToFastProperties(unused_property_fields));
228 }
229 
230 
NumberDictionarySet(Handle<NumberDictionary> dictionary,uint32_t index,Handle<Object> value,PropertyDetails details)231 void NumberDictionarySet(Handle<NumberDictionary> dictionary,
232                          uint32_t index,
233                          Handle<Object> value,
234                          PropertyDetails details) {
235   CALL_HEAP_FUNCTION_VOID(dictionary->GetIsolate(),
236                           dictionary->Set(index, *value, details));
237 }
238 
239 
FlattenString(Handle<String> string)240 void FlattenString(Handle<String> string) {
241   CALL_HEAP_FUNCTION_VOID(string->GetIsolate(), string->TryFlatten());
242 }
243 
244 
FlattenGetString(Handle<String> string)245 Handle<String> FlattenGetString(Handle<String> string) {
246   CALL_HEAP_FUNCTION(string->GetIsolate(), string->TryFlatten(), String);
247 }
248 
249 
SetPrototype(Handle<JSFunction> function,Handle<Object> prototype)250 Handle<Object> SetPrototype(Handle<JSFunction> function,
251                             Handle<Object> prototype) {
252   ASSERT(function->should_have_prototype());
253   CALL_HEAP_FUNCTION(function->GetIsolate(),
254                      Accessors::FunctionSetPrototype(*function,
255                                                      *prototype,
256                                                      NULL),
257                      Object);
258 }
259 
260 
SetProperty(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyAttributes attributes,StrictModeFlag strict_mode)261 Handle<Object> SetProperty(Handle<JSObject> object,
262                            Handle<String> key,
263                            Handle<Object> value,
264                            PropertyAttributes attributes,
265                            StrictModeFlag strict_mode) {
266   CALL_HEAP_FUNCTION(object->GetIsolate(),
267                      object->SetProperty(*key, *value, attributes, strict_mode),
268                      Object);
269 }
270 
271 
SetProperty(Handle<Object> object,Handle<Object> key,Handle<Object> value,PropertyAttributes attributes,StrictModeFlag strict_mode)272 Handle<Object> SetProperty(Handle<Object> object,
273                            Handle<Object> key,
274                            Handle<Object> value,
275                            PropertyAttributes attributes,
276                            StrictModeFlag strict_mode) {
277   Isolate* isolate = Isolate::Current();
278   CALL_HEAP_FUNCTION(
279       isolate,
280       Runtime::SetObjectProperty(
281           isolate, object, key, value, attributes, strict_mode),
282       Object);
283 }
284 
285 
ForceSetProperty(Handle<JSObject> object,Handle<Object> key,Handle<Object> value,PropertyAttributes attributes)286 Handle<Object> ForceSetProperty(Handle<JSObject> object,
287                                 Handle<Object> key,
288                                 Handle<Object> value,
289                                 PropertyAttributes attributes) {
290   Isolate* isolate = object->GetIsolate();
291   CALL_HEAP_FUNCTION(
292       isolate,
293       Runtime::ForceSetObjectProperty(
294           isolate, object, key, value, attributes),
295       Object);
296 }
297 
298 
SetNormalizedProperty(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyDetails details)299 Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
300                                      Handle<String> key,
301                                      Handle<Object> value,
302                                      PropertyDetails details) {
303   CALL_HEAP_FUNCTION(object->GetIsolate(),
304                      object->SetNormalizedProperty(*key, *value, details),
305                      Object);
306 }
307 
308 
ForceDeleteProperty(Handle<JSObject> object,Handle<Object> key)309 Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
310                                    Handle<Object> key) {
311   Isolate* isolate = object->GetIsolate();
312   CALL_HEAP_FUNCTION(isolate,
313                      Runtime::ForceDeleteObjectProperty(isolate, object, key),
314                      Object);
315 }
316 
317 
SetLocalPropertyIgnoreAttributes(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyAttributes attributes)318 Handle<Object> SetLocalPropertyIgnoreAttributes(
319     Handle<JSObject> object,
320     Handle<String> key,
321     Handle<Object> value,
322     PropertyAttributes attributes) {
323   CALL_HEAP_FUNCTION(
324     object->GetIsolate(),
325     object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
326     Object);
327 }
328 
329 
SetLocalPropertyNoThrow(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyAttributes attributes)330 void SetLocalPropertyNoThrow(Handle<JSObject> object,
331                              Handle<String> key,
332                              Handle<Object> value,
333                              PropertyAttributes attributes) {
334   Isolate* isolate = object->GetIsolate();
335   ASSERT(!isolate->has_pending_exception());
336   CHECK(!SetLocalPropertyIgnoreAttributes(
337         object, key, value, attributes).is_null());
338   CHECK(!isolate->has_pending_exception());
339 }
340 
341 
SetPropertyWithInterceptor(Handle<JSObject> object,Handle<String> key,Handle<Object> value,PropertyAttributes attributes,StrictModeFlag strict_mode)342 Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
343                                           Handle<String> key,
344                                           Handle<Object> value,
345                                           PropertyAttributes attributes,
346                                           StrictModeFlag strict_mode) {
347   CALL_HEAP_FUNCTION(object->GetIsolate(),
348                      object->SetPropertyWithInterceptor(*key,
349                                                         *value,
350                                                         attributes,
351                                                         strict_mode),
352                      Object);
353 }
354 
355 
GetProperty(Handle<JSObject> obj,const char * name)356 Handle<Object> GetProperty(Handle<JSObject> obj,
357                            const char* name) {
358   Isolate* isolate = obj->GetIsolate();
359   Handle<String> str = isolate->factory()->LookupAsciiSymbol(name);
360   CALL_HEAP_FUNCTION(isolate, obj->GetProperty(*str), Object);
361 }
362 
363 
GetProperty(Handle<Object> obj,Handle<Object> key)364 Handle<Object> GetProperty(Handle<Object> obj,
365                            Handle<Object> key) {
366   Isolate* isolate = Isolate::Current();
367   CALL_HEAP_FUNCTION(isolate,
368                      Runtime::GetObjectProperty(isolate, obj, key), Object);
369 }
370 
371 
GetProperty(Handle<JSObject> obj,Handle<String> name,LookupResult * result)372 Handle<Object> GetProperty(Handle<JSObject> obj,
373                            Handle<String> name,
374                            LookupResult* result) {
375   PropertyAttributes attributes;
376   Isolate* isolate = Isolate::Current();
377   CALL_HEAP_FUNCTION(isolate,
378                      obj->GetProperty(*obj, result, *name, &attributes),
379                      Object);
380 }
381 
382 
GetElement(Handle<Object> obj,uint32_t index)383 Handle<Object> GetElement(Handle<Object> obj,
384                           uint32_t index) {
385   Isolate* isolate = Isolate::Current();
386   CALL_HEAP_FUNCTION(isolate, Runtime::GetElement(obj, index), Object);
387 }
388 
389 
GetPropertyWithInterceptor(Handle<JSObject> receiver,Handle<JSObject> holder,Handle<String> name,PropertyAttributes * attributes)390 Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
391                                           Handle<JSObject> holder,
392                                           Handle<String> name,
393                                           PropertyAttributes* attributes) {
394   Isolate* isolate = receiver->GetIsolate();
395   CALL_HEAP_FUNCTION(isolate,
396                      holder->GetPropertyWithInterceptor(*receiver,
397                                                         *name,
398                                                         attributes),
399                      Object);
400 }
401 
402 
GetPrototype(Handle<Object> obj)403 Handle<Object> GetPrototype(Handle<Object> obj) {
404   Handle<Object> result(obj->GetPrototype());
405   return result;
406 }
407 
408 
SetPrototype(Handle<JSObject> obj,Handle<Object> value)409 Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) {
410   const bool skip_hidden_prototypes = false;
411   CALL_HEAP_FUNCTION(obj->GetIsolate(),
412                      obj->SetPrototype(*value, skip_hidden_prototypes), Object);
413 }
414 
415 
PreventExtensions(Handle<JSObject> object)416 Handle<Object> PreventExtensions(Handle<JSObject> object) {
417   CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
418 }
419 
420 
GetHiddenProperties(Handle<JSObject> obj,bool create_if_needed)421 Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
422                                    bool create_if_needed) {
423   Isolate* isolate = obj->GetIsolate();
424   Object* holder = obj->BypassGlobalProxy();
425   if (holder->IsUndefined()) return isolate->factory()->undefined_value();
426   obj = Handle<JSObject>(JSObject::cast(holder), isolate);
427 
428   if (obj->HasFastProperties()) {
429     // If the object has fast properties, check whether the first slot
430     // in the descriptor array matches the hidden symbol. Since the
431     // hidden symbols hash code is zero (and no other string has hash
432     // code zero) it will always occupy the first entry if present.
433     DescriptorArray* descriptors = obj->map()->instance_descriptors();
434     if ((descriptors->number_of_descriptors() > 0) &&
435         (descriptors->GetKey(0) == isolate->heap()->hidden_symbol()) &&
436         descriptors->IsProperty(0)) {
437       ASSERT(descriptors->GetType(0) == FIELD);
438       return Handle<Object>(obj->FastPropertyAt(descriptors->GetFieldIndex(0)),
439                             isolate);
440     }
441   }
442 
443   // Only attempt to find the hidden properties in the local object and not
444   // in the prototype chain.  Note that HasLocalProperty() can cause a GC in
445   // the general case in the presence of interceptors.
446   if (!obj->HasHiddenPropertiesObject()) {
447     // Hidden properties object not found. Allocate a new hidden properties
448     // object if requested. Otherwise return the undefined value.
449     if (create_if_needed) {
450       Handle<Object> hidden_obj =
451           isolate->factory()->NewJSObject(isolate->object_function());
452       CALL_HEAP_FUNCTION(isolate,
453                          obj->SetHiddenPropertiesObject(*hidden_obj), Object);
454     } else {
455       return isolate->factory()->undefined_value();
456     }
457   }
458   return Handle<Object>(obj->GetHiddenPropertiesObject(), isolate);
459 }
460 
461 
DeleteElement(Handle<JSObject> obj,uint32_t index)462 Handle<Object> DeleteElement(Handle<JSObject> obj,
463                              uint32_t index) {
464   CALL_HEAP_FUNCTION(obj->GetIsolate(),
465                      obj->DeleteElement(index, JSObject::NORMAL_DELETION),
466                      Object);
467 }
468 
469 
DeleteProperty(Handle<JSObject> obj,Handle<String> prop)470 Handle<Object> DeleteProperty(Handle<JSObject> obj,
471                               Handle<String> prop) {
472   CALL_HEAP_FUNCTION(obj->GetIsolate(),
473                      obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
474                      Object);
475 }
476 
477 
LookupSingleCharacterStringFromCode(uint32_t index)478 Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) {
479   Isolate* isolate = Isolate::Current();
480   CALL_HEAP_FUNCTION(
481       isolate,
482       isolate->heap()->LookupSingleCharacterStringFromCode(index), Object);
483 }
484 
485 
SubString(Handle<String> str,int start,int end,PretenureFlag pretenure)486 Handle<String> SubString(Handle<String> str,
487                          int start,
488                          int end,
489                          PretenureFlag pretenure) {
490   CALL_HEAP_FUNCTION(str->GetIsolate(),
491                      str->SubString(start, end, pretenure), String);
492 }
493 
494 
SetElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,StrictModeFlag strict_mode)495 Handle<Object> SetElement(Handle<JSObject> object,
496                           uint32_t index,
497                           Handle<Object> value,
498                           StrictModeFlag strict_mode) {
499   if (object->HasExternalArrayElements()) {
500     if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
501       bool has_exception;
502       Handle<Object> number = Execution::ToNumber(value, &has_exception);
503       if (has_exception) return Handle<Object>();
504       value = number;
505     }
506   }
507   CALL_HEAP_FUNCTION(object->GetIsolate(),
508                      object->SetElement(index, *value, strict_mode), Object);
509 }
510 
511 
SetOwnElement(Handle<JSObject> object,uint32_t index,Handle<Object> value,StrictModeFlag strict_mode)512 Handle<Object> SetOwnElement(Handle<JSObject> object,
513                              uint32_t index,
514                              Handle<Object> value,
515                              StrictModeFlag strict_mode) {
516   ASSERT(!object->HasExternalArrayElements());
517   CALL_HEAP_FUNCTION(object->GetIsolate(),
518                      object->SetElement(index, *value, strict_mode, false),
519                      Object);
520 }
521 
522 
Copy(Handle<JSObject> obj)523 Handle<JSObject> Copy(Handle<JSObject> obj) {
524   Isolate* isolate = obj->GetIsolate();
525   CALL_HEAP_FUNCTION(isolate,
526                      isolate->heap()->CopyJSObject(*obj), JSObject);
527 }
528 
529 
SetAccessor(Handle<JSObject> obj,Handle<AccessorInfo> info)530 Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info) {
531   CALL_HEAP_FUNCTION(obj->GetIsolate(), obj->DefineAccessor(*info), Object);
532 }
533 
534 
535 // Wrappers for scripts are kept alive and cached in weak global
536 // handles referred from proxy objects held by the scripts as long as
537 // they are used. When they are not used anymore, the garbage
538 // collector will call the weak callback on the global handle
539 // associated with the wrapper and get rid of both the wrapper and the
540 // handle.
ClearWrapperCache(Persistent<v8::Value> handle,void *)541 static void ClearWrapperCache(Persistent<v8::Value> handle, void*) {
542 #ifdef ENABLE_HEAP_PROTECTION
543   // Weak reference callbacks are called as if from outside V8.  We
544   // need to reeenter to unprotect the heap.
545   VMState state(OTHER);
546 #endif
547   Handle<Object> cache = Utils::OpenHandle(*handle);
548   JSValue* wrapper = JSValue::cast(*cache);
549   Proxy* proxy = Script::cast(wrapper->value())->wrapper();
550   ASSERT(proxy->proxy() == reinterpret_cast<Address>(cache.location()));
551   proxy->set_proxy(0);
552   Isolate* isolate = Isolate::Current();
553   isolate->global_handles()->Destroy(cache.location());
554   isolate->counters()->script_wrappers()->Decrement();
555 }
556 
557 
GetScriptWrapper(Handle<Script> script)558 Handle<JSValue> GetScriptWrapper(Handle<Script> script) {
559   if (script->wrapper()->proxy() != NULL) {
560     // Return the script wrapper directly from the cache.
561     return Handle<JSValue>(
562         reinterpret_cast<JSValue**>(script->wrapper()->proxy()));
563   }
564   Isolate* isolate = Isolate::Current();
565   // Construct a new script wrapper.
566   isolate->counters()->script_wrappers()->Increment();
567   Handle<JSFunction> constructor = isolate->script_function();
568   Handle<JSValue> result =
569       Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
570   result->set_value(*script);
571 
572   // Create a new weak global handle and use it to cache the wrapper
573   // for future use. The cache will automatically be cleared by the
574   // garbage collector when it is not used anymore.
575   Handle<Object> handle = isolate->global_handles()->Create(*result);
576   isolate->global_handles()->MakeWeak(handle.location(), NULL,
577                                       &ClearWrapperCache);
578   script->wrapper()->set_proxy(reinterpret_cast<Address>(handle.location()));
579   return result;
580 }
581 
582 
583 // Init line_ends array with code positions of line ends inside script
584 // source.
InitScriptLineEnds(Handle<Script> script)585 void InitScriptLineEnds(Handle<Script> script) {
586   if (!script->line_ends()->IsUndefined()) return;
587 
588   Isolate* isolate = script->GetIsolate();
589 
590   if (!script->source()->IsString()) {
591     ASSERT(script->source()->IsUndefined());
592     Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
593     script->set_line_ends(*empty);
594     ASSERT(script->line_ends()->IsFixedArray());
595     return;
596   }
597 
598   Handle<String> src(String::cast(script->source()), isolate);
599 
600   Handle<FixedArray> array = CalculateLineEnds(src, true);
601 
602   if (*array != isolate->heap()->empty_fixed_array()) {
603     array->set_map(isolate->heap()->fixed_cow_array_map());
604   }
605 
606   script->set_line_ends(*array);
607   ASSERT(script->line_ends()->IsFixedArray());
608 }
609 
610 
611 template <typename SourceChar>
CalculateLineEnds(Isolate * isolate,List<int> * line_ends,Vector<const SourceChar> src,bool with_last_line)612 static void CalculateLineEnds(Isolate* isolate,
613                               List<int>* line_ends,
614                               Vector<const SourceChar> src,
615                               bool with_last_line) {
616   const int src_len = src.length();
617   StringSearch<char, SourceChar> search(isolate, CStrVector("\n"));
618 
619   // Find and record line ends.
620   int position = 0;
621   while (position != -1 && position < src_len) {
622     position = search.Search(src, position);
623     if (position != -1) {
624       line_ends->Add(position);
625       position++;
626     } else if (with_last_line) {
627       // Even if the last line misses a line end, it is counted.
628       line_ends->Add(src_len);
629       return;
630     }
631   }
632 }
633 
634 
CalculateLineEnds(Handle<String> src,bool with_last_line)635 Handle<FixedArray> CalculateLineEnds(Handle<String> src,
636                                      bool with_last_line) {
637   src = FlattenGetString(src);
638   // Rough estimate of line count based on a roughly estimated average
639   // length of (unpacked) code.
640   int line_count_estimate = src->length() >> 4;
641   List<int> line_ends(line_count_estimate);
642   Isolate* isolate = src->GetIsolate();
643   {
644     AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid.
645     // Dispatch on type of strings.
646     if (src->IsAsciiRepresentation()) {
647       CalculateLineEnds(isolate,
648                         &line_ends,
649                         src->ToAsciiVector(),
650                         with_last_line);
651     } else {
652       CalculateLineEnds(isolate,
653                         &line_ends,
654                         src->ToUC16Vector(),
655                         with_last_line);
656     }
657   }
658   int line_count = line_ends.length();
659   Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
660   for (int i = 0; i < line_count; i++) {
661     array->set(i, Smi::FromInt(line_ends[i]));
662   }
663   return array;
664 }
665 
666 
667 // Convert code position into line number.
GetScriptLineNumber(Handle<Script> script,int code_pos)668 int GetScriptLineNumber(Handle<Script> script, int code_pos) {
669   InitScriptLineEnds(script);
670   AssertNoAllocation no_allocation;
671   FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
672   const int line_ends_len = line_ends_array->length();
673 
674   if (!line_ends_len) return -1;
675 
676   if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
677     return script->line_offset()->value();
678   }
679 
680   int left = 0;
681   int right = line_ends_len;
682   while (int half = (right - left) / 2) {
683     if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
684       right -= half;
685     } else {
686       left += half;
687     }
688   }
689   return right + script->line_offset()->value();
690 }
691 
692 
GetScriptLineNumberSafe(Handle<Script> script,int code_pos)693 int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) {
694   AssertNoAllocation no_allocation;
695   if (!script->line_ends()->IsUndefined()) {
696     return GetScriptLineNumber(script, code_pos);
697   }
698   // Slow mode: we do not have line_ends. We have to iterate through source.
699   if (!script->source()->IsString()) {
700     return -1;
701   }
702   String* source = String::cast(script->source());
703   int line = 0;
704   int len = source->length();
705   for (int pos = 0; pos < len; pos++) {
706     if (pos == code_pos) {
707       break;
708     }
709     if (source->Get(pos) == '\n') {
710       line++;
711     }
712   }
713   return line;
714 }
715 
716 
IterateInstance(ObjectVisitor * v)717 void CustomArguments::IterateInstance(ObjectVisitor* v) {
718   v->VisitPointers(values_, values_ + ARRAY_SIZE(values_));
719 }
720 
721 
722 // Compute the property keys from the interceptor.
GetKeysForNamedInterceptor(Handle<JSObject> receiver,Handle<JSObject> object)723 v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
724                                                  Handle<JSObject> object) {
725   Isolate* isolate = receiver->GetIsolate();
726   Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
727   CustomArguments args(isolate, interceptor->data(), *receiver, *object);
728   v8::AccessorInfo info(args.end());
729   v8::Handle<v8::Array> result;
730   if (!interceptor->enumerator()->IsUndefined()) {
731     v8::NamedPropertyEnumerator enum_fun =
732         v8::ToCData<v8::NamedPropertyEnumerator>(interceptor->enumerator());
733     LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object));
734     {
735       // Leaving JavaScript.
736       VMState state(isolate, EXTERNAL);
737       result = enum_fun(info);
738     }
739   }
740   return result;
741 }
742 
743 
744 // Compute the element keys from the interceptor.
GetKeysForIndexedInterceptor(Handle<JSObject> receiver,Handle<JSObject> object)745 v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
746                                                    Handle<JSObject> object) {
747   Isolate* isolate = receiver->GetIsolate();
748   Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
749   CustomArguments args(isolate, interceptor->data(), *receiver, *object);
750   v8::AccessorInfo info(args.end());
751   v8::Handle<v8::Array> result;
752   if (!interceptor->enumerator()->IsUndefined()) {
753     v8::IndexedPropertyEnumerator enum_fun =
754         v8::ToCData<v8::IndexedPropertyEnumerator>(interceptor->enumerator());
755     LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object));
756     {
757       // Leaving JavaScript.
758       VMState state(isolate, EXTERNAL);
759       result = enum_fun(info);
760     }
761   }
762   return result;
763 }
764 
765 
ContainsOnlyValidKeys(Handle<FixedArray> array)766 static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
767   int len = array->length();
768   for (int i = 0; i < len; i++) {
769     Object* e = array->get(i);
770     if (!(e->IsString() || e->IsNumber())) return false;
771   }
772   return true;
773 }
774 
775 
GetKeysInFixedArrayFor(Handle<JSObject> object,KeyCollectionType type)776 Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
777                                           KeyCollectionType type) {
778   USE(ContainsOnlyValidKeys);
779   Isolate* isolate = object->GetIsolate();
780   Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
781   Handle<JSObject> arguments_boilerplate = Handle<JSObject>(
782       isolate->context()->global_context()->arguments_boilerplate(),
783       isolate);
784   Handle<JSFunction> arguments_function = Handle<JSFunction>(
785       JSFunction::cast(arguments_boilerplate->map()->constructor()),
786       isolate);
787 
788   // Only collect keys if access is permitted.
789   for (Handle<Object> p = object;
790        *p != isolate->heap()->null_value();
791        p = Handle<Object>(p->GetPrototype(), isolate)) {
792     Handle<JSObject> current(JSObject::cast(*p), isolate);
793 
794     // Check access rights if required.
795     if (current->IsAccessCheckNeeded() &&
796         !isolate->MayNamedAccess(*current,
797                                  isolate->heap()->undefined_value(),
798                                  v8::ACCESS_KEYS)) {
799       isolate->ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
800       break;
801     }
802 
803     // Compute the element keys.
804     Handle<FixedArray> element_keys =
805         isolate->factory()->NewFixedArray(current->NumberOfEnumElements());
806     current->GetEnumElementKeys(*element_keys);
807     content = UnionOfKeys(content, element_keys);
808     ASSERT(ContainsOnlyValidKeys(content));
809 
810     // Add the element keys from the interceptor.
811     if (current->HasIndexedInterceptor()) {
812       v8::Handle<v8::Array> result =
813           GetKeysForIndexedInterceptor(object, current);
814       if (!result.IsEmpty())
815         content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
816       ASSERT(ContainsOnlyValidKeys(content));
817     }
818 
819     // We can cache the computed property keys if access checks are
820     // not needed and no interceptors are involved.
821     //
822     // We do not use the cache if the object has elements and
823     // therefore it does not make sense to cache the property names
824     // for arguments objects.  Arguments objects will always have
825     // elements.
826     // Wrapped strings have elements, but don't have an elements
827     // array or dictionary.  So the fast inline test for whether to
828     // use the cache says yes, so we should not create a cache.
829     bool cache_enum_keys =
830         ((current->map()->constructor() != *arguments_function) &&
831          !current->IsJSValue() &&
832          !current->IsAccessCheckNeeded() &&
833          !current->HasNamedInterceptor() &&
834          !current->HasIndexedInterceptor());
835     // Compute the property keys and cache them if possible.
836     content =
837         UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys));
838     ASSERT(ContainsOnlyValidKeys(content));
839 
840     // Add the property keys from the interceptor.
841     if (current->HasNamedInterceptor()) {
842       v8::Handle<v8::Array> result =
843           GetKeysForNamedInterceptor(object, current);
844       if (!result.IsEmpty())
845         content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
846       ASSERT(ContainsOnlyValidKeys(content));
847     }
848 
849     // If we only want local properties we bail out after the first
850     // iteration.
851     if (type == LOCAL_ONLY)
852       break;
853   }
854   return content;
855 }
856 
857 
GetKeysFor(Handle<JSObject> object)858 Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
859   Isolate* isolate = object->GetIsolate();
860   isolate->counters()->for_in()->Increment();
861   Handle<FixedArray> elements = GetKeysInFixedArrayFor(object,
862                                                        INCLUDE_PROTOS);
863   return isolate->factory()->NewJSArrayWithElements(elements);
864 }
865 
866 
GetEnumPropertyKeys(Handle<JSObject> object,bool cache_result)867 Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
868                                        bool cache_result) {
869   int index = 0;
870   Isolate* isolate = object->GetIsolate();
871   if (object->HasFastProperties()) {
872     if (object->map()->instance_descriptors()->HasEnumCache()) {
873       isolate->counters()->enum_cache_hits()->Increment();
874       DescriptorArray* desc = object->map()->instance_descriptors();
875       return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache()),
876                                 isolate);
877     }
878     isolate->counters()->enum_cache_misses()->Increment();
879     int num_enum = object->NumberOfEnumProperties();
880     Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum);
881     Handle<FixedArray> sort_array = isolate->factory()->NewFixedArray(num_enum);
882     Handle<DescriptorArray> descs =
883         Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
884     for (int i = 0; i < descs->number_of_descriptors(); i++) {
885       if (descs->IsProperty(i) && !descs->IsDontEnum(i)) {
886         (*storage)->set(index, descs->GetKey(i));
887         PropertyDetails details(descs->GetDetails(i));
888         (*sort_array)->set(index, Smi::FromInt(details.index()));
889         index++;
890       }
891     }
892     (*storage)->SortPairs(*sort_array, sort_array->length());
893     if (cache_result) {
894       Handle<FixedArray> bridge_storage =
895           isolate->factory()->NewFixedArray(
896               DescriptorArray::kEnumCacheBridgeLength);
897       DescriptorArray* desc = object->map()->instance_descriptors();
898       desc->SetEnumCache(*bridge_storage, *storage);
899     }
900     ASSERT(storage->length() == index);
901     return storage;
902   } else {
903     int num_enum = object->NumberOfEnumProperties();
904     Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum);
905     Handle<FixedArray> sort_array = isolate->factory()->NewFixedArray(num_enum);
906     object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array);
907     return storage;
908   }
909 }
910 
911 
EnsureCompiled(Handle<SharedFunctionInfo> shared,ClearExceptionFlag flag)912 bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
913                     ClearExceptionFlag flag) {
914   return shared->is_compiled() || CompileLazyShared(shared, flag);
915 }
916 
917 
CompileLazyHelper(CompilationInfo * info,ClearExceptionFlag flag)918 static bool CompileLazyHelper(CompilationInfo* info,
919                               ClearExceptionFlag flag) {
920   // Compile the source information to a code object.
921   ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
922   ASSERT(!info->isolate()->has_pending_exception());
923   bool result = Compiler::CompileLazy(info);
924   ASSERT(result != Isolate::Current()->has_pending_exception());
925   if (!result && flag == CLEAR_EXCEPTION) {
926     info->isolate()->clear_pending_exception();
927   }
928   return result;
929 }
930 
931 
CompileLazyShared(Handle<SharedFunctionInfo> shared,ClearExceptionFlag flag)932 bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
933                        ClearExceptionFlag flag) {
934   CompilationInfo info(shared);
935   return CompileLazyHelper(&info, flag);
936 }
937 
938 
CompileLazyFunction(Handle<JSFunction> function,ClearExceptionFlag flag,InLoopFlag in_loop_flag)939 static bool CompileLazyFunction(Handle<JSFunction> function,
940                                 ClearExceptionFlag flag,
941                                 InLoopFlag in_loop_flag) {
942   bool result = true;
943   if (function->shared()->is_compiled()) {
944     function->ReplaceCode(function->shared()->code());
945     function->shared()->set_code_age(0);
946   } else {
947     CompilationInfo info(function);
948     if (in_loop_flag == IN_LOOP) info.MarkAsInLoop();
949     result = CompileLazyHelper(&info, flag);
950     ASSERT(!result || function->is_compiled());
951   }
952   return result;
953 }
954 
955 
CompileLazy(Handle<JSFunction> function,ClearExceptionFlag flag)956 bool CompileLazy(Handle<JSFunction> function,
957                  ClearExceptionFlag flag) {
958   return CompileLazyFunction(function, flag, NOT_IN_LOOP);
959 }
960 
961 
CompileLazyInLoop(Handle<JSFunction> function,ClearExceptionFlag flag)962 bool CompileLazyInLoop(Handle<JSFunction> function,
963                        ClearExceptionFlag flag) {
964   return CompileLazyFunction(function, flag, IN_LOOP);
965 }
966 
967 
CompileOptimized(Handle<JSFunction> function,int osr_ast_id,ClearExceptionFlag flag)968 bool CompileOptimized(Handle<JSFunction> function,
969                       int osr_ast_id,
970                       ClearExceptionFlag flag) {
971   CompilationInfo info(function);
972   info.SetOptimizing(osr_ast_id);
973   return CompileLazyHelper(&info, flag);
974 }
975 
976 } }  // namespace v8::internal
977