Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: src/runtime.cc

Issue 11415051: Revert r12990 and r12991 from trunk. (Closed) Base URL: https://v8.googlecode.com/svn/trunk
Patch Set: Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects-inl.h ('k') | src/version.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 959 matching lines...) Expand 10 before | Expand all | Expand 10 after
970 // Recursively traverses hidden prototypes if property is not found 970 // Recursively traverses hidden prototypes if property is not found
971 static void GetOwnPropertyImplementation(JSObject* obj, 971 static void GetOwnPropertyImplementation(JSObject* obj,
972 String* name, 972 String* name,
973 LookupResult* result) { 973 LookupResult* result) {
974 obj->LocalLookupRealNamedProperty(name, result); 974 obj->LocalLookupRealNamedProperty(name, result);
975 975
976 if (result->IsFound()) return; 976 if (result->IsFound()) return;
977 977
978 Object* proto = obj->GetPrototype(); 978 Object* proto = obj->GetPrototype();
979 if (proto->IsJSObject() && 979 if (proto->IsJSObject() &&
980 JSObject::cast(proto)->map()->is_hidden_prototype()) { 980 JSObject::cast(proto)->map()->is_hidden_prototype())
981 GetOwnPropertyImplementation(JSObject::cast(proto), 981 GetOwnPropertyImplementation(JSObject::cast(proto),
982 name, result); 982 name, result);
983 }
984 } 983 }
985 984
986 985
987 static bool CheckAccessException(Object* callback, 986 static bool CheckAccessException(LookupResult* result,
988 v8::AccessType access_type) { 987 v8::AccessType access_type) {
989 if (callback->IsAccessorInfo()) { 988 if (result->type() == CALLBACKS) {
990 AccessorInfo* info = AccessorInfo::cast(callback); 989 Object* callback = result->GetCallbackObject();
991 return 990 if (callback->IsAccessorInfo()) {
992 (access_type == v8::ACCESS_HAS && 991 AccessorInfo* info = AccessorInfo::cast(callback);
993 (info->all_can_read() || info->all_can_write())) || 992 bool can_access =
994 (access_type == v8::ACCESS_GET && info->all_can_read()) || 993 (access_type == v8::ACCESS_HAS &&
995 (access_type == v8::ACCESS_SET && info->all_can_write()); 994 (info->all_can_read() || info->all_can_write())) ||
995 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
996 (access_type == v8::ACCESS_SET && info->all_can_write());
997 return can_access;
998 }
996 } 999 }
1000
997 return false; 1001 return false;
998 } 1002 }
999 1003
1000 1004
1001 template<class Key> 1005 static bool CheckAccess(JSObject* obj,
1002 static bool CheckGenericAccess( 1006 String* name,
1003 JSObject* receiver, 1007 LookupResult* result,
1004 JSObject* holder, 1008 v8::AccessType access_type) {
1005 Key key, 1009 ASSERT(result->IsProperty());
1006 v8::AccessType access_type, 1010
1007 bool (Isolate::*mayAccess)(JSObject*, Key, v8::AccessType)) { 1011 JSObject* holder = result->holder();
1008 Isolate* isolate = receiver->GetIsolate(); 1012 JSObject* current = obj;
1009 for (JSObject* current = receiver; 1013 Isolate* isolate = obj->GetIsolate();
1010 true; 1014 while (true) {
1011 current = JSObject::cast(current->GetPrototype())) {
1012 if (current->IsAccessCheckNeeded() && 1015 if (current->IsAccessCheckNeeded() &&
1013 !(isolate->*mayAccess)(current, key, access_type)) { 1016 !isolate->MayNamedAccess(current, name, access_type)) {
1014 return false; 1017 // Access check callback denied the access, but some properties
1018 // can have a special permissions which override callbacks descision
1019 // (currently see v8::AccessControl).
1020 break;
1015 } 1021 }
1016 if (current == holder) break;
1017 }
1018 return true;
1019 }
1020 1022
1023 if (current == holder) {
1024 return true;
1025 }
1021 1026
1022 static bool CheckElementAccess( 1027 current = JSObject::cast(current->GetPrototype());
1023 JSObject* obj,
1024 uint32_t index,
1025 v8::AccessType access_type) {
1026 // TODO(1095): we should traverse hidden prototype hierachy as well.
1027 if (CheckGenericAccess(
1028 obj, obj, index, access_type, &Isolate::MayIndexedAccess)) {
1029 return true;
1030 } 1028 }
1031 1029
1032 obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type); 1030 // API callbacks can have per callback access exceptions.
1031 switch (result->type()) {
1032 case CALLBACKS: {
1033 if (CheckAccessException(result, access_type)) {
1034 return true;
1035 }
1036 break;
1037 }
1038 case INTERCEPTOR: {
1039 // If the object has an interceptor, try real named properties.
1040 // Overwrite the result to fetch the correct property later.
1041 holder->LookupRealNamedProperty(name, result);
1042 if (result->IsProperty()) {
1043 if (CheckAccessException(result, access_type)) {
1044 return true;
1045 }
1046 }
1047 break;
1048 }
1049 default:
1050 break;
1051 }
1052
1053 isolate->ReportFailedAccessCheck(current, access_type);
1033 return false; 1054 return false;
1034 } 1055 }
1035 1056
1036 1057
1037 static bool CheckPropertyAccess( 1058 // TODO(1095): we should traverse hidden prototype hierachy as well.
1038 JSObject* obj, 1059 static bool CheckElementAccess(JSObject* obj,
1039 String* name, 1060 uint32_t index,
1040 v8::AccessType access_type) { 1061 v8::AccessType access_type) {
1041 uint32_t index; 1062 if (obj->IsAccessCheckNeeded() &&
1042 if (name->AsArrayIndex(&index)) { 1063 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
1043 return CheckElementAccess(obj, index, access_type); 1064 return false;
1044 } 1065 }
1045 1066
1046 LookupResult lookup(obj->GetIsolate()); 1067 return true;
1047 obj->LocalLookup(name, &lookup);
1048
1049 if (CheckGenericAccess<Object*>(
1050 obj, lookup.holder(), name, access_type, &Isolate::MayNamedAccess)) {
1051 return true;
1052 }
1053
1054 // Access check callback denied the access, but some properties
1055 // can have a special permissions which override callbacks descision
1056 // (currently see v8::AccessControl).
1057 // API callbacks can have per callback access exceptions.
1058 switch (lookup.type()) {
1059 case CALLBACKS:
1060 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1061 return true;
1062 }
1063 break;
1064 case INTERCEPTOR:
1065 // If the object has an interceptor, try real named properties.
1066 // Overwrite the result to fetch the correct property later.
1067 lookup.holder()->LookupRealNamedProperty(name, &lookup);
1068 if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) {
1069 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1070 return true;
1071 }
1072 }
1073 break;
1074 default:
1075 break;
1076 }
1077
1078 obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type);
1079 return false;
1080 } 1068 }
1081 1069
1082 1070
1083 // Enumerator used as indices into the array returned from GetOwnProperty 1071 // Enumerator used as indices into the array returned from GetOwnProperty
1084 enum PropertyDescriptorIndices { 1072 enum PropertyDescriptorIndices {
1085 IS_ACCESSOR_INDEX, 1073 IS_ACCESSOR_INDEX,
1086 VALUE_INDEX, 1074 VALUE_INDEX,
1087 GETTER_INDEX, 1075 GETTER_INDEX,
1088 SETTER_INDEX, 1076 SETTER_INDEX,
1089 WRITABLE_INDEX, 1077 WRITABLE_INDEX,
1090 ENUMERABLE_INDEX, 1078 ENUMERABLE_INDEX,
1091 CONFIGURABLE_INDEX, 1079 CONFIGURABLE_INDEX,
1092 DESCRIPTOR_SIZE 1080 DESCRIPTOR_SIZE
1093 }; 1081 };
1094 1082
1095 1083
1096 static MaybeObject* GetOwnProperty(Isolate* isolate, 1084 static MaybeObject* GetOwnProperty(Isolate* isolate,
1097 Handle<JSObject> obj, 1085 Handle<JSObject> obj,
1098 Handle<String> name) { 1086 Handle<String> name) {
1099 Heap* heap = isolate->heap(); 1087 Heap* heap = isolate->heap();
1100 PropertyAttributes attrs = obj->GetLocalPropertyAttribute(*name); 1088 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1101 if (attrs == ABSENT) return heap->undefined_value(); 1089 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
1102 AccessorPair* accessors = obj->GetLocalPropertyAccessorPair(*name); 1090 LookupResult result(isolate);
1091 // This could be an element.
1092 uint32_t index;
1093 if (name->AsArrayIndex(&index)) {
1094 switch (obj->GetLocalElementKind(index)) {
1095 case JSObject::UNDEFINED_ELEMENT:
1096 return heap->undefined_value();
1103 1097
1104 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE); 1098 case JSObject::STRING_CHARACTER_ELEMENT: {
1105 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0)); 1099 // Special handling of string objects according to ECMAScript 5
1106 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0)); 1100 // 15.5.5.2. Note that this might be a string object with elements
1107 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(accessors != NULL)); 1101 // other than the actual string value. This is covered by the
1102 // subsequent cases.
1103 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1104 Handle<String> str(String::cast(js_value->value()));
1105 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
1108 1106
1109 if (accessors == NULL) { 1107 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1110 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0)); 1108 elms->set(VALUE_INDEX, *substr);
1111 // GetProperty does access check. 1109 elms->set(WRITABLE_INDEX, heap->false_value());
1112 elms->set(VALUE_INDEX, *GetProperty(obj, name)); 1110 elms->set(ENUMERABLE_INDEX, heap->true_value());
1113 } else { 1111 elms->set(CONFIGURABLE_INDEX, heap->false_value());
1114 // Access checks are performed for both accessors separately. 1112 return *desc;
1115 // When they fail, the respective field is not set in the descriptor. 1113 }
1116 Object* getter = accessors->GetComponent(ACCESSOR_GETTER); 1114
1117 Object* setter = accessors->GetComponent(ACCESSOR_SETTER); 1115 case JSObject::INTERCEPTED_ELEMENT:
1118 if (!getter->IsMap() && CheckPropertyAccess(*obj, *name, v8::ACCESS_GET)) { 1116 case JSObject::FAST_ELEMENT: {
1119 elms->set(GETTER_INDEX, getter); 1117 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1120 } 1118 Handle<Object> value = Object::GetElement(obj, index);
1121 if (!setter->IsMap() && CheckPropertyAccess(*obj, *name, v8::ACCESS_SET)) { 1119 RETURN_IF_EMPTY_HANDLE(isolate, value);
1122 elms->set(SETTER_INDEX, setter); 1120 elms->set(VALUE_INDEX, *value);
1121 elms->set(WRITABLE_INDEX, heap->true_value());
1122 elms->set(ENUMERABLE_INDEX, heap->true_value());
1123 elms->set(CONFIGURABLE_INDEX, heap->true_value());
1124 return *desc;
1125 }
1126
1127 case JSObject::DICTIONARY_ELEMENT: {
1128 Handle<JSObject> holder = obj;
1129 if (obj->IsJSGlobalProxy()) {
1130 Object* proto = obj->GetPrototype();
1131 if (proto->IsNull()) return heap->undefined_value();
1132 ASSERT(proto->IsJSGlobalObject());
1133 holder = Handle<JSObject>(JSObject::cast(proto));
1134 }
1135 FixedArray* elements = FixedArray::cast(holder->elements());
1136 SeededNumberDictionary* dictionary = NULL;
1137 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1138 dictionary = SeededNumberDictionary::cast(elements->get(1));
1139 } else {
1140 dictionary = SeededNumberDictionary::cast(elements);
1141 }
1142 int entry = dictionary->FindEntry(index);
1143 ASSERT(entry != SeededNumberDictionary::kNotFound);
1144 PropertyDetails details = dictionary->DetailsAt(entry);
1145 switch (details.type()) {
1146 case CALLBACKS: {
1147 // This is an accessor property with getter and/or setter.
1148 AccessorPair* accessors =
1149 AccessorPair::cast(dictionary->ValueAt(entry));
1150 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
1151 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1152 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
1153 }
1154 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1155 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
1156 }
1157 break;
1158 }
1159 case NORMAL: {
1160 // This is a data property.
1161 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1162 Handle<Object> value = Object::GetElement(obj, index);
1163 ASSERT(!value.is_null());
1164 elms->set(VALUE_INDEX, *value);
1165 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
1166 break;
1167 }
1168 default:
1169 UNREACHABLE();
1170 break;
1171 }
1172 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1173 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
1174 return *desc;
1175 }
1123 } 1176 }
1124 } 1177 }
1125 1178
1126 return *isolate->factory()->NewJSArrayWithElements(elms); 1179 // Use recursive implementation to also traverse hidden prototypes
1180 GetOwnPropertyImplementation(*obj, *name, &result);
1181
1182 if (!result.IsProperty()) {
1183 return heap->undefined_value();
1184 }
1185
1186 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
1187 return heap->false_value();
1188 }
1189
1190 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1191 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
1192
1193 bool is_js_accessor = result.IsPropertyCallbacks() &&
1194 (result.GetCallbackObject()->IsAccessorPair());
1195
1196 if (is_js_accessor) {
1197 // __defineGetter__/__defineSetter__ callback.
1198 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
1199
1200 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
1201 Object* getter = accessors->GetComponent(ACCESSOR_GETTER);
1202 if (!getter->IsMap() && CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1203 elms->set(GETTER_INDEX, getter);
1204 }
1205 Object* setter = accessors->GetComponent(ACCESSOR_SETTER);
1206 if (!setter->IsMap() && CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1207 elms->set(SETTER_INDEX, setter);
1208 }
1209 } else {
1210 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1211 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
1212
1213 PropertyAttributes attrs;
1214 Object* value;
1215 // GetProperty will check access and report any violations.
1216 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1217 if (!maybe_value->ToObject(&value)) return maybe_value;
1218 }
1219 elms->set(VALUE_INDEX, value);
1220 }
1221
1222 return *desc;
1127 } 1223 }
1128 1224
1129 1225
1130 // Returns an array with the property description: 1226 // Returns an array with the property description:
1131 // if args[1] is not a property on args[0] 1227 // if args[1] is not a property on args[0]
1132 // returns undefined 1228 // returns undefined
1133 // if args[1] is a data property on args[0] 1229 // if args[1] is a data property on args[0]
1134 // [false, value, Writeable, Enumerable, Configurable] 1230 // [false, value, Writeable, Enumerable, Configurable]
1135 // if args[1] is an accessor on args[0] 1231 // if args[1] is an accessor on args[0]
1136 // [true, GetFunction, SetFunction, Enumerable, Configurable] 1232 // [true, GetFunction, SetFunction, Enumerable, Configurable]
(...skipping 3487 matching lines...) Expand 10 before | Expand all | Expand 10 after
4624 } 4720 }
4625 4721
4626 4722
4627 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) { 4723 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
4628 NoHandleAllocation ha; 4724 NoHandleAllocation ha;
4629 ASSERT(args.length() == 2); 4725 ASSERT(args.length() == 2);
4630 4726
4631 CONVERT_ARG_CHECKED(JSObject, object, 0); 4727 CONVERT_ARG_CHECKED(JSObject, object, 0);
4632 CONVERT_ARG_CHECKED(String, key, 1); 4728 CONVERT_ARG_CHECKED(String, key, 1);
4633 4729
4730 uint32_t index;
4731 if (key->AsArrayIndex(&index)) {
4732 JSObject::LocalElementKind type = object->GetLocalElementKind(index);
4733 switch (type) {
4734 case JSObject::UNDEFINED_ELEMENT:
4735 case JSObject::STRING_CHARACTER_ELEMENT:
4736 return isolate->heap()->false_value();
4737 case JSObject::INTERCEPTED_ELEMENT:
4738 case JSObject::FAST_ELEMENT:
4739 return isolate->heap()->true_value();
4740 case JSObject::DICTIONARY_ELEMENT: {
4741 if (object->IsJSGlobalProxy()) {
4742 Object* proto = object->GetPrototype();
4743 if (proto->IsNull()) {
4744 return isolate->heap()->false_value();
4745 }
4746 ASSERT(proto->IsJSGlobalObject());
4747 object = JSObject::cast(proto);
4748 }
4749 FixedArray* elements = FixedArray::cast(object->elements());
4750 SeededNumberDictionary* dictionary = NULL;
4751 if (elements->map() ==
4752 isolate->heap()->non_strict_arguments_elements_map()) {
4753 dictionary = SeededNumberDictionary::cast(elements->get(1));
4754 } else {
4755 dictionary = SeededNumberDictionary::cast(elements);
4756 }
4757 int entry = dictionary->FindEntry(index);
4758 ASSERT(entry != SeededNumberDictionary::kNotFound);
4759 PropertyDetails details = dictionary->DetailsAt(entry);
4760 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4761 }
4762 }
4763 }
4764
4634 PropertyAttributes att = object->GetLocalPropertyAttribute(key); 4765 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
4635 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0); 4766 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
4636 } 4767 }
4637 4768
4638 4769
4639 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) { 4770 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
4640 HandleScope scope(isolate); 4771 HandleScope scope(isolate);
4641 ASSERT(args.length() == 1); 4772 ASSERT(args.length() == 1);
4642 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 4773 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
4643 bool threw = false; 4774 bool threw = false;
(...skipping 8673 matching lines...) Expand 10 before | Expand all | Expand 10 after
13317 // Handle last resort GC and make sure to allow future allocations 13448 // Handle last resort GC and make sure to allow future allocations
13318 // to grow the heap without causing GCs (if possible). 13449 // to grow the heap without causing GCs (if possible).
13319 isolate->counters()->gc_last_resort_from_js()->Increment(); 13450 isolate->counters()->gc_last_resort_from_js()->Increment();
13320 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, 13451 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13321 "Runtime::PerformGC"); 13452 "Runtime::PerformGC");
13322 } 13453 }
13323 } 13454 }
13324 13455
13325 13456
13326 } } // namespace v8::internal 13457 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects-inl.h ('k') | src/version.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698