Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/runtime/runtime-utils.h" | 5 #include "src/runtime/runtime-utils.h" |
| 6 | 6 |
| 7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
| 8 #include "src/arguments.h" | 8 #include "src/arguments.h" |
| 9 #include "src/ast/scopeinfo.h" | 9 #include "src/ast/scopeinfo.h" |
| 10 #include "src/ast/scopes.h" | 10 #include "src/ast/scopes.h" |
| (...skipping 947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 958 | 958 |
| 959 // The slot was found in a JSReceiver, either a context extension object, | 959 // The slot was found in a JSReceiver, either a context extension object, |
| 960 // the global object, or the subject of a with. Try to delete it | 960 // the global object, or the subject of a with. Try to delete it |
| 961 // (respecting DONT_DELETE). | 961 // (respecting DONT_DELETE). |
| 962 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder); | 962 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder); |
| 963 Maybe<bool> result = JSReceiver::DeleteProperty(object, name); | 963 Maybe<bool> result = JSReceiver::DeleteProperty(object, name); |
| 964 MAYBE_RETURN(result, isolate->heap()->exception()); | 964 MAYBE_RETURN(result, isolate->heap()->exception()); |
| 965 return isolate->heap()->ToBoolean(result.FromJust()); | 965 return isolate->heap()->ToBoolean(result.FromJust()); |
| 966 } | 966 } |
| 967 | 967 |
| 968 namespace { | |
| 968 | 969 |
| 969 static Object* ComputeReceiverForNonGlobal(Isolate* isolate, JSObject* holder) { | 970 MaybeHandle<Object> LoadLookupSlot(Handle<String> name, |
| 970 DCHECK(!holder->IsJSGlobalObject()); | 971 Object::ShouldThrow should_throw, |
| 971 | 972 Handle<Object>* receiver_return = nullptr) { |
| 972 // If the holder isn't a context extension object, we just return it | 973 Isolate* const isolate = name->GetIsolate(); |
| 973 // as the receiver. This allows arguments objects to be used as | |
| 974 // receivers, but only if they are put in the context scope chain | |
| 975 // explicitly via a with-statement. | |
| 976 if (holder->map()->instance_type() != JS_CONTEXT_EXTENSION_OBJECT_TYPE) { | |
| 977 return holder; | |
| 978 } | |
| 979 // Fall back to using the global object as the implicit receiver if | |
| 980 // the property turns out to be a local variable allocated in a | |
| 981 // context extension object - introduced via eval. | |
| 982 return isolate->heap()->undefined_value(); | |
| 983 } | |
| 984 | |
| 985 | |
| 986 static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate, | |
| 987 bool throw_error) { | |
| 988 HandleScope scope(isolate); | |
| 989 DCHECK_EQ(2, args.length()); | |
| 990 | |
| 991 if (!args[0]->IsContext() || !args[1]->IsString()) { | |
| 992 return MakePair(isolate->ThrowIllegalOperation(), NULL); | |
| 993 } | |
| 994 Handle<Context> context = args.at<Context>(0); | |
| 995 Handle<String> name = args.at<String>(1); | |
| 996 | 974 |
| 997 int index; | 975 int index; |
| 998 PropertyAttributes attributes; | 976 PropertyAttributes attributes; |
| 999 ContextLookupFlags flags = FOLLOW_CHAINS; | 977 BindingFlags flags; |
| 1000 BindingFlags binding_flags; | 978 Handle<Object> holder = isolate->context()->Lookup( |
| 1001 Handle<Object> holder = | 979 name, FOLLOW_CHAINS, &index, &attributes, &flags); |
| 1002 context->Lookup(name, flags, &index, &attributes, &binding_flags); | 980 if (isolate->has_pending_exception()) return MaybeHandle<Object>(); |
| 1003 if (isolate->has_pending_exception()) { | |
| 1004 return MakePair(isolate->heap()->exception(), NULL); | |
| 1005 } | |
| 1006 | 981 |
| 1007 if (index != Context::kNotFound) { | 982 if (index != Context::kNotFound) { |
| 1008 DCHECK(holder->IsContext()); | 983 DCHECK(holder->IsContext()); |
| 1009 // If the "property" we were looking for is a local variable, the | 984 // If the "property" we were looking for is a local variable, the |
| 1010 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3. | 985 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3. |
| 1011 Handle<Object> receiver = isolate->factory()->undefined_value(); | 986 Handle<Object> receiver = isolate->factory()->undefined_value(); |
| 1012 Object* value = Context::cast(*holder)->get(index); | 987 Handle<Object> value = handle(Context::cast(*holder)->get(index), isolate); |
| 1013 // Check for uninitialized bindings. | 988 // Check for uninitialized bindings. |
| 1014 switch (binding_flags) { | 989 switch (flags) { |
| 1015 case MUTABLE_CHECK_INITIALIZED: | 990 case MUTABLE_CHECK_INITIALIZED: |
| 1016 case IMMUTABLE_CHECK_INITIALIZED_HARMONY: | 991 case IMMUTABLE_CHECK_INITIALIZED_HARMONY: |
| 1017 if (value->IsTheHole()) { | 992 if (value->IsTheHole()) { |
| 1018 Handle<Object> error = isolate->factory()->NewReferenceError( | 993 THROW_NEW_ERROR(isolate, |
| 1019 MessageTemplate::kNotDefined, name); | 994 NewReferenceError(MessageTemplate::kNotDefined, name), |
| 1020 isolate->Throw(*error); | 995 Object); |
| 1021 return MakePair(isolate->heap()->exception(), NULL); | 996 } |
| 997 // FALLTHROUGH | |
| 998 case IMMUTABLE_CHECK_INITIALIZED: | |
| 999 if (value->IsTheHole()) { | |
| 1000 DCHECK(attributes & READ_ONLY); | |
| 1001 value = isolate->factory()->undefined_value(); | |
| 1022 } | 1002 } |
| 1023 // FALLTHROUGH | 1003 // FALLTHROUGH |
| 1024 case MUTABLE_IS_INITIALIZED: | 1004 case MUTABLE_IS_INITIALIZED: |
| 1025 case IMMUTABLE_IS_INITIALIZED: | 1005 case IMMUTABLE_IS_INITIALIZED: |
| 1026 case IMMUTABLE_IS_INITIALIZED_HARMONY: | 1006 case IMMUTABLE_IS_INITIALIZED_HARMONY: |
| 1027 DCHECK(!value->IsTheHole()); | 1007 DCHECK(!value->IsTheHole()); |
| 1028 return MakePair(value, *receiver); | 1008 if (receiver_return) *receiver_return = receiver; |
| 1029 case IMMUTABLE_CHECK_INITIALIZED: | 1009 return value; |
| 1030 if (value->IsTheHole()) { | |
| 1031 DCHECK((attributes & READ_ONLY) != 0); | |
| 1032 value = isolate->heap()->undefined_value(); | |
| 1033 } | |
| 1034 return MakePair(value, *receiver); | |
| 1035 case MISSING_BINDING: | 1010 case MISSING_BINDING: |
| 1036 UNREACHABLE(); | 1011 break; |
| 1037 return MakePair(NULL, NULL); | |
| 1038 } | 1012 } |
| 1013 UNREACHABLE(); | |
| 1039 } | 1014 } |
| 1040 | 1015 |
| 1041 // Otherwise, if the slot was found the holder is a context extension | 1016 // Otherwise, if the slot was found the holder is a context extension |
| 1042 // object, subject of a with, or a global object. We read the named | 1017 // object, subject of a with, or a global object. We read the named |
| 1043 // property from it. | 1018 // property from it. |
| 1044 if (!holder.is_null()) { | 1019 if (!holder.is_null()) { |
| 1045 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder); | |
| 1046 // GetProperty below can cause GC. | |
| 1047 Handle<Object> receiver_handle( | |
| 1048 object->IsJSGlobalObject() | |
| 1049 ? Object::cast(isolate->heap()->undefined_value()) | |
| 1050 : object->IsJSProxy() ? static_cast<Object*>(*object) | |
| 1051 : ComputeReceiverForNonGlobal( | |
| 1052 isolate, JSObject::cast(*object)), | |
| 1053 isolate); | |
| 1054 | |
| 1055 // No need to unhole the value here. This is taken care of by the | 1020 // No need to unhole the value here. This is taken care of by the |
| 1056 // GetProperty function. | 1021 // GetProperty function. |
| 1057 Handle<Object> value; | 1022 Handle<Object> value; |
| 1058 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 1023 ASSIGN_RETURN_ON_EXCEPTION( |
| 1059 isolate, value, Object::GetProperty(object, name), | 1024 isolate, value, Object::GetProperty(holder, name), |
| 1060 MakePair(isolate->heap()->exception(), NULL)); | 1025 Object); |
| 1061 return MakePair(*value, *receiver_handle); | 1026 if (receiver_return) { |
| 1027 *receiver_return = | |
| 1028 (holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject()) | |
| 1029 ? Handle<Object>::cast(isolate->factory()->undefined_value()) | |
| 1030 : holder; | |
| 1031 } | |
| 1032 return value; | |
| 1062 } | 1033 } |
| 1063 | 1034 |
| 1064 if (throw_error) { | 1035 if (should_throw == Object::THROW_ON_ERROR) { |
| 1065 // The property doesn't exist - throw exception. | 1036 // The property doesn't exist - throw exception. |
| 1066 Handle<Object> error = isolate->factory()->NewReferenceError( | 1037 THROW_NEW_ERROR( |
| 1067 MessageTemplate::kNotDefined, name); | 1038 isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object); |
| 1068 isolate->Throw(*error); | |
| 1069 return MakePair(isolate->heap()->exception(), NULL); | |
| 1070 } else { | |
| 1071 // The property doesn't exist - return undefined. | |
| 1072 return MakePair(isolate->heap()->undefined_value(), | |
| 1073 isolate->heap()->undefined_value()); | |
| 1074 } | 1039 } |
| 1040 | |
| 1041 // The property doesn't exist - return undefined. | |
| 1042 if (receiver_return) *receiver_return = isolate->factory()->undefined_value(); | |
| 1043 return isolate->factory()->undefined_value(); | |
| 1044 } | |
| 1045 | |
| 1046 } // namespace | |
| 1047 | |
| 1048 | |
| 1049 RUNTIME_FUNCTION(Runtime_LoadLookupSlot) { | |
| 1050 HandleScope scope(isolate); | |
| 1051 DCHECK_EQ(1, args.length()); | |
| 1052 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); | |
| 1053 Handle<Object> value; | |
| 1054 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1055 isolate, value, LoadLookupSlot(name, Object::THROW_ON_ERROR)); | |
| 1056 return *value; | |
| 1075 } | 1057 } |
| 1076 | 1058 |
| 1077 | 1059 |
| 1078 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlot) { | 1060 RUNTIME_FUNCTION(Runtime_LoadLookupSlotInsideTypeof) { |
| 1079 return LoadLookupSlotHelper(args, isolate, true); | 1061 HandleScope scope(isolate); |
| 1062 DCHECK_EQ(1, args.length()); | |
| 1063 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); | |
| 1064 Handle<Object> value; | |
| 1065 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 1066 isolate, value, LoadLookupSlot(name, Object::DONT_THROW)); | |
| 1067 return *value; | |
| 1080 } | 1068 } |
| 1081 | 1069 |
| 1082 | 1070 |
| 1083 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotNoReferenceError) { | 1071 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotForCall) { |
| 1084 return LoadLookupSlotHelper(args, isolate, false); | 1072 HandleScope scope(isolate); |
| 1073 DCHECK_EQ(1, args.length()); | |
| 1074 DCHECK(args[0]->IsString()); | |
| 1075 Handle<String> name = args.at<String>(0); | |
|
Michael Starzinger
2016/02/10 19:48:16
nit: Please use CONVERT_ARG_HANDLE_CHECKED(String,
Benedikt Meurer
2016/02/11 05:25:05
Not possible unfortunately until we change CONVERT
| |
| 1076 Handle<Object> value; | |
| 1077 Handle<Object> receiver; | |
| 1078 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
| 1079 isolate, value, LoadLookupSlot(name, Object::THROW_ON_ERROR, &receiver), | |
| 1080 MakePair(isolate->heap()->exception(), nullptr)); | |
| 1081 return MakePair(*value, *receiver); | |
| 1085 } | 1082 } |
| 1086 | 1083 |
| 1087 | 1084 |
| 1088 RUNTIME_FUNCTION(Runtime_StoreLookupSlot) { | 1085 namespace { |
| 1089 HandleScope scope(isolate); | |
| 1090 DCHECK(args.length() == 4); | |
| 1091 | 1086 |
| 1092 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); | 1087 MaybeHandle<Object> StoreLookupSlot(Handle<String> name, Handle<Object> value, |
| 1093 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1); | 1088 LanguageMode language_mode) { |
| 1094 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); | 1089 Isolate* const isolate = name->GetIsolate(); |
| 1095 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3); | 1090 Handle<Context> context(isolate->context(), isolate); |
| 1096 | 1091 |
| 1097 int index; | 1092 int index; |
| 1098 PropertyAttributes attributes; | 1093 PropertyAttributes attributes; |
| 1099 ContextLookupFlags flags = FOLLOW_CHAINS; | 1094 BindingFlags flags; |
| 1100 BindingFlags binding_flags; | |
| 1101 Handle<Object> holder = | 1095 Handle<Object> holder = |
| 1102 context->Lookup(name, flags, &index, &attributes, &binding_flags); | 1096 context->Lookup(name, FOLLOW_CHAINS, &index, &attributes, &flags); |
| 1103 if (holder.is_null()) { | 1097 if (holder.is_null()) { |
| 1104 // In case of JSProxy, an exception might have been thrown. | 1098 // In case of JSProxy, an exception might have been thrown. |
| 1105 if (isolate->has_pending_exception()) return isolate->heap()->exception(); | 1099 if (isolate->has_pending_exception()) return MaybeHandle<Object>(); |
| 1106 } | 1100 } |
| 1107 | 1101 |
| 1108 // The property was found in a context slot. | 1102 // The property was found in a context slot. |
| 1109 if (index != Context::kNotFound) { | 1103 if (index != Context::kNotFound) { |
| 1110 if ((binding_flags == MUTABLE_CHECK_INITIALIZED || | 1104 if ((flags == MUTABLE_CHECK_INITIALIZED || |
| 1111 binding_flags == IMMUTABLE_CHECK_INITIALIZED_HARMONY) && | 1105 flags == IMMUTABLE_CHECK_INITIALIZED_HARMONY) && |
| 1112 Handle<Context>::cast(holder)->is_the_hole(index)) { | 1106 Handle<Context>::cast(holder)->is_the_hole(index)) { |
| 1113 THROW_NEW_ERROR_RETURN_FAILURE( | 1107 THROW_NEW_ERROR(isolate, |
| 1114 isolate, NewReferenceError(MessageTemplate::kNotDefined, name)); | 1108 NewReferenceError(MessageTemplate::kNotDefined, name), |
| 1109 Object); | |
| 1115 } | 1110 } |
| 1116 if ((attributes & READ_ONLY) == 0) { | 1111 if ((attributes & READ_ONLY) == 0) { |
| 1117 Handle<Context>::cast(holder)->set(index, *value); | 1112 Handle<Context>::cast(holder)->set(index, *value); |
| 1118 } else if (is_strict(language_mode)) { | 1113 } else if (is_strict(language_mode)) { |
| 1119 // Setting read only property in strict mode. | 1114 // Setting read only property in strict mode. |
| 1120 THROW_NEW_ERROR_RETURN_FAILURE( | 1115 THROW_NEW_ERROR(isolate, |
| 1121 isolate, NewTypeError(MessageTemplate::kStrictCannotAssign, name)); | 1116 NewTypeError(MessageTemplate::kStrictCannotAssign, name), |
| 1117 Object); | |
| 1122 } | 1118 } |
| 1123 return *value; | 1119 return value; |
| 1124 } | 1120 } |
| 1125 | 1121 |
| 1126 // Slow case: The property is not in a context slot. It is either in a | 1122 // Slow case: The property is not in a context slot. It is either in a |
| 1127 // context extension object, a property of the subject of a with, or a | 1123 // context extension object, a property of the subject of a with, or a |
| 1128 // property of the global object. | 1124 // property of the global object. |
| 1129 Handle<JSReceiver> object; | 1125 Handle<JSReceiver> object; |
| 1130 if (attributes != ABSENT) { | 1126 if (attributes != ABSENT) { |
| 1131 // The property exists on the holder. | 1127 // The property exists on the holder. |
| 1132 object = Handle<JSReceiver>::cast(holder); | 1128 object = Handle<JSReceiver>::cast(holder); |
| 1133 } else if (is_strict(language_mode)) { | 1129 } else if (is_strict(language_mode)) { |
| 1134 // If absent in strict mode: throw. | 1130 // If absent in strict mode: throw. |
| 1135 THROW_NEW_ERROR_RETURN_FAILURE( | 1131 THROW_NEW_ERROR( |
| 1136 isolate, NewReferenceError(MessageTemplate::kNotDefined, name)); | 1132 isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object); |
| 1137 } else { | 1133 } else { |
| 1138 // If absent in sloppy mode: add the property to the global object. | 1134 // If absent in sloppy mode: add the property to the global object. |
| 1139 object = Handle<JSReceiver>(context->global_object()); | 1135 object = Handle<JSReceiver>(context->global_object()); |
| 1140 } | 1136 } |
| 1141 | 1137 |
| 1142 RETURN_FAILURE_ON_EXCEPTION( | 1138 ASSIGN_RETURN_ON_EXCEPTION( |
| 1143 isolate, Object::SetProperty(object, name, value, language_mode)); | 1139 isolate, value, Object::SetProperty(object, name, value, language_mode), |
| 1140 Object); | |
| 1141 return value; | |
| 1142 } | |
| 1144 | 1143 |
| 1144 } // namespace | |
| 1145 | |
| 1146 | |
| 1147 RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Sloppy) { | |
| 1148 HandleScope scope(isolate); | |
| 1149 DCHECK_EQ(2, args.length()); | |
| 1150 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); | |
| 1151 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); | |
| 1152 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, | |
| 1153 StoreLookupSlot(name, value, SLOPPY)); | |
| 1145 return *value; | 1154 return *value; |
| 1146 } | 1155 } |
| 1147 | 1156 |
| 1157 | |
| 1158 RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict) { | |
| 1159 HandleScope scope(isolate); | |
| 1160 DCHECK_EQ(2, args.length()); | |
| 1161 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); | |
| 1162 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); | |
| 1163 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, | |
| 1164 StoreLookupSlot(name, value, STRICT)); | |
| 1165 return *value; | |
| 1166 } | |
| 1167 | |
| 1148 | 1168 |
| 1149 RUNTIME_FUNCTION(Runtime_ArgumentsLength) { | 1169 RUNTIME_FUNCTION(Runtime_ArgumentsLength) { |
| 1150 HandleScope scope(isolate); | 1170 HandleScope scope(isolate); |
| 1151 DCHECK(args.length() == 0); | 1171 DCHECK(args.length() == 0); |
| 1152 int argument_count = 0; | 1172 int argument_count = 0; |
| 1153 GetCallerArguments(isolate, &argument_count); | 1173 GetCallerArguments(isolate, &argument_count); |
| 1154 return Smi::FromInt(argument_count); | 1174 return Smi::FromInt(argument_count); |
| 1155 } | 1175 } |
| 1156 | 1176 |
| 1157 | 1177 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1223 | 1243 |
| 1224 // Lookup in the initial Object.prototype object. | 1244 // Lookup in the initial Object.prototype object. |
| 1225 Handle<Object> result; | 1245 Handle<Object> result; |
| 1226 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 1246 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1227 isolate, result, | 1247 isolate, result, |
| 1228 Object::GetProperty(isolate->initial_object_prototype(), key)); | 1248 Object::GetProperty(isolate->initial_object_prototype(), key)); |
| 1229 return *result; | 1249 return *result; |
| 1230 } | 1250 } |
| 1231 } // namespace internal | 1251 } // namespace internal |
| 1232 } // namespace v8 | 1252 } // namespace v8 |
| OLD | NEW |