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

Side by Side Diff: src/runtime.cc

Issue 11420011: Clean-up refactoring to eliminate GetLocalElementKind. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed comments. 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') | test/mjsunit/regress/regress-1692.js » ('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 }
983 } 984 }
984 985
985 986
986 static bool CheckAccessException(LookupResult* result, 987 static bool CheckAccessException(Object* callback,
987 v8::AccessType access_type) { 988 v8::AccessType access_type) {
988 if (result->type() == CALLBACKS) { 989 if (callback->IsAccessorInfo()) {
989 Object* callback = result->GetCallbackObject(); 990 AccessorInfo* info = AccessorInfo::cast(callback);
990 if (callback->IsAccessorInfo()) { 991 return
991 AccessorInfo* info = AccessorInfo::cast(callback); 992 (access_type == v8::ACCESS_HAS &&
992 bool can_access = 993 (info->all_can_read() || info->all_can_write())) ||
993 (access_type == v8::ACCESS_HAS && 994 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
994 (info->all_can_read() || info->all_can_write())) || 995 (access_type == v8::ACCESS_SET && 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 }
999 } 996 }
1000
1001 return false; 997 return false;
1002 } 998 }
1003 999
1004 1000
1005 static bool CheckAccess(JSObject* obj, 1001 template<class Key>
1006 String* name, 1002 static bool CheckGenericAccess(
1007 LookupResult* result, 1003 JSObject* receiver,
1008 v8::AccessType access_type) { 1004 JSObject* holder,
1009 ASSERT(result->IsProperty()); 1005 Key key,
1006 v8::AccessType access_type,
1007 bool (Isolate::*mayAccess)(JSObject*, Key, v8::AccessType)) {
1008 Isolate* isolate = receiver->GetIsolate();
1009 for (JSObject* current = receiver;
1010 true;
1011 current = JSObject::cast(current->GetPrototype())) {
1012 if (current->IsAccessCheckNeeded() &&
1013 !(isolate->*mayAccess)(current, key, access_type)) {
1014 return false;
1015 }
1016 if (current == holder) break;
1017 }
1018 return true;
1019 }
1010 1020
1011 JSObject* holder = result->holder();
1012 JSObject* current = obj;
1013 Isolate* isolate = obj->GetIsolate();
1014 while (true) {
1015 if (current->IsAccessCheckNeeded() &&
1016 !isolate->MayNamedAccess(current, name, access_type)) {
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;
1021 }
1022 1021
1023 if (current == holder) { 1022 static bool CheckElementAccess(
1024 return true; 1023 JSObject* obj,
1025 } 1024 uint32_t index,
1026 1025 v8::AccessType access_type) {
1027 current = JSObject::cast(current->GetPrototype()); 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;
1028 } 1030 }
1029 1031
1032 obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type);
1033 return false;
1034 }
1035
1036
1037 static bool CheckPropertyAccess(
1038 JSObject* obj,
1039 String* name,
1040 v8::AccessType access_type) {
1041 uint32_t index;
1042 if (name->AsArrayIndex(&index)) {
1043 return CheckElementAccess(obj, index, access_type);
1044 }
1045
1046 LookupResult lookup(obj->GetIsolate());
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).
1030 // API callbacks can have per callback access exceptions. 1057 // API callbacks can have per callback access exceptions.
1031 switch (result->type()) { 1058 switch (lookup.type()) {
1032 case CALLBACKS: { 1059 case CALLBACKS:
1033 if (CheckAccessException(result, access_type)) { 1060 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1034 return true; 1061 return true;
1035 } 1062 }
1036 break; 1063 break;
1037 } 1064 case INTERCEPTOR:
1038 case INTERCEPTOR: {
1039 // If the object has an interceptor, try real named properties. 1065 // If the object has an interceptor, try real named properties.
1040 // Overwrite the result to fetch the correct property later. 1066 // Overwrite the result to fetch the correct property later.
1041 holder->LookupRealNamedProperty(name, result); 1067 lookup.holder()->LookupRealNamedProperty(name, &lookup);
1042 if (result->IsProperty()) { 1068 if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) {
1043 if (CheckAccessException(result, access_type)) { 1069 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1044 return true; 1070 return true;
1045 } 1071 }
1046 } 1072 }
1047 break; 1073 break;
1048 }
1049 default: 1074 default:
1050 break; 1075 break;
1051 } 1076 }
1052 1077
1053 isolate->ReportFailedAccessCheck(current, access_type); 1078 obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type);
1054 return false; 1079 return false;
1055 } 1080 }
1056 1081
1057 1082
1058 // TODO(1095): we should traverse hidden prototype hierachy as well.
1059 static bool CheckElementAccess(JSObject* obj,
1060 uint32_t index,
1061 v8::AccessType access_type) {
1062 if (obj->IsAccessCheckNeeded() &&
1063 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
1064 return false;
1065 }
1066
1067 return true;
1068 }
1069
1070
1071 // Enumerator used as indices into the array returned from GetOwnProperty 1083 // Enumerator used as indices into the array returned from GetOwnProperty
1072 enum PropertyDescriptorIndices { 1084 enum PropertyDescriptorIndices {
1073 IS_ACCESSOR_INDEX, 1085 IS_ACCESSOR_INDEX,
1074 VALUE_INDEX, 1086 VALUE_INDEX,
1075 GETTER_INDEX, 1087 GETTER_INDEX,
1076 SETTER_INDEX, 1088 SETTER_INDEX,
1077 WRITABLE_INDEX, 1089 WRITABLE_INDEX,
1078 ENUMERABLE_INDEX, 1090 ENUMERABLE_INDEX,
1079 CONFIGURABLE_INDEX, 1091 CONFIGURABLE_INDEX,
1080 DESCRIPTOR_SIZE 1092 DESCRIPTOR_SIZE
1081 }; 1093 };
1082 1094
1083 1095
1084 static MaybeObject* GetOwnProperty(Isolate* isolate, 1096 static MaybeObject* GetOwnProperty(Isolate* isolate,
1085 Handle<JSObject> obj, 1097 Handle<JSObject> obj,
1086 Handle<String> name) { 1098 Handle<String> name) {
1087 Heap* heap = isolate->heap(); 1099 Heap* heap = isolate->heap();
1100 PropertyAttributes attrs = obj->GetLocalPropertyAttribute(*name);
1101 if (attrs == ABSENT) return heap->undefined_value();
1102 AccessorPair* accessors = obj->GetLocalPropertyAccessorPair(*name);
1103
1088 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE); 1104 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1089 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms); 1105 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
1090 LookupResult result(isolate); 1106 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
1091 // This could be an element. 1107 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(accessors != NULL));
1092 uint32_t index;
1093 if (name->AsArrayIndex(&index)) {
1094 switch (obj->GetLocalElementKind(index)) {
1095 case JSObject::UNDEFINED_ELEMENT:
1096 return heap->undefined_value();
1097 1108
1098 case JSObject::STRING_CHARACTER_ELEMENT: { 1109 if (accessors == NULL) {
1099 // Special handling of string objects according to ECMAScript 5 1110 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
1100 // 15.5.5.2. Note that this might be a string object with elements 1111 // GetProperty does access check.
1101 // other than the actual string value. This is covered by the 1112 elms->set(VALUE_INDEX, *GetProperty(obj, name));
1102 // subsequent cases. 1113 } else {
1103 Handle<JSValue> js_value = Handle<JSValue>::cast(obj); 1114 // Access checks are performed for both accessors separately.
1104 Handle<String> str(String::cast(js_value->value())); 1115 // When they fail, the respective field is not set in the descriptor.
1105 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED); 1116 Object* getter = accessors->GetComponent(ACCESSOR_GETTER);
1106 1117 Object* setter = accessors->GetComponent(ACCESSOR_SETTER);
1107 elms->set(IS_ACCESSOR_INDEX, heap->false_value()); 1118 if (!getter->IsMap() && CheckPropertyAccess(*obj, *name, v8::ACCESS_GET)) {
1108 elms->set(VALUE_INDEX, *substr); 1119 elms->set(GETTER_INDEX, getter);
1109 elms->set(WRITABLE_INDEX, heap->false_value()); 1120 }
1110 elms->set(ENUMERABLE_INDEX, heap->true_value()); 1121 if (!setter->IsMap() && CheckPropertyAccess(*obj, *name, v8::ACCESS_SET)) {
1111 elms->set(CONFIGURABLE_INDEX, heap->false_value()); 1122 elms->set(SETTER_INDEX, setter);
1112 return *desc;
1113 }
1114
1115 case JSObject::INTERCEPTED_ELEMENT:
1116 case JSObject::FAST_ELEMENT: {
1117 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1118 Handle<Object> value = Object::GetElement(obj, index);
1119 RETURN_IF_EMPTY_HANDLE(isolate, value);
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 }
1176 } 1123 }
1177 } 1124 }
1178 1125
1179 // Use recursive implementation to also traverse hidden prototypes 1126 return *isolate->factory()->NewJSArrayWithElements(elms);
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;
1223 } 1127 }
1224 1128
1225 1129
1226 // Returns an array with the property description: 1130 // Returns an array with the property description:
1227 // if args[1] is not a property on args[0] 1131 // if args[1] is not a property on args[0]
1228 // returns undefined 1132 // returns undefined
1229 // if args[1] is a data property on args[0] 1133 // if args[1] is a data property on args[0]
1230 // [false, value, Writeable, Enumerable, Configurable] 1134 // [false, value, Writeable, Enumerable, Configurable]
1231 // if args[1] is an accessor on args[0] 1135 // if args[1] is an accessor on args[0]
1232 // [true, GetFunction, SetFunction, Enumerable, Configurable] 1136 // [true, GetFunction, SetFunction, Enumerable, Configurable]
(...skipping 3487 matching lines...) Expand 10 before | Expand all | Expand 10 after
4720 } 4624 }
4721 4625
4722 4626
4723 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) { 4627 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
4724 NoHandleAllocation ha; 4628 NoHandleAllocation ha;
4725 ASSERT(args.length() == 2); 4629 ASSERT(args.length() == 2);
4726 4630
4727 CONVERT_ARG_CHECKED(JSObject, object, 0); 4631 CONVERT_ARG_CHECKED(JSObject, object, 0);
4728 CONVERT_ARG_CHECKED(String, key, 1); 4632 CONVERT_ARG_CHECKED(String, key, 1);
4729 4633
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
4765 PropertyAttributes att = object->GetLocalPropertyAttribute(key); 4634 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
4766 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0); 4635 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
4767 } 4636 }
4768 4637
4769 4638
4770 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) { 4639 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
4771 HandleScope scope(isolate); 4640 HandleScope scope(isolate);
4772 ASSERT(args.length() == 1); 4641 ASSERT(args.length() == 1);
4773 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 4642 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
4774 bool threw = false; 4643 bool threw = false;
(...skipping 8646 matching lines...) Expand 10 before | Expand all | Expand 10 after
13421 // Handle last resort GC and make sure to allow future allocations 13290 // Handle last resort GC and make sure to allow future allocations
13422 // to grow the heap without causing GCs (if possible). 13291 // to grow the heap without causing GCs (if possible).
13423 isolate->counters()->gc_last_resort_from_js()->Increment(); 13292 isolate->counters()->gc_last_resort_from_js()->Increment();
13424 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, 13293 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13425 "Runtime::PerformGC"); 13294 "Runtime::PerformGC");
13426 } 13295 }
13427 } 13296 }
13428 13297
13429 13298
13430 } } // namespace v8::internal 13299 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects-inl.h ('k') | test/mjsunit/regress/regress-1692.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698