419
Handle<Object> PreventExtensions(Handle<JSObject> object) {
420
CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
424
Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
425
JSObject::HiddenPropertiesFlag flag) {
426
CALL_HEAP_FUNCTION(obj->GetIsolate(),
427
obj->GetHiddenProperties(flag),
432
int GetIdentityHash(Handle<JSObject> obj) {
433
CALL_AND_RETRY(obj->GetIsolate(),
434
obj->GetIdentityHash(JSObject::ALLOW_CREATION),
435
return Smi::cast(__object__)->value(),
440
Handle<Object> DeleteElement(Handle<JSObject> obj,
442
CALL_HEAP_FUNCTION(obj->GetIsolate(),
443
obj->DeleteElement(index, JSObject::NORMAL_DELETION),
448
Handle<Object> DeleteProperty(Handle<JSObject> obj,
449
Handle<String> prop) {
450
CALL_HEAP_FUNCTION(obj->GetIsolate(),
451
obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
456
318
Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) {
457
319
Isolate* isolate = Isolate::Current();
458
320
CALL_HEAP_FUNCTION(
834
Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
699
Handle<JSArray> GetKeysFor(Handle<JSReceiver> object, bool* threw) {
835
700
Isolate* isolate = object->GetIsolate();
836
701
isolate->counters()->for_in()->Increment();
837
Handle<FixedArray> elements = GetKeysInFixedArrayFor(object,
702
Handle<FixedArray> elements =
703
GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, threw);
839
704
return isolate->factory()->NewJSArrayWithElements(elements);
708
Handle<FixedArray> ReduceFixedArrayTo(Handle<FixedArray> array, int length) {
709
ASSERT(array->length() >= length);
710
if (array->length() == length) return array;
712
Handle<FixedArray> new_array =
713
array->GetIsolate()->factory()->NewFixedArray(length);
714
for (int i = 0; i < length; ++i) new_array->set(i, array->get(i));
843
719
Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
844
720
bool cache_result) {
846
721
Isolate* isolate = object->GetIsolate();
847
722
if (object->HasFastProperties()) {
848
723
if (object->map()->instance_descriptors()->HasEnumCache()) {
724
int own_property_count = object->map()->EnumLength();
725
// If we have an enum cache, but the enum length of the given map is set
726
// to kInvalidEnumCache, this means that the map itself has never used the
727
// present enum cache. The first step to using the cache is to set the
728
// enum length of the map by counting the number of own descriptors that
729
// are not DONT_ENUM.
730
if (own_property_count == Map::kInvalidEnumCache) {
731
own_property_count = object->map()->NumberOfDescribedProperties(
732
OWN_DESCRIPTORS, DONT_ENUM);
734
if (cache_result) object->map()->SetEnumLength(own_property_count);
737
DescriptorArray* desc = object->map()->instance_descriptors();
738
Handle<FixedArray> keys(desc->GetEnumCache(), isolate);
740
// In case the number of properties required in the enum are actually
741
// present, we can reuse the enum cache. Otherwise, this means that the
742
// enum cache was generated for a previous (smaller) version of the
743
// Descriptor Array. In that case we regenerate the enum cache.
744
if (own_property_count <= keys->length()) {
745
isolate->counters()->enum_cache_hits()->Increment();
746
return ReduceFixedArrayTo(keys, own_property_count);
750
Handle<Map> map(object->map());
752
if (map->instance_descriptors()->IsEmpty()) {
849
753
isolate->counters()->enum_cache_hits()->Increment();
850
DescriptorArray* desc = object->map()->instance_descriptors();
851
return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache()),
754
if (cache_result) map->SetEnumLength(0);
755
return isolate->factory()->empty_fixed_array();
854
758
isolate->counters()->enum_cache_misses()->Increment();
855
int num_enum = object->NumberOfEnumProperties();
759
int num_enum = map->NumberOfDescribedProperties(ALL_DESCRIPTORS, DONT_ENUM);
856
761
Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum);
857
Handle<FixedArray> sort_array = isolate->factory()->NewFixedArray(num_enum);
762
Handle<FixedArray> indices = isolate->factory()->NewFixedArray(num_enum);
858
764
Handle<DescriptorArray> descs =
859
765
Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
767
int real_size = map->NumberOfOwnDescriptors();
860
771
for (int i = 0; i < descs->number_of_descriptors(); i++) {
861
if (descs->IsProperty(i) && !descs->IsDontEnum(i)) {
862
(*storage)->set(index, descs->GetKey(i));
863
PropertyDetails details(descs->GetDetails(i));
864
(*sort_array)->set(index, Smi::FromInt(details.index()));
772
PropertyDetails details = descs->GetDetails(i);
773
if (!details.IsDontEnum()) {
774
if (i < real_size) ++enum_size;
775
storage->set(index, descs->GetKey(i));
776
if (!indices.is_null()) {
777
if (details.type() != FIELD) {
778
indices = Handle<FixedArray>();
780
int field_index = Descriptor::IndexFromValue(descs->GetValue(i));
781
if (field_index >= map->inobject_properties()) {
782
field_index = -(field_index - map->inobject_properties() + 1);
784
indices->set(index, Smi::FromInt(field_index));
868
(*storage)->SortPairs(*sort_array, sort_array->length());
790
ASSERT(index == storage->length());
792
Handle<FixedArray> bridge_storage =
793
isolate->factory()->NewFixedArray(
794
DescriptorArray::kEnumCacheBridgeLength);
795
DescriptorArray* desc = object->map()->instance_descriptors();
796
desc->SetEnumCache(*bridge_storage,
798
indices.is_null() ? Object::cast(Smi::FromInt(0))
799
: Object::cast(*indices));
869
800
if (cache_result) {
870
Handle<FixedArray> bridge_storage =
871
isolate->factory()->NewFixedArray(
872
DescriptorArray::kEnumCacheBridgeLength);
873
DescriptorArray* desc = object->map()->instance_descriptors();
874
desc->SetEnumCache(*bridge_storage, *storage);
801
object->map()->SetEnumLength(enum_size);
876
ASSERT(storage->length() == index);
804
return ReduceFixedArrayTo(storage, enum_size);
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
object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array);
806
Handle<StringDictionary> dictionary(object->property_dictionary());
808
int length = dictionary->NumberOfElements();
810
return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
813
// The enumeration array is generated by allocating an array big enough to
814
// hold all properties that have been seen, whether they are are deleted or
815
// not. Subsequently all visible properties are added to the array. If some
816
// properties were not visible, the array is trimmed so it only contains
817
// visible properties. This improves over adding elements and sorting by
818
// index by having linear complexity rather than n*log(n).
820
// By comparing the monotonous NextEnumerationIndex to the NumberOfElements,
821
// we can predict the number of holes in the final array. If there will be
822
// more than 50% holes, regenerate the enumeration indices to reduce the
823
// number of holes to a minimum. This avoids allocating a large array if
824
// many properties were added but subsequently deleted.
825
int next_enumeration = dictionary->NextEnumerationIndex();
826
if (!object->IsGlobalObject() && next_enumeration > (length * 3) / 2) {
827
StringDictionary::DoGenerateNewEnumerationIndices(dictionary);
828
next_enumeration = dictionary->NextEnumerationIndex();
831
Handle<FixedArray> storage =
832
isolate->factory()->NewFixedArray(next_enumeration);
834
storage = Handle<FixedArray>(dictionary->CopyEnumKeysTo(*storage));
835
ASSERT(storage->length() == object->NumberOfLocalProperties(DONT_ENUM));
841
Handle<ObjectHashSet> ObjectHashSetAdd(Handle<ObjectHashSet> table,
842
Handle<Object> key) {
843
CALL_HEAP_FUNCTION(table->GetIsolate(),
849
Handle<ObjectHashSet> ObjectHashSetRemove(Handle<ObjectHashSet> table,
850
Handle<Object> key) {
851
CALL_HEAP_FUNCTION(table->GetIsolate(),
888
857
Handle<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
889
Handle<JSObject> key,
890
859
Handle<Object> value) {
891
860
CALL_HEAP_FUNCTION(table->GetIsolate(),
892
861
table->Put(*key, *value),
897
bool EnsureCompiled(Handle<SharedFunctionInfo> shared,
898
ClearExceptionFlag flag) {
899
return shared->is_compiled() || CompileLazyShared(shared, flag);
903
static bool CompileLazyHelper(CompilationInfo* info,
904
ClearExceptionFlag flag) {
905
// Compile the source information to a code object.
906
ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
907
ASSERT(!info->isolate()->has_pending_exception());
908
bool result = Compiler::CompileLazy(info);
909
ASSERT(result != Isolate::Current()->has_pending_exception());
910
if (!result && flag == CLEAR_EXCEPTION) {
911
info->isolate()->clear_pending_exception();
917
bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
918
ClearExceptionFlag flag) {
919
CompilationInfo info(shared);
920
return CompileLazyHelper(&info, flag);
924
bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag) {
926
if (function->shared()->is_compiled()) {
927
function->ReplaceCode(function->shared()->code());
928
function->shared()->set_code_age(0);
930
CompilationInfo info(function);
931
result = CompileLazyHelper(&info, flag);
932
ASSERT(!result || function->is_compiled());
938
bool CompileOptimized(Handle<JSFunction> function,
940
ClearExceptionFlag flag) {
941
CompilationInfo info(function);
942
info.SetOptimizing(osr_ast_id);
943
return CompileLazyHelper(&info, flag);
866
// This method determines the type of string involved and then gets the UTF8
867
// length of the string. It doesn't flatten the string and has log(n) recursion
868
// for a string of length n. If the failure flag gets set, then we have to
869
// flatten the string and retry. Failures are caused by surrogate pairs in deep
872
// Single surrogate characters that are encountered in the UTF-16 character
873
// sequence of the input string get counted as 3 UTF-8 bytes, because that
874
// is the way that WriteUtf8 will encode them. Surrogate pairs are counted and
875
// encoded as one 4-byte UTF-8 sequence.
877
// This function conceptually uses recursion on the two halves of cons strings.
878
// However, in order to avoid the recursion going too deep it recurses on the
879
// second string of the cons, but iterates on the first substring (by manually
880
// eliminating it as a tail recursion). This means it counts the UTF-8 length
881
// from the end to the start, which makes no difference to the total.
883
// Surrogate pairs are recognized even if they are split across two sides of a
884
// cons, which complicates the implementation somewhat. Therefore, too deep
885
// recursion cannot always be avoided. This case is detected, and the failure
886
// flag is set, a signal to the caller that the string should be flattened and
887
// the operation retried.
888
int Utf8LengthHelper(String* input,
891
bool followed_by_surrogate,
894
bool* starts_with_surrogate) {
895
if (from == to) return 0;
899
if (input->IsAsciiRepresentation()) {
900
*starts_with_surrogate = false;
901
return total + to - from;
903
switch (StringShape(input).representation_tag()) {
904
case kConsStringTag: {
905
ConsString* str = ConsString::cast(input);
906
String* first = str->first();
907
String* second = str->second();
908
int first_length = first->length();
909
if (first_length - from > to - first_length) {
910
if (first_length < to) {
911
// Right hand side is shorter. No need to check the recursion depth
912
// since this can only happen log(n) times.
913
bool right_starts_with_surrogate = false;
914
total += Utf8LengthHelper(second,
917
followed_by_surrogate,
920
&right_starts_with_surrogate);
921
if (*failure) return 0;
922
followed_by_surrogate = right_starts_with_surrogate;
926
// We only need the left hand side.
930
if (first_length > from) {
931
// Left hand side is shorter.
932
if (first->IsAsciiRepresentation()) {
933
total += first_length - from;
934
*starts_with_surrogate = false;
935
starts_with_surrogate = &dummy;
939
} else if (second->IsAsciiRepresentation()) {
940
followed_by_surrogate = false;
941
total += to - first_length;
944
} else if (max_recursion > 0) {
945
bool right_starts_with_surrogate = false;
946
// Recursing on the long one. This may fail.
947
total += Utf8LengthHelper(second,
950
followed_by_surrogate,
953
&right_starts_with_surrogate);
954
if (*failure) return 0;
957
followed_by_surrogate = right_starts_with_surrogate;
963
// We only need the right hand side.
971
case kExternalStringTag:
972
case kSeqStringTag: {
973
Vector<const uc16> vector = input->GetFlatContent().ToUC16Vector();
974
const uc16* p = vector.start();
975
int previous = unibrow::Utf16::kNoPreviousCharacter;
976
for (int i = from; i < to; i++) {
978
total += unibrow::Utf8::Length(c, previous);
982
if (unibrow::Utf16::IsLeadSurrogate(previous) &&
983
followed_by_surrogate) {
984
total -= unibrow::Utf8::kBytesSavedByCombiningSurrogates;
986
if (unibrow::Utf16::IsTrailSurrogate(p[from])) {
987
*starts_with_surrogate = true;
992
case kSlicedStringTag: {
993
SlicedString* str = SlicedString::cast(input);
994
int offset = str->offset();
995
input = str->parent();
1010
int Utf8Length(Handle<String> str) {
1014
const int kRecursionBudget = 100;
1017
len = Utf8LengthHelper(
1018
*str, 0, str->length(), false, kRecursionBudget, &failure, &dummy);
1019
if (failure) FlattenString(str);
1025
DeferredHandleScope::DeferredHandleScope(Isolate* isolate)
1026
: impl_(isolate->handle_scope_implementer()) {
1027
ASSERT(impl_->isolate() == Isolate::Current());
1028
impl_->BeginDeferredScope();
1029
v8::ImplementationUtilities::HandleScopeData* data =
1030
impl_->isolate()->handle_scope_data();
1031
Object** new_next = impl_->GetSpareOrNewBlock();
1032
Object** new_limit = &new_next[kHandleBlockSize];
1033
ASSERT(data->limit == &impl_->blocks()->last()[kHandleBlockSize]);
1034
impl_->blocks()->Add(new_next);
1037
prev_level_ = data->level;
1040
prev_limit_ = data->limit;
1041
prev_next_ = data->next;
1042
data->next = new_next;
1043
data->limit = new_limit;
1047
DeferredHandleScope::~DeferredHandleScope() {
1048
impl_->isolate()->handle_scope_data()->level--;
1049
ASSERT(handles_detached_);
1050
ASSERT(impl_->isolate()->handle_scope_data()->level == prev_level_);
1054
DeferredHandles* DeferredHandleScope::Detach() {
1055
DeferredHandles* deferred = impl_->Detach(prev_limit_);
1056
v8::ImplementationUtilities::HandleScopeData* data =
1057
impl_->isolate()->handle_scope_data();
1058
data->next = prev_next_;
1059
data->limit = prev_limit_;
1061
handles_detached_ = true;
946
1067
} } // namespace v8::internal